diff options
| -rw-r--r-- | fs/exec.c | 8 | ||||
| -rw-r--r-- | fs/lockd/svcsubs.c | 15 | ||||
| -rw-r--r-- | fs/namei.c | 11 | ||||
| -rw-r--r-- | fs/nfs/file.c | 8 | ||||
| -rw-r--r-- | fs/nfs/idmap.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 29 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 21 | ||||
| -rw-r--r-- | fs/nfs/read.c | 23 | ||||
| -rw-r--r-- | include/linux/nfs_xdr.h | 2 | ||||
| -rw-r--r-- | include/linux/sunrpc/rpc_pipe_fs.h | 4 | ||||
| -rw-r--r-- | include/linux/sunrpc/xprt.h | 2 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 3 | ||||
| -rw-r--r-- | net/sunrpc/clnt.c | 30 | ||||
| -rw-r--r-- | net/sunrpc/rpc_pipe.c | 55 |
14 files changed, 125 insertions, 90 deletions
| @@ -486,8 +486,6 @@ struct file *open_exec(const char *name) | |||
| 486 | if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && | 486 | if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && |
| 487 | S_ISREG(inode->i_mode)) { | 487 | S_ISREG(inode->i_mode)) { |
| 488 | int err = vfs_permission(&nd, MAY_EXEC); | 488 | int err = vfs_permission(&nd, MAY_EXEC); |
| 489 | if (!err && !(inode->i_mode & 0111)) | ||
| 490 | err = -EACCES; | ||
| 491 | file = ERR_PTR(err); | 489 | file = ERR_PTR(err); |
| 492 | if (!err) { | 490 | if (!err) { |
| 493 | file = nameidata_to_filp(&nd, O_RDONLY); | 491 | file = nameidata_to_filp(&nd, O_RDONLY); |
| @@ -922,12 +920,6 @@ int prepare_binprm(struct linux_binprm *bprm) | |||
| 922 | int retval; | 920 | int retval; |
| 923 | 921 | ||
| 924 | mode = inode->i_mode; | 922 | mode = inode->i_mode; |
| 925 | /* | ||
| 926 | * Check execute perms again - if the caller has CAP_DAC_OVERRIDE, | ||
| 927 | * generic_permission lets a non-executable through | ||
| 928 | */ | ||
| 929 | if (!(mode & 0111)) /* with at least _one_ execute bit set */ | ||
| 930 | return -EACCES; | ||
| 931 | if (bprm->file->f_op == NULL) | 923 | if (bprm->file->f_op == NULL) |
| 932 | return -EACCES; | 924 | return -EACCES; |
| 933 | 925 | ||
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 2a4df9b3779a..01b4db9e5466 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
| @@ -237,19 +237,22 @@ static int | |||
| 237 | nlm_traverse_files(struct nlm_host *host, int action) | 237 | nlm_traverse_files(struct nlm_host *host, int action) |
| 238 | { | 238 | { |
| 239 | struct nlm_file *file, **fp; | 239 | struct nlm_file *file, **fp; |
| 240 | int i; | 240 | int i, ret = 0; |
| 241 | 241 | ||
| 242 | mutex_lock(&nlm_file_mutex); | 242 | mutex_lock(&nlm_file_mutex); |
| 243 | for (i = 0; i < FILE_NRHASH; i++) { | 243 | for (i = 0; i < FILE_NRHASH; i++) { |
| 244 | fp = nlm_files + i; | 244 | fp = nlm_files + i; |
| 245 | while ((file = *fp) != NULL) { | 245 | while ((file = *fp) != NULL) { |
| 246 | file->f_count++; | ||
| 247 | mutex_unlock(&nlm_file_mutex); | ||
| 248 | |||
| 246 | /* Traverse locks, blocks and shares of this file | 249 | /* Traverse locks, blocks and shares of this file |
| 247 | * and update file->f_locks count */ | 250 | * and update file->f_locks count */ |
| 248 | if (nlm_inspect_file(host, file, action)) { | 251 | if (nlm_inspect_file(host, file, action)) |
| 249 | mutex_unlock(&nlm_file_mutex); | 252 | ret = 1; |
| 250 | return 1; | ||
| 251 | } | ||
| 252 | 253 | ||
| 254 | mutex_lock(&nlm_file_mutex); | ||
| 255 | file->f_count--; | ||
| 253 | /* No more references to this file. Let go of it. */ | 256 | /* No more references to this file. Let go of it. */ |
| 254 | if (!file->f_blocks && !file->f_locks | 257 | if (!file->f_blocks && !file->f_locks |
| 255 | && !file->f_shares && !file->f_count) { | 258 | && !file->f_shares && !file->f_count) { |
| @@ -262,7 +265,7 @@ nlm_traverse_files(struct nlm_host *host, int action) | |||
| 262 | } | 265 | } |
| 263 | } | 266 | } |
| 264 | mutex_unlock(&nlm_file_mutex); | 267 | mutex_unlock(&nlm_file_mutex); |
| 265 | return 0; | 268 | return ret; |
| 266 | } | 269 | } |
| 267 | 270 | ||
| 268 | /* | 271 | /* |
diff --git a/fs/namei.c b/fs/namei.c index 55a131230f94..432d6bc6fab0 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -227,10 +227,10 @@ int generic_permission(struct inode *inode, int mask, | |||
| 227 | 227 | ||
| 228 | int permission(struct inode *inode, int mask, struct nameidata *nd) | 228 | int permission(struct inode *inode, int mask, struct nameidata *nd) |
| 229 | { | 229 | { |
| 230 | umode_t mode = inode->i_mode; | ||
| 230 | int retval, submask; | 231 | int retval, submask; |
| 231 | 232 | ||
| 232 | if (mask & MAY_WRITE) { | 233 | if (mask & MAY_WRITE) { |
| 233 | umode_t mode = inode->i_mode; | ||
| 234 | 234 | ||
| 235 | /* | 235 | /* |
| 236 | * Nobody gets write access to a read-only fs. | 236 | * Nobody gets write access to a read-only fs. |
| @@ -247,6 +247,13 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | 249 | ||
| 250 | /* | ||
| 251 | * MAY_EXEC on regular files requires special handling: We override | ||
| 252 | * filesystem execute permissions if the mode bits aren't set. | ||
| 253 | */ | ||
| 254 | if ((mask & MAY_EXEC) && S_ISREG(mode) && !(mode & S_IXUGO)) | ||
| 255 | return -EACCES; | ||
| 256 | |||
| 250 | /* Ordinary permission routines do not understand MAY_APPEND. */ | 257 | /* Ordinary permission routines do not understand MAY_APPEND. */ |
| 251 | submask = mask & ~MAY_APPEND; | 258 | submask = mask & ~MAY_APPEND; |
| 252 | if (inode->i_op && inode->i_op->permission) | 259 | if (inode->i_op && inode->i_op->permission) |
| @@ -1767,6 +1774,8 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir) | |||
| 1767 | if (nd->last_type != LAST_NORM) | 1774 | if (nd->last_type != LAST_NORM) |
| 1768 | goto fail; | 1775 | goto fail; |
| 1769 | nd->flags &= ~LOOKUP_PARENT; | 1776 | nd->flags &= ~LOOKUP_PARENT; |
| 1777 | nd->flags |= LOOKUP_CREATE; | ||
| 1778 | nd->intent.open.flags = O_EXCL; | ||
| 1770 | 1779 | ||
| 1771 | /* | 1780 | /* |
| 1772 | * Do the final lookup. | 1781 | * Do the final lookup. |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index cc2b874ad5a4..48e892880d5b 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -312,7 +312,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) | |||
| 312 | 312 | ||
| 313 | static int nfs_release_page(struct page *page, gfp_t gfp) | 313 | static int nfs_release_page(struct page *page, gfp_t gfp) |
| 314 | { | 314 | { |
| 315 | return !nfs_wb_page(page->mapping->host, page); | 315 | if (gfp & __GFP_FS) |
| 316 | return !nfs_wb_page(page->mapping->host, page); | ||
| 317 | else | ||
| 318 | /* | ||
| 319 | * Avoid deadlock on nfs_wait_on_request(). | ||
| 320 | */ | ||
| 321 | return 0; | ||
| 316 | } | 322 | } |
| 317 | 323 | ||
| 318 | const struct address_space_operations nfs_file_aops = { | 324 | const struct address_space_operations nfs_file_aops = { |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index b81e7ed3c902..07a5dd57646e 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
| @@ -130,9 +130,7 @@ nfs_idmap_delete(struct nfs4_client *clp) | |||
| 130 | 130 | ||
| 131 | if (!idmap) | 131 | if (!idmap) |
| 132 | return; | 132 | return; |
| 133 | dput(idmap->idmap_dentry); | 133 | rpc_unlink(idmap->idmap_dentry); |
| 134 | idmap->idmap_dentry = NULL; | ||
| 135 | rpc_unlink(idmap->idmap_path); | ||
| 136 | clp->cl_idmap = NULL; | 134 | clp->cl_idmap = NULL; |
| 137 | kfree(idmap); | 135 | kfree(idmap); |
| 138 | } | 136 | } |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index e6ee97f19d81..153898e1331f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -2668,7 +2668,7 @@ out: | |||
| 2668 | nfs4_set_cached_acl(inode, acl); | 2668 | nfs4_set_cached_acl(inode, acl); |
| 2669 | } | 2669 | } |
| 2670 | 2670 | ||
| 2671 | static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | 2671 | static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) |
| 2672 | { | 2672 | { |
| 2673 | struct page *pages[NFS4ACL_MAXPAGES]; | 2673 | struct page *pages[NFS4ACL_MAXPAGES]; |
| 2674 | struct nfs_getaclargs args = { | 2674 | struct nfs_getaclargs args = { |
| @@ -2721,6 +2721,19 @@ out_free: | |||
| 2721 | return ret; | 2721 | return ret; |
| 2722 | } | 2722 | } |
| 2723 | 2723 | ||
| 2724 | static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) | ||
| 2725 | { | ||
| 2726 | struct nfs4_exception exception = { }; | ||
| 2727 | ssize_t ret; | ||
| 2728 | do { | ||
| 2729 | ret = __nfs4_get_acl_uncached(inode, buf, buflen); | ||
| 2730 | if (ret >= 0) | ||
| 2731 | break; | ||
| 2732 | ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception); | ||
| 2733 | } while (exception.retry); | ||
| 2734 | return ret; | ||
| 2735 | } | ||
| 2736 | |||
| 2724 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | 2737 | static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) |
| 2725 | { | 2738 | { |
| 2726 | struct nfs_server *server = NFS_SERVER(inode); | 2739 | 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) | |||
| 2737 | return nfs4_get_acl_uncached(inode, buf, buflen); | 2750 | return nfs4_get_acl_uncached(inode, buf, buflen); |
| 2738 | } | 2751 | } |
| 2739 | 2752 | ||
| 2740 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | 2753 | static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) |
| 2741 | { | 2754 | { |
| 2742 | struct nfs_server *server = NFS_SERVER(inode); | 2755 | struct nfs_server *server = NFS_SERVER(inode); |
| 2743 | struct page *pages[NFS4ACL_MAXPAGES]; | 2756 | struct page *pages[NFS4ACL_MAXPAGES]; |
| @@ -2763,6 +2776,18 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
| 2763 | return ret; | 2776 | return ret; |
| 2764 | } | 2777 | } |
| 2765 | 2778 | ||
| 2779 | static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) | ||
| 2780 | { | ||
| 2781 | struct nfs4_exception exception = { }; | ||
| 2782 | int err; | ||
| 2783 | do { | ||
| 2784 | err = nfs4_handle_exception(NFS_SERVER(inode), | ||
| 2785 | __nfs4_proc_set_acl(inode, buf, buflen), | ||
| 2786 | &exception); | ||
| 2787 | } while (exception.retry); | ||
| 2788 | return err; | ||
| 2789 | } | ||
| 2790 | |||
| 2766 | static int | 2791 | static int |
| 2767 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | 2792 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) |
| 2768 | { | 2793 | { |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1750d996f49f..730ec8fb31c6 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -3355,7 +3355,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
| 3355 | struct kvec *iov = rcvbuf->head; | 3355 | struct kvec *iov = rcvbuf->head; |
| 3356 | unsigned int nr, pglen = rcvbuf->page_len; | 3356 | unsigned int nr, pglen = rcvbuf->page_len; |
| 3357 | uint32_t *end, *entry, *p, *kaddr; | 3357 | uint32_t *end, *entry, *p, *kaddr; |
| 3358 | uint32_t len, attrlen; | 3358 | uint32_t len, attrlen, xlen; |
| 3359 | int hdrlen, recvd, status; | 3359 | int hdrlen, recvd, status; |
| 3360 | 3360 | ||
| 3361 | status = decode_op_hdr(xdr, OP_READDIR); | 3361 | 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 | |||
| 3377 | 3377 | ||
| 3378 | BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); | 3378 | BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE); |
| 3379 | kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0); | 3379 | kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0); |
| 3380 | end = (uint32_t *) ((char *)p + pglen + readdir->pgbase); | 3380 | end = p + ((pglen + readdir->pgbase) >> 2); |
| 3381 | entry = p; | 3381 | entry = p; |
| 3382 | for (nr = 0; *p++; nr++) { | 3382 | for (nr = 0; *p++; nr++) { |
| 3383 | if (p + 3 > end) | 3383 | if (end - p < 3) |
| 3384 | goto short_pkt; | 3384 | goto short_pkt; |
| 3385 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); | 3385 | dprintk("cookie = %Lu, ", *((unsigned long long *)p)); |
| 3386 | p += 2; /* cookie */ | 3386 | p += 2; /* cookie */ |
| @@ -3389,18 +3389,19 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
| 3389 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); | 3389 | printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len); |
| 3390 | goto err_unmap; | 3390 | goto err_unmap; |
| 3391 | } | 3391 | } |
| 3392 | dprintk("filename = %*s\n", len, (char *)p); | 3392 | xlen = XDR_QUADLEN(len); |
| 3393 | p += XDR_QUADLEN(len); | 3393 | if (end - p < xlen + 1) |
| 3394 | if (p + 1 > end) | ||
| 3395 | goto short_pkt; | 3394 | goto short_pkt; |
| 3395 | dprintk("filename = %*s\n", len, (char *)p); | ||
| 3396 | p += xlen; | ||
| 3396 | len = ntohl(*p++); /* bitmap length */ | 3397 | len = ntohl(*p++); /* bitmap length */ |
| 3397 | p += len; | 3398 | if (end - p < len + 1) |
| 3398 | if (p + 1 > end) | ||
| 3399 | goto short_pkt; | 3399 | goto short_pkt; |
| 3400 | p += len; | ||
| 3400 | attrlen = XDR_QUADLEN(ntohl(*p++)); | 3401 | attrlen = XDR_QUADLEN(ntohl(*p++)); |
| 3401 | p += attrlen; /* attributes */ | 3402 | if (end - p < attrlen + 2) |
| 3402 | if (p + 2 > end) | ||
| 3403 | goto short_pkt; | 3403 | goto short_pkt; |
| 3404 | p += attrlen; /* attributes */ | ||
| 3404 | entry = p; | 3405 | entry = p; |
| 3405 | } | 3406 | } |
| 3406 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 3407 | if (!nr && (entry[0] != 0 || entry[1] == 0)) |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 65c0c5b32351..da9cf11c326f 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -116,10 +116,17 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) | |||
| 116 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | 116 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; |
| 117 | base &= ~PAGE_CACHE_MASK; | 117 | base &= ~PAGE_CACHE_MASK; |
| 118 | pglen = PAGE_CACHE_SIZE - base; | 118 | pglen = PAGE_CACHE_SIZE - base; |
| 119 | if (pglen < remainder) | 119 | for (;;) { |
| 120 | if (remainder <= pglen) { | ||
| 121 | memclear_highpage_flush(*pages, base, remainder); | ||
| 122 | break; | ||
| 123 | } | ||
| 120 | memclear_highpage_flush(*pages, base, pglen); | 124 | memclear_highpage_flush(*pages, base, pglen); |
| 121 | else | 125 | pages++; |
| 122 | memclear_highpage_flush(*pages, base, remainder); | 126 | remainder -= pglen; |
| 127 | pglen = PAGE_CACHE_SIZE; | ||
| 128 | base = 0; | ||
| 129 | } | ||
| 123 | } | 130 | } |
| 124 | 131 | ||
| 125 | /* | 132 | /* |
| @@ -476,6 +483,8 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | |||
| 476 | unsigned int base = data->args.pgbase; | 483 | unsigned int base = data->args.pgbase; |
| 477 | struct page **pages; | 484 | struct page **pages; |
| 478 | 485 | ||
| 486 | if (data->res.eof) | ||
| 487 | count = data->args.count; | ||
| 479 | if (unlikely(count == 0)) | 488 | if (unlikely(count == 0)) |
| 480 | return; | 489 | return; |
| 481 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | 490 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; |
| @@ -483,11 +492,7 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | |||
| 483 | count += base; | 492 | count += base; |
| 484 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | 493 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) |
| 485 | SetPageUptodate(*pages); | 494 | SetPageUptodate(*pages); |
| 486 | /* | 495 | if (count != 0) |
| 487 | * Was this an eof or a short read? If the latter, don't mark the page | ||
| 488 | * as uptodate yet. | ||
| 489 | */ | ||
| 490 | if (count > 0 && (data->res.eof || data->args.count == data->res.count)) | ||
| 491 | SetPageUptodate(*pages); | 496 | SetPageUptodate(*pages); |
| 492 | } | 497 | } |
| 493 | 498 | ||
| @@ -502,6 +507,8 @@ static void nfs_readpage_set_pages_error(struct nfs_read_data *data) | |||
| 502 | count += base; | 507 | count += base; |
| 503 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | 508 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) |
| 504 | SetPageError(*pages); | 509 | SetPageError(*pages); |
| 510 | if (count != 0) | ||
| 511 | SetPageError(*pages); | ||
| 505 | } | 512 | } |
| 506 | 513 | ||
| 507 | /* | 514 | /* |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 2d3fb6416d91..db9cbf68e12b 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -659,7 +659,7 @@ struct nfs4_rename_res { | |||
| 659 | struct nfs4_setclientid { | 659 | struct nfs4_setclientid { |
| 660 | const nfs4_verifier * sc_verifier; /* request */ | 660 | const nfs4_verifier * sc_verifier; /* request */ |
| 661 | unsigned int sc_name_len; | 661 | unsigned int sc_name_len; |
| 662 | char sc_name[32]; /* request */ | 662 | char sc_name[48]; /* request */ |
| 663 | u32 sc_prog; /* request */ | 663 | u32 sc_prog; /* request */ |
| 664 | unsigned int sc_netid_len; | 664 | unsigned int sc_netid_len; |
| 665 | char sc_netid[4]; /* request */ | 665 | char sc_netid[4]; /* request */ |
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 2c2189cb30aa..a481472c9484 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h | |||
| @@ -42,9 +42,9 @@ RPC_I(struct inode *inode) | |||
| 42 | extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); | 42 | extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *); |
| 43 | 43 | ||
| 44 | extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); | 44 | extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); |
| 45 | extern int rpc_rmdir(char *); | 45 | extern int rpc_rmdir(struct dentry *); |
| 46 | extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); | 46 | extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); |
| 47 | extern int rpc_unlink(char *); | 47 | extern int rpc_unlink(struct dentry *); |
| 48 | extern struct vfsmount *rpc_get_mount(void); | 48 | extern struct vfsmount *rpc_get_mount(void); |
| 49 | extern void rpc_put_mount(void); | 49 | extern void rpc_put_mount(void); |
| 50 | 50 | ||
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 840e47a4ccc5..3a0cca255b76 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -37,7 +37,7 @@ extern unsigned int xprt_max_resvport; | |||
| 37 | 37 | ||
| 38 | #define RPC_MIN_RESVPORT (1U) | 38 | #define RPC_MIN_RESVPORT (1U) |
| 39 | #define RPC_MAX_RESVPORT (65535U) | 39 | #define RPC_MAX_RESVPORT (65535U) |
| 40 | #define RPC_DEF_MIN_RESVPORT (650U) | 40 | #define RPC_DEF_MIN_RESVPORT (665U) |
| 41 | #define RPC_DEF_MAX_RESVPORT (1023U) | 41 | #define RPC_DEF_MAX_RESVPORT (1023U) |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 4a9aa9393b97..ef1cf5b476c8 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -718,8 +718,7 @@ gss_destroy(struct rpc_auth *auth) | |||
| 718 | auth, auth->au_flavor); | 718 | auth, auth->au_flavor); |
| 719 | 719 | ||
| 720 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | 720 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); |
| 721 | rpc_unlink(gss_auth->path); | 721 | rpc_unlink(gss_auth->dentry); |
| 722 | dput(gss_auth->dentry); | ||
| 723 | gss_auth->dentry = NULL; | 722 | gss_auth->dentry = NULL; |
| 724 | gss_mech_put(gss_auth->mech); | 723 | gss_mech_put(gss_auth->mech); |
| 725 | 724 | ||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d6409e757219..3e19d321067a 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -183,8 +183,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, | |||
| 183 | 183 | ||
| 184 | out_no_auth: | 184 | out_no_auth: |
| 185 | if (!IS_ERR(clnt->cl_dentry)) { | 185 | if (!IS_ERR(clnt->cl_dentry)) { |
| 186 | rpc_rmdir(clnt->cl_pathname); | 186 | rpc_rmdir(clnt->cl_dentry); |
| 187 | dput(clnt->cl_dentry); | ||
| 188 | rpc_put_mount(); | 187 | rpc_put_mount(); |
| 189 | } | 188 | } |
| 190 | out_no_path: | 189 | out_no_path: |
| @@ -251,10 +250,8 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
| 251 | new->cl_autobind = 0; | 250 | new->cl_autobind = 0; |
| 252 | new->cl_oneshot = 0; | 251 | new->cl_oneshot = 0; |
| 253 | new->cl_dead = 0; | 252 | new->cl_dead = 0; |
| 254 | if (!IS_ERR(new->cl_dentry)) { | 253 | if (!IS_ERR(new->cl_dentry)) |
| 255 | dget(new->cl_dentry); | 254 | dget(new->cl_dentry); |
| 256 | rpc_get_mount(); | ||
| 257 | } | ||
| 258 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | 255 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); |
| 259 | if (new->cl_auth) | 256 | if (new->cl_auth) |
| 260 | atomic_inc(&new->cl_auth->au_count); | 257 | atomic_inc(&new->cl_auth->au_count); |
| @@ -317,11 +314,15 @@ rpc_destroy_client(struct rpc_clnt *clnt) | |||
| 317 | clnt->cl_auth = NULL; | 314 | clnt->cl_auth = NULL; |
| 318 | } | 315 | } |
| 319 | if (clnt->cl_parent != clnt) { | 316 | if (clnt->cl_parent != clnt) { |
| 317 | if (!IS_ERR(clnt->cl_dentry)) | ||
| 318 | dput(clnt->cl_dentry); | ||
| 320 | rpc_destroy_client(clnt->cl_parent); | 319 | rpc_destroy_client(clnt->cl_parent); |
| 321 | goto out_free; | 320 | goto out_free; |
| 322 | } | 321 | } |
| 323 | if (clnt->cl_pathname[0]) | 322 | if (!IS_ERR(clnt->cl_dentry)) { |
| 324 | rpc_rmdir(clnt->cl_pathname); | 323 | rpc_rmdir(clnt->cl_dentry); |
| 324 | rpc_put_mount(); | ||
| 325 | } | ||
| 325 | if (clnt->cl_xprt) { | 326 | if (clnt->cl_xprt) { |
| 326 | xprt_destroy(clnt->cl_xprt); | 327 | xprt_destroy(clnt->cl_xprt); |
| 327 | clnt->cl_xprt = NULL; | 328 | clnt->cl_xprt = NULL; |
| @@ -331,10 +332,6 @@ rpc_destroy_client(struct rpc_clnt *clnt) | |||
| 331 | out_free: | 332 | out_free: |
| 332 | rpc_free_iostats(clnt->cl_metrics); | 333 | rpc_free_iostats(clnt->cl_metrics); |
| 333 | clnt->cl_metrics = NULL; | 334 | clnt->cl_metrics = NULL; |
| 334 | if (!IS_ERR(clnt->cl_dentry)) { | ||
| 335 | dput(clnt->cl_dentry); | ||
| 336 | rpc_put_mount(); | ||
| 337 | } | ||
| 338 | kfree(clnt); | 335 | kfree(clnt); |
| 339 | return 0; | 336 | return 0; |
| 340 | } | 337 | } |
| @@ -1184,6 +1181,17 @@ call_verify(struct rpc_task *task) | |||
| 1184 | u32 *p = iov->iov_base, n; | 1181 | u32 *p = iov->iov_base, n; |
| 1185 | int error = -EACCES; | 1182 | int error = -EACCES; |
| 1186 | 1183 | ||
| 1184 | if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) { | ||
| 1185 | /* RFC-1014 says that the representation of XDR data must be a | ||
| 1186 | * multiple of four bytes | ||
| 1187 | * - if it isn't pointer subtraction in the NFS client may give | ||
| 1188 | * undefined results | ||
| 1189 | */ | ||
| 1190 | printk(KERN_WARNING | ||
| 1191 | "call_verify: XDR representation not a multiple of" | ||
| 1192 | " 4 bytes: 0x%x\n", task->tk_rqstp->rq_rcv_buf.len); | ||
| 1193 | goto out_eio; | ||
| 1194 | } | ||
| 1187 | if ((len -= 3) < 0) | 1195 | if ((len -= 3) < 0) |
| 1188 | goto out_overflow; | 1196 | goto out_overflow; |
| 1189 | p += 1; /* skip XID */ | 1197 | p += 1; /* skip XID */ |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index a3bd2db2e024..0b1a1ac8a4bc 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
| @@ -539,6 +539,7 @@ repeat: | |||
| 539 | rpc_close_pipes(dentry->d_inode); | 539 | rpc_close_pipes(dentry->d_inode); |
| 540 | simple_unlink(dir, dentry); | 540 | simple_unlink(dir, dentry); |
| 541 | } | 541 | } |
| 542 | inode_dir_notify(dir, DN_DELETE); | ||
| 542 | dput(dentry); | 543 | dput(dentry); |
| 543 | } while (n); | 544 | } while (n); |
| 544 | goto repeat; | 545 | goto repeat; |
| @@ -610,8 +611,8 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 610 | int error; | 611 | int error; |
| 611 | 612 | ||
| 612 | shrink_dcache_parent(dentry); | 613 | shrink_dcache_parent(dentry); |
| 613 | if (dentry->d_inode) | 614 | if (d_unhashed(dentry)) |
| 614 | rpc_close_pipes(dentry->d_inode); | 615 | return 0; |
| 615 | if ((error = simple_rmdir(dir, dentry)) != 0) | 616 | if ((error = simple_rmdir(dir, dentry)) != 0) |
| 616 | return error; | 617 | return error; |
| 617 | if (!error) { | 618 | if (!error) { |
| @@ -684,28 +685,20 @@ err_dput: | |||
| 684 | } | 685 | } |
| 685 | 686 | ||
| 686 | int | 687 | int |
| 687 | rpc_rmdir(char *path) | 688 | rpc_rmdir(struct dentry *dentry) |
| 688 | { | 689 | { |
| 689 | struct nameidata nd; | 690 | struct dentry *parent; |
| 690 | struct dentry *dentry; | ||
| 691 | struct inode *dir; | 691 | struct inode *dir; |
| 692 | int error; | 692 | int error; |
| 693 | 693 | ||
| 694 | if ((error = rpc_lookup_parent(path, &nd)) != 0) | 694 | parent = dget_parent(dentry); |
| 695 | return error; | 695 | dir = parent->d_inode; |
| 696 | dir = nd.dentry->d_inode; | ||
| 697 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 696 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
| 698 | dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); | ||
| 699 | if (IS_ERR(dentry)) { | ||
| 700 | error = PTR_ERR(dentry); | ||
| 701 | goto out_release; | ||
| 702 | } | ||
| 703 | rpc_depopulate(dentry); | 697 | rpc_depopulate(dentry); |
| 704 | error = __rpc_rmdir(dir, dentry); | 698 | error = __rpc_rmdir(dir, dentry); |
| 705 | dput(dentry); | 699 | dput(dentry); |
| 706 | out_release: | ||
| 707 | mutex_unlock(&dir->i_mutex); | 700 | mutex_unlock(&dir->i_mutex); |
| 708 | rpc_release_path(&nd); | 701 | dput(parent); |
| 709 | return error; | 702 | return error; |
| 710 | } | 703 | } |
| 711 | 704 | ||
| @@ -746,32 +739,26 @@ err_dput: | |||
| 746 | } | 739 | } |
| 747 | 740 | ||
| 748 | int | 741 | int |
| 749 | rpc_unlink(char *path) | 742 | rpc_unlink(struct dentry *dentry) |
| 750 | { | 743 | { |
| 751 | struct nameidata nd; | 744 | struct dentry *parent; |
| 752 | struct dentry *dentry; | ||
| 753 | struct inode *dir; | 745 | struct inode *dir; |
| 754 | int error; | 746 | int error = 0; |
| 755 | 747 | ||
| 756 | if ((error = rpc_lookup_parent(path, &nd)) != 0) | 748 | parent = dget_parent(dentry); |
| 757 | return error; | 749 | dir = parent->d_inode; |
| 758 | dir = nd.dentry->d_inode; | ||
| 759 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 750 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
| 760 | dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len); | 751 | if (!d_unhashed(dentry)) { |
| 761 | if (IS_ERR(dentry)) { | 752 | d_drop(dentry); |
| 762 | error = PTR_ERR(dentry); | 753 | if (dentry->d_inode) { |
| 763 | goto out_release; | 754 | rpc_close_pipes(dentry->d_inode); |
| 764 | } | 755 | error = simple_unlink(dir, dentry); |
| 765 | d_drop(dentry); | 756 | } |
| 766 | if (dentry->d_inode) { | 757 | inode_dir_notify(dir, DN_DELETE); |
| 767 | rpc_close_pipes(dentry->d_inode); | ||
| 768 | error = simple_unlink(dir, dentry); | ||
| 769 | } | 758 | } |
| 770 | dput(dentry); | 759 | dput(dentry); |
| 771 | inode_dir_notify(dir, DN_DELETE); | ||
| 772 | out_release: | ||
| 773 | mutex_unlock(&dir->i_mutex); | 760 | mutex_unlock(&dir->i_mutex); |
| 774 | rpc_release_path(&nd); | 761 | dput(parent); |
| 775 | return error; | 762 | return error; |
| 776 | } | 763 | } |
| 777 | 764 | ||
