forked from Minki/linux
NFS client bugfixes for 4.13
Stable bugfixes:
- Fix error reporting regression
Bugfixes:
- Fix setting filelayout ds address race
- Fix subtle access bug when using ACLs
- Fix setting mnt3_counts array size
- Fix a couple of pNFS commit races
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEnZ5MQTpR7cLU7KEp18tUv7ClQOsFAllyVYYACgkQ18tUv7Cl
QOtTwBAA8ek0Ba5wIfwlQe4MvIX1t6v7q7Otrwdombhuw1a6nW410hFwu2SG8kGd
fQWr1xnqRsMKwu83UuImtlYYvMa271TZgXxPNWx7KJpi/zocnigJRg5sVpkcRqza
AjjPc245pHCooQoaTAlm5WrO9zDm0s7lRGuTB1cvPRsElnFVWT0jwhTASIDOU1Zy
9K/hElAnXp/dZv/ydjSePTPPsVQPJWLbJPlSm6vAIQPyeXWUeCgAym0yf2FVvtsd
AQeozaq9xq6tofVPZhsYWeBKswjTHs3FxL8vhDOF9gF3QMPm43mwsfrKVidWo4vW
0UJnRZRCFgG0WIxxhA7l1Z9MovAsXlbWmFufgCa4Ev/bC5WuUT4ZEkjBGJw2vXD4
0/lxkhD41PBhCl/LIod9OT6iJ8koifl50JUC4N67D2illFy9a7Btzx3EPxfDz9uG
6jEek9x6B1xf7AC4HhxByN/E8gKX08N4Q/afxTFuAwrzKRKqI4Me3qbCyU86bp+T
wiAxgVPVnmb/VBVLU68i7titdsA6U8ZO12FFqu9QOr9wHMXxa6108h2Nia9jVTdk
EZhanXa6tJThQQ/QZicuR5hTtoM4BuikaaJSHZ4ODbgrAjsMAyqy4qsf4tf3LLAo
tEDu5sJDmHJhhdtqzuz+OtDn5iJ2Nga6a4/fMwt9YU2ZQBm7X/8=
=ZcQv
-----END PGP SIGNATURE-----
Merge tag 'nfs-for-4.13-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client bugfixes from Anna Schumaker:
"Stable bugfix:
- Fix error reporting regression
Bugfixes:
- Fix setting filelayout ds address race
- Fix subtle access bug when using ACLs
- Fix setting mnt3_counts array size
- Fix a couple of pNFS commit races"
* tag 'nfs-for-4.13-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
NFS/filelayout: Fix racy setting of fl->dsaddr in filelayout_check_deviceid()
NFS: Be more careful about mapping file permissions
NFS: Store the raw NFS access mask in the inode's access cache
NFSv3: Convert nfs3_proc_access() to use nfs_access_set_mask()
NFS: Refactor NFS access to kernel access mask calculation
net/sunrpc/xprt_sock: fix regression in connection error reporting.
nfs: count correct array for mnt3_counts array size
Revert commit 722f0b8911
("pNFS: Don't send COMMITs to the DSes if...")
pNFS/flexfiles: Handle expired layout segments in ff_layout_initiate_commit()
NFS: Fix another COMMIT race in pNFS
NFS: Fix a COMMIT race in pNFS
mount: copy the port field into the cloned nfs_server structure.
NFS: Don't run wake_up_bit() when nobody is waiting...
nfs: add export operations
This commit is contained in:
commit
505d5c1119
@ -820,6 +820,7 @@ void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *sour
|
||||
target->caps = source->caps;
|
||||
target->options = source->options;
|
||||
target->auth_info = source->auth_info;
|
||||
target->port = source->port;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_server_copy_userdata);
|
||||
|
||||
|
47
fs/nfs/dir.c
47
fs/nfs/dir.c
@ -2372,16 +2372,40 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_access_add_cache);
|
||||
|
||||
#define NFS_MAY_READ (NFS4_ACCESS_READ)
|
||||
#define NFS_MAY_WRITE (NFS4_ACCESS_MODIFY | \
|
||||
NFS4_ACCESS_EXTEND | \
|
||||
NFS4_ACCESS_DELETE)
|
||||
#define NFS_FILE_MAY_WRITE (NFS4_ACCESS_MODIFY | \
|
||||
NFS4_ACCESS_EXTEND)
|
||||
#define NFS_DIR_MAY_WRITE NFS_MAY_WRITE
|
||||
#define NFS_MAY_LOOKUP (NFS4_ACCESS_LOOKUP)
|
||||
#define NFS_MAY_EXECUTE (NFS4_ACCESS_EXECUTE)
|
||||
static int
|
||||
nfs_access_calc_mask(u32 access_result, umode_t umode)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
if (access_result & NFS_MAY_READ)
|
||||
mask |= MAY_READ;
|
||||
if (S_ISDIR(umode)) {
|
||||
if ((access_result & NFS_DIR_MAY_WRITE) == NFS_DIR_MAY_WRITE)
|
||||
mask |= MAY_WRITE;
|
||||
if ((access_result & NFS_MAY_LOOKUP) == NFS_MAY_LOOKUP)
|
||||
mask |= MAY_EXEC;
|
||||
} else if (S_ISREG(umode)) {
|
||||
if ((access_result & NFS_FILE_MAY_WRITE) == NFS_FILE_MAY_WRITE)
|
||||
mask |= MAY_WRITE;
|
||||
if ((access_result & NFS_MAY_EXECUTE) == NFS_MAY_EXECUTE)
|
||||
mask |= MAY_EXEC;
|
||||
} else if (access_result & NFS_MAY_WRITE)
|
||||
mask |= MAY_WRITE;
|
||||
return mask;
|
||||
}
|
||||
|
||||
void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
|
||||
{
|
||||
entry->mask = 0;
|
||||
if (access_result & NFS4_ACCESS_READ)
|
||||
entry->mask |= MAY_READ;
|
||||
if (access_result &
|
||||
(NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
|
||||
entry->mask |= MAY_WRITE;
|
||||
if (access_result & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
|
||||
entry->mask |= MAY_EXEC;
|
||||
entry->mask = access_result;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_access_set_mask);
|
||||
|
||||
@ -2389,6 +2413,7 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
|
||||
{
|
||||
struct nfs_access_entry cache;
|
||||
bool may_block = (mask & MAY_NOT_BLOCK) == 0;
|
||||
int cache_mask;
|
||||
int status;
|
||||
|
||||
trace_nfs_access_enter(inode);
|
||||
@ -2404,7 +2429,8 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
|
||||
goto out;
|
||||
|
||||
/* Be clever: ask server to check for all possible rights */
|
||||
cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
|
||||
cache.mask = NFS_MAY_LOOKUP | NFS_MAY_EXECUTE
|
||||
| NFS_MAY_WRITE | NFS_MAY_READ;
|
||||
cache.cred = cred;
|
||||
cache.jiffies = jiffies;
|
||||
status = NFS_PROTO(inode)->access(inode, &cache);
|
||||
@ -2418,7 +2444,8 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
|
||||
}
|
||||
nfs_access_add_cache(inode, &cache);
|
||||
out_cached:
|
||||
if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
|
||||
cache_mask = nfs_access_calc_mask(cache.mask, inode->i_mode);
|
||||
if ((mask & ~cache_mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
|
||||
status = -EACCES;
|
||||
out:
|
||||
trace_nfs_access_exit(inode, status);
|
||||
|
@ -542,6 +542,10 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
|
||||
struct nfs4_file_layout_dsaddr *dsaddr;
|
||||
int status = -EINVAL;
|
||||
|
||||
/* Is the deviceid already set? If so, we're good. */
|
||||
if (fl->dsaddr != NULL)
|
||||
return 0;
|
||||
|
||||
/* find and reference the deviceid */
|
||||
d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), &fl->deviceid,
|
||||
lo->plh_lc_cred, gfp_flags);
|
||||
@ -553,8 +557,6 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
|
||||
if (filelayout_test_devid_unavailable(&dsaddr->id_node))
|
||||
goto out_put;
|
||||
|
||||
fl->dsaddr = dsaddr;
|
||||
|
||||
if (fl->first_stripe_index >= dsaddr->stripe_count) {
|
||||
dprintk("%s Bad first_stripe_index %u\n",
|
||||
__func__, fl->first_stripe_index);
|
||||
@ -570,6 +572,13 @@ filelayout_check_deviceid(struct pnfs_layout_hdr *lo,
|
||||
goto out_put;
|
||||
}
|
||||
status = 0;
|
||||
|
||||
/*
|
||||
* Atomic compare and xchange to ensure we don't scribble
|
||||
* over a non-NULL pointer.
|
||||
*/
|
||||
if (cmpxchg(&fl->dsaddr, NULL, dsaddr) != NULL)
|
||||
goto out_put;
|
||||
out:
|
||||
return status;
|
||||
out_put:
|
||||
|
@ -1842,6 +1842,10 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
|
||||
int vers, ret;
|
||||
struct nfs_fh *fh;
|
||||
|
||||
if (!lseg || !(pnfs_is_valid_lseg(lseg) ||
|
||||
test_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags)))
|
||||
goto out_err;
|
||||
|
||||
idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
|
||||
ds = nfs4_ff_layout_prepare_ds(lseg, idx, true);
|
||||
if (!ds)
|
||||
|
@ -512,7 +512,7 @@ static const struct rpc_version mnt_version1 = {
|
||||
.counts = mnt_counts,
|
||||
};
|
||||
|
||||
static unsigned int mnt3_counts[ARRAY_SIZE(mnt_procedures)];
|
||||
static unsigned int mnt3_counts[ARRAY_SIZE(mnt3_procedures)];
|
||||
static const struct rpc_version mnt_version3 = {
|
||||
.number = 3,
|
||||
.nrprocs = ARRAY_SIZE(mnt3_procedures),
|
||||
|
@ -220,15 +220,8 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
|
||||
|
||||
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
|
||||
nfs_refresh_inode(inode, res.fattr);
|
||||
if (status == 0) {
|
||||
entry->mask = 0;
|
||||
if (res.access & NFS3_ACCESS_READ)
|
||||
entry->mask |= MAY_READ;
|
||||
if (res.access & (NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE))
|
||||
entry->mask |= MAY_WRITE;
|
||||
if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE))
|
||||
entry->mask |= MAY_EXEC;
|
||||
}
|
||||
if (status == 0)
|
||||
nfs_access_set_mask(entry, res.access);
|
||||
nfs_free_fattr(res.fattr);
|
||||
out:
|
||||
dprintk("NFS reply access: %d\n", status);
|
||||
|
@ -159,13 +159,18 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
|
||||
{
|
||||
struct pnfs_commit_bucket *b;
|
||||
struct pnfs_layout_segment *freeme;
|
||||
int nwritten;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&cinfo->inode->i_lock);
|
||||
restart:
|
||||
for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
|
||||
if (pnfs_generic_transfer_commit_list(&b->written, dst,
|
||||
cinfo, 0)) {
|
||||
nwritten = pnfs_generic_transfer_commit_list(&b->written,
|
||||
dst, cinfo, 0);
|
||||
if (!nwritten)
|
||||
continue;
|
||||
cinfo->ds->nwritten -= nwritten;
|
||||
if (list_empty(&b->written)) {
|
||||
freeme = b->wlseg;
|
||||
b->wlseg = NULL;
|
||||
spin_unlock(&cinfo->inode->i_lock);
|
||||
@ -174,7 +179,6 @@ restart:
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
cinfo->ds->nwritten = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pnfs_generic_recover_commit_reqs);
|
||||
|
||||
@ -183,6 +187,7 @@ static void pnfs_generic_retry_commit(struct nfs_commit_info *cinfo, int idx)
|
||||
struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
|
||||
struct pnfs_commit_bucket *bucket;
|
||||
struct pnfs_layout_segment *freeme;
|
||||
struct list_head *pos;
|
||||
LIST_HEAD(pages);
|
||||
int i;
|
||||
|
||||
@ -193,6 +198,8 @@ static void pnfs_generic_retry_commit(struct nfs_commit_info *cinfo, int idx)
|
||||
continue;
|
||||
freeme = bucket->clseg;
|
||||
bucket->clseg = NULL;
|
||||
list_for_each(pos, &bucket->committing)
|
||||
cinfo->ds->ncommitting--;
|
||||
list_splice_init(&bucket->committing, &pages);
|
||||
spin_unlock(&cinfo->inode->i_lock);
|
||||
nfs_retry_commit(&pages, freeme, cinfo, i);
|
||||
@ -217,13 +224,6 @@ pnfs_generic_alloc_ds_commits(struct nfs_commit_info *cinfo,
|
||||
for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) {
|
||||
if (list_empty(&bucket->committing))
|
||||
continue;
|
||||
/*
|
||||
* If the layout segment is invalid, then let
|
||||
* pnfs_generic_retry_commit() clean up the bucket.
|
||||
*/
|
||||
if (bucket->clseg && !pnfs_is_valid_lseg(bucket->clseg) &&
|
||||
!test_bit(NFS_LSEG_LAYOUTRETURN, &bucket->clseg->pls_flags))
|
||||
break;
|
||||
data = nfs_commitdata_alloc(false);
|
||||
if (!data)
|
||||
break;
|
||||
@ -243,9 +243,12 @@ void pnfs_fetch_commit_bucket_list(struct list_head *pages,
|
||||
struct nfs_commit_info *cinfo)
|
||||
{
|
||||
struct pnfs_commit_bucket *bucket;
|
||||
struct list_head *pos;
|
||||
|
||||
bucket = &cinfo->ds->buckets[data->ds_commit_index];
|
||||
spin_lock(&cinfo->inode->i_lock);
|
||||
list_for_each(pos, &bucket->committing)
|
||||
cinfo->ds->ncommitting--;
|
||||
list_splice_init(&bucket->committing, pages);
|
||||
data->lseg = bucket->clseg;
|
||||
bucket->clseg = NULL;
|
||||
@ -330,7 +333,6 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
|
||||
}
|
||||
}
|
||||
out:
|
||||
cinfo->ds->ncommitting = 0;
|
||||
return PNFS_ATTEMPTED;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pnfs_generic_commit_pagelist);
|
||||
|
@ -51,7 +51,7 @@ struct nfs_access_entry {
|
||||
struct list_head lru;
|
||||
unsigned long jiffies;
|
||||
struct rpc_cred * cred;
|
||||
int mask;
|
||||
__u32 mask;
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
|
@ -1624,6 +1624,8 @@ static void xs_tcp_state_change(struct sock *sk)
|
||||
if (test_and_clear_bit(XPRT_SOCK_CONNECTING,
|
||||
&transport->sock_state))
|
||||
xprt_clear_connecting(xprt);
|
||||
if (sk->sk_err)
|
||||
xprt_wake_pending_tasks(xprt, -sk->sk_err);
|
||||
xs_sock_mark_closed(xprt);
|
||||
}
|
||||
out:
|
||||
|
Loading…
Reference in New Issue
Block a user