Merge branch 'fixes' of git://git.linux-nfs.org/pub/linux/nfs-2.6

This commit is contained in:
Greg Kroah-Hartman 2006-08-24 22:29:46 -07:00
commit 62250b3bb5
14 changed files with 125 additions and 90 deletions

View File

@ -486,8 +486,6 @@ struct file *open_exec(const char *name)
if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
S_ISREG(inode->i_mode)) { S_ISREG(inode->i_mode)) {
int err = vfs_permission(&nd, MAY_EXEC); int err = vfs_permission(&nd, MAY_EXEC);
if (!err && !(inode->i_mode & 0111))
err = -EACCES;
file = ERR_PTR(err); file = ERR_PTR(err);
if (!err) { if (!err) {
file = nameidata_to_filp(&nd, O_RDONLY); file = nameidata_to_filp(&nd, O_RDONLY);
@ -922,12 +920,6 @@ int prepare_binprm(struct linux_binprm *bprm)
int retval; int retval;
mode = inode->i_mode; mode = inode->i_mode;
/*
* Check execute perms again - if the caller has CAP_DAC_OVERRIDE,
* generic_permission lets a non-executable through
*/
if (!(mode & 0111)) /* with at least _one_ execute bit set */
return -EACCES;
if (bprm->file->f_op == NULL) if (bprm->file->f_op == NULL)
return -EACCES; return -EACCES;

View File

@ -237,19 +237,22 @@ static int
nlm_traverse_files(struct nlm_host *host, int action) nlm_traverse_files(struct nlm_host *host, int action)
{ {
struct nlm_file *file, **fp; struct nlm_file *file, **fp;
int i; int i, ret = 0;
mutex_lock(&nlm_file_mutex); mutex_lock(&nlm_file_mutex);
for (i = 0; i < FILE_NRHASH; i++) { for (i = 0; i < FILE_NRHASH; i++) {
fp = nlm_files + i; fp = nlm_files + i;
while ((file = *fp) != NULL) { while ((file = *fp) != NULL) {
file->f_count++;
mutex_unlock(&nlm_file_mutex);
/* Traverse locks, blocks and shares of this file /* Traverse locks, blocks and shares of this file
* and update file->f_locks count */ * and update file->f_locks count */
if (nlm_inspect_file(host, file, action)) { if (nlm_inspect_file(host, file, action))
mutex_unlock(&nlm_file_mutex); ret = 1;
return 1;
}
mutex_lock(&nlm_file_mutex);
file->f_count--;
/* No more references to this file. Let go of it. */ /* No more references to this file. Let go of it. */
if (!file->f_blocks && !file->f_locks if (!file->f_blocks && !file->f_locks
&& !file->f_shares && !file->f_count) { && !file->f_shares && !file->f_count) {
@ -262,7 +265,7 @@ nlm_traverse_files(struct nlm_host *host, int action)
} }
} }
mutex_unlock(&nlm_file_mutex); mutex_unlock(&nlm_file_mutex);
return 0; return ret;
} }
/* /*

View File

@ -227,10 +227,10 @@ int generic_permission(struct inode *inode, int mask,
int permission(struct inode *inode, int mask, struct nameidata *nd) int permission(struct inode *inode, int mask, struct nameidata *nd)
{ {
umode_t mode = inode->i_mode;
int retval, submask; int retval, submask;
if (mask & MAY_WRITE) { if (mask & MAY_WRITE) {
umode_t mode = inode->i_mode;
/* /*
* Nobody gets write access to a read-only fs. * Nobody gets write access to a read-only fs.
@ -247,6 +247,13 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
} }
/*
* MAY_EXEC on regular files requires special handling: We override
* filesystem execute permissions if the mode bits aren't set.
*/
if ((mask & MAY_EXEC) && S_ISREG(mode) && !(mode & S_IXUGO))
return -EACCES;
/* Ordinary permission routines do not understand MAY_APPEND. */ /* Ordinary permission routines do not understand MAY_APPEND. */
submask = mask & ~MAY_APPEND; submask = mask & ~MAY_APPEND;
if (inode->i_op && inode->i_op->permission) if (inode->i_op && inode->i_op->permission)
@ -1767,6 +1774,8 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
if (nd->last_type != LAST_NORM) if (nd->last_type != LAST_NORM)
goto fail; goto fail;
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
nd->flags |= LOOKUP_CREATE;
nd->intent.open.flags = O_EXCL;
/* /*
* Do the final lookup. * Do the final lookup.

View File

@ -312,7 +312,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
static int nfs_release_page(struct page *page, gfp_t gfp) static int nfs_release_page(struct page *page, gfp_t gfp)
{ {
return !nfs_wb_page(page->mapping->host, page); if (gfp & __GFP_FS)
return !nfs_wb_page(page->mapping->host, page);
else
/*
* Avoid deadlock on nfs_wait_on_request().
*/
return 0;
} }
const struct address_space_operations nfs_file_aops = { const struct address_space_operations nfs_file_aops = {

View File

@ -130,9 +130,7 @@ nfs_idmap_delete(struct nfs4_client *clp)
if (!idmap) if (!idmap)
return; return;
dput(idmap->idmap_dentry); rpc_unlink(idmap->idmap_dentry);
idmap->idmap_dentry = NULL;
rpc_unlink(idmap->idmap_path);
clp->cl_idmap = NULL; clp->cl_idmap = NULL;
kfree(idmap); kfree(idmap);
} }

View File

@ -2668,7 +2668,7 @@ static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t a
nfs4_set_cached_acl(inode, acl); nfs4_set_cached_acl(inode, acl);
} }
static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
{ {
struct page *pages[NFS4ACL_MAXPAGES]; struct page *pages[NFS4ACL_MAXPAGES];
struct nfs_getaclargs args = { struct nfs_getaclargs args = {
@ -2721,6 +2721,19 @@ static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size
return ret; return ret;
} }
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
{
struct nfs4_exception exception = { };
ssize_t ret;
do {
ret = __nfs4_get_acl_uncached(inode, buf, buflen);
if (ret >= 0)
break;
ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
} while (exception.retry);
return ret;
}
static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
@ -2737,7 +2750,7 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
return nfs4_get_acl_uncached(inode, buf, buflen); return nfs4_get_acl_uncached(inode, buf, buflen);
} }
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct page *pages[NFS4ACL_MAXPAGES]; struct page *pages[NFS4ACL_MAXPAGES];
@ -2763,6 +2776,18 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
return ret; return ret;
} }
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(inode),
__nfs4_proc_set_acl(inode, buf, buflen),
&exception);
} while (exception.retry);
return err;
}
static int static int
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
{ {

View File

@ -3355,7 +3355,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
struct kvec *iov = rcvbuf->head; struct kvec *iov = rcvbuf->head;
unsigned int nr, pglen = rcvbuf->page_len; unsigned int nr, pglen = rcvbuf->page_len;
uint32_t *end, *entry, *p, *kaddr; uint32_t *end, *entry, *p, *kaddr;
uint32_t len, attrlen; uint32_t len, attrlen, xlen;
int hdrlen, recvd, status; int hdrlen, recvd, status;
status = decode_op_hdr(xdr, OP_READDIR); status = decode_op_hdr(xdr, OP_READDIR);
@ -3377,10 +3377,10 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0); kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
end = (uint32_t *) ((char *)p + pglen + readdir->pgbase); end = p + ((pglen + readdir->pgbase) >> 2);
entry = p; entry = p;
for (nr = 0; *p++; nr++) { for (nr = 0; *p++; nr++) {
if (p + 3 > end) if (end - p < 3)
goto short_pkt; goto short_pkt;
dprintk("cookie = %Lu, ", *((unsigned long long *)p)); dprintk("cookie = %Lu, ", *((unsigned long long *)p));
p += 2; /* cookie */ p += 2; /* cookie */
@ -3389,18 +3389,19 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
goto err_unmap; goto err_unmap;
} }
xlen = XDR_QUADLEN(len);
if (end - p < xlen + 1)
goto short_pkt;
dprintk("filename = %*s\n", len, (char *)p); dprintk("filename = %*s\n", len, (char *)p);
p += XDR_QUADLEN(len); p += xlen;
if (p + 1 > end)
goto short_pkt;
len = ntohl(*p++); /* bitmap length */ len = ntohl(*p++); /* bitmap length */
if (end - p < len + 1)
goto short_pkt;
p += len; p += len;
if (p + 1 > end)
goto short_pkt;
attrlen = XDR_QUADLEN(ntohl(*p++)); attrlen = XDR_QUADLEN(ntohl(*p++));
p += attrlen; /* attributes */ if (end - p < attrlen + 2)
if (p + 2 > end)
goto short_pkt; goto short_pkt;
p += attrlen; /* attributes */
entry = p; entry = p;
} }
if (!nr && (entry[0] != 0 || entry[1] == 0)) if (!nr && (entry[0] != 0 || entry[1] == 0))

