tree 9088c5e29cbd4b33e907a7b5f9a950dd0dce36c1
parent 5529680981807b44abf3be30fb6d612ff04f68ff
author Chuck Lever <[EMAIL PROTECTED]> Fri, 19 Aug 2005 01:24:11 -0700
committer Linus Torvalds <[EMAIL PROTECTED]> Fri, 19 Aug 2005 02:53:56 -0700

[PATCH] NFS: use atomic bitops to manipulate flags in nfsi->flags

Introduce atomic bitops to manipulate the bits in the nfs_inode structure's
"flags" field.

Using bitops means we can use a generic wait_on_bit call instead of an ad hoc
locking scheme in fs/nfs/inode.c, so we can remove the "nfs_i_wait" field from
nfs_inode at the same time.

The other new flags field will continue to use bitmask and logic AND and OR.
This permits several flags to be set at the same time efficiently.  The
following patch adds a spin lock to protect these flags, and this spin lock
will later cover other fields in the nfs_inode structure, amortizing the cost
of using this type of serialization.

Test plan:
 Millions of fsx ops on SMP clients.

Signed-off-by: Chuck Lever <[EMAIL PROTECTED]>
Cc: Trond Myklebust <[EMAIL PROTECTED]>
Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>

 fs/nfs/dir.c           |    4 +-
 fs/nfs/inode.c         |   69 ++++++++++++++++++++++++++++++-------------------
 include/linux/nfs_fs.h |   19 +++++--------
 3 files changed, 53 insertions(+), 39 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -182,7 +182,7 @@ int nfs_readdir_filler(nfs_readdir_descr
                /* We requested READDIRPLUS, but the server doesn't grok it */
                if (error == -ENOTSUPP && desc->plus) {
                        NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS;
-                       NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+                       clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
                        desc->plus = 0;
                        goto again;
                }
@@ -545,7 +545,7 @@ static int nfs_readdir(struct file *filp
                        break;
                }
                if (res == -ETOOSMALL && desc->plus) {
-                       NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+                       clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
                        nfs_zap_caches(inode);
                        desc->plus = 0;
                        desc->entry->eof = 0;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -739,7 +739,7 @@ nfs_fhget(struct super_block *sb, struct
                        inode->i_fop = &nfs_dir_operations;
                        if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
                            && fattr->size <= NFS_LIMIT_READDIRPLUS)
-                               NFS_FLAGS(inode) |= NFS_INO_ADVISE_RDPLUS;
+                               set_bit(NFS_INO_ADVISE_RDPLUS, 
&NFS_FLAGS(inode));
                } else if (S_ISLNK(inode->i_mode))
                        inode->i_op = &nfs_symlink_inode_operations;
                else
@@ -849,26 +849,43 @@ void nfs_setattr_update_inode(struct ino
        }
 }
 
+static int nfs_wait_schedule(void *word)
+{
+       if (signal_pending(current))
+               return -ERESTARTSYS;
+       schedule();
+       return 0;
+}
+
 /*
  * Wait for the inode to get unlocked.
- * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
  */
-static int
-nfs_wait_on_inode(struct inode *inode, int flag)
+static int nfs_wait_on_inode(struct inode *inode)
 {
        struct rpc_clnt *clnt = NFS_CLIENT(inode);
        struct nfs_inode *nfsi = NFS_I(inode);
-
+       sigset_t oldmask;
        int error;
-       if (!(NFS_FLAGS(inode) & flag))
-               return 0;
+
        atomic_inc(&inode->i_count);
-       error = nfs_wait_event(clnt, nfsi->nfs_i_wait,
-                               !(NFS_FLAGS(inode) & flag));
+       rpc_clnt_sigmask(clnt, &oldmask);
+       error = wait_on_bit_lock(&nfsi->flags, NFS_INO_REVALIDATING,
+                                       nfs_wait_schedule, TASK_INTERRUPTIBLE);
+       rpc_clnt_sigunmask(clnt, &oldmask);
        iput(inode);
+
        return error;
 }
 
+static void nfs_wake_up_inode(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       clear_bit(NFS_INO_REVALIDATING, &nfsi->flags);
+       smp_mb__after_clear_bit();
+       wake_up_bit(&nfsi->flags, NFS_INO_REVALIDATING);
+}
+
 int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat 
