NFSv4: do exact check about attribute specified

Server should return NFS4ERR_ATTRNOTSUPP if an attribute specified is
not supported in current environment.
Operations CREATE, NVERIFY, OPEN, SETATTR and VERIFY should do this check.

This bug is found when do newpynfs tests. The names of the tests that failed
are following:
  CR12 NVF7a NVF7b NVF7c NVF7d NVF7f NVF7r NVF7s
  OPEN15 VF7a VF7b VF7c VF7d VF7f VF7r VF7s

Add function do_check_fattr() to do exact check:
1, Check attribute specified is supported by the NFSv4 server or not.
2, Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS are supported
   in current environment or not.
3, Check attribute specified is writable or not.

step 1 and 3 are done in function nfsd4_decode_fattr() but removed
to this function now.

Signed-off-by: Yu Zhiguo <yuzg@cn.fujitsu.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index ab005fc..254e5b2 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -244,20 +244,8 @@
 	DECODE_TAIL;
 }
 
-static u32 nfsd_attrmask[] = {
-	NFSD_WRITEABLE_ATTRS_WORD0,
-	NFSD_WRITEABLE_ATTRS_WORD1,
-	NFSD_WRITEABLE_ATTRS_WORD2
-};
-
-static u32 nfsd41_ex_attrmask[] = {
-	NFSD_SUPPATTR_EXCLCREAT_WORD0,
-	NFSD_SUPPATTR_EXCLCREAT_WORD1,
-	NFSD_SUPPATTR_EXCLCREAT_WORD2
-};
-
 static __be32
-nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable,
+nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
 		   struct iattr *iattr, struct nfs4_acl **acl)
 {
 	int expected_len, len = 0;
@@ -270,18 +258,6 @@
 	if ((status = nfsd4_decode_bitmap(argp, bmval)))
 		return status;
 
-	/*
-	 * According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
-	 * read-only attributes return ERR_INVAL.
-	 */
-	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]))
-		return nfserr_inval;
-
 	READ_BUF(4);
 	READ32(expected_len);
 
@@ -414,8 +390,11 @@
 			goto xdr_error;
 		}
 	}
-	BUG_ON(bmval[2]);	/* no such writeable attr supported yet */
-	if (len != expected_len)
+	if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
+	    || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
+	    || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
+		READ_BUF(expected_len - len);
+	else if (len != expected_len)
 		goto xdr_error;
 
 	DECODE_TAIL;
@@ -508,8 +487,8 @@
 	if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
 		return status;
 
-	status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask,
-				    &create->cr_iattr, &create->cr_acl);
+	status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
+				    &create->cr_acl);
 	if (status)
 		goto out;
 
@@ -672,7 +651,7 @@
 		case NFS4_CREATE_UNCHECKED:
 		case NFS4_CREATE_GUARDED:
 			status = nfsd4_decode_fattr(argp, open->op_bmval,
-				nfsd_attrmask, &open->op_iattr, &open->op_acl);
+				&open->op_iattr, &open->op_acl);
 			if (status)
 				goto out;
 			break;
@@ -686,8 +665,7 @@
 			READ_BUF(8);
 			COPYMEM(open->op_verf.data, 8);
 			status = nfsd4_decode_fattr(argp, open->op_bmval,
-				nfsd41_ex_attrmask, &open->op_iattr,
-				&open->op_acl);
+				&open->op_iattr, &open->op_acl);
 			if (status)
 				goto out;
 			break;
@@ -883,8 +861,8 @@
 	status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
 	if (status)
 		return status;
-	return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask,
-				  &setattr->sa_iattr, &setattr->sa_acl);
+	return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
+				  &setattr->sa_acl);
 }
 
 static __be32