Commit 27999f25 authored by Trond Myklebust's avatar Trond Myklebust

NFSv4.1: Ensure that the layout recall callback matches layout stateids

It is not sufficient to compare filehandles when we receive a layout
recall from the server; we also need to check that the layout stateids
match.
Reported-by: default avatarshaobingqing <shaobingqing@bwstor.com.cn>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent e999e80e
...@@ -112,7 +112,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, ...@@ -112,7 +112,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
* TODO: keep track of all layouts (and delegations) in a hash table * TODO: keep track of all layouts (and delegations) in a hash table
* hashed by filehandle. * hashed by filehandle.
*/ */
static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh) static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
struct nfs_fh *fh, nfs4_stateid *stateid)
{ {
struct nfs_server *server; struct nfs_server *server;
struct inode *ino; struct inode *ino;
...@@ -120,6 +121,8 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, ...@@ -120,6 +121,8 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
list_for_each_entry(lo, &server->layouts, plh_layouts) { list_for_each_entry(lo, &server->layouts, plh_layouts) {
if (!nfs4_stateid_match_other(&lo->plh_stateid, stateid))
continue;
if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh)) if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
continue; continue;
ino = igrab(lo->plh_inode); ino = igrab(lo->plh_inode);
...@@ -141,13 +144,14 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, ...@@ -141,13 +144,14 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
return NULL; return NULL;
} }
static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh) static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
struct nfs_fh *fh, nfs4_stateid *stateid)
{ {
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
rcu_read_lock(); rcu_read_lock();
lo = get_layout_by_fh_locked(clp, fh); lo = get_layout_by_fh_locked(clp, fh, stateid);
rcu_read_unlock(); rcu_read_unlock();
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
...@@ -162,9 +166,9 @@ static u32 initiate_file_draining(struct nfs_client *clp, ...@@ -162,9 +166,9 @@ static u32 initiate_file_draining(struct nfs_client *clp,
u32 rv = NFS4ERR_NOMATCHING_LAYOUT; u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
LIST_HEAD(free_me_list); LIST_HEAD(free_me_list);
lo = get_layout_by_fh(clp, &args->cbl_fh); lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid);
if (!lo) if (!lo)
return NFS4ERR_NOMATCHING_LAYOUT; goto out;
ino = lo->plh_inode; ino = lo->plh_inode;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
...@@ -179,6 +183,7 @@ static u32 initiate_file_draining(struct nfs_client *clp, ...@@ -179,6 +183,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
pnfs_free_lseg_list(&free_me_list); pnfs_free_lseg_list(&free_me_list);
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
iput(ino); iput(ino);
out:
return rv; return rv;
} }
......
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