View File

@ -116,10 +116,17 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
base &= ~PAGE_CACHE_MASK; base &= ~PAGE_CACHE_MASK;
pglen = PAGE_CACHE_SIZE - base; pglen = PAGE_CACHE_SIZE - base;
if (pglen < remainder) for (;;) {
if (remainder <= pglen) {
memclear_highpage_flush(*pages, base, remainder);
break;
}
memclear_highpage_flush(*pages, base, pglen); memclear_highpage_flush(*pages, base, pglen);
else pages++;
memclear_highpage_flush(*pages, base, remainder); remainder -= pglen;
pglen = PAGE_CACHE_SIZE;
base = 0;
}
} }
/* /*
@ -476,6 +483,8 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
unsigned int base = data->args.pgbase; unsigned int base = data->args.pgbase;
struct page **pages; struct page **pages;
if (data->res.eof)
count = data->args.count;
if (unlikely(count == 0)) if (unlikely(count == 0))
return; return;
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
@ -483,11 +492,7 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
count += base; count += base;
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
SetPageUptodate(*pages); SetPageUptodate(*pages);
/* if (count != 0)
* Was this an eof or a short read? If the latter, don't mark the page
* as uptodate yet.
*/
if (count > 0 && (data->res.eof || data->args.count == data->res.count))
SetPageUptodate(*pages); SetPageUptodate(*pages);
} }
@ -502,6 +507,8 @@ static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
count += base; count += base;
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
SetPageError(*pages); SetPageError(*pages);
if (count != 0)
SetPageError(*pages);
} }
/* /*

View File

@ -659,7 +659,7 @@ struct nfs4_rename_res {
struct nfs4_setclientid { struct nfs4_setclientid {
const nfs4_verifier * sc_verifier; /* request */ const nfs4_verifier * sc_verifier; /* request */
unsigned int sc_name_len; unsigned int sc_name_len;
char sc_name[32]; /* request */ char sc_name[48]; /* request */
u32 sc_prog; /* request */ u32 sc_prog; /* request */
unsigned int sc_netid_len; unsigned int sc_netid_len;
char sc_netid[4]; /* request */ char sc_netid[4]; /* request */

