Support for micro/nanosecond [acm]time in the NFS client

Support for micro/nanosecond [acm]time in the NFS client

Post by Trond Myklebus » Wed, 20 Nov 2002 07:50:11



Given Andi Kleen's patch that introduces of VFS-level support for
nanosecond time resolutions, we should finally be able to export the
existing NFS client level support to userland.

In order to do so, the following patch will convert all NFS private
'raw u64' values into the kernel-supported struct timespec directly in
the xdr_encode/xdr_decode routines.
It adds support for the nanosecond field in NFS 'setattr' calls, and
in nfs_refresh_inode().

Finally, there are a few cleanups in the nfs_refresh_inode code that
convert multiple use of the NFS_*(inode) macros into a single
dereference of NFS_I(inode).

Cheers,
  Trond

diff -u --recursive --new-file linux-2.5.48/fs/nfs/inode.c linux-2.5.48-01-fix_time/fs/nfs/inode.c
--- linux-2.5.48/fs/nfs/inode.c 2002-11-17 20:12:25.000000000 -0500
+++ linux-2.5.48-01-fix_time/fs/nfs/inode.c     2002-11-18 09:29:11.000000000 -0500
@@ -656,9 +656,7 @@
                goto out_no_inode;

        if (inode->i_state & I_NEW) {
-               __u64           new_size, new_mtime;
-               loff_t          new_isize;
-               time_t          new_atime;
+               struct nfs_inode *nfsi = NFS_I(inode);

                /* We set i_ino for the few things that still rely on it,
                 * such as stat(2) */
@@ -686,24 +684,17 @@
                else
                        init_special_inode(inode, inode->i_mode, fattr->rdev);

-               new_mtime = fattr->mtime;
-               new_size = fattr->size;
-               new_isize = nfs_size_to_loff_t(fattr->size);
-               new_atime = nfs_time_to_secs(fattr->atime);
-
-               NFS_READTIME(inode) = fattr->timestamp;
-               NFS_CACHE_CTIME(inode) = fattr->ctime;
-               inode->i_ctime.tv_sec = nfs_time_to_secs(fattr->ctime);
-               inode->i_ctime.tv_nsec = nfs_time_to_nsecs(fattr->ctime);
-               inode->i_atime.tv_sec = new_atime;
-               NFS_CACHE_MTIME(inode) = new_mtime;
-               inode->i_mtime.tv_sec = nfs_time_to_secs(new_mtime);
-               inode->i_mtime.tv_nsec = nfs_time_to_nsecs(new_mtime);
-               NFS_MTIME_UPDATE(inode) = fattr->timestamp;
-               NFS_CACHE_ISIZE(inode) = new_size;
+               nfsi->read_cache_jiffies = fattr->timestamp;
+               inode->i_atime = fattr->atime;
+               inode->i_mtime = fattr->mtime;
+               inode->i_ctime = fattr->ctime;
+               nfsi->read_cache_ctime = fattr->ctime;
+               nfsi->read_cache_mtime = fattr->mtime;
+               nfsi->cache_mtime_jiffies = fattr->timestamp;
+               nfsi->read_cache_isize = fattr->size;
                if (fattr->valid & NFS_ATTR_FATTR_V4)
-                       NFS_CHANGE_ATTR(inode) = fattr->change_attr;
-               inode->i_size = new_isize;
+                       nfsi->change_attr = fattr->change_attr;
+               inode->i_size = nfs_size_to_loff_t(fattr->size);
                inode->i_mode = fattr->mode;
                inode->i_nlink = fattr->nlink;
                inode->i_uid = fattr->uid;
@@ -718,10 +709,10 @@
                        inode->i_blocks = fattr->du.nfs2.blocks;
                        inode->i_blksize = fattr->du.nfs2.blocksize;
                }
-               NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
-               NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
-               memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
-               NFS_I(inode)->cache_access.cred = NULL;
+               nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
+               nfsi->attrtimeo_timestamp = jiffies;
+               memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
+               nfsi->cache_access.cred = NULL;

                unlock_new_inode(inode);
        } else
@@ -787,9 +778,10 @@
         * now to avoid invalidating the page cache.
         */
        if (!(fattr.valid & NFS_ATTR_WCC)) {
-               fattr.pre_size = NFS_CACHE_ISIZE(inode);
-               fattr.pre_mtime = NFS_CACHE_MTIME(inode);
-               fattr.pre_ctime = NFS_CACHE_CTIME(inode);
+               struct nfs_inode *nfsi = NFS_I(inode);
+               fattr.pre_size = nfsi->read_cache_isize;
+               fattr.pre_mtime = nfsi->read_cache_mtime;
+               fattr.pre_ctime = nfsi->read_cache_ctime;
                fattr.valid |= NFS_ATTR_WCC;
        }
        /* Force an attribute cache update */
