Commit 960f0716 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-5.13-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

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

  Stable fixes:

   - Fix use-after-free in nfs4_init_client()

  Bugfixes:

   - Fix deadlock between nfs4_evict_inode() and nfs4_opendata_get_inode()

   - Fix second deadlock in nfs4_evict_inode()

   - nfs4_proc_set_acl should not change the value of NFS_CAP_UIDGID_NOMAP

   - Fix setting of the NFS_CAP_SECURITY_LABEL capability"

* tag 'nfs-for-5.13-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4: Fix second deadlock in nfs4_evict_inode()
  NFSv4: Fix deadlock between nfs4_evict_inode() and nfs4_opendata_get_inode()
  NFS: FMODE_READ and friends are C macros, not enum types
  NFS: Fix a potential NULL dereference in nfs_get_client()
  NFS: Fix use-after-free in nfs4_init_client()
  NFS: Ensure the NFS_CAP_SECURITY_LABEL capability is set when appropriate
  NFSv4: nfs4_proc_set_acl needs to restore NFS_CAP_UIDGID_NOMAP on error.
parents 331a6edb c3aba897
...@@ -406,7 +406,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init) ...@@ -406,7 +406,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
if (cl_init->hostname == NULL) { if (cl_init->hostname == NULL) {
WARN_ON(1); WARN_ON(1);
return NULL; return ERR_PTR(-EINVAL);
} }
/* see if the client already exists */ /* see if the client already exists */
......
...@@ -205,6 +205,7 @@ struct nfs4_exception { ...@@ -205,6 +205,7 @@ struct nfs4_exception {
struct inode *inode; struct inode *inode;
nfs4_stateid *stateid; nfs4_stateid *stateid;
long timeout; long timeout;
unsigned char task_is_privileged : 1;
unsigned char delay : 1, unsigned char delay : 1,
recovering : 1, recovering : 1,
retry : 1; retry : 1;
......
...@@ -435,8 +435,8 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, ...@@ -435,8 +435,8 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
*/ */
nfs_mark_client_ready(clp, -EPERM); nfs_mark_client_ready(clp, -EPERM);
} }
nfs_put_client(clp);
clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags); clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
nfs_put_client(clp);
return old; return old;
error: error:
......
...@@ -589,6 +589,8 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ ...@@ -589,6 +589,8 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
goto out_retry; goto out_retry;
} }
if (exception->recovering) { if (exception->recovering) {
if (exception->task_is_privileged)
return -EDEADLOCK;
ret = nfs4_wait_clnt_recover(clp); ret = nfs4_wait_clnt_recover(clp);
if (test_bit(NFS_MIG_FAILED, &server->mig_status)) if (test_bit(NFS_MIG_FAILED, &server->mig_status))
return -EIO; return -EIO;
...@@ -614,6 +616,8 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server, ...@@ -614,6 +616,8 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
goto out_retry; goto out_retry;
} }
if (exception->recovering) { if (exception->recovering) {
if (exception->task_is_privileged)
return -EDEADLOCK;
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
...@@ -3878,6 +3882,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f ...@@ -3878,6 +3882,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
server->caps |= NFS_CAP_HARDLINKS; server->caps |= NFS_CAP_HARDLINKS;
if (res.has_symlinks != 0) if (res.has_symlinks != 0)
server->caps |= NFS_CAP_SYMLINKS; server->caps |= NFS_CAP_SYMLINKS;
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
server->caps |= NFS_CAP_SECURITY_LABEL;
#endif
if (!(res.attr_bitmask[0] & FATTR4_WORD0_FILEID)) if (!(res.attr_bitmask[0] & FATTR4_WORD0_FILEID))
server->fattr_valid &= ~NFS_ATTR_FATTR_FILEID; server->fattr_valid &= ~NFS_ATTR_FATTR_FILEID;
if (!(res.attr_bitmask[1] & FATTR4_WORD1_MODE)) if (!(res.attr_bitmask[1] & FATTR4_WORD1_MODE))
...@@ -3898,10 +3906,6 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f ...@@ -3898,10 +3906,6 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
server->fattr_valid &= ~NFS_ATTR_FATTR_CTIME; server->fattr_valid &= ~NFS_ATTR_FATTR_CTIME;
if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)) if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME; server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
if (!(res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL))
server->fattr_valid &= ~NFS_ATTR_FATTR_V4_SECURITY_LABEL;
#endif
memcpy(server->attr_bitmask_nl, res.attr_bitmask, memcpy(server->attr_bitmask_nl, res.attr_bitmask,
sizeof(server->attr_bitmask)); sizeof(server->attr_bitmask));
server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
...@@ -5968,6 +5972,14 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen ...@@ -5968,6 +5972,14 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
do { do {
err = __nfs4_proc_set_acl(inode, buf, buflen); err = __nfs4_proc_set_acl(inode, buf, buflen);
trace_nfs4_set_acl(inode, err); trace_nfs4_set_acl(inode, err);
if (err == -NFS4ERR_BADOWNER || err == -NFS4ERR_BADNAME) {
/*
* no need to retry since the kernel
* isn't involved in encoding the ACEs.
*/
err = -EINVAL;
break;
}
err = nfs4_handle_exception(NFS_SERVER(inode), err, err = nfs4_handle_exception(NFS_SERVER(inode), err,
&exception); &exception);
} while (exception.retry); } while (exception.retry);
...@@ -6409,6 +6421,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) ...@@ -6409,6 +6421,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
struct nfs4_exception exception = { struct nfs4_exception exception = {
.inode = data->inode, .inode = data->inode,
.stateid = &data->stateid, .stateid = &data->stateid,
.task_is_privileged = data->args.seq_args.sa_privileged,
}; };
if (!nfs4_sequence_done(task, &data->res.seq_res)) if (!nfs4_sequence_done(task, &data->res.seq_res))
...@@ -6532,7 +6545,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, ...@@ -6532,7 +6545,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
data = kzalloc(sizeof(*data), GFP_NOFS); data = kzalloc(sizeof(*data), GFP_NOFS);
if (data == NULL) if (data == NULL)
return -ENOMEM; return -ENOMEM;
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);
nfs4_state_protect(server->nfs_client, nfs4_state_protect(server->nfs_client,
NFS_SP4_MACH_CRED_CLEANUP, NFS_SP4_MACH_CRED_CLEANUP,
...@@ -6563,6 +6575,12 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, ...@@ -6563,6 +6575,12 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
} }
} }
if (!data->inode)
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1,
1);
else
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1,
0);
task_setup_data.callback_data = data; task_setup_data.callback_data = data;
msg.rpc_argp = &data->args; msg.rpc_argp = &data->args;
msg.rpc_resp = &data->res; msg.rpc_resp = &data->res;
...@@ -9640,15 +9658,20 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync) ...@@ -9640,15 +9658,20 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
&task_setup_data.rpc_client, &msg); &task_setup_data.rpc_client, &msg);
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
if (!sync) {
lrp->inode = nfs_igrab_and_active(lrp->args.inode); lrp->inode = nfs_igrab_and_active(lrp->args.inode);
if (!sync) {
if (!lrp->inode) { if (!lrp->inode) {
nfs4_layoutreturn_release(lrp); nfs4_layoutreturn_release(lrp);
return -EAGAIN; return -EAGAIN;
} }
task_setup_data.flags |= RPC_TASK_ASYNC; task_setup_data.flags |= RPC_TASK_ASYNC;
} }
nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1, 0); if (!lrp->inode)
nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1,
1);
else
nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1,
0);
task = rpc_run_task(&task_setup_data); task = rpc_run_task(&task_setup_data);
if (IS_ERR(task)) if (IS_ERR(task))
return PTR_ERR(task); return PTR_ERR(task);
......
...@@ -430,10 +430,6 @@ TRACE_DEFINE_ENUM(O_CLOEXEC); ...@@ -430,10 +430,6 @@ TRACE_DEFINE_ENUM(O_CLOEXEC);
{ O_NOATIME, "O_NOATIME" }, \ { O_NOATIME, "O_NOATIME" }, \
{ O_CLOEXEC, "O_CLOEXEC" }) { O_CLOEXEC, "O_CLOEXEC" })
TRACE_DEFINE_ENUM(FMODE_READ);
TRACE_DEFINE_ENUM(FMODE_WRITE);
TRACE_DEFINE_ENUM(FMODE_EXEC);
#define show_fmode_flags(mode) \ #define show_fmode_flags(mode) \
__print_flags(mode, "|", \ __print_flags(mode, "|", \
{ ((__force unsigned long)FMODE_READ), "READ" }, \ { ((__force unsigned long)FMODE_READ), "READ" }, \
......
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