Loading fs/nfsd/nfs4state.c +26 −15 Original line number Diff line number Diff line Loading @@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags) && 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 */ Loading Loading @@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl goto out; stidp = &stp->st_stateid; } if (stateid->si_generation > stidp->si_generation) goto out; /* OLD STATEID */ status = nfserr_old_stateid; if (stateid->si_generation < stidp->si_generation) status = check_stateid_generation(stateid, stidp); if (status) goto out; if (stp) { if ((status = nfs4_check_openmode(stp,flags))) Loading Loading @@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei { struct nfs4_stateid *stp; struct nfs4_stateowner *sop; __be32 status; dprintk("NFSD: preprocess_seqid_op: seqid=%d " "stateid = (%08x/%08x/%08x/%08x)\n", seqid, Loading Loading @@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei " confirmed yet!\n"); return nfserr_bad_stateid; } if (stateid->si_generation > stp->st_stateid.si_generation) { dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); return nfserr_bad_stateid; } if (stateid->si_generation < stp->st_stateid.si_generation) { dprintk("NFSD: preprocess_seqid_op: old stateid!\n"); return nfserr_old_stateid; } status = check_stateid_generation(stateid, &stp->st_stateid); if (status) return status; renew_client(sop->so_client); return nfs_ok; Loading Loading
fs/nfsd/nfs4state.c +26 −15 Original line number Diff line number Diff line Loading @@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags) && 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 */ Loading Loading @@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl goto out; stidp = &stp->st_stateid; } if (stateid->si_generation > stidp->si_generation) goto out; /* OLD STATEID */ status = nfserr_old_stateid; if (stateid->si_generation < stidp->si_generation) status = check_stateid_generation(stateid, stidp); if (status) goto out; if (stp) { if ((status = nfs4_check_openmode(stp,flags))) Loading Loading @@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei { struct nfs4_stateid *stp; struct nfs4_stateowner *sop; __be32 status; dprintk("NFSD: preprocess_seqid_op: seqid=%d " "stateid = (%08x/%08x/%08x/%08x)\n", seqid, Loading Loading @@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei " confirmed yet!\n"); return nfserr_bad_stateid; } if (stateid->si_generation > stp->st_stateid.si_generation) { dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); return nfserr_bad_stateid; } if (stateid->si_generation < stp->st_stateid.si_generation) { dprintk("NFSD: preprocess_seqid_op: old stateid!\n"); return nfserr_old_stateid; } status = check_stateid_generation(stateid, &stp->st_stateid); if (status) return status; renew_client(sop->so_client); return nfs_ok; Loading