You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'nfs-for-3.6-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust: - Final (hopefully) fix for the range checking code in NFSv4 getacl. This should fix the Oopses being seen when the acl size is close to PAGE_SIZE. - Fix a regression with the legacy binary mount code - Fix a regression in the readdir cookieverf initialisation - Fix an RPC over UDP regression - Ensure that we report all errors in the NFSv4 open code - Ensure that fsync() reports all relevant synchronisation errors. * tag 'nfs-for-3.6-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS: fsync() must exit with an error if page writeback failed SUNRPC: Fix a UDP transport regression NFS: return error from decode_getfh in decode open NFSv4: Fix buffer overflow checking in __nfs4_get_acl_uncached NFSv4: Fix range checking in __nfs4_get_acl_uncached and __nfs4_proc_set_acl NFS: Fix a problem with the legacy binary mount code NFS: Fix the initialisation of the readdir 'cookieverf' array
This commit is contained in:
+3
-1
@@ -287,10 +287,12 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = nfs_file_fsync_commit(file, start, end, datasync);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -154,7 +154,7 @@ static void nfs_zap_caches_locked(struct inode *inode)
|
||||
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
|
||||
nfsi->attrtimeo_timestamp = jiffies;
|
||||
|
||||
memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
|
||||
memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));
|
||||
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
|
||||
else
|
||||
|
||||
+1
-1
@@ -643,7 +643,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
|
||||
u64 cookie, struct page **pages, unsigned int count, int plus)
|
||||
{
|
||||
struct inode *dir = dentry->d_inode;
|
||||
__be32 *verf = NFS_COOKIEVERF(dir);
|
||||
__be32 *verf = NFS_I(dir)->cookieverf;
|
||||
struct nfs3_readdirargs arg = {
|
||||
.fh = NFS_FH(dir),
|
||||
.cookie = cookie,
|
||||
|
||||
+3
-1
@@ -96,13 +96,15 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = nfs_file_fsync_commit(file, start, end, datasync);
|
||||
if (!ret && !datasync)
|
||||
/* application has asked for meta-data sync */
|
||||
ret = pnfs_layoutcommit_inode(inode, true);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+25
-30
@@ -3215,11 +3215,11 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
|
||||
dentry->d_parent->d_name.name,
|
||||
dentry->d_name.name,
|
||||
(unsigned long long)cookie);
|
||||
nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
|
||||
nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
|
||||
res.pgbase = args.pgbase;
|
||||
status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
|
||||
if (status >= 0) {
|
||||
memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
|
||||
memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
|
||||
status += args.pgbase;
|
||||
}
|
||||
|
||||
@@ -3653,11 +3653,11 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
|
||||
&& (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
|
||||
}
|
||||
|
||||
/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that
|
||||
* it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on
|
||||
/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
|
||||
* it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on
|
||||
* the stack.
|
||||
*/
|
||||
#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
|
||||
#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
|
||||
|
||||
static int buf_to_pages_noslab(const void *buf, size_t buflen,
|
||||
struct page **pages, unsigned int *pgbase)
|
||||
@@ -3668,7 +3668,7 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen,
|
||||
spages = pages;
|
||||
|
||||
do {
|
||||
len = min_t(size_t, PAGE_CACHE_SIZE, buflen);
|
||||
len = min_t(size_t, PAGE_SIZE, buflen);
|
||||
newpage = alloc_page(GFP_KERNEL);
|
||||
|
||||
if (newpage == NULL)
|
||||
@@ -3739,7 +3739,7 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size
|
||||
struct nfs4_cached_acl *acl;
|
||||
size_t buflen = sizeof(*acl) + acl_len;
|
||||
|
||||
if (pages && buflen <= PAGE_SIZE) {
|
||||
if (buflen <= PAGE_SIZE) {
|
||||
acl = kmalloc(buflen, GFP_KERNEL);
|
||||
if (acl == NULL)
|
||||
goto out;
|
||||
@@ -3782,17 +3782,15 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
|
||||
.rpc_argp = &args,
|
||||
.rpc_resp = &res,
|
||||
};
|
||||
int ret = -ENOMEM, npages, i;
|
||||
size_t acl_len = 0;
|
||||
unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
|
||||
int ret = -ENOMEM, i;
|
||||
|
||||
npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
/* As long as we're doing a round trip to the server anyway,
|
||||
* let's be prepared for a page of acl data. */
|
||||
if (npages == 0)
|
||||
npages = 1;
|
||||
|
||||
/* Add an extra page to handle the bitmap returned */
|
||||
npages++;
|
||||
if (npages > ARRAY_SIZE(pages))
|
||||
return -ERANGE;
|
||||
|
||||
for (i = 0; i < npages; i++) {
|
||||
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
|
||||
args.acl_len = npages * PAGE_SIZE;
|
||||
args.acl_pgbase = 0;
|
||||
|
||||
/* Let decode_getfacl know not to fail if the ACL data is larger than
|
||||
* the page we send as a guess */
|
||||
if (buf == NULL)
|
||||
res.acl_flags |= NFS4_ACL_LEN_REQUEST;
|
||||
|
||||
dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
|
||||
__func__, buf, buflen, npages, args.acl_len);
|
||||
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
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
acl_len = res.acl_len;
|
||||
if (acl_len > args.acl_len)
|
||||
nfs4_write_cached_acl(inode, NULL, 0, acl_len);
|
||||
else
|
||||
nfs4_write_cached_acl(inode, pages, res.acl_data_offset,
|
||||
acl_len);
|
||||
if (buf) {
|
||||
/* Handle the case where the passed-in buffer is too short */
|
||||
if (res.acl_flags & NFS4_ACL_TRUNC) {
|
||||
/* Did the user only issue a request for the acl length? */
|
||||
if (buf == NULL)
|
||||
goto out_ok;
|
||||
ret = -ERANGE;
|
||||
if (acl_len > buflen)
|
||||
goto out_free;
|
||||
_copy_from_pages(buf, pages, res.acl_data_offset,
|
||||
acl_len);
|
||||
goto out_free;
|
||||
}
|
||||
ret = acl_len;
|
||||
nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len);
|
||||
if (buf)
|
||||
_copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len);
|
||||
out_ok:
|
||||
ret = res.acl_len;
|
||||
out_free:
|
||||
for (i = 0; i < npages; i++)
|
||||
if (pages[i])
|
||||
@@ -3891,10 +3883,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
|
||||
.rpc_argp = &arg,
|
||||
.rpc_resp = &res,
|
||||
};
|
||||
unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
|
||||
int ret, i;
|
||||
|
||||
if (!nfs4_server_supports_acls(server))
|
||||
return -EOPNOTSUPP;
|
||||
if (npages > ARRAY_SIZE(pages))
|
||||
return -ERANGE;
|
||||
i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
|
||||
if (i < 0)
|
||||
return i;
|
||||
|
||||
+7
-10
@@ -5072,18 +5072,14 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
|
||||
* are stored with the acl data to handle the problem of
|
||||
* variable length bitmaps.*/
|
||||
res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset;
|
||||
|
||||
/* We ignore &savep and don't do consistency checks on
|
||||
* the attr length. Let userspace figure it out.... */
|
||||
res->acl_len = attrlen;
|
||||
if (attrlen > (xdr->nwords << 2)) {
|
||||
if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
|
||||
/* getxattr interface called with a NULL buf */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for receive buffer overflow */
|
||||
if (res->acl_len > (xdr->nwords << 2) ||
|
||||
res->acl_len + res->acl_data_offset > xdr->buf->page_len) {
|
||||
res->acl_flags |= NFS4_ACL_TRUNC;
|
||||
dprintk("NFS: acl reply: attrlen %u > page_len %u\n",
|
||||
attrlen, xdr->nwords << 2);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else
|
||||
status = -EOPNOTSUPP;
|
||||
@@ -6229,7 +6225,8 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
status = decode_open(xdr, res);
|
||||
if (status)
|
||||
goto out;
|
||||
if (decode_getfh(xdr, &res->fh) != 0)
|
||||
status = decode_getfh(xdr, &res->fh);
|
||||
if (status)
|
||||
goto out;
|
||||
decode_getfattr(xdr, res->f_attr, res->server);
|
||||
out:
|
||||
|
||||
@@ -1867,6 +1867,7 @@ static int nfs23_validate_mount_data(void *options,
|
||||
|
||||
memcpy(sap, &data->addr, sizeof(data->addr));
|
||||
args->nfs_server.addrlen = sizeof(data->addr);
|
||||
args->nfs_server.port = ntohs(data->addr.sin_port);
|
||||
if (!nfs_verify_server_address(sap))
|
||||
goto out_no_address;
|
||||
|
||||
@@ -2564,6 +2565,7 @@ static int nfs4_validate_mount_data(void *options,
|
||||
return -EFAULT;
|
||||
if (!nfs_verify_server_address(sap))
|
||||
goto out_no_address;
|
||||
args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
|
||||
|
||||
if (data->auth_flavourlen) {
|
||||
if (data->auth_flavourlen > 1)
|
||||
|
||||
Reference in New Issue
Block a user