]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
nfs: Add timecreate to nfs inode
authorAnne Marie Merritt <annemarie.merritt@primarydata.com>
Thu, 29 May 2025 10:45:46 +0000 (06:45 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 14 Jul 2025 22:20:02 +0000 (15:20 -0700)
Add tracking of the create time (a.k.a. btime) along with corresponding
bitfields, request, and decode xdr routines.

Signed-off-by: Anne Marie Merritt <annemarie.merritt@primarydata.com>
Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com>
Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Link: https://lore.kernel.org/r/1e3677b0655fa2bbaba0817b41d111d94a06e5ee.1748515333.git.bcodding@redhat.com
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/inode.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
fs/nfs/nfstrace.h
include/linux/nfs_fs.h
include/linux/nfs_xdr.h

index 17f5dcda2a00066dedca9f1cc0aa9d9caba0cfd0..c5462aed6bf5e8fff11665f871228f975155ecbf 100644 (file)
@@ -197,6 +197,7 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
                if (!(flags & NFS_INO_REVAL_FORCED))
                        flags &= ~(NFS_INO_INVALID_MODE |
                                   NFS_INO_INVALID_OTHER |
+                                  NFS_INO_INVALID_BTIME |
                                   NFS_INO_INVALID_XATTR);
                flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
        }
@@ -522,6 +523,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                inode_set_atime(inode, 0, 0);
                inode_set_mtime(inode, 0, 0);
                inode_set_ctime(inode, 0, 0);
+               memset(&nfsi->btime, 0, sizeof(nfsi->btime));
                inode_set_iversion_raw(inode, 0);
                inode->i_size = 0;
                clear_nlink(inode);
@@ -545,6 +547,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                        inode_set_ctime_to_ts(inode, fattr->ctime);
                else if (fattr_supported & NFS_ATTR_FATTR_CTIME)
                        nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME);
+               if (fattr->valid & NFS_ATTR_FATTR_BTIME)
+                       nfsi->btime = fattr->btime;
+               else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
+                       nfs_set_cache_invalid(inode, NFS_INO_INVALID_BTIME);
                if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
                        inode_set_iversion_raw(inode, fattr->change_attr);
                else
@@ -1943,7 +1949,7 @@ static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
                NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
                NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
                NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
-               NFS_INO_INVALID_NLINK;
+               NFS_INO_INVALID_NLINK | NFS_INO_INVALID_BTIME;
        unsigned long cache_validity = NFS_I(inode)->cache_validity;
        enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
 
@@ -2304,7 +2310,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                                        | NFS_INO_INVALID_BLOCKS
                                        | NFS_INO_INVALID_NLINK
                                        | NFS_INO_INVALID_MODE
-                                       | NFS_INO_INVALID_OTHER;
+                                       | NFS_INO_INVALID_OTHER
+                                       | NFS_INO_INVALID_BTIME;
                                if (S_ISDIR(inode->i_mode))
                                        nfs_force_lookup_revalidate(inode);
                                attr_changed = true;
@@ -2338,6 +2345,12 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                nfsi->cache_validity |=
                        save_cache_validity & NFS_INO_INVALID_CTIME;
 
+       if (fattr->valid & NFS_ATTR_FATTR_BTIME)
+               nfsi->btime = fattr->btime;
+       else if (fattr_supported & NFS_ATTR_FATTR_BTIME)
+               nfsi->cache_validity |=
+                       save_cache_validity & NFS_INO_INVALID_BTIME;
+
        /* Check if our cached file size is stale */
        if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
                new_isize = nfs_size_to_loff_t(fattr->size);
