Commit 0836f587 authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: simplify stateid sequencing checks

Pull this common code into a separate function.
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
parent f3362737
...@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags) ...@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags)
&& mandatory_lock(inode); && mandatory_lock(inode);
} }
static int check_stateid_generation(stateid_t *in, stateid_t *ref)
{
/* If the client sends us a stateid from the future, it's buggy: */
if (in->si_generation > ref->si_generation)
return nfserr_bad_stateid;
/*
* The following, however, can happen. For example, if the
* client sends an open and some IO at the same time, the open
* may bump si_generation while the IO is still in flight.
* Thanks to hard links and renames, the client never knows what
* file an open will affect. So it could avoid that situation
* only by serializing all opens and IO from the same open
* owner. To recover from the old_stateid error, the client
* will just have to retry the IO:
*/
if (in->si_generation < ref->si_generation)
return nfserr_old_stateid;
return nfs_ok;
}
/* /*
* Checks for stateid operations * Checks for stateid operations
*/ */
...@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl ...@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
goto out; goto out;
stidp = &stp->st_stateid; stidp = &stp->st_stateid;
} }
if (stateid->si_generation > stidp->si_generation) status = check_stateid_generation(stateid, stidp);
goto out; if (status)
/* OLD STATEID */
status = nfserr_old_stateid;
if (stateid->si_generation < stidp->si_generation)
goto out; goto out;
if (stp) { if (stp) {
if ((status = nfs4_check_openmode(stp,flags))) if ((status = nfs4_check_openmode(stp,flags)))
...@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei ...@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
{ {
struct nfs4_stateid *stp; struct nfs4_stateid *stp;
struct nfs4_stateowner *sop; struct nfs4_stateowner *sop;
__be32 status;
dprintk("NFSD: preprocess_seqid_op: seqid=%d " dprintk("NFSD: preprocess_seqid_op: seqid=%d "
"stateid = (%08x/%08x/%08x/%08x)\n", seqid, "stateid = (%08x/%08x/%08x/%08x)\n", seqid,
...@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei ...@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
" confirmed yet!\n"); " confirmed yet!\n");
return nfserr_bad_stateid; return nfserr_bad_stateid;
} }
if (stateid->si_generation > stp->st_stateid.si_generation) { status = check_stateid_generation(stateid, &stp->st_stateid);
dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); if (status)
return nfserr_bad_stateid; return status;
}
if (stateid->si_generation < stp->st_stateid.si_generation) {
dprintk("NFSD: preprocess_seqid_op: old stateid!\n");
return nfserr_old_stateid;
}
renew_client(sop->so_client); renew_client(sop->so_client);
return nfs_ok; return nfs_ok;
......
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