Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7067b2d authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFSv4: encode_attrs should not backfill the bitmap and attribute length



The attribute length is already calculated in advance. There is no
reason why we cannot calculate the bitmap in advance too so that
we don't have to play pointer games.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 7c6d4dca
Loading
Loading
Loading
Loading
+53 −72
Original line number Original line Diff line number Diff line
@@ -997,12 +997,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
	int owner_namelen = 0;
	int owner_namelen = 0;
	int owner_grouplen = 0;
	int owner_grouplen = 0;
	__be32 *p;
	__be32 *p;
	__be32 *q;
	unsigned i;
	int len;
	uint32_t len = 0;
	uint32_t bmval_len = 2;
	uint32_t bmval_len;
	uint32_t bmval0 = 0;
	uint32_t bmval[3] = { 0 };
	uint32_t bmval1 = 0;
	uint32_t bmval2 = 0;


	/*
	/*
	 * We reserve enough space to write the entire attribute buffer at once.
	 * We reserve enough space to write the entire attribute buffer at once.
@@ -1011,13 +1009,14 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
	 * = 40 bytes, plus any contribution from variable-length fields
	 * = 40 bytes, plus any contribution from variable-length fields
	 *            such as owner/group.
	 *            such as owner/group.
	 */
	 */
	len = 8;
	if (iap->ia_valid & ATTR_SIZE) {

		bmval[0] |= FATTR4_WORD0_SIZE;
	/* Sigh */
	if (iap->ia_valid & ATTR_SIZE)
		len += 8;
		len += 8;
	if (iap->ia_valid & ATTR_MODE)
	}
	if (iap->ia_valid & ATTR_MODE) {
		bmval[1] |= FATTR4_WORD1_MODE;
		len += 4;
		len += 4;
	}
	if (iap->ia_valid & ATTR_UID) {
	if (iap->ia_valid & ATTR_UID) {
		owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
		owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
		if (owner_namelen < 0) {
		if (owner_namelen < 0) {
@@ -1028,6 +1027,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
			owner_namelen = sizeof("nobody") - 1;
			owner_namelen = sizeof("nobody") - 1;
			/* goto out; */
			/* goto out; */
		}
		}
		bmval[1] |= FATTR4_WORD1_OWNER;
		len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
		len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
	}
	}
	if (iap->ia_valid & ATTR_GID) {
	if (iap->ia_valid & ATTR_GID) {
@@ -1039,92 +1039,73 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
			owner_grouplen = sizeof("nobody") - 1;
			owner_grouplen = sizeof("nobody") - 1;
			/* goto out; */
			/* goto out; */
		}
		}
		bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
	}
	}
	if (iap->ia_valid & ATTR_ATIME_SET)
	if (iap->ia_valid & ATTR_ATIME_SET) {
		bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
		len += 16;
		len += 16;
	else if (iap->ia_valid & ATTR_ATIME)
	} else if (iap->ia_valid & ATTR_ATIME) {
		bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
		len += 4;
		len += 4;
	if (iap->ia_valid & ATTR_MTIME_SET)
	}
	if (iap->ia_valid & ATTR_MTIME_SET) {
		bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
		len += 16;
		len += 16;
	else if (iap->ia_valid & ATTR_MTIME)
	} else if (iap->ia_valid & ATTR_MTIME) {
		bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
		len += 4;
		len += 4;
	}
	if (label) {
	if (label) {
		len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
		len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
		bmval_len = 3;
		bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
	}
	}


	len += bmval_len << 2;
	if (bmval[2] != 0)
	p = reserve_space(xdr, len);
		bmval_len = 3;
	else if (bmval[1] != 0)
		bmval_len = 2;
	else
		bmval_len = 1;

	p = reserve_space(xdr, 4 + (bmval_len << 2) + 4 + len);


	/*
	 * We write the bitmap length now, but leave the bitmap and the attribute
	 * buffer length to be backfilled at the end of this routine.
	 */
	*p++ = cpu_to_be32(bmval_len);
	*p++ = cpu_to_be32(bmval_len);
	q = p;
	for (i = 0; i < bmval_len; i++)
	/* Skip bitmap entries + attrlen */
		*p++ = cpu_to_be32(bmval[i]);
	p += bmval_len + 1;
	*p++ = cpu_to_be32(len);


	if (iap->ia_valid & ATTR_SIZE) {
	if (bmval[0] & FATTR4_WORD0_SIZE)
		bmval0 |= FATTR4_WORD0_SIZE;
		p = xdr_encode_hyper(p, iap->ia_size);
		p = xdr_encode_hyper(p, iap->ia_size);
	}
	if (bmval[1] & FATTR4_WORD1_MODE)
	if (iap->ia_valid & ATTR_MODE) {
		bmval1 |= FATTR4_WORD1_MODE;
		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
	}
	if (bmval[1] & FATTR4_WORD1_OWNER)
	if (iap->ia_valid & ATTR_UID) {
		bmval1 |= FATTR4_WORD1_OWNER;
		p = xdr_encode_opaque(p, owner_name, owner_namelen);
		p = xdr_encode_opaque(p, owner_name, owner_namelen);
	}
	if (bmval[1] & FATTR4_WORD1_OWNER_GROUP)
	if (iap->ia_valid & ATTR_GID) {
		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
	}
	if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
		if (iap->ia_valid & ATTR_ATIME_SET) {
		if (iap->ia_valid & ATTR_ATIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
			p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
			p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
			*p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
			*p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
	}
		} else
	else if (iap->ia_valid & ATTR_ATIME) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
	}
	}
	if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
		if (iap->ia_valid & ATTR_MTIME_SET) {
		if (iap->ia_valid & ATTR_MTIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
			p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
			p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
			*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
			*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
	}
		} else
	else if (iap->ia_valid & ATTR_MTIME) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
	}
	}
	if (label) {
	if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
		bmval2 |= FATTR4_WORD2_SECURITY_LABEL;
		*p++ = cpu_to_be32(label->lfs);
		*p++ = cpu_to_be32(label->lfs);
		*p++ = cpu_to_be32(label->pi);
		*p++ = cpu_to_be32(label->pi);
		*p++ = cpu_to_be32(label->len);
		*p++ = cpu_to_be32(label->len);
		p = xdr_encode_opaque_fixed(p, label->label, label->len);
		p = xdr_encode_opaque_fixed(p, label->label, label->len);
	}
	}


	/*
	 * Now we backfill the bitmap and the attribute buffer length.
	 */
	if (len != ((char *)p - (char *)q) + 4) {
		printk(KERN_ERR "NFS: Attr length error, %u != %Zu\n",
				len, ((char *)p - (char *)q) + 4);
		BUG();
	}
	*q++ = htonl(bmval0);
	*q++ = htonl(bmval1);
	if (bmval_len == 3)
		*q++ = htonl(bmval2);
	len = (char *)p - (char *)(q + 1);
	*q = htonl(len);

/* out: */
/* out: */
}
}