index 341740fa293d8fb1cfabe0813c7fcadf04df4f62..92f1b2601b67cad5bf5f80e80208f0e94e26678c 100644 (file)
@@ -222,6 +222,7 @@ const u32 nfs4_fattr_bitmap[3] = {
        | FATTR4_WORD1_RAWDEV
        | FATTR4_WORD1_SPACE_USED
        | FATTR4_WORD1_TIME_ACCESS
+       | FATTR4_WORD1_TIME_CREATE
        | FATTR4_WORD1_TIME_METADATA
        | FATTR4_WORD1_TIME_MODIFY
        | FATTR4_WORD1_MOUNTED_ON_FILEID,
@@ -243,6 +244,7 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
        | FATTR4_WORD1_RAWDEV
        | FATTR4_WORD1_SPACE_USED
        | FATTR4_WORD1_TIME_ACCESS
+       | FATTR4_WORD1_TIME_CREATE
        | FATTR4_WORD1_TIME_METADATA
        | FATTR4_WORD1_TIME_MODIFY,
        FATTR4_WORD2_MDSTHRESHOLD
@@ -323,6 +325,9 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
        if (!(cache_validity & NFS_INO_INVALID_OTHER))
                dst[1] &= ~(FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP);
 
+       if (!(cache_validity & NFS_INO_INVALID_BTIME))
+               dst[1] &= ~FATTR4_WORD1_TIME_CREATE;
+
        if (nfs_have_delegated_mtime(inode)) {
                if (!(cache_validity & NFS_INO_INVALID_ATIME))
                        dst[1] &= ~(FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET);
@@ -1307,7 +1312,8 @@ nfs4_update_changeattr_locked(struct inode *inode,
                                NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
                                NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
                                NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
-                               NFS_INO_INVALID_MODE | NFS_INO_INVALID_XATTR;
+                               NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME |
+                               NFS_INO_INVALID_XATTR;
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
        }
        nfsi->attrtimeo_timestamp = jiffies;
@@ -4047,6 +4053,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                        server->fattr_valid &= ~NFS_ATTR_FATTR_CTIME;
                if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
                        server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
+               if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
+                       server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
+               if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_CREATE))
+                       server->fattr_valid &= ~NFS_ATTR_FATTR_BTIME;
                memcpy(server->attr_bitmask_nl, res.attr_bitmask,
                                sizeof(server->attr_bitmask));
                server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -5781,6 +5791,8 @@ void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[],
                bitmask[1] |= FATTR4_WORD1_TIME_MODIFY;
        if (cache_validity & NFS_INO_INVALID_BLOCKS)
                bitmask[1] |= FATTR4_WORD1_SPACE_USED;
+       if (cache_validity & NFS_INO_INVALID_BTIME)
+               bitmask[1] |= FATTR4_WORD1_TIME_CREATE;
 
        if (cache_validity & NFS_INO_INVALID_SIZE)
                bitmask[0] |= FATTR4_WORD0_SIZE;
index 318afde38057832f603139276275a60549a0d273..49ff98571fa5d60dbe761a84fcdaad982d9e58cd 100644 (file)
@@ -1623,6 +1623,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
                        | FATTR4_WORD1_RAWDEV
                        | FATTR4_WORD1_SPACE_USED
                        | FATTR4_WORD1_TIME_ACCESS
+                       | FATTR4_WORD1_TIME_CREATE
                        | FATTR4_WORD1_TIME_METADATA
                        | FATTR4_WORD1_TIME_MODIFY;
                attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
@@ -4207,6 +4208,24 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
        return status;
 }
 
