Skip to content

Commit

Permalink
NFSv4 reduce attribute requests for open reclaim
Browse files Browse the repository at this point in the history
We currently make no distinction in attribute requests between normal OPENs
and OPEN with CLAIM_PREVIOUS.  This offers more possibility of failures in
the GETATTR response which foils OPEN reclaim attempts.

Reduce the requested attributes to the bare minimum needed to update the
reclaim open stateid and split nfs4_opendata_to_nfs4_state processing
accordingly.

Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Andy Adamson authored and Trond Myklebust committed Oct 3, 2012
1 parent 807d66d commit e23008e
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 27 deletions.
114 changes: 88 additions & 26 deletions fs/nfs/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
FATTR4_WORD2_MDSTHRESHOLD
};

static const u32 nfs4_open_noattr_bitmap[3] = {
FATTR4_WORD0_TYPE
| FATTR4_WORD0_CHANGE
| FATTR4_WORD0_FILEID,
};

const u32 nfs4_statfs_bitmap[2] = {
FATTR4_WORD0_FILES_AVAIL
| FATTR4_WORD0_FILES_FREE
Expand Down Expand Up @@ -1126,11 +1132,80 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
return state;
}

static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
static void
nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
{
struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
struct nfs_delegation *delegation;
int delegation_flags = 0;

rcu_read_lock();
delegation = rcu_dereference(NFS_I(state->inode)->delegation);
if (delegation)
delegation_flags = delegation->flags;
rcu_read_unlock();
if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
"returning a delegation for "
"OPEN(CLAIM_DELEGATE_CUR)\n",
clp->cl_hostname);
} else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
nfs_inode_set_delegation(state->inode,
data->owner->so_cred,
&data->o_res);
else
nfs_inode_reclaim_delegation(state->inode,
data->owner->so_cred,
&data->o_res);
}

/*
* Check the inode attributes against the CLAIM_PREVIOUS returned attributes
* and update the nfs4_state.
*/
static struct nfs4_state *
_nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
{
struct inode *inode = data->state->inode;
struct nfs4_state *state = data->state;
int ret;

if (!data->rpc_done) {
ret = data->rpc_status;
goto err;
}

ret = -ESTALE;
if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) ||
!(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) ||
!(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE))
goto err;

ret = -ENOMEM;
state = nfs4_get_open_state(inode, data->owner);
if (state == NULL)
goto err;

ret = nfs_refresh_inode(inode, &data->f_attr);
if (ret)
goto err;

if (data->o_res.delegation_type != 0)
nfs4_opendata_check_deleg(data, state);
update_open_stateid(state, &data->o_res.stateid, NULL,
data->o_arg.fmode);

return state;
err:
return ERR_PTR(ret);

}

static struct nfs4_state *
_nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
{
struct inode *inode;
struct nfs4_state *state = NULL;
struct nfs_delegation *delegation;
int ret;

if (!data->rpc_done) {
Expand All @@ -1149,30 +1224,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
state = nfs4_get_open_state(inode, data->owner);
if (state == NULL)
goto err_put_inode;
if (data->o_res.delegation_type != 0) {
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
int delegation_flags = 0;

rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation)
delegation_flags = delegation->flags;
rcu_read_unlock();
if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
"returning a delegation for "
"OPEN(CLAIM_DELEGATE_CUR)\n",
clp->cl_hostname);
} else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
nfs_inode_set_delegation(state->inode,
data->owner->so_cred,
&data->o_res);
else
nfs_inode_reclaim_delegation(state->inode,
data->owner->so_cred,
&data->o_res);
}

if (data->o_res.delegation_type != 0)
nfs4_opendata_check_deleg(data, state);
update_open_stateid(state, &data->o_res.stateid, NULL,
data->o_arg.fmode);
iput(inode);
Expand All @@ -1184,6 +1237,14 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
return ERR_PTR(ret);
}

static struct nfs4_state *
nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
{
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
return _nfs4_opendata_reclaim_to_nfs4_state(data);
return _nfs4_opendata_to_nfs4_state(data);
}

static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
{
struct nfs_inode *nfsi = NFS_I(state->inode);
Expand Down Expand Up @@ -1505,6 +1566,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
}
data->timestamp = jiffies;
Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/nfs4xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2264,7 +2264,7 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
encode_open(xdr, args, &hdr);
if (args->access)
encode_access(xdr, args->access, &hdr);
encode_getfattr(xdr, args->bitmask, &hdr);
encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
encode_nops(&hdr);
}

Expand Down

0 comments on commit e23008e

Please sign in to comment.