[pnfs] [PATCH 3/4] nfsd41: SUPPATTR_EXCLCREAT attribute

Benny Halevy bhalevy at panasas.com
Mon May 12 22:39:05 EDT 2008


Sorry about the noise but please ignore my previous reply since
I've found a few more places that need minorversion attention.

Here's the latest version (might change further while I'm testing it...)

For performance reasons I tried to stick to macros and static inline
functions rather than using global arrays to keep the per-minorversion
word masks.  What do you think?

Benny

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index ba1fce7..4661dba 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -533,6 +533,7 @@ static __be32
 nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	      struct nfsd4_getattr *getattr)
 {
+	u32 minorversion;
 	__be32 status;
 
 	status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
@@ -542,8 +543,10 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
 		return nfserr_inval;
 
-	getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
-	getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
+	minorversion = nfsd4_compound_minorversion(cstate);
+	getattr->ga_bmval[0] &= nfsd_suppattrs0(minorversion);
+	getattr->ga_bmval[1] &= nfsd_suppattrs1(minorversion);
+	getattr->ga_bmval[2] &= nfsd_suppattrs2(minorversion);
 
 	getattr->ga_fhp = &cstate->current_fh;
 	return nfs_ok;
@@ -631,6 +634,7 @@ static __be32
 nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	      struct nfsd4_readdir *readdir)
 {
+	u32 minorversion;
 	u64 cookie = readdir->rd_cookie;
 	static const nfs4_verifier zeroverf;
 
@@ -639,8 +643,10 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
 		return nfserr_inval;
 
-	readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
-	readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
+	minorversion = nfsd4_compound_minorversion(cstate);
+	readdir->rd_bmval[0] &= nfsd_suppattrs0(minorversion);
+	readdir->rd_bmval[1] &= nfsd_suppattrs1(minorversion);
+	readdir->rd_bmval[2] &= nfsd_suppattrs2(minorversion);
 
 	if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
 	    (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
@@ -823,14 +829,17 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
 	__be32 *buf, *p;
 	int count;
+	u32 minorversion;
 	__be32 status;
 
 	status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
 	if (status)
 		return status;
 
-	if ((verify->ve_bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0)
-	    || (verify->ve_bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
+	minorversion = nfsd4_compound_minorversion(cstate);
+	if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(minorversion))
+	    || (verify->ve_bmval[1] & ~nfsd_suppattrs1(minorversion))
+	    || (verify->ve_bmval[2] & ~nfsd_suppattrs2(minorversion)))
 		return nfserr_attrnotsupp;
 	if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
 	    || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
@@ -850,7 +859,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 				    cstate->current_fh.fh_export,
 				    cstate->current_fh.fh_dentry, buf,
 				    &count, verify->ve_bmval,
-				    rqstp, 0);
+				    rqstp, 0, verify->ve_minorversion);
 
 	/* this means that nfsd4_encode_fattr() ran out of space */
 	if (status == nfserr_resource && count == 0)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index cf66cc2..c71d517 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -250,8 +250,9 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
 	if (bmlen > 1)
 		READ32(bmval[1]);
 #if defined(CONFIG_NFSD_V4_1)
-	if (bmlen > 2)
+	if (bmlen > 2) {
 		READ32(bmval[2]);
+	}
 #endif /* CONFIG_NFSD_V4_1 */
 
 	DECODE_TAIL;
@@ -289,9 +290,9 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable,
 	 * According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
 	 * read-only attributes return ERR_INVAL.
 	 */
-	if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) ||
-	    (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1) ||
-	    (bmval[2] & ~NFSD_SUPPORTED_ATTRS_WORD2))
+	if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) ||
+	    (bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) ||
+	    (bmval[2] & ~nfsd_suppattrs2(argp->minorversion)))
 		return nfserr_attrnotsupp;
 	if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
 	    (bmval[2] & ~writable[2]))
@@ -824,6 +825,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read
 	COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data));
 	READ32(readdir->rd_dircount);    /* just in case you needed a useless field... */
 	READ32(readdir->rd_maxcount);
+	readdir->minorversion = argp->minorversion;
 	if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval)))
 		goto out;
 
@@ -1202,6 +1204,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
 	READ32(verify->ve_attrlen);
 	READ_BUF(verify->ve_attrlen);
 	SAVEMEM(verify->ve_attrval, verify->ve_attrlen);
