Commit 12bf0b63 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-5.7-5' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

  Stable fixes:
   - nfs: fix NULL deference in nfs4_get_valid_delegation

  Bugfixes:
   - Fix corruption of the return value in cachefiles_read_or_alloc_pages()
   - Fix several fscache cookie issues
   - Fix a fscache queuing race that can trigger a BUG_ON
   - NFS: Fix two use-after-free regressions due to the RPC_TASK_CRED_NOREF flag
   - SUNRPC: Fix a use-after-free regression in rpc_free_client_work()
   - SUNRPC: Fix a race when tearing down the rpc client debugfs directory
   - SUNRPC: Signalled ASYNC tasks need to exit
   - NFSv3: fix rpc receive buffer size for MOUNT call"

* tag 'nfs-for-5.7-5' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv3: fix rpc receive buffer size for MOUNT call
  SUNRPC: 'Directory with parent 'rpc_clnt' already present!'
  NFS/pnfs: Don't use RPC_TASK_CRED_NOREF with pnfs
  NFS: Don't use RPC_TASK_CRED_NOREF with delegreturn
  SUNRPC: Signalled ASYNC tasks need to exit
  nfs: fix NULL deference in nfs4_get_valid_delegation
  SUNRPC: fix use-after-free in rpc_free_client_work()
  cachefiles: Fix race between read_waiter and read_copier involving op->to_do
  NFSv4: Fix fscache cookie aux_data to ensure change_attr is included
  NFS: Fix fscache super_cookie allocation
  NFS: Fix fscache super_cookie index_key from changing after umount
  cachefiles: Fix corruption of the return value in cachefiles_read_or_alloc_pages()