View File

@ -42,9 +42,9 @@ RPC_I(struct inode *inode)
extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
extern int rpc_rmdir(char *); extern int rpc_rmdir(struct dentry *);
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
extern int rpc_unlink(char *); extern int rpc_unlink(struct dentry *);
extern struct vfsmount *rpc_get_mount(void); extern struct vfsmount *rpc_get_mount(void);
extern void rpc_put_mount(void); extern void rpc_put_mount(void);

View File

@ -37,7 +37,7 @@ extern unsigned int xprt_max_resvport;
#define RPC_MIN_RESVPORT (1U) #define RPC_MIN_RESVPORT (1U)
#define RPC_MAX_RESVPORT (65535U) #define RPC_MAX_RESVPORT (65535U)
#define RPC_DEF_MIN_RESVPORT (650U) #define RPC_DEF_MIN_RESVPORT (665U)
#define RPC_DEF_MAX_RESVPORT (1023U) #define RPC_DEF_MAX_RESVPORT (1023U)
/* /*

View File

@ -718,8 +718,7 @@ gss_destroy(struct rpc_auth *auth)
auth, auth->au_flavor); auth, auth->au_flavor);
gss_auth = container_of(auth, struct gss_auth, rpc_auth); gss_auth = container_of(auth, struct gss_auth, rpc_auth);
rpc_unlink(gss_auth->path); rpc_unlink(gss_auth->dentry);
dput(gss_auth->dentry);
gss_auth->dentry = NULL; gss_auth->dentry = NULL;
gss_mech_put(gss_auth->mech); gss_mech_put(gss_auth->mech);

View File

@ -183,8 +183,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
out_no_auth: out_no_auth:
if (!IS_ERR(clnt->cl_dentry)) { if (!IS_ERR(clnt->cl_dentry)) {
rpc_rmdir(clnt->cl_pathname); rpc_rmdir(clnt->cl_dentry);
dput(clnt->cl_dentry);
rpc_put_mount(); rpc_put_mount();
} }
out_no_path: out_no_path:
@ -251,10 +250,8 @@ rpc_clone_client(struct rpc_clnt *clnt)
new->cl_autobind = 0; new->cl_autobind = 0;
new->cl_oneshot = 0; new->cl_oneshot = 0;
new->cl_dead = 0; new->cl_dead = 0;
if (!IS_ERR(new->cl_dentry)) { if (!IS_ERR(new->cl_dentry))
dget(new->cl_dentry); dget(new->cl_dentry);
rpc_get_mount();
}
rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
if (new->cl_auth) if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count); atomic_inc(&new->cl_auth->au_count);
@ -317,11 +314,15 @@ rpc_destroy_client(struct rpc_clnt *clnt)
clnt->cl_auth = NULL; clnt->cl_auth = NULL;
} }
if (clnt->cl_parent != clnt) { if (clnt->cl_parent != clnt) {
if (!IS_ERR(clnt->cl_dentry))
dput(clnt->cl_dentry);
rpc_destroy_client(clnt->cl_parent); rpc_destroy_client(clnt->cl_parent);
goto out_free; goto out_free;
} }
if (clnt->cl_pathname[0]) if (!IS_ERR(clnt->cl_dentry)) {
rpc_rmdir(clnt->cl_pathname); rpc_rmdir(clnt->cl_dentry);
rpc_put_mount();
}
if (clnt->cl_xprt) { if (clnt->cl_xprt) {
xprt_destroy(clnt->cl_xprt); xprt_destroy(clnt->cl_xprt);
clnt->cl_xprt = NULL; clnt->cl_xprt = NULL;
@ -331,10 +332,6 @@ rpc_destroy_client(struct rpc_clnt *clnt)
out_free: out_free:
rpc_free_iostats(clnt->cl_metrics); rpc_free_iostats(clnt->cl_metrics);
clnt->cl_metrics = NULL; clnt->cl_metrics = NULL;
if (!IS_ERR(clnt->cl_dentry)) {
dput(clnt->cl_dentry);
rpc_put_mount();
}
kfree(clnt); kfree(clnt);
return 0; return 0;
} }
@ -1184,6 +1181,17 @@ call_verify(struct rpc_task *task)
u32 *p = iov->iov_base, n; u32 *p = iov->iov_base, n;
int error = -EACCES; int error = -EACCES;
if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
/* RFC-1014 says that the representation of XDR data must be a
* multiple of four bytes
* - if it isn't pointer subtraction in the NFS client may give
* undefined results
*/
printk(KERN_WARNING
"call_verify: XDR representation not a multiple of"
" 4 bytes: 0x%x\n", task->tk_rqstp->rq_rcv_buf.len);
goto out_eio;
}
if ((len -= 3) < 0) if ((len -= 3) < 0)
goto out_overflow; goto out_overflow;
p += 1; /* skip XID */ p += 1; /* skip XID */