@@ -962,14 +954,18 @@
 static inline
 int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr)
 {
-       s64 cdif;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       long cdif;

-       if (time_after(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
+       if (time_after(jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo))
                goto out_valid;
-       if ((cdif = (s64)fattr->ctime - (s64)NFS_CACHE_CTIME(inode)) > 0)
+       cdif = fattr->ctime.tv_sec - nfsi->read_cache_ctime.tv_sec;
+       if (cdif == 0)
+               cdif = fattr->ctime.tv_nsec - nfsi->read_cache_ctime.tv_nsec;
+       if (cdif > 0)
                goto out_valid;
        /* Ugh... */
-       if (cdif == 0 && fattr->size > NFS_CACHE_ISIZE(inode))
+       if (cdif == 0 && fattr->size > nfsi->read_cache_isize)
                goto out_valid;
        return -1;
  out_valid:
@@ -991,19 +987,20 @@
 int
 __nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
-       __u64           new_size, new_mtime;
+       struct nfs_inode *nfsi = NFS_I(inode);
+       __u64           new_size;
        loff_t          new_isize;
-       struct timespec new_atime;
        int             invalid = 0;
+       int             mtime_update = 0;

        dfprintk(VFS, "NFS: refresh_inode(%s/%ld ct=%d info=0x%x)\n",
                        inode->i_sb->s_id, inode->i_ino,
                        atomic_read(&inode->i_count), fattr->valid);

-       if (NFS_FILEID(inode) != fattr->fileid) {
+       if (nfsi->fileid != fattr->fileid) {
                printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
                       "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
-                      inode->i_sb->s_id, (long long)NFS_FILEID(inode),
+                      inode->i_sb->s_id, (long long)nfsi->fileid,
                       inode->i_sb->s_id, (long long)fattr->fileid);
                goto out_err;
        }
@@ -1017,12 +1014,9 @@
        if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
                goto out_changed;

-       new_mtime = fattr->mtime;
        new_size = fattr->size;
        new_isize = nfs_size_to_loff_t(fattr->size);

-       new_atime.tv_sec = nfs_time_to_secs(fattr->atime);
-       new_atime.tv_nsec = nfs_time_to_nsecs(fattr->atime);
        /* Avoid races */
        if (nfs_fattr_obsolete(inode, fattr))
                goto out_nochange;
@@ -1030,13 +1024,13 @@
        /*
         * Update the read time so we don't revalidate too often.
         */
-       NFS_READTIME(inode) = fattr->timestamp;
+       nfsi->read_cache_jiffies = fattr->timestamp;

        /*
         * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
         *       NOT inode->i_size!!!
         */
-       if (NFS_CACHE_ISIZE(inode) != new_size) {
+       if (nfsi->read_cache_isize != new_size) {
 #ifdef NFS_DEBUG_VERBOSE
                printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
 #endif
@@ -1048,15 +1042,16 @@
         *       can change this value in VFS without requiring a
         *       cache revalidation.
         */
-       if (NFS_CACHE_MTIME(inode) != new_mtime) {
+       if (!timespec_equal(&nfsi->read_cache_mtime, &fattr->mtime)) {
 #ifdef NFS_DEBUG_VERBOSE
                printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
 #endif
                invalid = 1;
+               mtime_update = 1;
        }

        if ((fattr->valid & NFS_ATTR_FATTR_V4)
-           && NFS_CHANGE_ATTR(inode) != fattr->change_attr) {
+           && nfsi->change_attr != fattr->change_attr) {
 #ifdef NFS_DEBUG_VERBOSE
                printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n",
                       inode->i_sb->s_id, inode->i_ino);
@@ -1070,12 +1065,12 @@
          * operation, so there's no need to invalidate the caches.
          */
        if ((fattr->valid & NFS_ATTR_PRE_CHANGE)
-           && NFS_CHANGE_ATTR(inode) == fattr->pre_change_attr) {
+           && nfsi->change_attr == fattr->pre_change_attr) {
                invalid = 0;
        }
        else if ((fattr->valid & NFS_ATTR_WCC)
-           && NFS_CACHE_ISIZE(inode) == fattr->pre_size
-           && NFS_CACHE_MTIME(inode) == fattr->pre_mtime) {
+           && nfsi->read_cache_isize == fattr->pre_size
+           && timespec_equal(&nfsi->read_cache_mtime, &fattr->pre_mtime)) {
                invalid = 0;
        }

@@ -1086,21 +1081,18 @@
        if (nfs_have_writebacks(inode) && new_isize < inode->i_size)
                new_isize = inode->i_size;

-       NFS_CACHE_CTIME(inode) = fattr->ctime;
-       inode->i_ctime.tv_sec = nfs_time_to_secs(fattr->ctime);
-       inode->i_ctime.tv_nsec = nfs_time_to_nsecs(fattr->ctime);
-
-       inode->i_atime = new_atime;
+       nfsi->read_cache_ctime = fattr->ctime;
+       inode->i_ctime = fattr->ctime;
+       inode->i_atime = fattr->atime;

-       if (NFS_CACHE_MTIME(inode) != new_mtime) {
+       if (mtime_update) {
                if (invalid)
-                       NFS_MTIME_UPDATE(inode) = fattr->timestamp;
-               NFS_CACHE_MTIME(inode) = new_mtime;
-               inode->i_mtime.tv_sec = nfs_time_to_secs(new_mtime);
-               inode->i_mtime.tv_nsec = nfs_time_to_nsecs(new_mtime);
+                       nfsi->cache_mtime_jiffies = fattr->timestamp;
+               nfsi->read_cache_mtime = fattr->mtime;
+               inode->i_mtime = fattr->mtime;
        }

-       NFS_CACHE_ISIZE(inode) = new_size;
+       nfsi->read_cache_isize = new_size;
        inode->i_size = new_isize;

        if (inode->i_mode != fattr->mode ||
@@ -1114,7 +1106,7 @@
        }

        if (fattr->valid & NFS_ATTR_FATTR_V4)
-               NFS_CHANGE_ATTR(inode) = fattr->change_attr;
+               nfsi->change_attr = fattr->change_attr;

        inode->i_mode = fattr->mode;
        inode->i_nlink = fattr->nlink;
@@ -1134,20 +1126,20 @@

        /* Update attrtimeo value */
        if (invalid) {
-               NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
-               NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+               nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
+               nfsi->attrtimeo_timestamp = jiffies;
                invalidate_inode_pages(inode->i_mapping);
                memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
-       } else if (time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) {
-               if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
-                       NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
-               NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+       } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
+               if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
+                       nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
+               nfsi->attrtimeo_timestamp = jiffies;
        }

        return 0;
  out_nochange:
-       if (!timespec_equal(&new_atime, &inode->i_atime))
-               inode->i_atime = new_atime;
+       if (!timespec_equal(&fattr->atime, &inode->i_atime))
+               inode->i_atime = fattr->atime;
        return 0;
  out_changed:
        /*
diff -u --recursive --new-file linux-2.5.48/fs/nfs/nfs2xdr.c linux-2.5.48-01-fix_time/fs/nfs/nfs2xdr.c
--- linux-2.5.48/fs/nfs/nfs2xdr.c       2002-11-17 20:12:25.000000000 -0500
+++ linux-2.5.48-01-fix_time/fs/nfs/nfs2xdr.c   2002-11-18 09:46:43.000000000 -0500
@@ -86,10 +86,20 @@
 }

 static inline u32*
-xdr_decode_time(u32 *p, u64 *timep)
+xdr_encode_time(u32 *p, struct timespec *timep)
 {
-       u64 tmp = (u64)ntohl(*p++) << 32;
-       *timep = tmp + (u64)ntohl(*p++);
+       *p++ = htonl(timep->tv_sec);
+       /* Convert nanoseconds into microseconds */
+       *p++ = htonl(timep->tv_nsec / 1000);
+       return p;
+}
+
+static inline u32*
+xdr_decode_time(u32 *p, struct timespec *timep)
+{
+       timep->tv_sec = ntohl(*p++);
+       /* Convert microseconds into nanoseconds */
+       timep->tv_nsec = ntohl(*p++) * 1000;
        return p;
 }

@@ -131,16 +141,14 @@
        SATTR(p, attr, ATTR_SIZE, ia_size);

        if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
-               *p++ = htonl(attr->ia_atime.tv_sec);
-               *p++ = 0;
+               p = xdr_encode_time(p, &attr->ia_atime);
        } else {
                *p++ = ~(u32) 0;
                *p++ = ~(u32) 0;
        }

        if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
-               *p++ = htonl(attr->ia_mtime.tv_sec);
-               *p++ = 0;
+               p = xdr_encode_time(p, &attr->ia_mtime);
        } else {
                *p++ = ~(u32) 0;        
                *p++ = ~(u32) 0;
diff -u --recursive --new-file linux-2.5.48/fs/nfs/nfs3xdr.c linux-2.5.48-01-fix_time/fs/nfs/nfs3xdr.c
--- linux-2.5.48/fs/nfs/nfs3xdr.c       2002-11-17 20:12:25.000000000 -0500
+++ linux-2.5.48-01-fix_time/fs/nfs/nfs3xdr.c   2002-11-18 09:47:22.000000000 -0500
@@ -128,26 +128,18 @@
  * nanosecond field.
  */
 static inline u32 *
-xdr_encode_time(u32 *p, time_t time)
+xdr_encode_time3(u32 *p, struct timespec *timep)
 {
-       *p++ = htonl(time);
-       *p++ = 0;
+       *p++ = htonl(timep->tv_sec);
+       *p++ = htonl(timep->tv_nsec);
        return p;
 }

 static inline u32 *
-xdr_decode_time3(u32 *p, u64 *timep)
+xdr_decode_time3(u32 *p, struct timespec *timep)
 {
-       u64 tmp = (u64)ntohl(*p++) << 32;
-       *timep = tmp + (u64)ntohl(*p++);
-       return p;
-}
-
-static inline u32 *
-xdr_encode_time3(u32 *p, u64 time)
-{
-       *p++ = htonl(time >> 32);
-       *p++ = htonl(time & 0xFFFFFFFF);
+       timep->tv_sec = ntohl(*p++);
+       timep->tv_nsec = ntohl(*p++);
        return p;
 }

@@ -212,7 +204,7 @@
        }
        if (attr->ia_valid & ATTR_ATIME_SET) {
                *p++ = xdr_two;
-               p = xdr_encode_time(p, attr->ia_atime.tv_sec);
+               p = xdr_encode_time3(p, &attr->ia_atime);
        } else if (attr->ia_valid & ATTR_ATIME) {
                *p++ = xdr_one;
        } else {
@@ -220,7 +212,7 @@
        }
        if (attr->ia_valid & ATTR_MTIME_SET) {
                *p++ = xdr_two;
-               p = xdr_encode_time(p, attr->ia_mtime.tv_sec);
+               p = xdr_encode_time3(p, &attr->ia_mtime);
        } else if (attr->ia_valid & ATTR_MTIME) {
                *p++ = xdr_one;
        } else {
@@ -288,7 +280,7 @@
        p = xdr_encode_sattr(p, args->sattr);
        *p++ = htonl(args->guard);
        if (args->guard)
-               p = xdr_encode_time3(p, args->guardtime);
+               p = xdr_encode_time3(p, &args->guardtime);
        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
        return 0;
 }
diff -u --recursive --new-file linux-2.5.48/fs/nfs/nfs4proc.c linux-2.5.48-01-fix_time/fs/nfs/nfs4proc.c
--- linux-2.5.48/fs/nfs/nfs4proc.c      2002-11-13 09:58:44.000000000 -0500
+++ linux-2.5.48-01-fix_time/fs/nfs/nfs4proc.c  2002-11-18 09:26:57.000000000 -0500
@@ -563,13 +563,13 @@
 {
        struct nfs4_setclientid *setclientid = GET_OP(cp, setclientid);
        struct nfs_server *server = cp->server;
-       struct timeval tv;
+       struct timespec tv;
        u32 *p;

-       do_gettimeofday(&tv);
-       p = (u32 *)setclientid->sc_verifier;
+       tv = CURRENT_TIME;
+       p = (u32 *)setclientid->sc_verifier;
        *p++ = tv.tv_sec;
-       *p++ = tv.tv_usec;
+       *p++ = tv.tv_nsec;
        setclientid->sc_name = server->ip_addr;
        sprintf(setclientid->sc_netid, "udp");
        sprintf(setclientid->sc_uaddr, "%s.%d.%d", server->ip_addr, port >> 8, port & 255);
diff -u --recursive --new-file linux-2.5.48/fs/nfs/nfs4xdr.c linux-2.5.48-01-fix_time/fs/nfs/nfs4xdr.c
--- linux-2.5.48/fs/nfs/nfs4xdr.c       2002-11-17 20:12:25.000000000 -0500
+++ linux-2.5.48-01-fix_time/fs/nfs/nfs4xdr.c   2002-11-18 09:49:48.000000000 -0500
@@ -873,8 +873,8 @@
 } while (0)
 #define READTIME(x)       do {                 \
        p++;                                    \
-       (x) = (u64)ntohl(*p++) << 32;             \
-       (x) |= ntohl(*p++);                     \
+       (x.tv_sec) = ntohl(*p++);               \
+       (x.tv_nsec) = ntohl(*p++);              \
 } while (0)
 #define COPYMEM(x,nbytes) do {                 \
        memcpy((x), p, nbytes);                 \
@@ -1228,19 +1228,19 @@
                 READ_BUF(12);
                 len += 12;
                 READTIME(nfp->atime);
-                dprintk("read_attrs: atime=%d\n", (int)nfp->atime);
+                dprintk("read_attrs: atime=%ld\n", (long)nfp->atime.tv_sec);
         }
         if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
                 READ_BUF(12);
                 len += 12;
                 READTIME(nfp->ctime);
-                dprintk("read_attrs: ctime=%d\n", (int)nfp->ctime);
+                dprintk("read_attrs: ctime=%ld\n", (long)nfp->ctime.tv_sec);
         }
         if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
                 READ_BUF(12);
                 len += 12;
                 READTIME(nfp->mtime);
