@@ -2948,6 +2948,7 @@ struct nfsd4_fattr_args {
struct nfs4_acl *acl;
u32 rdattr_err;
bool contextsupport;
+ bool ignore_crossmnt;
};
typedef __be32(*nfsd4_enc_attr)(struct xdr_stream *xdr,
@@ -3276,6 +3277,191 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_word0_ops[] = {
[31] = nfsd4_encode_fattr4_maxwrite,
};
+static __be32 nfsd4_encode_fattr4_mode(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ if (xdr_stream_encode_u32(xdr, args->stat.mode & S_IALLUGO) < 0)
+ return nfserr_resource;
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_numlinks(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ if (xdr_stream_encode_u32(xdr, args->stat.nlink) < 0)
+ return nfserr_resource;
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_owner(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ return nfsd4_encode_user(xdr, args->rqstp, args->stat.uid);
+}
+
+static __be32 nfsd4_encode_fattr4_owner_group(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ return nfsd4_encode_group(xdr, args->rqstp, args->stat.gid);
+}
+
+static __be32 nfsd4_encode_fattr4_rawdev(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ __be32 *p;
+
+ p = xdr_reserve_space(xdr, 8);
+ if (!p)
+ return nfserr_resource;
+ *p++ = cpu_to_be32((u32) MAJOR(args->stat.rdev));
+ *p = cpu_to_be32((u32) MINOR(args->stat.rdev));
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_avail(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ u64 space = (u64)args->statfs.f_bavail * (u64)args->statfs.f_bsize;
+
+ if (xdr_stream_encode_u64(xdr, space) < 0)
+ return nfserr_resource;
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_free(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ u64 space = (u64)args->statfs.f_bfree * (u64)args->statfs.f_bsize;
+
+ if (xdr_stream_encode_u64(xdr, space) < 0)
+ return nfserr_resource;
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_total(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ u64 space = (u64)args->statfs.f_blocks * (u64)args->statfs.f_bsize;
+
+ if (xdr_stream_encode_u64(xdr, space) < 0)
+ return nfserr_resource;
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_space_used(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ u64 space = (u64)args->stat.blocks << 9;
+
+ if (xdr_stream_encode_u64(xdr, space) < 0)
+ return nfserr_resource;
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_time_access(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ return nfsd4_encode_nfstime4(xdr, &args->stat.atime);
+}
+
+static __be32 nfsd4_encode_fattr4_time_create(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ return nfsd4_encode_nfstime4(xdr, &args->stat.btime);
+}
+
+static __be32 nfsd4_encode_fattr4_time_delta(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ __be32 *p;
+
+ p = xdr_reserve_space(xdr, XDR_UNIT * 3);
+ if (!p)
+ return nfserr_resource;
+
+ encode_time_delta(p, d_inode(args->dentry));
+ return nfs_ok;
+}
+
+static __be32 nfsd4_encode_fattr4_time_metadata(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ return nfsd4_encode_nfstime4(xdr, &args->stat.ctime);
+}
+
+static __be32 nfsd4_encode_fattr4_time_modify(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ return nfsd4_encode_nfstime4(xdr, &args->stat.mtime);
+}
+
+static __be32 nfsd4_encode_fattr4_mounted_on_fileid(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ u64 ino = args->stat.ino;
+ int err;
+
+ if (!args->ignore_crossmnt &&
+ args->dentry == args->exp->ex_path.mnt->mnt_root) {
+ err = nfsd4_get_mounted_on_ino(args->exp, &ino);
+ if (err)
+ return nfserrno(err);
+ }
+
+ if (xdr_stream_encode_u64(xdr, ino) < 0)
+ return nfserr_resource;
+ return nfs_ok;
+}
+
+#ifdef CONFIG_NFSD_PNFS
+
+static __be32 nfsd4_encode_fattr4_layout_types(struct xdr_stream *xdr,
+ struct nfsd4_fattr_args *args)
+{
+ return nfsd4_encode_layout_types(xdr, args->exp->ex_layout_types);
+}
+
+#endif
+
+static const nfsd4_enc_attr nfsd4_enc_fattr4_word1_ops[] = {
+ [0] = nfsd4_encode_fattr4__noop, /* mime type */
+ [1] = nfsd4_encode_fattr4_mode,
+ [2] = nfsd4_encode_fattr4__true, /* no trunc */
+ [3] = nfsd4_encode_fattr4_numlinks,
+ [4] = nfsd4_encode_fattr4_owner,
+ [5] = nfsd4_encode_fattr4_owner_group,
+ [6] = nfsd4_encode_fattr4__noop, /* quota_hard */
+ [7] = nfsd4_encode_fattr4__noop, /* quota_soft */
+ [8] = nfsd4_encode_fattr4__noop, /* quota_used */
+ [9] = nfsd4_encode_fattr4_rawdev,
+ [10] = nfsd4_encode_fattr4_space_avail,
+ [11] = nfsd4_encode_fattr4_space_free,
+ [12] = nfsd4_encode_fattr4_space_total,
+ [13] = nfsd4_encode_fattr4_space_used,
+ [14] = nfsd4_encode_fattr4__noop, /* system */
+ [15] = nfsd4_encode_fattr4_time_access,
+ [16] = nfsd4_encode_fattr4__noop, /* time_access_set */
+ [17] = nfsd4_encode_fattr4__noop, /* time_backup */
+ [18] = nfsd4_encode_fattr4_time_create,
+ [19] = nfsd4_encode_fattr4_time_delta,
+ [20] = nfsd4_encode_fattr4_time_metadata,
+ [21] = nfsd4_encode_fattr4_time_modify,
+ [22] = nfsd4_encode_fattr4__noop, /* time_modify_set */
+ [23] = nfsd4_encode_fattr4_mounted_on_fileid,
+ [24] = nfsd4_encode_fattr4__noop, /* dir notif delay */
+ [25] = nfsd4_encode_fattr4__noop, /* dirent notif delay */
+ [26] = nfsd4_encode_fattr4__noop, /* dacl */
+ [27] = nfsd4_encode_fattr4__noop, /* sacl */
+ [28] = nfsd4_encode_fattr4__noop, /* change policy */
+ [29] = nfsd4_encode_fattr4__noop, /* fs status */
+#ifdef CONFIG_NFSD_PNFS
+ [30] = nfsd4_encode_fattr4_layout_types,
+#else
+ [30] = nfsd4_encode_fattr4__noop,
+#endif
+ [31] = nfsd4_encode_fattr4__noop, /* layout hint */
+};
+
/*
* Note: @fhp can be NULL; in this case, we might have to compose the filehandle
* ourselves.
@@ -3292,7 +3478,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
u32 bmval2 = bmval[2];
struct svc_fh *tempfh = NULL;
int starting_len = xdr->buf->len;
- u64 dummy64;
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
void *context = NULL;
int contextlen;
@@ -3312,6 +3497,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
args.fhp = fhp;
args.exp = exp;
args.dentry = dentry;
+ args.ignore_crossmnt = (ignore_crossmnt != 0);
args.rdattr_err = 0;
if (exp->ex_fslocs.migrated) {
@@ -3399,121 +3585,14 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
goto out;
}
- if (bmval1 & FATTR4_WORD1_MODE) {
- p = xdr_reserve_space(xdr, 4);
- if (!p)
- goto out_resource;
- *p++ = cpu_to_be32(args.stat.mode & S_IALLUGO);
- }
- if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
- p = xdr_reserve_space(xdr, 4);
- if (!p)
- goto out_resource;
- *p++ = cpu_to_be32(1);
- }
- if (bmval1 & FATTR4_WORD1_NUMLINKS) {
- p = xdr_reserve_space(xdr, 4);
- if (!p)
- goto out_resource;
- *p++ = cpu_to_be32(args.stat.nlink);
- }
- if (bmval1 & FATTR4_WORD1_OWNER) {
- status = nfsd4_encode_user(xdr, rqstp, args.stat.uid);
- if (status)
- goto out;
- }
- if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
- status = nfsd4_encode_group(xdr, rqstp, args.stat.gid);
- if (status)
- goto out;
- }
- if (bmval1 & FATTR4_WORD1_RAWDEV) {
- p = xdr_reserve_space(xdr, 8);
- if (!p)
- goto out_resource;
- *p++ = cpu_to_be32((u32) MAJOR(args.stat.rdev));
- *p++ = cpu_to_be32((u32) MINOR(args.stat.rdev));
- }
- if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
- p = xdr_reserve_space(xdr, 8);
- if (!p)
- goto out_resource;
- dummy64 = (u64)args.statfs.f_bavail * (u64)args.statfs.f_bsize;
- p = xdr_encode_hyper(p, dummy64);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
- p = xdr_reserve_space(xdr, 8);
- if (!p)
- goto out_resource;
- dummy64 = (u64)args.statfs.f_bfree * (u64)args.statfs.f_bsize;
- p = xdr_encode_hyper(p, dummy64);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
- p = xdr_reserve_space(xdr, 8);
- if (!p)
- goto out_resource;
- dummy64 = (u64)args.statfs.f_blocks * (u64)args.statfs.f_bsize;
- p = xdr_encode_hyper(p, dummy64);
- }
- if (bmval1 & FATTR4_WORD1_SPACE_USED) {
- p = xdr_reserve_space(xdr, 8);
- if (!p)
- goto out_resource;
- dummy64 = (u64)args.stat.blocks << 9;
- p = xdr_encode_hyper(p, dummy64);
- }
- if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
- status = nfsd4_encode_nfstime4(xdr, &args.stat.atime);
- if (status)
- goto out;
- }
- if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
- p = xdr_reserve_space(xdr, 12);
- if (!p)
- goto out_resource;
- p = encode_time_delta(p, d_inode(dentry));
- }
- if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
- status = nfsd4_encode_nfstime4(xdr, &args.stat.ctime);
- if (status)
- goto out;
- }
- if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
- status = nfsd4_encode_nfstime4(xdr, &args.stat.mtime);
- if (status)
- goto out;
- }
- if (bmval1 & FATTR4_WORD1_TIME_CREATE) {
- status = nfsd4_encode_nfstime4(xdr, &args.stat.btime);
+ mask = bmval1;
+ for_each_set_bit(i, &mask, 32) {
+ status = nfsd4_enc_fattr4_word1_ops[i](xdr, &args);
if (status)
goto out;
}
- if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
- u64 ino = args.stat.ino;
- p = xdr_reserve_space(xdr, 8);
- if (!p)
- goto out_resource;
- /*
- * Get ino of mountpoint in parent filesystem, if not ignoring
- * crossmount and this is the root of a cross-mounted
- * filesystem.
- */
- if (ignore_crossmnt == 0 &&
- dentry == exp->ex_path.mnt->mnt_root) {
- err = nfsd4_get_mounted_on_ino(exp, &ino);
- if (err)
- goto out_nfserr;
- }
- p = xdr_encode_hyper(p, ino);
- }
#ifdef CONFIG_NFSD_PNFS
- if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
- status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
- if (status)
- goto out;
- }
-
if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) {
status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
if (status)