mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 07:04:10 +08:00
nfs41: v2 fix cb_recall bug
in NFSv4.1 the seqid part of a stateid in CB_RECALL must be 0 Signed-off-by: Alexandros Batsakis <batsakis@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
0629e370dd
commit
2597641dea
@ -106,6 +106,8 @@ struct cb_sequenceres {
|
||||
extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args,
|
||||
struct cb_sequenceres *res);
|
||||
|
||||
extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation,
|
||||
const nfs4_stateid *stateid);
|
||||
|
||||
#define RCA4_TYPE_MASK_RDATA_DLG 0
|
||||
#define RCA4_TYPE_MASK_WDATA_DLG 1
|
||||
@ -125,8 +127,9 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
|
||||
#ifdef CONFIG_NFS_V4
|
||||
extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt);
|
||||
extern void nfs_callback_down(int minorversion);
|
||||
extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation,
|
||||
const nfs4_stateid *stateid);
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
|
||||
/*
|
||||
* nfs41: Callbacks are expected to not cause substantial latency,
|
||||
* so we limit their concurrency to 1 by setting up the maximum number
|
||||
|
@ -61,6 +61,16 @@ out:
|
||||
return res->status;
|
||||
}
|
||||
|
||||
static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *)
|
||||
{
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
if (clp->cl_minorversion > 0)
|
||||
return nfs41_validate_delegation_stateid;
|
||||
#endif
|
||||
return nfs4_validate_delegation_stateid;
|
||||
}
|
||||
|
||||
|
||||
__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
@ -81,7 +91,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
|
||||
inode = nfs_delegation_find_inode(clp, &args->fh);
|
||||
if (inode != NULL) {
|
||||
/* Set up a helper thread to actually return the delegation */
|
||||
switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
|
||||
switch (nfs_async_inode_return_delegation(inode, &args->stateid,
|
||||
nfs_validate_delegation_stateid(clp))) {
|
||||
case 0:
|
||||
res = 0;
|
||||
break;
|
||||
@ -102,8 +113,31 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
|
||||
{
|
||||
if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
|
||||
sizeof(delegation->stateid.data)) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
|
||||
int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid)
|
||||
{
|
||||
if (delegation == NULL)
|
||||
return 0;
|
||||
|
||||
/* seqid is 4-bytes long */
|
||||
if (((u32 *) &stateid->data)[0] != 0)
|
||||
return 0;
|
||||
if (memcmp(&delegation->stateid.data[4], &stateid->data[4],
|
||||
sizeof(stateid->data)-4))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the sequenceID sent by the server.
|
||||
* Return success if the sequenceID is one more than what we last saw on
|
||||
@ -255,5 +289,4 @@ out:
|
||||
dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
@ -454,18 +454,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
|
||||
/*
|
||||
* Asynchronous delegation recall!
|
||||
*/
|
||||
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
|
||||
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
|
||||
int (*validate_stateid)(struct nfs_delegation *delegation,
|
||||
const nfs4_stateid *stateid))
|
||||
{
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
struct nfs_delegation *delegation;
|
||||
|
||||
rcu_read_lock();
|
||||
delegation = rcu_dereference(NFS_I(inode)->delegation);
|
||||
if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data,
|
||||
sizeof(delegation->stateid.data)) != 0) {
|
||||
|
||||
if (!validate_stateid(delegation, stateid)) {
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
nfs_mark_return_delegation(clp, delegation);
|
||||
rcu_read_unlock();
|
||||
nfs_delegation_run_state_manager(clp);
|
||||
|
@ -34,7 +34,9 @@ enum {
|
||||
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
|
||||
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
|
||||
int nfs_inode_return_delegation(struct inode *inode);
|
||||
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
|
||||
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid,
|
||||
int (*validate_stateid)(struct nfs_delegation *delegation,
|
||||
const nfs4_stateid *stateid));
|
||||
void nfs_inode_return_delegation_noreclaim(struct inode *inode);
|
||||
|
||||
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
|
||||
|
Loading…
Reference in New Issue
Block a user