Commit c01d3645 authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFSv4: Don't return the delegation when not needed by NFSv4.x (x>0)

Starting with NFSv4.1, the server is able to deduce the client id from
the SEQUENCE op which means it can always figure out whether or not
the client is holding a delegation on a file that is being changed.
For that reason, RFC5661 does not require a delegation to be unconditionally
recalled on operations such as SETATTR, RENAME, or REMOVE.

Note that for now, we continue to return READ delegations since that is
still expected by the Linux knfsd server.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent c135cb39
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/nfs_xdr.h> #include <linux/nfs_xdr.h>
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "nfs4session.h"
#include "delegation.h" #include "delegation.h"
#include "internal.h" #include "internal.h"
#include "nfs4trace.h" #include "nfs4trace.h"
...@@ -547,6 +548,22 @@ int nfs4_inode_return_delegation(struct inode *inode) ...@@ -547,6 +548,22 @@ int nfs4_inode_return_delegation(struct inode *inode)
return err; return err;
} }
/**
* nfs4_inode_make_writeable
* @inode: pointer to inode
*
* Make the inode writeable by returning the delegation if necessary
*
* Returns zero on success, or a negative errno value.
*/
int nfs4_inode_make_writeable(struct inode *inode)
{
if (!nfs4_has_session(NFS_SERVER(inode)->nfs_client) ||
!nfs4_check_delegation(inode, FMODE_WRITE))
return nfs4_inode_return_delegation(inode);
return 0;
}
static void nfs_mark_return_if_closed_delegation(struct nfs_server *server, static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
struct nfs_delegation *delegation) struct nfs_delegation *delegation)
{ {
......
...@@ -70,6 +70,7 @@ int nfs4_check_delegation(struct inode *inode, fmode_t flags); ...@@ -70,6 +70,7 @@ int nfs4_check_delegation(struct inode *inode, fmode_t flags);
bool nfs4_delegation_flush_on_close(const struct inode *inode); bool nfs4_delegation_flush_on_close(const struct inode *inode);
void nfs_inode_find_delegation_state_and_recover(struct inode *inode, void nfs_inode_find_delegation_state_and_recover(struct inode *inode,
const nfs4_stateid *stateid); const nfs4_stateid *stateid);
int nfs4_inode_make_writeable(struct inode *inode);
#endif #endif
......
...@@ -3877,7 +3877,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -3877,7 +3877,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
/* Return any delegations if we're going to change ACLs */ /* Return any delegations if we're going to change ACLs */
if ((sattr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) if ((sattr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
nfs4_inode_return_delegation(inode); nfs4_inode_make_writeable(inode);
status = nfs4_do_setattr(inode, cred, fattr, sattr, ctx, NULL, label); status = nfs4_do_setattr(inode, cred, fattr, sattr, ctx, NULL, label);
if (status == 0) { if (status == 0) {
...@@ -4210,8 +4210,12 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry) ...@@ -4210,8 +4210,12 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int err; int err;
if (inode) if (inode) {
nfs4_inode_return_delegation(inode); if (inode->i_nlink == 1)
nfs4_inode_return_delegation(inode);
else
nfs4_inode_make_writeable(inode);
}
do { do {
err = _nfs4_proc_remove(dir, &dentry->d_name); err = _nfs4_proc_remove(dir, &dentry->d_name);
trace_nfs4_remove(dir, &dentry->d_name, err); trace_nfs4_remove(dir, &dentry->d_name, err);
...@@ -4284,7 +4288,7 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, ...@@ -4284,7 +4288,7 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg,
struct inode *new_inode = d_inode(new_dentry); struct inode *new_inode = d_inode(new_dentry);
if (old_inode) if (old_inode)
nfs4_inode_return_delegation(old_inode); nfs4_inode_make_writeable(old_inode);
if (new_inode) if (new_inode)
nfs4_inode_return_delegation(new_inode); nfs4_inode_return_delegation(new_inode);
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME]; msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
...@@ -4350,7 +4354,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct ...@@ -4350,7 +4354,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct
} }
arg.bitmask = nfs4_bitmask(server, res.label); arg.bitmask = nfs4_bitmask(server, res.label);
nfs4_inode_return_delegation(inode); nfs4_inode_make_writeable(inode);
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
if (!status) { if (!status) {
...@@ -5345,7 +5349,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl ...@@ -5345,7 +5349,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
i = buf_to_pages_noslab(buf, buflen, arg.acl_pages); i = buf_to_pages_noslab(buf, buflen, arg.acl_pages);
if (i < 0) if (i < 0)
return i; return i;
nfs4_inode_return_delegation(inode); nfs4_inode_make_writeable(inode);
ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
/* /*
......
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