nfsd4: distinguish expired from stale stateids
[safe/jmp/linux-2.6] / fs / nfsd / nfs4state.c
index c65a27b..74e822e 100644 (file)
@@ -206,7 +206,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
        dp->dl_recall.cbr_dp = NULL;
        dp->dl_recall.cbr_ident = cb->cb_ident;
        dp->dl_recall.cbr_trunc = 0;
-       dp->dl_stateid.si_boot = boot_time;
+       dp->dl_stateid.si_boot = get_seconds();
        dp->dl_stateid.si_stateownerid = current_delegid++;
        dp->dl_stateid.si_fileid = 0;
        dp->dl_stateid.si_generation = 0;
@@ -1883,7 +1883,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
        stp->st_stateowner = sop;
        get_nfs4_file(fp);
        stp->st_file = fp;
-       stp->st_stateid.si_boot = boot_time;
+       stp->st_stateid.si_boot = get_seconds();
        stp->st_stateid.si_stateownerid = sop->so_id;
        stp->st_stateid.si_fileid = fp->fi_id;
        stp->st_stateid.si_generation = 0;
@@ -2739,12 +2739,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
 static int
 STALE_STATEID(stateid_t *stateid)
 {
-       if (stateid->si_boot == boot_time)
-               return 0;
-       dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
-               stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
-               stateid->si_generation);
-       return 1;
+       if (time_after((unsigned long)boot_time,
+                       (unsigned long)stateid->si_boot)) {
+               dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
+                       stateid->si_boot, stateid->si_stateownerid,
+                       stateid->si_fileid, stateid->si_generation);
+               return 1;
+       }
+       return 0;
+}
+
+static int
+EXPIRED_STATEID(stateid_t *stateid)
+{
+       if (time_before((unsigned long)boot_time,
+                       ((unsigned long)stateid->si_boot)) &&
+           time_before((stateid->si_boot + lease_time), get_seconds())) {
+               dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n",
+                       stateid->si_boot, stateid->si_stateownerid,
+                       stateid->si_fileid, stateid->si_generation);
+               return 1;
+       }
+       return 0;
+}
+
+static __be32
+stateid_error_map(stateid_t *stateid)
+{
+       if (STALE_STATEID(stateid))
+               return nfserr_stale_stateid;
+       if (EXPIRED_STATEID(stateid))
+               return nfserr_expired;
+
+       dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n",
+               stateid->si_boot, stateid->si_stateownerid,
+               stateid->si_fileid, stateid->si_generation);
+       return nfserr_bad_stateid;
 }
 
 static inline int
@@ -2868,8 +2898,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
        status = nfserr_bad_stateid;
        if (is_delegation_stateid(stateid)) {
                dp = find_delegation_stateid(ino, stateid);
-               if (!dp)
+               if (!dp) {
+                       status = stateid_error_map(stateid);
                        goto out;
+               }
                status = check_stateid_generation(stateid, &dp->dl_stateid,
                                                  flags);
                if (status)
@@ -2882,8 +2914,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
                        *filpp = dp->dl_vfs_file;
        } else { /* open or lock stateid */
                stp = find_stateid(stateid, flags);
-               if (!stp)
+               if (!stp) {
+                       status = stateid_error_map(stateid);
                        goto out;
+               }
                if (nfs4_check_fh(current_fh, stp))
                        goto out;
                if (!stp->st_stateowner->so_confirmed)
@@ -2957,7 +2991,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
                 */
                sop = search_close_lru(stateid->si_stateownerid, flags);
                if (sop == NULL)
-                       return nfserr_bad_stateid;
+                       return stateid_error_map(stateid);
                *sopp = sop;
                goto check_replay;
        }
@@ -3228,8 +3262,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (!is_delegation_stateid(stateid))
                goto out;
        dp = find_delegation_stateid(inode, stateid);
-       if (!dp)
+       if (!dp) {
+               status = stateid_error_map(stateid);
                goto out;
+       }
        status = check_stateid_generation(stateid, &dp->dl_stateid, flags);
        if (status)
                goto out;
@@ -3456,7 +3492,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
        stp->st_stateowner = sop;
        get_nfs4_file(fp);
        stp->st_file = fp;
-       stp->st_stateid.si_boot = boot_time;
+       stp->st_stateid.si_boot = get_seconds();
        stp->st_stateid.si_stateownerid = sop->so_id;
        stp->st_stateid.si_fileid = fp->fi_id;
        stp->st_stateid.si_generation = 0;