*stat)
 {
        struct inode *inode = dentry->d_inode;
@@ -1029,18 +1046,19 @@ __nfs_revalidate_inode(struct nfs_server
        if (NFS_STALE(inode))
                goto out_nowait;
 
-       while (NFS_REVALIDATING(inode)) {
-               status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
-               if (status < 0)
-                       goto out_nowait;
-               if (NFS_ATTRTIMEO(inode) == 0)
-                       continue;
-               if (nfsi->cache_validity & 
(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME))
-                       continue;
-               status = NFS_STALE(inode) ? -ESTALE : 0;
-               goto out_nowait;
+       status = nfs_wait_on_inode(inode);
+       if (status < 0)
+               goto out;
+       if (NFS_STALE(inode)) {
+               status = -ESTALE;
+               /* Do we trust the cached ESTALE? */
+               if (NFS_ATTRTIMEO(inode) != 0) {
+                       if (nfsi->cache_validity & 
(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) {
+                               /* no */
+                       } else
+                               goto out;
+               }
        }
-       NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
 
        /* Protect against RPC races by saving the change attribute */
        verifier = nfs_save_change_attribute(inode);
@@ -1052,7 +1070,7 @@ __nfs_revalidate_inode(struct nfs_server
                if (status == -ESTALE) {
                        nfs_zap_caches(inode);
                        if (!S_ISDIR(inode->i_mode))
-                               NFS_FLAGS(inode) |= NFS_INO_STALE;
+                               set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
                }
                goto out;
        }
@@ -1083,9 +1101,9 @@ __nfs_revalidate_inode(struct nfs_server
                inode->i_sb->s_id,
                (long long)NFS_FILEID(inode));
 
-out:
-       NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
-       wake_up(&nfsi->nfs_i_wait);
+ out:
+       nfs_wake_up_inode(inode);
+
  out_nowait:
        unlock_kernel();
        return status;
@@ -1404,7 +1422,7 @@ static int nfs_update_inode(struct inode
         */
        nfs_invalidate_inode(inode);
  out_err:
-       NFS_FLAGS(inode) |= NFS_INO_STALE;
+       set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
        return -ESTALE;
 }
 
@@ -1996,7 +2014,6 @@ static void init_once(void * foo, kmem_c
                nfsi->ndirty = 0;
                nfsi->ncommit = 0;
                nfsi->npages = 0;
-               init_waitqueue_head(&nfsi->nfs_i_wait);
                nfs4_init_once(nfsi);
        }
 }
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -112,8 +112,8 @@ struct nfs_inode {
        /*
         * Various flags
         */
-       unsigned int            flags;
-       unsigned long           cache_validity;
+       unsigned long           flags;                  /* atomic bit ops */
+       unsigned long           cache_validity;         /* bit mask */
 
        /*
         * read_cache_jiffies is when we started read-caching this inode,
@@ -175,8 +175,6 @@ struct nfs_inode {
        /* Open contexts for shared mmap writes */
        struct list_head        open_files;
 
-       wait_queue_head_t       nfs_i_wait;
-
 #ifdef CONFIG_NFS_V4
        struct nfs4_cached_acl  *nfs4_acl;
         /* NFSv4 state */
@@ -199,11 +197,11 @@ struct nfs_inode {
 #define NFS_INO_REVAL_PAGECACHE        0x0020          /* must revalidate 
pagecache */
 
 /*
- * Legal values of flags field
+ * Bit offsets in flags field
  */
-#define NFS_INO_REVALIDATING   0x0001          /* revalidating attrs */
-#define NFS_INO_ADVISE_RDPLUS  0x0002          /* advise readdirplus */
-#define NFS_INO_STALE          0x0004          /* possible stale inode */
+#define NFS_INO_REVALIDATING   (0)             /* revalidating attrs */
+#define NFS_INO_ADVISE_RDPLUS  (1)             /* advise readdirplus */
+#define NFS_INO_STALE          (2)             /* possible stale inode */
 
 static inline struct nfs_inode *NFS_I(struct inode *inode)
 {
@@ -229,8 +227,7 @@ static inline struct nfs_inode *NFS_I(st
 #define NFS_ATTRTIMEO_UPDATE(inode)    (NFS_I(inode)->attrtimeo_timestamp)
 
 #define NFS_FLAGS(inode)               (NFS_I(inode)->flags)
-#define NFS_REVALIDATING(inode)                (NFS_FLAGS(inode) & 
NFS_INO_REVALIDATING)
-#define NFS_STALE(inode)               (NFS_FLAGS(inode) & NFS_INO_STALE)
+#define NFS_STALE(inode)               (test_bit(NFS_INO_STALE, 
&NFS_FLAGS(inode)))
 
 #define NFS_FILEID(inode)              (NFS_I(inode)->fileid)
 
@@ -252,7 +249,7 @@ static inline int nfs_server_capable(str
 
 static inline int NFS_USE_READDIRPLUS(struct inode *inode)
 {
-       return NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS;
+       return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
 }
 
 /**
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to