+	verify->ve_minorversion = argp->minorversion;
 
 	DECODE_TAIL;
 }
@@ -1755,7 +1758,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
 __be32
 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 		struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
-		struct svc_rqst *rqstp, int ignore_crossmnt)
+		struct svc_rqst *rqstp, int ignore_crossmnt, u32 minorversion)
 {
 	u32 bmval0 = bmval[0];
 	u32 bmval1 = bmval[1];
@@ -1775,12 +1778,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 	struct nfs4_acl *acl = NULL;
 
 	BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
-	BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
-	BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
-	if (bmval2 & ~NFSD_SUPPORTED_ATTRS_WORD2) {
-		printk(KERN_ERR "%s: bmval2=0x%x\n", __func__, bmval2);
-		WARN_ON(1);
-	}
+	BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion));
+	BUG_ON(bmval1 & ~nfsd_suppattrs1(minorversion));
+	BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
 
 	if (exp->ex_fslocs.migrated) {
 		BUG_ON(bmval[2]);
@@ -1845,22 +1845,25 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 	attrlenp = p++;                /* to be backfilled later */
 
 	if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
-		u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
+		u32 word0 = nfsd_suppattrs0(minorversion);
+		u32 word1 = nfsd_suppattrs1(minorversion);
+		u32 word2 = nfsd_suppattrs2(minorversion);
+
 		if ((buflen -= 12) < 0)
 			goto out_resource;
 		if (!aclsupport)
 			word0 &= ~FATTR4_WORD0_ACL;
 		if (!exp->ex_fslocs.locations)
 			word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
-		if (!NFSD_SUPPORTED_ATTRS_WORD2) {
+		if (!word2) {
 			WRITE32(2);
 			WRITE32(word0);
-			WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
+			WRITE32(word1);
 		} else {
 			WRITE32(3);
 			WRITE32(word0);
-			WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
-			WRITE32(NFSD_SUPPORTED_ATTRS_WORD2);
+			WRITE32(word1);
+			WRITE32(word2);
 		}
 	}
 	if (bmval0 & FATTR4_WORD0_TYPE) {
@@ -2245,7 +2248,8 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
 
 	}
 	nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
-					cd->rd_rqstp, ignore_crossmnt);
+					cd->rd_rqstp, ignore_crossmnt,
+					cd->minorversion);
 out_put:
 	dput(dentry);
 	exp_put(exp);
@@ -2399,7 +2403,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 	buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
 	nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
 				    resp->p, &buflen, getattr->ga_bmval,
-				    resp->rqstp, 0);
+				    resp->rqstp, 0, resp->minorversion);
 	if (!nfserr)
 		resp->p += buflen;
 	return nfserr;
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index f9f0467..62a7905 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -313,7 +313,7 @@ extern struct timeval	nfssvc_boot;
  *    TIME_BACKUP   (unlikely to be supported any time soon)
  *    TIME_CREATE   (unlikely to be supported any time soon)
  */
-#define NFSD_SUPPORTED_ATTRS_WORD0                                                          \
+#define NFSD4_SUPPORTED_ATTRS_WORD0                                                          \
 (FATTR4_WORD0_SUPPORTED_ATTRS   | FATTR4_WORD0_TYPE         | FATTR4_WORD0_FH_EXPIRE_TYPE   \
  | FATTR4_WORD0_CHANGE          | FATTR4_WORD0_SIZE         | FATTR4_WORD0_LINK_SUPPORT     \
  | FATTR4_WORD0_SYMLINK_SUPPORT | FATTR4_WORD0_NAMED_ATTR   | FATTR4_WORD0_FSID             \
@@ -325,7 +325,7 @@ extern struct timeval	nfssvc_boot;
  | FATTR4_WORD0_MAXFILESIZE     | FATTR4_WORD0_MAXLINK      | FATTR4_WORD0_MAXNAME          \
  | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE     | FATTR4_WORD0_ACL)
 
