|
@@ -119,27 +119,30 @@ out:
|
|
|
* hashed by filehandle.
|
|
|
*/
|
|
|
static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
|
|
|
- struct nfs_fh *fh, nfs4_stateid *stateid)
|
|
|
+ struct nfs_fh *fh)
|
|
|
{
|
|
|
struct nfs_server *server;
|
|
|
+ struct nfs_inode *nfsi;
|
|
|
struct inode *ino;
|
|
|
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 (!nfs4_stateid_match_other(&lo->plh_stateid, stateid))
|
|
|
+ nfsi = NFS_I(lo->plh_inode);
|
|
|
+ if (nfs_compare_fh(fh, &nfsi->fh))
|
|
|
continue;
|
|
|
- if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
|
|
|
+ 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 (NFS_I(ino)->layout != lo) {
|
|
|
+ if (nfsi->layout != lo) {
|
|
|
spin_unlock(&ino->i_lock);
|
|
|
iput(ino);
|
|
|
- break;
|
|
|
+ goto restart;
|
|
|
}
|
|
|
pnfs_get_layout_hdr(lo);
|
|
|
spin_unlock(&ino->i_lock);
|
|
@@ -151,13 +154,13 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
|
|
|
}
|
|
|
|
|
|
static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
|
|
|
- struct nfs_fh *fh, nfs4_stateid *stateid)
|
|
|
+ struct nfs_fh *fh)
|
|
|
{
|
|
|
struct pnfs_layout_hdr *lo;
|
|
|
|
|
|
spin_lock(&clp->cl_lock);
|
|
|
rcu_read_lock();
|
|
|
- lo = get_layout_by_fh_locked(clp, fh, stateid);
|
|
|
+ lo = get_layout_by_fh_locked(clp, fh);
|
|
|
rcu_read_unlock();
|
|
|
spin_unlock(&clp->cl_lock);
|
|
|
|
|
@@ -167,17 +170,39 @@ static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
|
|
|
/*
|
|
|
* Enforce RFC5661 section 12.5.5.2.1. (Layout Recall and Return Sequencing)
|
|
|
*/
|
|
|
-static bool pnfs_check_stateid_sequence(struct pnfs_layout_hdr *lo,
|
|
|
+static u32 pnfs_check_callback_stateid(struct pnfs_layout_hdr *lo,
|
|
|
const nfs4_stateid *new)
|
|
|
{
|
|
|
u32 oldseq, newseq;
|
|
|
|
|
|
- oldseq = be32_to_cpu(lo->plh_stateid.seqid);
|
|
|
+ /* Is the stateid still not initialised? */
|
|
|
+ if (!pnfs_layout_is_valid(lo))
|
|
|
+ return NFS4ERR_DELAY;
|
|
|
+
|
|
|
+ /* Mismatched stateid? */
|
|
|
+ if (!nfs4_stateid_match_other(&lo->plh_stateid, new))
|
|
|
+ return NFS4ERR_BAD_STATEID;
|
|
|
+
|
|
|
newseq = be32_to_cpu(new->seqid);
|
|
|
+ /* Are we already in a layout recall situation? */
|
|
|
+ if (test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) &&
|
|
|
+ lo->plh_return_seq != 0) {
|
|
|
+ if (newseq < lo->plh_return_seq)
|
|
|
+ return NFS4ERR_OLD_STATEID;
|
|
|
+ if (newseq > lo->plh_return_seq)
|
|
|
+ return NFS4ERR_DELAY;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
+ /* Check that the stateid matches what we think it should be. */
|
|
|
+ oldseq = be32_to_cpu(lo->plh_stateid.seqid);
|
|
|
if (newseq > oldseq + 1)
|
|
|
- return false;
|
|
|
- return true;
|
|
|
+ return NFS4ERR_DELAY;
|
|
|
+ /* Crazy server! */
|
|
|
+ if (newseq <= oldseq)
|
|
|
+ return NFS4ERR_OLD_STATEID;
|
|
|
+out:
|
|
|
+ return NFS_OK;
|
|
|
}
|
|
|
|
|
|
static u32 initiate_file_draining(struct nfs_client *clp,
|
|
@@ -188,7 +213,7 @@ 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, &args->cbl_stateid);
|
|
|
+ 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);
|
|
@@ -196,18 +221,15 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|
|
}
|
|
|
|
|
|
ino = lo->plh_inode;
|
|
|
+ pnfs_layoutcommit_inode(ino, false);
|
|
|
+
|
|
|
|
|
|
spin_lock(&ino->i_lock);
|
|
|
- if (!pnfs_check_stateid_sequence(lo, &args->cbl_stateid)) {
|
|
|
- rv = NFS4ERR_DELAY;
|
|
|
+ rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid);
|
|
|
+ if (rv != NFS_OK)
|
|
|
goto unlock;
|
|
|
- }
|
|
|
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
|
|
|
- spin_unlock(&ino->i_lock);
|
|
|
-
|
|
|
- pnfs_layoutcommit_inode(ino, false);
|
|
|
|
|
|
- spin_lock(&ino->i_lock);
|
|
|
/*
|
|
|
* Enforce RFC5661 Section 12.5.5.2.1.5 (Bulk Recall and Return)
|
|
|
*/
|
|
@@ -223,6 +245,9 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|
|
goto unlock;
|
|
|
}
|
|
|
|
|
|
+ /* Embrace your forgetfulness! */
|
|
|
+ rv = NFS4ERR_NOMATCHING_LAYOUT;
|
|
|
+
|
|
|
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
|
|
|
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
|
|
|
&args->cbl_range);
|