Commit 7b410d9c authored by Trond Myklebust's avatar Trond Myklebust

pNFS: Delay getting the layout header in CB_LAYOUTRECALL handlers

Instead of grabbing the layout, we want to get the inode so that we
can reduce races between layoutget and layoutrecall when the server
does not support call referring.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 17822b20
...@@ -110,20 +110,52 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, ...@@ -110,20 +110,52 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
/* /*
* Lookup a layout by filehandle. * Lookup a layout inode by stateid
* *
* Note: gets a refcount on the layout hdr and on its respective inode. * Note: returns a refcount on the inode and superblock
* Caller must put the layout hdr and the inode. */
static struct inode *nfs_layout_find_inode_by_stateid(struct nfs_client *clp,
const nfs4_stateid *stateid)
{
struct nfs_server *server;
struct inode *inode;
struct pnfs_layout_hdr *lo;
restart:
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
list_for_each_entry(lo, &server->layouts, plh_layouts) {
if (stateid != NULL &&
!nfs4_stateid_match_other(stateid, &lo->plh_stateid))
continue;
inode = igrab(lo->plh_inode);
if (!inode)
continue;
if (!nfs_sb_active(inode->i_sb)) {
rcu_read_lock();
spin_unlock(&clp->cl_lock);
iput(inode);
spin_lock(&clp->cl_lock);
goto restart;
}
return inode;
}
}
return NULL;
}
/*
* Lookup a layout inode by filehandle.
*
* Note: returns a refcount on the inode and superblock
* *
* TODO: keep track of all layouts (and delegations) in a hash table
* hashed by filehandle.
*/ */
static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, static struct inode *nfs_layout_find_inode_by_fh(struct nfs_client *clp,
struct nfs_fh *fh) const struct nfs_fh *fh)
{ {
struct nfs_server *server; struct nfs_server *server;
struct nfs_inode *nfsi; struct nfs_inode *nfsi;
struct inode *ino; struct inode *inode;
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
restart: restart:
...@@ -134,37 +166,38 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, ...@@ -134,37 +166,38 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
continue; continue;
if (nfsi->layout != lo) if (nfsi->layout != lo)
continue; continue;
ino = igrab(lo->plh_inode); inode = igrab(lo->plh_inode);
if (!ino) if (!inode)
break; continue;
spin_lock(&ino->i_lock); if (!nfs_sb_active(inode->i_sb)) {
/* Is this layout in the process of being freed? */ rcu_read_lock();
if (nfsi->layout != lo) { spin_unlock(&clp->cl_lock);
spin_unlock(&ino->i_lock); iput(inode);
iput(ino); spin_lock(&clp->cl_lock);
goto restart; goto restart;
} }
pnfs_get_layout_hdr(lo); return inode;
spin_unlock(&ino->i_lock);
return lo;
} }
} }
return NULL; return NULL;
} }
static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, static struct inode *nfs_layout_find_inode(struct nfs_client *clp,
struct nfs_fh *fh) const struct nfs_fh *fh,
const nfs4_stateid *stateid)
{ {
struct pnfs_layout_hdr *lo; struct inode *inode;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
rcu_read_lock(); rcu_read_lock();
lo = get_layout_by_fh_locked(clp, fh); inode = nfs_layout_find_inode_by_stateid(clp, stateid);
if (!inode)
inode = nfs_layout_find_inode_by_fh(clp, fh);
rcu_read_unlock(); rcu_read_unlock();
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
return lo; return inode;
} }
/* /*
...@@ -213,18 +246,20 @@ static u32 initiate_file_draining(struct nfs_client *clp, ...@@ -213,18 +246,20 @@ 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); ino = nfs_layout_find_inode(clp, &args->cbl_fh, &args->cbl_stateid);
if (!lo) { if (!ino)
trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, NULL,
&args->cbl_stateid, -rv);
goto out; goto out;
}
ino = lo->plh_inode;
pnfs_layoutcommit_inode(ino, false); pnfs_layoutcommit_inode(ino, false);
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
lo = NFS_I(ino)->layout;
if (!lo) {
spin_unlock(&ino->i_lock);
goto out;
}
pnfs_get_layout_hdr(lo);
rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid); rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid);
if (rv != NFS_OK) if (rv != NFS_OK)
goto unlock; goto unlock;
...@@ -258,10 +293,10 @@ static u32 initiate_file_draining(struct nfs_client *clp, ...@@ -258,10 +293,10 @@ static u32 initiate_file_draining(struct nfs_client *clp,
/* Free all lsegs that are attached to commit buckets */ /* Free all lsegs that are attached to commit buckets */
nfs_commit_inode(ino, 0); nfs_commit_inode(ino, 0);
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
out:
trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino, trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino,
&args->cbl_stateid, -rv); &args->cbl_stateid, -rv);
iput(ino); nfs_iput_and_deactive(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