diff mbox series

NFSD: fix endianness issue in nfsd4_encode_fattr4

Message ID patch.git-0ff58649313e.your-ad-here.call-01712828617-ext-4049@work.hours (mailing list archive)
State New
Headers show
Series NFSD: fix endianness issue in nfsd4_encode_fattr4 | expand

Commit Message

Vasily Gorbik April 11, 2024, 9:45 a.m. UTC
The nfs4 mount fails with EIO on 64-bit big endian architectures since
v6.7. The issue arises from employing a union in the nfsd4_encode_fattr4()
function to overlay a 32-bit array with a 64-bit values based bitmap,
which does not function as intended. Address the endianness issue by
utilizing bitmap_from_arr32() to copy 32-bit attribute masks into a
bitmap in an endianness-agnostic manner.

Cc: <stable@vger.kernel.org>
Fixes: fce7913b13d0 ("NFSD: Use a bitmask loop to encode FATTR4 results")
Link: https://bugs.launchpad.net/ubuntu/+source/nfs-utils/+bug/2060217
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
---
 fs/nfsd/nfs4xdr.c | 47 +++++++++++++++++++++++------------------------
 1 file changed, 23 insertions(+), 24 deletions(-)

Comments

Jeffrey Layton April 11, 2024, 10:20 a.m. UTC | #1
On Thu, 2024-04-11 at 11:45 +0200, Vasily Gorbik wrote:
> The nfs4 mount fails with EIO on 64-bit big endian architectures since
> v6.7. The issue arises from employing a union in the nfsd4_encode_fattr4()
> function to overlay a 32-bit array with a 64-bit values based bitmap,
> which does not function as intended. Address the endianness issue by
> utilizing bitmap_from_arr32() to copy 32-bit attribute masks into a
> bitmap in an endianness-agnostic manner.
> 
> Cc: <stable@vger.kernel.org>
> Fixes: fce7913b13d0 ("NFSD: Use a bitmask loop to encode FATTR4 results")
> Link: https://bugs.launchpad.net/ubuntu/+source/nfs-utils/+bug/2060217
> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
> ---
>  fs/nfsd/nfs4xdr.c | 47 +++++++++++++++++++++++------------------------
>  1 file changed, 23 insertions(+), 24 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 10439d569d9c..85d43b3249f9 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3519,11 +3519,13 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  		    struct dentry *dentry, const u32 *bmval,
>  		    int ignore_crossmnt)
>  {
> +	DECLARE_BITMAP(attr_bitmap, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops));
>  	struct nfsd4_fattr_args args;
>  	struct svc_fh *tempfh = NULL;
>  	int starting_len = xdr->buf->len;
>  	__be32 *attrlen_p, status;
>  	int attrlen_offset;
> +	u32 attrmask[3];
>  	int err;
>  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
>  	u32 minorversion = resp->cstate.minorversion;
> @@ -3531,10 +3533,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  		.mnt	= exp->ex_path.mnt,
>  		.dentry	= dentry,
>  	};
> -	union {
> -		u32		attrmask[3];
> -		unsigned long	mask[2];
> -	} u;
>  	unsigned long bit;
>  	bool file_modified = false;
>  	u64 size = 0;
> @@ -3550,20 +3548,19 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  	/*
>  	 * Make a local copy of the attribute bitmap that can be modified.
>  	 */
> -	memset(&u, 0, sizeof(u));
> -	u.attrmask[0] = bmval[0];
> -	u.attrmask[1] = bmval[1];
> -	u.attrmask[2] = bmval[2];
> +	attrmask[0] = bmval[0];
> +	attrmask[1] = bmval[1];
> +	attrmask[2] = bmval[2];
>  
>  	args.rdattr_err = 0;
>  	if (exp->ex_fslocs.migrated) {
> -		status = fattr_handle_absent_fs(&u.attrmask[0], &u.attrmask[1],
> -						&u.attrmask[2], &args.rdattr_err);
> +		status = fattr_handle_absent_fs(&attrmask[0], &attrmask[1],
> +						&attrmask[2], &args.rdattr_err);
>  		if (status)
>  			goto out;
>  	}
>  	args.size = 0;
> -	if (u.attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
> +	if (attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
>  		status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry),
>  					&file_modified, &size);
>  		if (status)
> @@ -3582,16 +3579,16 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  
>  	if (!(args.stat.result_mask & STATX_BTIME))
>  		/* underlying FS does not offer btime so we can't share it */
> -		u.attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE;
> -	if ((u.attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
> +		attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE;
> +	if ((attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
>  			FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) ||
> -	    (u.attrmask[1] & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
> +	    (attrmask[1] & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
>  		       FATTR4_WORD1_SPACE_TOTAL))) {
>  		err = vfs_statfs(&path, &args.statfs);
>  		if (err)
>  			goto out_nfserr;
>  	}
> -	if ((u.attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
> +	if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
>  	    !fhp) {
>  		tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
>  		status = nfserr_jukebox;
> @@ -3606,10 +3603,10 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  		args.fhp = fhp;
>  
>  	args.acl = NULL;
> -	if (u.attrmask[0] & FATTR4_WORD0_ACL) {
> +	if (attrmask[0] & FATTR4_WORD0_ACL) {
>  		err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl);
>  		if (err == -EOPNOTSUPP)
> -			u.attrmask[0] &= ~FATTR4_WORD0_ACL;
> +			attrmask[0] &= ~FATTR4_WORD0_ACL;
>  		else if (err == -EINVAL) {
>  			status = nfserr_attrnotsupp;
>  			goto out;
> @@ -3621,17 +3618,17 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  
>  #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
>  	args.context = NULL;
> -	if ((u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
> -	     u.attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
> +	if ((attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
> +	     attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
>  		if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
>  			err = security_inode_getsecctx(d_inode(dentry),
>  						&args.context, &args.contextlen);
>  		else
>  			err = -EOPNOTSUPP;
>  		args.contextsupport = (err == 0);
> -		if (u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
> +		if (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
>  			if (err == -EOPNOTSUPP)
> -				u.attrmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> +				attrmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
>  			else if (err)
>  				goto out_nfserr;
>  		}
> @@ -3639,8 +3636,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
>  
>  	/* attrmask */
> -	status = nfsd4_encode_bitmap4(xdr, u.attrmask[0],
> -				      u.attrmask[1], u.attrmask[2]);
> +	status = nfsd4_encode_bitmap4(xdr, attrmask[0], attrmask[1],
> +				      attrmask[2]);
>  	if (status)
>  		goto out;
>  
> @@ -3649,7 +3646,9 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  	attrlen_p = xdr_reserve_space(xdr, XDR_UNIT);
>  	if (!attrlen_p)
>  		goto out_resource;
> -	for_each_set_bit(bit, (const unsigned long *)&u.mask,
> +	bitmap_from_arr32(attr_bitmap, attrmask,
> +			  ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops));
> +	for_each_set_bit(bit, attr_bitmap,
>  			 ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)) {
>  		status = nfsd4_enc_fattr4_encode_ops[bit](xdr, &args);
>  		if (status != nfs_ok)

I learned something new today -- I wasn't aware of lib/bitmap.c! This
looks like a nice cleanup too. The union was sort of nasty.

Reviewed-by: Jeff Layton <jlayton@kernel.org>
Chuck Lever April 11, 2024, 1:27 p.m. UTC | #2
On Thu, Apr 11, 2024 at 11:45:57AM +0200, Vasily Gorbik wrote:
> The nfs4 mount fails with EIO on 64-bit big endian architectures since
> v6.7. The issue arises from employing a union in the nfsd4_encode_fattr4()
> function to overlay a 32-bit array with a 64-bit values based bitmap,
> which does not function as intended. Address the endianness issue by
> utilizing bitmap_from_arr32() to copy 32-bit attribute masks into a
> bitmap in an endianness-agnostic manner.
> 
> Cc: <stable@vger.kernel.org>
> Fixes: fce7913b13d0 ("NFSD: Use a bitmask loop to encode FATTR4 results")
> Link: https://bugs.launchpad.net/ubuntu/+source/nfs-utils/+bug/2060217
> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

Thank you for the bug fix! Applied to nfsd-fixes (for v6.9-rc).


> ---
>  fs/nfsd/nfs4xdr.c | 47 +++++++++++++++++++++++------------------------
>  1 file changed, 23 insertions(+), 24 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 10439d569d9c..85d43b3249f9 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3519,11 +3519,13 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  		    struct dentry *dentry, const u32 *bmval,
>  		    int ignore_crossmnt)
>  {
> +	DECLARE_BITMAP(attr_bitmap, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops));
>  	struct nfsd4_fattr_args args;
>  	struct svc_fh *tempfh = NULL;
>  	int starting_len = xdr->buf->len;
>  	__be32 *attrlen_p, status;
>  	int attrlen_offset;
> +	u32 attrmask[3];
>  	int err;
>  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
>  	u32 minorversion = resp->cstate.minorversion;
> @@ -3531,10 +3533,6 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  		.mnt	= exp->ex_path.mnt,
>  		.dentry	= dentry,
>  	};
> -	union {
> -		u32		attrmask[3];
> -		unsigned long	mask[2];
> -	} u;
>  	unsigned long bit;
>  	bool file_modified = false;
>  	u64 size = 0;
> @@ -3550,20 +3548,19 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  	/*
>  	 * Make a local copy of the attribute bitmap that can be modified.
>  	 */
> -	memset(&u, 0, sizeof(u));
> -	u.attrmask[0] = bmval[0];
> -	u.attrmask[1] = bmval[1];
> -	u.attrmask[2] = bmval[2];
> +	attrmask[0] = bmval[0];
> +	attrmask[1] = bmval[1];
> +	attrmask[2] = bmval[2];
>  
>  	args.rdattr_err = 0;
>  	if (exp->ex_fslocs.migrated) {
> -		status = fattr_handle_absent_fs(&u.attrmask[0], &u.attrmask[1],
> -						&u.attrmask[2], &args.rdattr_err);
> +		status = fattr_handle_absent_fs(&attrmask[0], &attrmask[1],
> +						&attrmask[2], &args.rdattr_err);
>  		if (status)
>  			goto out;
>  	}
>  	args.size = 0;
> -	if (u.attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
> +	if (attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
>  		status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry),
>  					&file_modified, &size);
>  		if (status)
> @@ -3582,16 +3579,16 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  
>  	if (!(args.stat.result_mask & STATX_BTIME))
>  		/* underlying FS does not offer btime so we can't share it */
> -		u.attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE;
> -	if ((u.attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
> +		attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE;
> +	if ((attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
>  			FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) ||
> -	    (u.attrmask[1] & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
> +	    (attrmask[1] & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
>  		       FATTR4_WORD1_SPACE_TOTAL))) {
>  		err = vfs_statfs(&path, &args.statfs);
>  		if (err)
>  			goto out_nfserr;
>  	}
> -	if ((u.attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
> +	if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
>  	    !fhp) {
>  		tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
>  		status = nfserr_jukebox;
> @@ -3606,10 +3603,10 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  		args.fhp = fhp;
>  
>  	args.acl = NULL;
> -	if (u.attrmask[0] & FATTR4_WORD0_ACL) {
> +	if (attrmask[0] & FATTR4_WORD0_ACL) {
>  		err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl);
>  		if (err == -EOPNOTSUPP)
> -			u.attrmask[0] &= ~FATTR4_WORD0_ACL;
> +			attrmask[0] &= ~FATTR4_WORD0_ACL;
>  		else if (err == -EINVAL) {
>  			status = nfserr_attrnotsupp;
>  			goto out;
> @@ -3621,17 +3618,17 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  
>  #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
>  	args.context = NULL;
> -	if ((u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
> -	     u.attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
> +	if ((attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
> +	     attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
>  		if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
>  			err = security_inode_getsecctx(d_inode(dentry),
>  						&args.context, &args.contextlen);
>  		else
>  			err = -EOPNOTSUPP;
>  		args.contextsupport = (err == 0);
> -		if (u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
> +		if (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
>  			if (err == -EOPNOTSUPP)
> -				u.attrmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
> +				attrmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
>  			else if (err)
>  				goto out_nfserr;
>  		}
> @@ -3639,8 +3636,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
>  
>  	/* attrmask */
> -	status = nfsd4_encode_bitmap4(xdr, u.attrmask[0],
> -				      u.attrmask[1], u.attrmask[2]);
> +	status = nfsd4_encode_bitmap4(xdr, attrmask[0], attrmask[1],
> +				      attrmask[2]);
>  	if (status)
>  		goto out;
>  
> @@ -3649,7 +3646,9 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
>  	attrlen_p = xdr_reserve_space(xdr, XDR_UNIT);
>  	if (!attrlen_p)
>  		goto out_resource;
> -	for_each_set_bit(bit, (const unsigned long *)&u.mask,
> +	bitmap_from_arr32(attr_bitmap, attrmask,
> +			  ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops));
> +	for_each_set_bit(bit, attr_bitmap,
>  			 ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)) {
>  		status = nfsd4_enc_fattr4_encode_ops[bit](xdr, &args);
>  		if (status != nfs_ok)
> -- 
> 2.41.0
diff mbox series

Patch

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 10439d569d9c..85d43b3249f9 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3519,11 +3519,13 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 		    struct dentry *dentry, const u32 *bmval,
 		    int ignore_crossmnt)
 {
+	DECLARE_BITMAP(attr_bitmap, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops));
 	struct nfsd4_fattr_args args;
 	struct svc_fh *tempfh = NULL;
 	int starting_len = xdr->buf->len;
 	__be32 *attrlen_p, status;
 	int attrlen_offset;
+	u32 attrmask[3];
 	int err;
 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
 	u32 minorversion = resp->cstate.minorversion;
@@ -3531,10 +3533,6 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 		.mnt	= exp->ex_path.mnt,
 		.dentry	= dentry,
 	};
-	union {
-		u32		attrmask[3];
-		unsigned long	mask[2];
-	} u;
 	unsigned long bit;
 	bool file_modified = false;
 	u64 size = 0;
@@ -3550,20 +3548,19 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	/*
 	 * Make a local copy of the attribute bitmap that can be modified.
 	 */
-	memset(&u, 0, sizeof(u));
-	u.attrmask[0] = bmval[0];
-	u.attrmask[1] = bmval[1];
-	u.attrmask[2] = bmval[2];
+	attrmask[0] = bmval[0];
+	attrmask[1] = bmval[1];
+	attrmask[2] = bmval[2];
 
 	args.rdattr_err = 0;
 	if (exp->ex_fslocs.migrated) {
-		status = fattr_handle_absent_fs(&u.attrmask[0], &u.attrmask[1],
-						&u.attrmask[2], &args.rdattr_err);
+		status = fattr_handle_absent_fs(&attrmask[0], &attrmask[1],
+						&attrmask[2], &args.rdattr_err);
 		if (status)
 			goto out;
 	}
 	args.size = 0;
-	if (u.attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
+	if (attrmask[0] & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
 		status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry),
 					&file_modified, &size);
 		if (status)
@@ -3582,16 +3579,16 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 
 	if (!(args.stat.result_mask & STATX_BTIME))
 		/* underlying FS does not offer btime so we can't share it */
-		u.attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE;
-	if ((u.attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
+		attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE;
+	if ((attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
 			FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) ||
-	    (u.attrmask[1] & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
+	    (attrmask[1] & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
 		       FATTR4_WORD1_SPACE_TOTAL))) {
 		err = vfs_statfs(&path, &args.statfs);
 		if (err)
 			goto out_nfserr;
 	}
-	if ((u.attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
+	if ((attrmask[0] & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) &&
 	    !fhp) {
 		tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
 		status = nfserr_jukebox;
@@ -3606,10 +3603,10 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 		args.fhp = fhp;
 
 	args.acl = NULL;
-	if (u.attrmask[0] & FATTR4_WORD0_ACL) {
+	if (attrmask[0] & FATTR4_WORD0_ACL) {
 		err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl);
 		if (err == -EOPNOTSUPP)
-			u.attrmask[0] &= ~FATTR4_WORD0_ACL;
+			attrmask[0] &= ~FATTR4_WORD0_ACL;
 		else if (err == -EINVAL) {
 			status = nfserr_attrnotsupp;
 			goto out;
@@ -3621,17 +3618,17 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 	args.context = NULL;
-	if ((u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
-	     u.attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
+	if ((attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) ||
+	     attrmask[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
 		if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
 			err = security_inode_getsecctx(d_inode(dentry),
 						&args.context, &args.contextlen);
 		else
 			err = -EOPNOTSUPP;
 		args.contextsupport = (err == 0);
-		if (u.attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
+		if (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL) {
 			if (err == -EOPNOTSUPP)
-				u.attrmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+				attrmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
 			else if (err)
 				goto out_nfserr;
 		}
@@ -3639,8 +3636,8 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
 
 	/* attrmask */
-	status = nfsd4_encode_bitmap4(xdr, u.attrmask[0],
-				      u.attrmask[1], u.attrmask[2]);
+	status = nfsd4_encode_bitmap4(xdr, attrmask[0], attrmask[1],
+				      attrmask[2]);
 	if (status)
 		goto out;
 
@@ -3649,7 +3646,9 @@  nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	attrlen_p = xdr_reserve_space(xdr, XDR_UNIT);
 	if (!attrlen_p)
 		goto out_resource;
-	for_each_set_bit(bit, (const unsigned long *)&u.mask,
+	bitmap_from_arr32(attr_bitmap, attrmask,
+			  ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops));
+	for_each_set_bit(bit, attr_bitmap,
 			 ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops)) {
 		status = nfsd4_enc_fattr4_encode_ops[bit](xdr, &args);
 		if (status != nfs_ok)