Commit e547204f authored by Linus Torvalds's avatar Linus Torvalds

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

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

   - stable fix for exclusive create if the server supports the umask
     attribute

   - trunking detection should handle ERESTARTSYS/EINTR

   - stable fix for a race in the LAYOUTGET function

   - stable fix to revert "nfs_rename() handle -ERESTARTSYS dentry left
     behind"

   - nfs4_callback_free_slot() cannot call nfs4_slot_tbl_drain_complete()"

* tag 'nfs-for-4.12-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4.1: nfs4_callback_free_slot() cannot call nfs4_slot_tbl_drain_complete()
  Revert "NFS: nfs_rename() handle -ERESTARTSYS dentry left behind"
  NFSv4.1: Fix a race in nfs4_proc_layoutget
  NFS: Trunking detection should handle ERESTARTSYS/EINTR
  NFSv4.2: Don't send mode again in post-EXCLUSIVE4_1 SETATTR with umask
parents 5a37be4b 2e31b4cb
...@@ -753,7 +753,6 @@ static void nfs4_callback_free_slot(struct nfs4_session *session, ...@@ -753,7 +753,6 @@ static void nfs4_callback_free_slot(struct nfs4_session *session,
* A single slot, so highest used slotid is either 0 or -1 * A single slot, so highest used slotid is either 0 or -1
*/ */
nfs4_free_slot(tbl, slot); nfs4_free_slot(tbl, slot);
nfs4_slot_tbl_drain_complete(tbl);
spin_unlock(&tbl->slot_tbl_lock); spin_unlock(&tbl->slot_tbl_lock);
} }
......
...@@ -1946,29 +1946,6 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) ...@@ -1946,29 +1946,6 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
} }
EXPORT_SYMBOL_GPL(nfs_link); EXPORT_SYMBOL_GPL(nfs_link);
static void
nfs_complete_rename(struct rpc_task *task, struct nfs_renamedata *data)
{
struct dentry *old_dentry = data->old_dentry;
struct dentry *new_dentry = data->new_dentry;
struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry);
nfs_mark_for_revalidate(old_inode);
switch (task->tk_status) {
case 0:
if (new_inode != NULL)
nfs_drop_nlink(new_inode);
d_move(old_dentry, new_dentry);
nfs_set_verifier(new_dentry,
nfs_save_change_attribute(data->new_dir));
break;
case -ENOENT:
nfs_dentry_handle_enoent(old_dentry);
}
}
/* /*
* RENAME * RENAME
* FIXME: Some nfsds, like the Linux user space nfsd, may generate a * FIXME: Some nfsds, like the Linux user space nfsd, may generate a
...@@ -1999,7 +1976,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1999,7 +1976,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
{ {
struct inode *old_inode = d_inode(old_dentry); struct inode *old_inode = d_inode(old_dentry);
struct inode *new_inode = d_inode(new_dentry); struct inode *new_inode = d_inode(new_dentry);
struct dentry *dentry = NULL; struct dentry *dentry = NULL, *rehash = NULL;
struct rpc_task *task; struct rpc_task *task;
int error = -EBUSY; int error = -EBUSY;
...@@ -2022,8 +1999,10 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2022,8 +1999,10 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* To prevent any new references to the target during the * To prevent any new references to the target during the
* rename, we unhash the dentry in advance. * rename, we unhash the dentry in advance.
*/ */
if (!d_unhashed(new_dentry)) if (!d_unhashed(new_dentry)) {
d_drop(new_dentry); d_drop(new_dentry);
rehash = new_dentry;
}
if (d_count(new_dentry) > 2) { if (d_count(new_dentry) > 2) {
int err; int err;
...@@ -2040,6 +2019,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2040,6 +2019,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out; goto out;
new_dentry = dentry; new_dentry = dentry;
rehash = NULL;
new_inode = NULL; new_inode = NULL;
} }
} }
...@@ -2048,8 +2028,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2048,8 +2028,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_inode != NULL) if (new_inode != NULL)
NFS_PROTO(new_inode)->return_delegation(new_inode); NFS_PROTO(new_inode)->return_delegation(new_inode);
task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
nfs_complete_rename);
if (IS_ERR(task)) { if (IS_ERR(task)) {
error = PTR_ERR(task); error = PTR_ERR(task);
goto out; goto out;
...@@ -2059,9 +2038,27 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2059,9 +2038,27 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (error == 0) if (error == 0)
error = task->tk_status; error = task->tk_status;
rpc_put_task(task); rpc_put_task(task);
nfs_mark_for_revalidate(old_inode);
out: out:
if (rehash)
d_rehash(rehash);
trace_nfs_rename_exit(old_dir, old_dentry, trace_nfs_rename_exit(old_dir, old_dentry,
new_dir, new_dentry, error); new_dir, new_dentry, error);
if (!error) {
if (new_inode != NULL)
nfs_drop_nlink(new_inode);
/*
* The d_move() should be here instead of in an async RPC completion
* handler because we need the proper locks to move the dentry. If
* we're interrupted by a signal, the async RPC completion handler
* should mark the directories for revalidation.
*/
d_move(old_dentry, new_dentry);
nfs_set_verifier(new_dentry,
nfs_save_change_attribute(new_dir));
} else if (error == -ENOENT)
nfs_dentry_handle_enoent(old_dentry);
/* new dentry created? */ /* new dentry created? */
if (dentry) if (dentry)
dput(dentry); dput(dentry);
......
...@@ -2589,7 +2589,8 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, ...@@ -2589,7 +2589,8 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
/* Except MODE, it seems harmless of setting twice. */ /* Except MODE, it seems harmless of setting twice. */
if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE && if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE &&
attrset[1] & FATTR4_WORD1_MODE) (attrset[1] & FATTR4_WORD1_MODE ||
attrset[2] & FATTR4_WORD2_MODE_UMASK))
sattr->ia_valid &= ~ATTR_MODE; sattr->ia_valid &= ~ATTR_MODE;
if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL) if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL)
...@@ -8416,6 +8417,7 @@ static void nfs4_layoutget_release(void *calldata) ...@@ -8416,6 +8417,7 @@ static void nfs4_layoutget_release(void *calldata)
size_t max_pages = max_response_pages(server); size_t max_pages = max_response_pages(server);
dprintk("--> %s\n", __func__); dprintk("--> %s\n", __func__);
nfs4_sequence_free_slot(&lgp->res.seq_res);
nfs4_free_pages(lgp->args.layout.pages, max_pages); nfs4_free_pages(lgp->args.layout.pages, max_pages);
pnfs_put_layout_hdr(NFS_I(inode)->layout); pnfs_put_layout_hdr(NFS_I(inode)->layout);
put_nfs_open_context(lgp->args.ctx); put_nfs_open_context(lgp->args.ctx);
...@@ -8490,7 +8492,6 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags) ...@@ -8490,7 +8492,6 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
/* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */ /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
if (status == 0 && lgp->res.layoutp->len) if (status == 0 && lgp->res.layoutp->len)
lseg = pnfs_layout_process(lgp); lseg = pnfs_layout_process(lgp);
nfs4_sequence_free_slot(&lgp->res.seq_res);
rpc_put_task(task); rpc_put_task(task);
dprintk("<-- %s status=%d\n", __func__, status); dprintk("<-- %s status=%d\n", __func__, status);
if (status) if (status)
......
...@@ -2134,6 +2134,8 @@ int nfs4_discover_server_trunking(struct nfs_client *clp, ...@@ -2134,6 +2134,8 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
put_rpccred(cred); put_rpccred(cred);
switch (status) { switch (status) {
case 0: case 0:
case -EINTR:
case -ERESTARTSYS:
break; break;
case -ETIMEDOUT: case -ETIMEDOUT:
if (clnt->cl_softrtry) if (clnt->cl_softrtry)
......
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