parents f85c1598 8eed292b
...@@ -60,9 +60,9 @@ static int cachefiles_read_waiter(wait_queue_entry_t *wait, unsigned mode, ...@@ -60,9 +60,9 @@ static int cachefiles_read_waiter(wait_queue_entry_t *wait, unsigned mode,
object = container_of(op->op.object, struct cachefiles_object, fscache); object = container_of(op->op.object, struct cachefiles_object, fscache);
spin_lock(&object->work_lock); spin_lock(&object->work_lock);
list_add_tail(&monitor->op_link, &op->to_do); list_add_tail(&monitor->op_link, &op->to_do);
fscache_enqueue_retrieval(op);
spin_unlock(&object->work_lock); spin_unlock(&object->work_lock);
fscache_enqueue_retrieval(op);
fscache_put_retrieval(op); fscache_put_retrieval(op);
return 0; return 0;
} }
...@@ -398,7 +398,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, ...@@ -398,7 +398,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
struct inode *inode; struct inode *inode;
sector_t block; sector_t block;
unsigned shift; unsigned shift;
int ret; int ret, ret2;
object = container_of(op->op.object, object = container_of(op->op.object,
struct cachefiles_object, fscache); struct cachefiles_object, fscache);
...@@ -430,8 +430,8 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, ...@@ -430,8 +430,8 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
block = page->index; block = page->index;
block <<= shift; block <<= shift;
ret = bmap(inode, &block); ret2 = bmap(inode, &block);
ASSERT(ret < 0); ASSERT(ret2 == 0);
_debug("%llx -> %llx", _debug("%llx -> %llx",
(unsigned long long) (page->index << shift), (unsigned long long) (page->index << shift),
...@@ -739,8 +739,8 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, ...@@ -739,8 +739,8 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
block = page->index; block = page->index;
block <<= shift; block <<= shift;
ret = bmap(inode, &block); ret2 = bmap(inode, &block);
ASSERT(!ret); ASSERT(ret2 == 0);
_debug("%llx -> %llx", _debug("%llx -> %llx",
(unsigned long long) (page->index << shift), (unsigned long long) (page->index << shift),
......
...@@ -118,8 +118,6 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int ...@@ -118,8 +118,6 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int
nfss->fscache_key = NULL; nfss->fscache_key = NULL;
nfss->fscache = NULL; nfss->fscache = NULL;
if (!(nfss->options & NFS_OPTION_FSCACHE))
return;
if (!uniq) { if (!uniq) {
uniq = ""; uniq = "";
ulen = 1; ulen = 1;
...@@ -188,7 +186,8 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int ...@@ -188,7 +186,8 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int
/* create a cache index for looking up filehandles */ /* create a cache index for looking up filehandles */
nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache, nfss->fscache = fscache_acquire_cookie(nfss->nfs_client->fscache,
&nfs_fscache_super_index_def, &nfs_fscache_super_index_def,
key, sizeof(*key) + ulen, &key->key,
sizeof(key->key) + ulen,
NULL, 0, NULL, 0,
nfss, 0, true); nfss, 0, true);
dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n", dfprintk(FSCACHE, "NFS: get superblock cookie (0x%p/0x%p)\n",
...@@ -226,6 +225,19 @@ void nfs_fscache_release_super_cookie(struct super_block *sb) ...@@ -226,6 +225,19 @@ void nfs_fscache_release_super_cookie(struct super_block *sb)
} }
} }
static void nfs_fscache_update_auxdata(struct nfs_fscache_inode_auxdata *auxdata,
struct nfs_inode *nfsi)
{
memset(auxdata, 0, sizeof(*auxdata));
auxdata->mtime_sec = nfsi->vfs_inode.i_mtime.tv_sec;
auxdata->mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
auxdata->ctime_sec = nfsi->vfs_inode.i_ctime.tv_sec;
auxdata->ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
auxdata->change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
}
/* /*
* Initialise the per-inode cache cookie pointer for an NFS inode. * Initialise the per-inode cache cookie pointer for an NFS inode.
*/ */
...@@ -239,14 +251,7 @@ void nfs_fscache_init_inode(struct inode *inode) ...@@ -239,14 +251,7 @@ void nfs_fscache_init_inode(struct inode *inode)
if (!(nfss->fscache && S_ISREG(inode->i_mode))) if (!(nfss->fscache && S_ISREG(inode->i_mode)))
return; return;
memset(&auxdata, 0, sizeof(auxdata)); nfs_fscache_update_auxdata(&auxdata, nfsi);
auxdata.mtime_sec = nfsi->vfs_inode.i_mtime.tv_sec;
auxdata.mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
auxdata.ctime_sec = nfsi->vfs_inode.i_ctime.tv_sec;
auxdata.ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
if (NFS_SERVER(&nfsi->vfs_inode)->nfs_client->rpc_ops->version == 4)
auxdata.change_attr = inode_peek_iversion_raw(&nfsi->vfs_inode);
nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache, nfsi->fscache = fscache_acquire_cookie(NFS_SB(inode->i_sb)->fscache,
&nfs_fscache_inode_object_def, &nfs_fscache_inode_object_def,
...@@ -266,11 +271,7 @@ void nfs_fscache_clear_inode(struct inode *inode) ...@@ -266,11 +271,7 @@ void nfs_fscache_clear_inode(struct inode *inode)
dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie); dfprintk(FSCACHE, "NFS: clear cookie (0x%p/0x%p)\n", nfsi, cookie);
memset(&auxdata, 0, sizeof(auxdata)); nfs_fscache_update_auxdata(&auxdata, nfsi);
auxdata.mtime_sec = nfsi->vfs_inode.i_mtime.tv_sec;
auxdata.mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
auxdata.ctime_sec = nfsi->vfs_inode.i_ctime.tv_sec;
auxdata.ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
fscache_relinquish_cookie(cookie, &auxdata, false); fscache_relinquish_cookie(cookie, &auxdata, false);
nfsi->fscache = NULL; nfsi->fscache = NULL;
} }
...@@ -310,11 +311,7 @@ void nfs_fscache_open_file(struct inode *inode, struct file *filp) ...@@ -310,11 +311,7 @@ void nfs_fscache_open_file(struct inode *inode, struct file *filp)
if (!fscache_cookie_valid(cookie)) if (!fscache_cookie_valid(cookie))
return; return;
memset(&auxdata, 0, sizeof(auxdata)); nfs_fscache_update_auxdata(&auxdata, nfsi);
auxdata.mtime_sec = nfsi->vfs_inode.i_mtime.tv_sec;
auxdata.mtime_nsec = nfsi->vfs_inode.i_mtime.tv_nsec;
auxdata.ctime_sec = nfsi->vfs_inode.i_ctime.tv_sec;
auxdata.ctime_nsec = nfsi->vfs_inode.i_ctime.tv_nsec;
if (inode_is_open_for_write(inode)) { if (inode_is_open_for_write(inode)) {
dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi); dfprintk(FSCACHE, "NFS: nfsi 0x%p disabling cache\n", nfsi);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN)) #define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN))
#define MNT_status_sz (1) #define MNT_status_sz (1)
#define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE) #define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE)
#define MNT_fhandlev3_sz XDR_QUADLEN(NFS3_FHSIZE)
#define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS) #define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS)
/* /*
...@@ -37,7 +38,7 @@ ...@@ -37,7 +38,7 @@
*/ */
#define MNT_enc_dirpath_sz encode_dirpath_sz #define MNT_enc_dirpath_sz encode_dirpath_sz
#define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz) #define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz)
#define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandle_sz + \ #define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandlev3_sz + \
MNT_authflav3_sz) MNT_authflav3_sz)
/* /*
......
...@@ -6347,7 +6347,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, ...@@ -6347,7 +6347,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
.rpc_client = server->client, .rpc_client = server->client,
.rpc_message = &msg, .rpc_message = &msg,
.callback_ops = &nfs4_delegreturn_ops, .callback_ops = &nfs4_delegreturn_ops,
.flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF | RPC_TASK_TIMEOUT, .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
}; };
int status = 0; int status = 0;
......
...@@ -734,9 +734,9 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner) ...@@ -734,9 +734,9 @@ nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
state = new; state = new;
state->owner = owner; state->owner = owner;
atomic_inc(&owner->so_count); atomic_inc(&owner->so_count);
list_add_rcu(&state->inode_states, &nfsi->open_states);
ihold(inode); ihold(inode);
state->inode = inode; state->inode = inode;
list_add_rcu(&state->inode_states, &nfsi->open_states);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
/* Note: The reclaim code dictates that we add stateless /* Note: The reclaim code dictates that we add stateless
* and read-only stateids to the end of the list */ * and read-only stateids to the end of the list */
......
...@@ -752,7 +752,7 @@ int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, ...@@ -752,7 +752,7 @@ int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
.callback_ops = call_ops, .callback_ops = call_ops,
.callback_data = hdr, .callback_data = hdr,
.workqueue = nfsiod_workqueue, .workqueue = nfsiod_workqueue,
.flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF | flags, .flags = RPC_TASK_ASYNC | flags,
}; };
hdr->rw_ops->rw_initiate(hdr, &msg, rpc_ops, &task_setup_data, how); hdr->rw_ops->rw_initiate(hdr, &msg, rpc_ops, &task_setup_data, how);
...@@ -950,7 +950,8 @@ static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) ...@@ -950,7 +950,8 @@ static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
hdr->cred, hdr->cred,
NFS_PROTO(hdr->inode), NFS_PROTO(hdr->inode),
desc->pg_rpc_callops, desc->pg_rpc_callops,
desc->pg_ioflags, 0); desc->pg_ioflags,
RPC_TASK_CRED_NOREF);
return ret; return ret;
} }
......
...@@ -536,7 +536,8 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages, ...@@ -536,7 +536,8 @@ pnfs_generic_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
nfs_init_commit(data, NULL, NULL, cinfo); nfs_init_commit(data, NULL, NULL, cinfo);
nfs_initiate_commit(NFS_CLIENT(inode), data, nfs_initiate_commit(NFS_CLIENT(inode), data,
NFS_PROTO(data->inode), NFS_PROTO(data->inode),
data->mds_ops, how, 0); data->mds_ops, how,
RPC_TASK_CRED_NOREF);
} else { } else {
nfs_init_commit(data, NULL, data->lseg, cinfo); nfs_init_commit(data, NULL, data->lseg, cinfo);
initiate_commit(data, how); initiate_commit(data, how);
......
...@@ -1189,7 +1189,6 @@ static void nfs_get_cache_cookie(struct super_block *sb, ...@@ -1189,7 +1189,6 @@ static void nfs_get_cache_cookie(struct super_block *sb,
uniq = ctx->fscache_uniq; uniq = ctx->fscache_uniq;
ulen = strlen(ctx->fscache_uniq); ulen = strlen(ctx->fscache_uniq);
} }
return;
} }
nfs_fscache_get_super_cookie(sb, uniq, ulen); nfs_fscache_get_super_cookie(sb, uniq, ulen);
......
...@@ -1695,7 +1695,7 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data, ...@@ -1695,7 +1695,7 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data,
.callback_ops = call_ops, .callback_ops = call_ops,
.callback_data = data, .callback_data = data,
.workqueue = nfsiod_workqueue, .workqueue = nfsiod_workqueue,
.flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF | flags, .flags = RPC_TASK_ASYNC | flags,
.priority = priority, .priority = priority,
}; };
/* Set up the initial task struct. */ /* Set up the initial task struct. */
...@@ -1813,7 +1813,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how, ...@@ -1813,7 +1813,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how,
nfs_init_commit(data, head, NULL, cinfo); nfs_init_commit(data, head, NULL, cinfo);
atomic_inc(&cinfo->mds->rpcs_out); atomic_inc(&cinfo->mds->rpcs_out);
return nfs_initiate_commit(NFS_CLIENT(inode), data, NFS_PROTO(inode), return nfs_initiate_commit(NFS_CLIENT(inode), data, NFS_PROTO(inode),
data->mds_ops, how, 0); data->mds_ops, how, RPC_TASK_CRED_NOREF);
} }
/* /*
......
...@@ -889,7 +889,9 @@ static void rpc_free_client_work(struct work_struct *work) ...@@ -889,7 +889,9 @@ static void rpc_free_client_work(struct work_struct *work)
* here. * here.
*/ */
rpc_clnt_debugfs_unregister(clnt); rpc_clnt_debugfs_unregister(clnt);
rpc_free_clid(clnt);
rpc_clnt_remove_pipedir(clnt); rpc_clnt_remove_pipedir(clnt);
xprt_put(rcu_dereference_raw(clnt->cl_xprt));
kfree(clnt); kfree(clnt);
rpciod_down(); rpciod_down();
...@@ -907,10 +909,8 @@ rpc_free_client(struct rpc_clnt *clnt) ...@@ -907,10 +909,8 @@ rpc_free_client(struct rpc_clnt *clnt)
rpc_unregister_client(clnt); rpc_unregister_client(clnt);
rpc_free_iostats(clnt->cl_metrics); rpc_free_iostats(clnt->cl_metrics);
clnt->cl_metrics = NULL; clnt->cl_metrics = NULL;
xprt_put(rcu_dereference_raw(clnt->cl_xprt));
xprt_iter_destroy(&clnt->cl_xpi); xprt_iter_destroy(&clnt->cl_xpi);
put_cred(clnt->cl_cred); put_cred(clnt->cl_cred);
rpc_free_clid(clnt);
INIT_WORK(&clnt->cl_work, rpc_free_client_work); INIT_WORK(&clnt->cl_work, rpc_free_client_work);
schedule_work(&clnt->cl_work); schedule_work(&clnt->cl_work);
...@@ -2433,6 +2433,11 @@ rpc_check_timeout(struct rpc_task *task) ...@@ -2433,6 +2433,11 @@ rpc_check_timeout(struct rpc_task *task)
{ {
struct rpc_clnt *clnt = task->tk_client; struct rpc_clnt *clnt = task->tk_client;
if (RPC_SIGNALLED(task)) {
rpc_call_rpcerror(task, -ERESTARTSYS);
return;
}
if (xprt_adjust_timeout(task->tk_rqstp) == 0) if (xprt_adjust_timeout(task->tk_rqstp) == 0)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment