|
@@ -110,20 +110,52 @@ out:
|
|
|
#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.
|
|
|
- * Caller must put the layout hdr and the inode.
|
|
|
+ * Note: returns a refcount on the inode and superblock
|
|
|
+ */
|
|
|
+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,
|
|
|
- struct nfs_fh *fh)
|
|
|
+static struct inode *nfs_layout_find_inode_by_fh(struct nfs_client *clp,
|
|
|
+ const struct nfs_fh *fh)
|
|
|
{
|
|
|
struct nfs_server *server;
|
|
|
struct nfs_inode *nfsi;
|
|
|
- struct inode *ino;
|
|
|
+ struct inode *inode;
|
|
|
struct pnfs_layout_hdr *lo;
|
|
|
|
|
|
restart:
|
|
@@ -134,37 +166,38 @@ restart:
|
|
|
continue;
|
|
|
if (nfsi->layout != lo)
|
|
|
continue;
|
|
|
- ino = igrab(lo->plh_inode);
|
|
|
- if (!ino)
|
|
|
- break;
|
|
|
- spin_lock(&ino->i_lock);
|
|
|
- /* Is this layout in the process of being freed? */
|
|
|
- if (nfsi->layout != lo) {
|
|
|
- spin_unlock(&ino->i_lock);
|
|
|
- iput(ino);
|
|
|
+ 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;
|
|
|
}
|
|
|
- pnfs_get_layout_hdr(lo);
|
|
|
- spin_unlock(&ino->i_lock);
|
|
|
- return lo;
|
|
|
+ return inode;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
|
|
|
- struct nfs_fh *fh)
|
|
|
+static struct inode *nfs_layout_find_inode(struct nfs_client *clp,
|
|
|
+ const struct nfs_fh *fh,
|
|
|
+ const nfs4_stateid *stateid)
|
|
|
{
|
|
|
- struct pnfs_layout_hdr *lo;
|
|
|
+ struct inode *inode;
|
|
|
|
|
|
spin_lock(&clp->cl_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();
|
|
|
spin_unlock(&clp->cl_lock);
|
|
|
|
|
|
- return lo;
|
|
|
+ return inode;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -213,18 +246,20 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|
|
u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
|
|
|
LIST_HEAD(free_me_list);
|
|
|
|
|
|
- lo = get_layout_by_fh(clp, &args->cbl_fh);
|
|
|
- if (!lo) {
|
|
|
- trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, NULL,
|
|
|
- &args->cbl_stateid, -rv);
|
|
|
+ ino = nfs_layout_find_inode(clp, &args->cbl_fh, &args->cbl_stateid);
|
|
|
+ if (!ino)
|
|
|
goto out;
|
|
|
- }
|
|
|
|
|
|
- ino = lo->plh_inode;
|
|
|
pnfs_layoutcommit_inode(ino, false);
|
|
|
|
|
|
|
|
|
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);
|
|
|
if (rv != NFS_OK)
|
|
|
goto unlock;
|
|
@@ -258,10 +293,10 @@ unlock:
|
|
|
/* Free all lsegs that are attached to commit buckets */
|
|
|
nfs_commit_inode(ino, 0);
|
|
|
pnfs_put_layout_hdr(lo);
|
|
|
+out:
|
|
|
trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino,
|
|
|
&args->cbl_stateid, -rv);
|
|
|
- iput(ino);
|
|
|
-out:
|
|
|
+ nfs_iput_and_deactive(ino);
|
|
|
return rv;
|
|
|
}
|
|
|
|