-                dprintk("read_attrs: mtime=%d\n", (int)nfp->mtime);
+                dprintk("read_attrs: mtime=%ld\n", (long)nfp->mtime.tv_sec);
         }
         if (len != attrlen)
                 goto xdr_error;
diff -u --recursive --new-file linux-2.5.48/include/linux/nfs_fs.h linux-2.5.48-01-fix_time/include/linux/nfs_fs.h
--- linux-2.5.48/include/linux/nfs_fs.h 2002-11-17 14:53:57.000000000 -0500
+++ linux-2.5.48-01-fix_time/include/linux/nfs_fs.h     2002-11-18 09:18:08.000000000 -0500
@@ -118,8 +118,8 @@
         *      mtime != read_cache_mtime
         */
        unsigned long           read_cache_jiffies;
-       __u64                   read_cache_ctime;
-       __u64                   read_cache_mtime;
+       struct timespec         read_cache_ctime;
+       struct timespec         read_cache_mtime;
        __u64                   read_cache_isize;
        unsigned long           attrtimeo;
        unsigned long           attrtimeo_timestamp;
@@ -416,20 +416,6 @@
        return ino;
 }

-static inline time_t
-nfs_time_to_secs(__u64 time)
-{
-       return (time_t)(time >> 32);
-}
-
-
-static inline u32
-nfs_time_to_nsecs(__u64 time)
-{
-       return time & 0xffffffff;
-}
-
-
 /* NFS root */

 extern void * nfs_root_data(void);