View File

@ -539,6 +539,7 @@ rpc_depopulate(struct dentry *parent)
rpc_close_pipes(dentry->d_inode); rpc_close_pipes(dentry->d_inode);
simple_unlink(dir, dentry); simple_unlink(dir, dentry);
} }
inode_dir_notify(dir, DN_DELETE);
dput(dentry); dput(dentry);
} while (n); } while (n);
goto repeat; goto repeat;
@ -610,8 +611,8 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
int error; int error;
shrink_dcache_parent(dentry); shrink_dcache_parent(dentry);
if (dentry->d_inode) if (d_unhashed(dentry))
rpc_close_pipes(dentry->d_inode); return 0;
if ((error = simple_rmdir(dir, dentry)) != 0) if ((error = simple_rmdir(dir, dentry)) != 0)
return error; return error;
if (!error) { if (!error) {
@ -684,28 +685,20 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
} }
int int
rpc_rmdir(char *path) rpc_rmdir(struct dentry *dentry)
{ {
struct nameidata nd; struct dentry *parent;
struct dentry *dentry;
struct inode *dir; struct inode *dir;
int error; int error;
if ((error = rpc_lookup_parent(path, &nd)) != 0) parent = dget_parent(dentry);
return error; dir = parent->d_inode;
dir = nd.dentry->d_inode;
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_release;
}
rpc_depopulate(dentry); rpc_depopulate(dentry);
error = __rpc_rmdir(dir, dentry); error = __rpc_rmdir(dir, dentry);
dput(dentry); dput(dentry);
out_release:
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd); dput(parent);
return error; return error;
} }
@ -746,32 +739,26 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
} }
int int
rpc_unlink(char *path) rpc_unlink(struct dentry *dentry)
{ {
struct nameidata nd; struct dentry *parent;
struct dentry *dentry;
struct inode *dir; struct inode *dir;
int error; int error = 0;
if ((error = rpc_lookup_parent(path, &nd)) != 0) parent = dget_parent(dentry);
return error; dir = parent->d_inode;
dir = nd.dentry->d_inode;
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); if (!d_unhashed(dentry)) {
if (IS_ERR(dentry)) { d_drop(dentry);
error = PTR_ERR(dentry); if (dentry->d_inode) {
goto out_release; rpc_close_pipes(dentry->d_inode);
} error = simple_unlink(dir, dentry);
d_drop(dentry); }
if (dentry->d_inode) { inode_dir_notify(dir, DN_DELETE);
rpc_close_pipes(dentry->d_inode);
error = simple_unlink(dir, dentry);
} }
dput(dentry); dput(dentry);
inode_dir_notify(dir, DN_DELETE);
out_release:
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd); dput(parent);
return error; return error;
} }