+static int decode_attr_time_create(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
+{
+       int status = 0;
+
+       time->tv_sec = 0;
+       time->tv_nsec = 0;
+       if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_CREATE - 1U)))
+               return -EIO;
+       if (likely(bitmap[1] & FATTR4_WORD1_TIME_CREATE)) {
+               status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_BTIME;
+               bitmap[1] &= ~FATTR4_WORD1_TIME_CREATE;
+       }
+       dprintk("%s: btime=%lld\n", __func__, time->tv_sec);
+       return status;
+}
+
 static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec64 *time)
 {
        int status = 0;
@@ -4781,6 +4800,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
+       status = decode_attr_time_create(xdr, bitmap, &fattr->btime);
+       if (status < 0)
+               goto xdr_error;
+       fattr->valid |= status;
+
        status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
        if (status < 0)
                goto xdr_error;
index 7a058bd8c566e2976e24136e2901fbaa7070daac..f49f064c5ee571463c6596bf08a4a148acae50a7 100644 (file)
@@ -32,7 +32,8 @@
                        { NFS_INO_INVALID_BLOCKS, "INVALID_BLOCKS" }, \
                        { NFS_INO_INVALID_XATTR, "INVALID_XATTR" }, \
                        { NFS_INO_INVALID_NLINK, "INVALID_NLINK" }, \
-                       { NFS_INO_INVALID_MODE, "INVALID_MODE" })
+                       { NFS_INO_INVALID_MODE, "INVALID_MODE" }, \
+                       { NFS_INO_INVALID_BTIME, "INVALID_BTIME" })
 
 #define nfs_show_nfsi_flags(v) \
        __print_flags(v, "|", \
index 67ae2c3f41d2023dda496f6d7ba8fcadc7544d4a..c585939b6cd60f1f3ac511bc8011c38bbfb358d9 100644 (file)
@@ -160,6 +160,12 @@ struct nfs_inode {
        unsigned long           flags;                  /* atomic bit ops */
        unsigned long           cache_validity;         /* bit mask */
 
+       /*
+        * NFS Attributes not included in struct inode
+        */
+
+       struct timespec64       btime;
+
        /*
         * read_cache_jiffies is when we started read-caching this inode.
         * attrtimeo is for how long the cached information is assumed
@@ -316,10 +322,12 @@ struct nfs4_copy_state {
 #define NFS_INO_INVALID_XATTR  BIT(15)         /* xattrs are invalid */
 #define NFS_INO_INVALID_NLINK  BIT(16)         /* cached nlinks is invalid */
 #define NFS_INO_INVALID_MODE   BIT(17)         /* cached mode is invalid */
+#define NFS_INO_INVALID_BTIME  BIT(18)         /* cached btime is invalid */
 
 #define NFS_INO_INVALID_ATTR   (NFS_INO_INVALID_CHANGE \
                | NFS_INO_INVALID_CTIME \
                | NFS_INO_INVALID_MTIME \
+               | NFS_INO_INVALID_BTIME \
                | NFS_INO_INVALID_SIZE \
                | NFS_INO_INVALID_NLINK \
                | NFS_INO_INVALID_MODE \
index 9cacbbd147876b6e75fd5047c10bef2b2200f500..ac4bff6e99135f6275801c29012b829aefb45f22 100644 (file)
@@ -67,6 +67,7 @@ struct nfs_fattr {
        struct timespec64       atime;
        struct timespec64       mtime;
        struct timespec64       ctime;
+       struct timespec64       btime;
        __u64                   change_attr;    /* NFSv4 change attribute */
        __u64                   pre_change_attr;/* pre-op NFSv4 change attribute */
        __u64                   pre_size;       /* pre_op_attr.size       */
@@ -106,6 +107,7 @@ struct nfs_fattr {
 #define NFS_ATTR_FATTR_OWNER_NAME      BIT_ULL(23)
 #define NFS_ATTR_FATTR_GROUP_NAME      BIT_ULL(24)
 #define NFS_ATTR_FATTR_V4_SECURITY_LABEL BIT_ULL(25)
+#define NFS_ATTR_FATTR_BTIME           BIT_ULL(26)
 
 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
                | NFS_ATTR_FATTR_MODE \
@@ -126,6 +128,7 @@ struct nfs_fattr {
                | NFS_ATTR_FATTR_SPACE_USED)
 #define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
                | NFS_ATTR_FATTR_SPACE_USED \
+               | NFS_ATTR_FATTR_BTIME \
                | NFS_ATTR_FATTR_V4_SECURITY_LABEL)
 
 /*