diff -u --recursive --new-file linux-2.5.48/include/linux/nfs_xdr.h linux-2.5.48-01-fix_time/include/linux/nfs_xdr.h
--- linux-2.5.48/include/linux/nfs_xdr.h        2002-10-14 10:03:48.000000000 -0400
+++ linux-2.5.48-01-fix_time/include/linux/nfs_xdr.h    2002-11-18 08:16:31.000000000 -0500
@@ -6,8 +6,8 @@
 struct nfs_fattr {
        unsigned short          valid;          /* which fields are valid */
        __u64                   pre_size;       /* pre_op_attr.size       */
-       __u64                   pre_mtime;      /* pre_op_attr.mtime      */
-       __u64                   pre_ctime;      /* pre_op_attr.ctime      */
+       struct timespec         pre_mtime;      /* pre_op_attr.mtime      */
+       struct timespec         pre_ctime;      /* pre_op_attr.ctime      */
        enum nfs_ftype          type;           /* always use NFSv2 types */
        __u32                   mode;
        __u32                   nlink;
@@ -32,9 +32,9 @@
                } nfs4;
        } fsid_u;
        __u64                   fileid;
-       __u64                   atime;
-       __u64                   mtime;
-       __u64                   ctime;
+       struct timespec         atime;
+       struct timespec         mtime;
+       struct timespec         ctime;
        __u64                   change_attr;    /* NFSv4 change attribute */
        __u64                   pre_change_attr;/* pre-op NFSv4 change attribute */
        unsigned long           timestamp;
@@ -219,7 +219,7 @@
        struct nfs_fh *         fh;
        struct iattr *          sattr;
        unsigned int            guard;
-       __u64                   guardtime;
+       struct timespec         guardtime;
 };

 struct nfs3_diropargs {
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/