-#define NFSD_SUPPORTED_ATTRS_WORD1                                                          \
+#define NFSD4_SUPPORTED_ATTRS_WORD1                                                          \
 (FATTR4_WORD1_MODE              | FATTR4_WORD1_NO_TRUNC     | FATTR4_WORD1_NUMLINKS         \
  | FATTR4_WORD1_OWNER	        | FATTR4_WORD1_OWNER_GROUP  | FATTR4_WORD1_RAWDEV           \
  | FATTR4_WORD1_SPACE_AVAIL     | FATTR4_WORD1_SPACE_FREE   | FATTR4_WORD1_SPACE_TOTAL      \
@@ -333,11 +333,50 @@ extern struct timeval	nfssvc_boot;
  | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
  | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
 
+#define NFSD4_SUPPORTED_ATTRS_WORD2 0
+
 #if defined(CONFIG_NFSD_V4_1)
-#define NFSD_SUPPORTED_ATTRS_WORD2 \
-	FATTR4_WORD2_SUPPATTR_EXCLCREAT
-#else  /* CONFIG_NFSD_V4_1) */
-#define NFSD_SUPPORTED_ATTRS_WORD2 0
+#define NFSD4_1_SUPPORTED_ATTRS_WORD0 \
+	NFSD4_SUPPORTED_ATTRS_WORD0
+
+#define NFSD4_1_SUPPORTED_ATTRS_WORD1 \
+	NFSD4_SUPPORTED_ATTRS_WORD1
+
+#define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
+	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
+
+static inline u32 nfsd_suppattrs0(u32 minorversion)
+{
+	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
+			    : NFSD4_SUPPORTED_ATTRS_WORD0;
+}
+
+static inline u32 nfsd_suppattrs1(u32 minorversion)
+{
+	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD1
+			    : NFSD4_SUPPORTED_ATTRS_WORD1;
+}
+
+static inline u32 nfsd_suppattrs2(u32 minorversion)
+{
+	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
+			    : NFSD4_SUPPORTED_ATTRS_WORD2;
+}
+#else  /* CONFIG_NFSD_V4_1 */
+static inline u32 nfsd_suppattrs0(u32 minorversion)
+{
+	return NFSD4_SUPPORTED_ATTRS_WORD0;
+}
+
+static inline u32 nfsd_suppattrs1(u32 minorversion)
+{
+	return NFSD4_SUPPORTED_ATTRS_WORD1;
+}
+
+static inline u32 nfsd_suppattrs2(u32 minorversion)
+{
+	return NFSD4_SUPPORTED_ATTRS_WORD2;
+}
 #endif /* CONFIG_NFSD_V4_1 */
 
 /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 2988c8c..6715038 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -53,6 +53,15 @@ struct nfsd4_compound_state {
 #endif /* CONFIG_NFSD_V4_1 */
 };
 
+static inline u32 nfsd4_compound_minorversion(struct nfsd4_compound_state *cs)
+{
+#if defined(CONFIG_NFSD_V4_1)
+	return cs->current_ses ? 1 : 0;
+#else  /* CONFIG_NFSD_V4_1 */
+	return 0;
+#endif /* CONFIG_NFSD_V4_1 */
+}
+
 struct nfsd4_change_info {
 	u32		atomic;
 	u32		before_ctime_sec;
@@ -271,6 +280,7 @@ struct nfsd4_readdir {
 	__be32 *		buffer;
 	int			buflen;
 	__be32 *		offset;
+	u32			minorversion;
 };
 
 struct nfsd4_release_lockowner {
@@ -335,6 +345,7 @@ struct nfsd4_verify {
 	u32		ve_bmval[3];        /* request */
 	u32		ve_attrlen;         /* request */
 	char *		ve_attrval;         /* request */
+	u32		ve_minorversion;
 };
 
 struct nfsd4_write {
@@ -477,6 +488,7 @@ struct nfsd4_compoundres {
 	char *				tag;
 	u32				opcnt;
 	__be32 *			tagp; /* where to encode tag and  opcount */
+	u32				minorversion;
 };
 
 #define NFS4_SVC_XDRSIZE		sizeof(struct nfsd4_compoundargs)
@@ -500,8 +512,9 @@ int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
 void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
 void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
 __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
-		       struct dentry *dentry, __be32 *buffer, int *countp,
-		       u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
+			  struct dentry *dentry, __be32 *buffer, int *countp,
+			  u32 *bmval, struct svc_rqst *, int ignore_crossmnt,
+			  u32 minorversion);
 extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *,
 		struct nfsd4_setclientid *setclid);


On May. 12, 2008, 18:43 -0700, Benny Halevy <bhalevy at panasas.com> wrote:
> How about this?
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index ba1fce7..61836c6 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -850,7 +850,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  				    cstate->current_fh.fh_export,
>  				    cstate->current_fh.fh_dentry, buf,
>  				    &count, verify->ve_bmval,
> -				    rqstp, 0);
> +				    rqstp, 0, verify->ve_minorversion);
>  
>  	/* this means that nfsd4_encode_fattr() ran out of space */
>  	if (status == nfserr_resource && count == 0)
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index cf66cc2..7f0e62b 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -250,8 +250,9 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
>  	if (bmlen > 1)
>  		READ32(bmval[1]);
>  #if defined(CONFIG_NFSD_V4_1)
> -	if (bmlen > 2)
> +	if (bmlen > 2) {
>  		READ32(bmval[2]);
> +	}
>  #endif /* CONFIG_NFSD_V4_1 */
>  
>  	DECODE_TAIL;
> @@ -291,7 +292,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable,
>  	 */
>  	if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) ||
>  	    (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1) ||
> -	    (bmval[2] & ~NFSD_SUPPORTED_ATTRS_WORD2))
> +	    (bmval[2] & ~(argp->minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
> +					     : NFSD_SUPPORTED_ATTRS_WORD2)))
>  		return nfserr_attrnotsupp;
>  	if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
>  	    (bmval[2] & ~writable[2]))
> @@ -824,6 +826,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read
>  	COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data));
>  	READ32(readdir->rd_dircount);    /* just in case you needed a useless field... */
>  	READ32(readdir->rd_maxcount);
> +	readdir->minorversion = argp->minorversion;
>  	if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval)))
>  		goto out;
>  
> @@ -1202,6 +1205,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
>  	READ32(verify->ve_attrlen);
>  	READ_BUF(verify->ve_attrlen);
>  	SAVEMEM(verify->ve_attrval, verify->ve_attrlen);
> +	verify->ve_minorversion = argp->minorversion;
>  
>  	DECODE_TAIL;
>  }
> @@ -1755,7 +1759,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
>  __be32
>  nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
>  		struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
> -		struct svc_rqst *rqstp, int ignore_crossmnt)
> +		struct svc_rqst *rqstp, int ignore_crossmnt, u32 minorversion)
>  {
>  	u32 bmval0 = bmval[0];
>  	u32 bmval1 = bmval[1];
> @@ -1777,10 +1781,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
>  	BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
>  	BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
>  	BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
> -	if (bmval2 & ~NFSD_SUPPORTED_ATTRS_WORD2) {
> -		printk(KERN_ERR "%s: bmval2=0x%x\n", __func__, bmval2);
> +#if defined(CONFIG_NFSD_V4_1)
> +	if (bmval2 & ~NFSD4_1_SUPPORTED_ATTRS_WORD2) {
> +		printk(KERN_ERR "%s: bmval2=0x%08x "
> +			"supported_attrs_word2=0x%08x\n",
> +			__func__, bmval2, (u32)NFSD4_1_SUPPORTED_ATTRS_WORD2);
> +		/* FIXME: change to BUG_ON */
>  		WARN_ON(1);
>  	}
> +#endif /* CONFIG_NFSD_V4_1 */
>  
>  	if (exp->ex_fslocs.migrated) {
>  		BUG_ON(bmval[2]);
> @@ -1846,21 +1855,25 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
>  
>  	if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
>  		u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
> +		u32 word1 = NFSD_SUPPORTED_ATTRS_WORD1;
> +		u32 word2 = minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
> +					 : NFSD_SUPPORTED_ATTRS_WORD2;
> +
>  		if ((buflen -= 12) < 0)
>  			goto out_resource;
>  		if (!aclsupport)
>  			word0 &= ~FATTR4_WORD0_ACL;
>  		if (!exp->ex_fslocs.locations)
>  			word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
> -		if (!NFSD_SUPPORTED_ATTRS_WORD2) {
> +		if (!word2) {
>  			WRITE32(2);
>  			WRITE32(word0);
> -			WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
> +			WRITE32(word1);
>  		} else {
>  			WRITE32(3);
>  			WRITE32(word0);
> -			WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
> -			WRITE32(NFSD_SUPPORTED_ATTRS_WORD2);
> +			WRITE32(word1);
> +			WRITE32(word2);
>  		}
>  	}
>  	if (bmval0 & FATTR4_WORD0_TYPE) {
> @@ -2245,7 +2258,8 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
>  
>  	}
>  	nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
> -					cd->rd_rqstp, ignore_crossmnt);
> +					cd->rd_rqstp, ignore_crossmnt,
> +					cd->minorversion);
>  out_put:
>  	dput(dentry);
>  	exp_put(exp);
> @@ -2399,7 +2413,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>  	buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
>  	nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
>  				    resp->p, &buflen, getattr->ga_bmval,
> -				    resp->rqstp, 0);
> +				    resp->rqstp, 0, resp->minorversion);
>  	if (!nfserr)
>  		resp->p += buflen;
>  	return nfserr;
> diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
> index f9f0467..465106b 100644
> --- a/include/linux/nfsd/nfsd.h
> +++ b/include/linux/nfsd/nfsd.h
> @@ -333,11 +333,11 @@ extern struct timeval	nfssvc_boot;
>   | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
>   | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
>  
> -#if defined(CONFIG_NFSD_V4_1)
> -#define NFSD_SUPPORTED_ATTRS_WORD2 \
> -	FATTR4_WORD2_SUPPATTR_EXCLCREAT
> -#else  /* CONFIG_NFSD_V4_1) */
>  #define NFSD_SUPPORTED_ATTRS_WORD2 0
> +
> +#if defined(CONFIG_NFSD_V4_1)
> +#define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
> +	(NFSD_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
>  #endif /* CONFIG_NFSD_V4_1 */
>  
>  /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
> diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
> index 2988c8c..76f4638 100644
> --- a/include/linux/nfsd/xdr4.h
> +++ b/include/linux/nfsd/xdr4.h
> @@ -271,6 +271,7 @@ struct nfsd4_readdir {
>  	__be32 *		buffer;
>  	int			buflen;
>  	__be32 *		offset;
> +	u32			minorversion;
>  };
>  
>  struct nfsd4_release_lockowner {
> @@ -335,6 +336,7 @@ struct nfsd4_verify {
>  	u32		ve_bmval[3];        /* request */
>  	u32		ve_attrlen;         /* request */
>  	char *		ve_attrval;         /* request */
> +	u32		ve_minorversion;
>  };
>  
>  struct nfsd4_write {
> @@ -477,6 +479,7 @@ struct nfsd4_compoundres {
>  	char *				tag;
>  	u32				opcnt;
>  	__be32 *			tagp; /* where to encode tag and  opcount */
> +	u32				minorversion;
>  };
>  
>  #define NFS4_SVC_XDRSIZE		sizeof(struct nfsd4_compoundargs)
> @@ -500,8 +503,9 @@ int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
>  void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
>  void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
>  __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
> -		       struct dentry *dentry, __be32 *buffer, int *countp,
> -		       u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
> +			  struct dentry *dentry, __be32 *buffer, int *countp,
> +			  u32 *bmval, struct svc_rqst *, int ignore_crossmnt,
> +			  u32 minorversion);
>  extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
>  		struct nfsd4_compound_state *,
>  		struct nfsd4_setclientid *setclid);
> 
> On May. 12, 2008, 15:38 -0700, Benny Halevy <bhalevy at panasas.com> wrote:
>> On May. 12, 2008, 15:27 -0700, "J. Bruce Fields" <bfields at fieldses.org> wrote:
>>> On Mon, May 12, 2008 at 11:27:08AM -0700, Benny Halevy wrote:
>>>> Return bitmask for supported EXCLUSIVE4_1 create attributes.
>>>>
>>>> Signed-off-by: Benny Halevy <bhalevy at panasas.com>
>>>> ---
>>>>  fs/nfsd/nfs4xdr.c         |    9 ++++++++-
>>>>  include/linux/nfs4.h      |    2 ++
>>>>  include/linux/nfsd/nfsd.h |   19 +++++++++++++++++++
>>>>  3 files changed, 29 insertions(+), 1 deletions(-)
>>>>
>>>> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
>>>> index eac9656..8173af8 100644
>>>> --- a/fs/nfsd/nfs4xdr.c
>>>> +++ b/fs/nfsd/nfs4xdr.c
>>>> @@ -2149,7 +2149,14 @@ out_acl:
>>>>  		}
>>>>  		WRITE64(stat.ino);
>>>>  	}
>>>> -	BUG_ON(bmval2);	/* FIXME: not implemented yet */
>>>> +#if defined(CONFIG_NFSD_V4_1)
>>>> +	if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
>>>> +		WRITE32(3);
>>>> +		WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
>>>> +		WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1);
>>>> +		WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD2);
>>>> +	}
>>>> +#endif /* CONFIG_NFSD_V4_1 */
>>>>  
>>>>  	*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
>>>>  	*countp = p - buffer;
>>>> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
>>>> index f4c8ce2..190f070 100644
>>>> --- a/include/linux/nfs4.h
>>>> +++ b/include/linux/nfs4.h
>>>> @@ -367,6 +367,8 @@ enum lock_type4 {
>>>>  #define FATTR4_WORD0_UNIQUE_HANDLES     (1UL << 9)
>>>>  #define FATTR4_WORD0_LEASE_TIME         (1UL << 10)
>>>>  #define FATTR4_WORD0_RDATTR_ERROR       (1UL << 11)
>>>> +/* Mandatory in NFSv4.1 */
>>>> +#define FATTR4_WORD2_SUPPATTR_EXCLCREAT (1UL << 11)
>>>>  
>>>>  /* Recommended Attributes */
>>>>  #define FATTR4_WORD0_ACL                (1UL << 12)
>>>> diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
>>>> index 64b9e45..f9f0467 100644
>>>> --- a/include/linux/nfsd/nfsd.h
>>>> +++ b/include/linux/nfsd/nfsd.h
>>>> @@ -333,7 +333,12 @@ extern struct timeval	nfssvc_boot;
>>>>   | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
>>>>   | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
>>>>  
>>>> +#if defined(CONFIG_NFSD_V4_1)
>>>> +#define NFSD_SUPPORTED_ATTRS_WORD2 \
>>>> +	FATTR4_WORD2_SUPPATTR_EXCLCREAT
>>>> +#else  /* CONFIG_NFSD_V4_1) */
>>>>  #define NFSD_SUPPORTED_ATTRS_WORD2 0
>>>> +#endif /* CONFIG_NFSD_V4_1 */
>>> Won't we eventually need both of those definitions available at runtime,
>>> so that we can answer requests for the supported_attrs attribute from
>>> both 4.0 and 4.1 clients?
>> Yeah, although I'm not sure it actually illegal in NFSv4.0 to return
>> bits for attributes which are not in the spec I agree it's probably safer
>> to mask these out for NFSv4.0 clients like you said.
>>
>> Benny
>>
>>> --b.
>>>
>>>>  
>>>>  /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
>>>>  #define NFSD_WRITEONLY_ATTRS_WORD1							    \
>>>> @@ -347,6 +352,20 @@ extern struct timeval	nfssvc_boot;
>>>>   | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET)
>>>>  #define NFSD_WRITEABLE_ATTRS_WORD2 0
>>>>  
>>>> +#if defined(CONFIG_NFSD_V4_1)
>>>> +#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
>>>> +	NFSD_WRITEABLE_ATTRS_WORD0
>>>> +/*
>>>> + * we currently store the exclusive create verifier in the v_{a,m}time
>>>> + * attributes so the client can't set these at create time using EXCLUSIVE4_1
>>>> + */
>>>> +#define NFSD_SUPPATTR_EXCLCREAT_WORD1 \
>>>> +	(NFSD_WRITEABLE_ATTRS_WORD1 & \
>>>> +	 ~(FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET))
>>>> +#define NFSD_SUPPATTR_EXCLCREAT_WORD2 \
>>>> +	NFSD_WRITEABLE_ATTRS_WORD2
>>>> +#endif /* CONFIG_NFSD_V4_1 */
>>>> +
>>>>  #endif /* CONFIG_NFSD_V4 */
>>>>  
>>>>  #endif /* __KERNEL__ */
>>>> -- 
>>>> 1.5.3.3
>>>>
>>>> _______________________________________________
>>>> pNFS mailing list
>>>> pNFS at linux-nfs.org
>>>> http://linux-nfs.org/cgi-bin/mailman/listinfo/pnfs
>> _______________________________________________
>> pNFS mailing list
>> pNFS at linux-nfs.org
>> http://linux-nfs.org/cgi-bin/mailman/listinfo/pnfs
> 



More information about the pNFS mailing list