why NFS4ERR_BAD_STATEID but not NFS4ERR_EXPIRED

J. Bruce Fields bfields at fieldses.org
Thu Apr 16 12:31:38 EDT 2009


On Fri, Mar 27, 2009 at 05:58:35PM +0800, Bian Naimeng wrote:
> > It's almost good, but you'll have wraparound problem when the wall clock
> > time overflows. I'd suggest doing the comparisons as signed differences
> > in order to avoid that.
> > IOW:
> > 
> >   if (long)si_boot - (long)server_boot < 0
> > 	return NFS4ERR_STALE_STATEID
> >   else if (long)server_boot - (long)si_boot <= 0 &&
> >             (long)si_boot + (long)lease_time - (long)now <= 0
> > 	return NFS4ERR_EXPIRED
> >   else
> > 	return NFS4ERR_BAD_STATEID
> > 
> > Cheers
> >   Trond
> > 
>   
>   Thanks Trond. The new patch is attached.

Note units are seconds, not jiffies, so wraparound isn't a problem for
32-bit machines until 2038.  Do we really care?

> 
> Regard
>  Bian
> 
> -----
> 
>  Server should distinguish the expired, stale, and bad stateid.
> 
>  Signed-off-by: Bian Naimeng <biannm at cn.fujitsu.com>
> 
>  ---
>  fs/nfsd/nfs4state.c |   51 +++++++++++++++++++++++++++++++++++++++++----------
>  1 files changed, 41 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index b6f60f4..e52c212 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -216,7 +216,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;
> @@ -1094,7 +1094,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;
> @@ -1943,12 +1943,41 @@ 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",

Something weird happened to the encoding here; I see a yen sign instead
of a backslash at the end there.

> -		stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
> -		stateid->si_generation);
> -	return 1;
> +	if ((long)(stateid->si_boot) - (long)boot_time < 0) {
> +		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((long)boot_time - (long)(stateid->si_boot) <=0 &&
> +	   ((long)(stateid->si_boot) + (long)lease_time - (long)get_seconds()) <= 0) {

Defining some equivalent to time_after/time_before would clarify the
logic.

> +		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))

Here and elsewhere: make that "if (", not "if(".  Run
linux/scripts/checkpatch.pl on this and fix anything it complains about
that doesn't seem unreasonable.

--b.

> +		return nfserr_stale_stateid;
> +	else if(EXPIRED_STATEID(stateid))
> +		return nfserr_expired;
> +	else {
> +		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
> @@ -2065,12 +2094,14 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl
>  	if (!stateid->si_fileid) { /* delegation stateid */
>  		if(!(dp = find_delegation_stateid(ino, stateid))) {
>  			dprintk("NFSD: delegation stateid not found¥n");
> +			status = stateid_error_map(stateid);
>  			goto out;
>  		}
>  		stidp = &dp->dl_stateid;
>  	} else { /* open or lock stateid */
>  		if (!(stp = find_stateid(stateid, flags))) {
>  			dprintk("NFSD: open or lock stateid not found¥n");
> +			status = stateid_error_map(stateid);
>  			goto out;
>  		}
>  		if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp))
> @@ -2147,7 +2178,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
>  		 */
>  		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;
>  	}
> @@ -2621,7 +2652,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;
> -- 
> 1.6.0.3
> 
> 
> 


More information about the NFSv4 mailing list