Implement provenance time (ptime) in NFSD, as introduced in a previous commit ("vfs: add provenance time (ptime)"). Map ptime to FATTR4_TIME_CREATE, allowing clients to set it across CREATE, OPEN and SETATTR compounds. If the underlying filesystem supports it, use __vfs_fileattr_set_locked() to set it, returning -EOPNOTSUPP in case it's not supported (i.e. when __vfs_fileattr_set_locked() returns -ENOIOCTLCMD). When querying FATTR4_TIME_CREATE, request both STATX_PTIME and STATX_BTIME, preferring ptime over btime if available, and advertise FATTR4_TIME_CREATE support if either ptime or btime is available. Assisted-by: Gemini:3.8-flash-high antigravity-cli-1.5.7 Signed-off-by: koraynilay --- fs/nfsd/nfs4proc.c | 9 +++++++++ fs/nfsd/nfs4xdr.c | 40 +++++++++++++++++++++++++--------------- fs/nfsd/vfs.c | 17 +++++++++++++++++ fs/nfsd/vfs.h | 4 +++- fs/nfsd/xdr4.h | 3 +++ 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3a82af381a8d..06074a7f213e 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -322,6 +322,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, __be32 status, create_status; int want_write_err; + if (open->op_bmval[1] & FATTR4_WORD1_TIME_CREATE) + attrs.na_time_create = &open->op_time_create; + if (name_is_dot_dotdot(open->op_fname, open->op_fnamelen)) return nfserr_exist; if (!(iap->ia_valid & ATTR_MODE)) @@ -929,6 +932,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status; dev_t rdev; + if (create->cr_bmval[1] & FATTR4_WORD1_TIME_CREATE) + attrs.na_time_create = &create->cr_time_create; + fh_init(&resfh, NFS4_FHSIZE); status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_NOP); @@ -1347,6 +1353,9 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, __be32 status = nfs_ok; int err; + if (setattr->sa_bmval[1] & FATTR4_WORD1_TIME_CREATE) + attrs.na_time_create = &setattr->sa_time_create; + deleg_attrs = setattr->sa_bmval[2] & (FATTR4_WORD2_TIME_DELEG_ACCESS | FATTR4_WORD2_TIME_DELEG_MODIFY); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 84161dbecd1c..faca3b9b58b8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -509,7 +509,8 @@ static __be32 nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, struct iattr *iattr, struct nfs4_acl **acl, struct xdr_netobj *label, int *umask, - struct posix_acl **dpaclp, struct posix_acl **paclp) + struct posix_acl **dpaclp, struct posix_acl **paclp, + struct timespec64 *time_create) { unsigned int starting_pos; u32 attrlist4_count; @@ -603,11 +604,10 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, } } if (bmval[1] & FATTR4_WORD1_TIME_CREATE) { - struct timespec64 ts; + if (!time_create) + return nfserr_bad_xdr; - /* No Linux filesystem supports setting this attribute. */ - bmval[1] &= ~FATTR4_WORD1_TIME_CREATE; - status = nfsd4_decode_nfstime4(argp, &ts); + status = nfsd4_decode_nfstime4(argp, time_create); if (status) return status; } @@ -1013,7 +1013,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) ARRAY_SIZE(create->cr_bmval), &create->cr_iattr, &create->cr_acl, &create->cr_label, &create->cr_umask, - &create->cr_dpacl, &create->cr_pacl); + &create->cr_dpacl, &create->cr_pacl, + &create->cr_time_create); if (status) return status; @@ -1165,7 +1166,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open ARRAY_SIZE(open->op_bmval), &open->op_iattr, &open->op_acl, &open->op_label, &open->op_umask, - &open->op_dpacl, &open->op_pacl); + &open->op_dpacl, &open->op_pacl, + &open->op_time_create); if (status) return status; break; @@ -1184,7 +1186,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open ARRAY_SIZE(open->op_bmval), &open->op_iattr, &open->op_acl, &open->op_label, &open->op_umask, - &open->op_dpacl, &open->op_pacl); + &open->op_dpacl, &open->op_pacl, + &open->op_time_create); if (status) return status; break; @@ -1512,7 +1515,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) ARRAY_SIZE(setattr->sa_bmval), &setattr->sa_iattr, &setattr->sa_acl, &setattr->sa_label, NULL, &setattr->sa_dpacl, - &setattr->sa_pacl); + &setattr->sa_pacl, &setattr->sa_time_create); } static __be32 @@ -3646,7 +3649,14 @@ static __be32 nfsd4_encode_fattr4_time_access(struct xdr_stream *xdr, static __be32 nfsd4_encode_fattr4_time_create(struct xdr_stream *xdr, const struct nfsd4_fattr_args *args) { - return nfsd4_encode_nfstime4(xdr, &args->stat.btime); + const struct timespec64 *ts; + + if (args->stat.result_mask & STATX_PTIME) + ts = &args->stat.ptime; + else + ts = &args->stat.btime; + + return nfsd4_encode_nfstime4(xdr, ts); } /* @@ -4089,8 +4099,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, } err = vfs_getattr(&path, &args.stat, - STATX_BASIC_STATS | STATX_BTIME | STATX_CHANGE_COOKIE, - AT_STATX_SYNC_AS_STAT); + STATX_BASIC_STATS | STATX_BTIME | STATX_PTIME | + STATX_CHANGE_COOKIE, AT_STATX_SYNC_AS_STAT); if (dp) { struct nfs4_cb_fattr *ncf = &dp->dl_cb_fattr; @@ -4113,8 +4123,8 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr, if (err) goto out_nfserr; - if (!(args.stat.result_mask & STATX_BTIME)) - /* underlying FS does not offer btime so we can't share it */ + if (!(args.stat.result_mask & (STATX_BTIME | STATX_PTIME))) + /* underlying FS does not offer ptime or btime so we can't share it */ attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE; if ((attrmask[0] & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || @@ -4434,7 +4444,7 @@ nfsd4_setup_notify_entry4(struct notify_entry4 *ne, struct xdr_stream *xdr, if (!setup_notify_fhandle(dentry, dp, nf, &args)) attrmask[0] &= ~FATTR4_WORD0_FILEHANDLE; - if (!(args.stat.result_mask & STATX_BTIME)) + if (!(args.stat.result_mask & (STATX_PTIME | STATX_BTIME))) attrmask[1] &= ~FATTR4_WORD1_TIME_CREATE; } attrmask[2] = 0; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 56c49b5bc5bb..286ed7c98d91 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -621,6 +621,23 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, if (attr->na_seclabel && attr->na_seclabel->len) attr->na_labelerr = security_inode_setsecctx(dentry, attr->na_seclabel->data, attr->na_seclabel->len); + + if (attr->na_time_create) { + struct file_kattr fa = { + .fsx_valid = true, + .fsx_xflags = FS_XFLAG_PTIME, + .fsx_xflags_mask = FS_XFLAG_PTIME, + .fsx_ptime = *attr->na_time_create, + }; + + host_err = __vfs_fileattr_set_locked(&nop_mnt_idmap, dentry, &fa); + if (host_err) { + if (host_err == -ENOIOCTLCMD) + host_err = -EOPNOTSUPP; + goto out_fill_attrs; + } + } + if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_dpacl) { if (!S_ISDIR(inode->i_mode)) attr->na_dpaclerr = -EINVAL; diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 38f7d36bd4da..24c2c22b3e72 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -100,6 +100,7 @@ struct nfsd_attrs { struct xdr_netobj *na_seclabel; /* input */ struct posix_acl *na_pacl; /* input */ struct posix_acl *na_dpacl; /* input */ + struct timespec64 *na_time_create; /* input */ int na_labelerr; /* output */ int na_dpaclerr; /* output */ @@ -118,7 +119,8 @@ static inline bool nfsd_attrs_valid(struct nfsd_attrs *attrs) return (iap->ia_valid || (attrs->na_seclabel && attrs->na_seclabel->len) || - attrs->na_pacl || attrs->na_dpacl); + attrs->na_pacl || attrs->na_dpacl || + attrs->na_time_create); } struct nfsd_net; diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index ec198993429e..a495a20e5889 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -123,6 +123,7 @@ struct nfsd4_create { struct posix_acl *cr_dpacl; struct posix_acl *cr_pacl; struct xdr_netobj cr_label; + struct timespec64 cr_time_create; }; #define cr_datalen u.link.datalen #define cr_data u.link.data @@ -277,6 +278,7 @@ struct nfsd4_open { struct posix_acl *op_dpacl; struct posix_acl *op_pacl; struct xdr_netobj op_label; + struct timespec64 op_time_create; struct svc_rqst *op_rqstp; }; @@ -378,6 +380,7 @@ struct nfsd4_setattr { struct xdr_netobj sa_label; struct posix_acl *sa_dpacl; struct posix_acl *sa_pacl; + struct timespec64 sa_time_create; }; struct nfsd4_setclientid { -- 2.56.0