diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 55 |
1 files changed, 25 insertions, 30 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 635274140b18..1e50326d00dd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3215,11 +3215,11 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
3215 | dentry->d_parent->d_name.name, | 3215 | dentry->d_parent->d_name.name, |
3216 | dentry->d_name.name, | 3216 | dentry->d_name.name, |
3217 | (unsigned long long)cookie); | 3217 | (unsigned long long)cookie); |
3218 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 3218 | nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args); |
3219 | res.pgbase = args.pgbase; | 3219 | res.pgbase = args.pgbase; |
3220 | status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); | 3220 | status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); |
3221 | if (status >= 0) { | 3221 | if (status >= 0) { |
3222 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 3222 | memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE); |
3223 | status += args.pgbase; | 3223 | status += args.pgbase; |
3224 | } | 3224 | } |
3225 | 3225 | ||
@@ -3653,11 +3653,11 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server) | |||
3653 | && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); | 3653 | && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); |
3654 | } | 3654 | } |
3655 | 3655 | ||
3656 | /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that | 3656 | /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that |
3657 | * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on | 3657 | * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on |
3658 | * the stack. | 3658 | * the stack. |
3659 | */ | 3659 | */ |
3660 | #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) | 3660 | #define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE) |
3661 | 3661 | ||
3662 | static int buf_to_pages_noslab(const void *buf, size_t buflen, | 3662 | static int buf_to_pages_noslab(const void *buf, size_t buflen, |
3663 | struct page **pages, unsigned int *pgbase) | 3663 | struct page **pages, unsigned int *pgbase) |
@@ -3668,7 +3668,7 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen, | |||
3668 | spages = pages; | 3668 | spages = pages; |
3669 | 3669 | ||
3670 | do { | 3670 | do { |
3671 | len = min_t(size_t, PAGE_CACHE_SIZE, buflen); | 3671 | len = min_t(size_t, PAGE_SIZE, buflen); |
3672 | newpage = alloc_page(GFP_KERNEL); | 3672 | newpage = alloc_page(GFP_KERNEL); |
3673 | 3673 | ||
3674 | if (newpage == NULL) | 3674 | if (newpage == NULL) |
@@ -3739,7 +3739,7 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size | |||
3739 | struct nfs4_cached_acl *acl; | 3739 | struct nfs4_cached_acl *acl; |
3740 | size_t buflen = sizeof(*acl) + acl_len; | 3740 | size_t buflen = sizeof(*acl) + acl_len; |
3741 | 3741 | ||
3742 | if (pages && buflen <= PAGE_SIZE) { | 3742 | if (buflen <= PAGE_SIZE) { |
3743 | acl = kmalloc(buflen, GFP_KERNEL); | 3743 | acl = kmalloc(buflen, GFP_KERNEL); |
3744 | if (acl == NULL) | 3744 | if (acl == NULL) |
3745 | goto out; | 3745 | goto out; |
@@ -3782,17 +3782,15 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3782 | .rpc_argp = &args, | 3782 | .rpc_argp = &args, |
3783 | .rpc_resp = &res, | 3783 | .rpc_resp = &res, |
3784 | }; | 3784 | }; |
3785 | int ret = -ENOMEM, npages, i; | 3785 | unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE); |
3786 | size_t acl_len = 0; | 3786 | int ret = -ENOMEM, i; |
3787 | 3787 | ||
3788 | npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
3789 | /* As long as we're doing a round trip to the server anyway, | 3788 | /* As long as we're doing a round trip to the server anyway, |
3790 | * let's be prepared for a page of acl data. */ | 3789 | * let's be prepared for a page of acl data. */ |
3791 | if (npages == 0) | 3790 | if (npages == 0) |
3792 | npages = 1; | 3791 | npages = 1; |
3793 | 3792 | if (npages > ARRAY_SIZE(pages)) | |
3794 | /* Add an extra page to handle the bitmap returned */ | 3793 | return -ERANGE; |
3795 | npages++; | ||
3796 | 3794 | ||
3797 | for (i = 0; i < npages; i++) { | 3795 | for (i = 0; i < npages; i++) { |
3798 | pages[i] = alloc_page(GFP_KERNEL); | 3796 | pages[i] = alloc_page(GFP_KERNEL); |
@@ -3808,11 +3806,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3808 | args.acl_len = npages * PAGE_SIZE; | 3806 | args.acl_len = npages * PAGE_SIZE; |
3809 | args.acl_pgbase = 0; | 3807 | args.acl_pgbase = 0; |
3810 | 3808 | ||
3811 | /* Let decode_getfacl know not to fail if the ACL data is larger than | ||
3812 | * the page we send as a guess */ | ||
3813 | if (buf == NULL) | ||
3814 | res.acl_flags |= NFS4_ACL_LEN_REQUEST; | ||
3815 | |||
3816 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", | 3809 | dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n", |
3817 | __func__, buf, buflen, npages, args.acl_len); | 3810 | __func__, buf, buflen, npages, args.acl_len); |
3818 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), | 3811 | ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), |
@@ -3820,20 +3813,19 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3820 | if (ret) | 3813 | if (ret) |
3821 | goto out_free; | 3814 | goto out_free; |
3822 | 3815 | ||
3823 | acl_len = res.acl_len; | 3816 | /* Handle the case where the passed-in buffer is too short */ |
3824 | if (acl_len > args.acl_len) | 3817 | if (res.acl_flags & NFS4_ACL_TRUNC) { |
3825 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); | 3818 | /* Did the user only issue a request for the acl length? */ |
3826 | else | 3819 | if (buf == NULL) |
3827 | nfs4_write_cached_acl(inode, pages, res.acl_data_offset, | 3820 | goto out_ok; |
3828 | acl_len); | ||
3829 | if (buf) { | ||
3830 | ret = -ERANGE; | 3821 | ret = -ERANGE; |
3831 | if (acl_len > buflen) | 3822 | goto out_free; |
3832 | goto out_free; | ||
3833 | _copy_from_pages(buf, pages, res.acl_data_offset, | ||
3834 | acl_len); | ||
3835 | } | 3823 | } |
3836 | ret = acl_len; | 3824 | nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len); |
3825 | if (buf) | ||
3826 | _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len); | ||
3827 | out_ok: | ||
3828 | ret = res.acl_len; | ||
3837 | out_free: | 3829 | out_free: |
3838 | for (i = 0; i < npages; i++) | 3830 | for (i = 0; i < npages; i++) |
3839 | if (pages[i]) | 3831 | if (pages[i]) |
@@ -3891,10 +3883,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
3891 | .rpc_argp = &arg, | 3883 | .rpc_argp = &arg, |
3892 | .rpc_resp = &res, | 3884 | .rpc_resp = &res, |
3893 | }; | 3885 | }; |
3886 | unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE); | ||
3894 | int ret, i; | 3887 | int ret, i; |
3895 | 3888 | ||
3896 | if (!nfs4_server_supports_acls(server)) | 3889 | if (!nfs4_server_supports_acls(server)) |
3897 | return -EOPNOTSUPP; | 3890 | return -EOPNOTSUPP; |
3891 | if (npages > ARRAY_SIZE(pages)) | ||
3892 | return -ERANGE; | ||
3898 | i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3893 | i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
3899 | if (i < 0) | 3894 | if (i < 0) |
3900 | return i; | 3895 | return i; |