aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <cel@citi.umich.edu>2005-08-18 14:24:11 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-08-18 15:53:56 -0400
commit412d582ec1dd59aab2353f8cb7e74f2c79cd20b9 (patch)
tree9088c5e29cbd4b33e907a7b5f9a950dd0dce36c1
parent5529680981807b44abf3be30fb6d612ff04f68ff (diff)
[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 <cel@netapp.com> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/nfs/dir.c4
-rw-r--r--fs/nfs/inode.c69
-rw-r--r--include/linux/nfs_fs.h19
3 files changed, 53 insertions, 39 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 5732e13cd0da..27cf5577f239 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -182,7 +182,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
182 /* We requested READDIRPLUS, but the server doesn't grok it */ 182 /* We requested READDIRPLUS, but the server doesn't grok it */
183 if (error == -ENOTSUPP && desc->plus) { 183 if (error == -ENOTSUPP && desc->plus) {
184 NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; 184 NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS;
185 NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; 185 clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
186 desc->plus = 0; 186 desc->plus = 0;
187 goto again; 187 goto again;
188 } 188 }
@@ -545,7 +545,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
545 break; 545 break;
546 } 546 }
547 if (res == -ETOOSMALL && desc->plus) { 547 if (res == -ETOOSMALL && desc->plus) {
548 NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; 548 clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
549 nfs_zap_caches(inode); 549 nfs_zap_caches(inode);
550 desc->plus = 0; 550 desc->plus = 0;
551 desc->entry->eof = 0; 551 desc->entry->eof = 0;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 622184553516..ee27578277f3 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -739,7 +739,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
739 inode->i_fop = &nfs_dir_operations; 739 inode->i_fop = &nfs_dir_operations;
740 if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS) 740 if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
741 && fattr->size <= NFS_LIMIT_READDIRPLUS) 741 && fattr->size <= NFS_LIMIT_READDIRPLUS)
742 NFS_FLAGS(inode) |= NFS_INO_ADVISE_RDPLUS; 742 set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
743 } else if (S_ISLNK(inode->i_mode)) 743 } else if (S_ISLNK(inode->i_mode))
744 inode->i_op = &nfs_symlink_inode_operations; 744 inode->i_op = &nfs_symlink_inode_operations;
745 else 745 else
@@ -849,26 +849,43 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
849 } 849 }
850} 850}
851 851
852static int nfs_wait_schedule(void *word)
853{
854 if (signal_pending(current))
855 return -ERESTARTSYS;
856 schedule();
857 return 0;
858}
859
852/* 860/*
853 * Wait for the inode to get unlocked. 861 * Wait for the inode to get unlocked.
854 * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
855 */ 862 */
856static int 863static int nfs_wait_on_inode(struct inode *inode)
857nfs_wait_on_inode(struct inode *inode, int flag)
858{ 864{
859 struct rpc_clnt *clnt = NFS_CLIENT(inode); 865 struct rpc_clnt *clnt = NFS_CLIENT(inode);
860 struct nfs_inode *nfsi = NFS_I(inode); 866 struct nfs_inode *nfsi = NFS_I(inode);
861 867 sigset_t oldmask;
862 int error; 868 int error;
863 if (!(NFS_FLAGS(inode) & flag)) 869
864 return 0;
865 atomic_inc(&inode->i_count); 870 atomic_inc(&inode->i_count);
866 error = nfs_wait_event(clnt, nfsi->nfs_i_wait, 871 rpc_clnt_sigmask(clnt, &oldmask);
867 !(NFS_FLAGS(inode) & flag)); 872 error = wait_on_bit_lock(&nfsi->flags, NFS_INO_REVALIDATING,
873 nfs_wait_schedule, TASK_INTERRUPTIBLE);
874 rpc_clnt_sigunmask(clnt, &oldmask);
868 iput(inode); 875 iput(inode);
876
869 return error; 877 return error;
870} 878}
871 879
880static void nfs_wake_up_inode(struct inode *inode)
881{
882 struct nfs_inode *nfsi = NFS_I(inode);
883
884 clear_bit(NFS_INO_REVALIDATING, &nfsi->flags);
885 smp_mb__after_clear_bit();
886 wake_up_bit(&nfsi->flags, NFS_INO_REVALIDATING);
887}
888
872int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 889int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
873{ 890{
874 struct inode *inode = dentry->d_inode; 891 struct inode *inode = dentry->d_inode;
@@ -1029,18 +1046,19 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
1029 if (NFS_STALE(inode)) 1046 if (NFS_STALE(inode))
1030 goto out_nowait; 1047 goto out_nowait;
1031 1048
1032 while (NFS_REVALIDATING(inode)) { 1049 status = nfs_wait_on_inode(inode);
1033 status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING); 1050 if (status < 0)
1034 if (status < 0) 1051 goto out;
1035 goto out_nowait; 1052 if (NFS_STALE(inode)) {
1036 if (NFS_ATTRTIMEO(inode) == 0) 1053 status = -ESTALE;
1037 continue; 1054 /* Do we trust the cached ESTALE? */
1038 if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) 1055 if (NFS_ATTRTIMEO(inode) != 0) {
1039 continue; 1056 if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) {
1040 status = NFS_STALE(inode) ? -ESTALE : 0; 1057 /* no */
1041 goto out_nowait; 1058 } else
1059 goto out;
1060 }
1042 } 1061 }
1043 NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
1044 1062
1045 /* Protect against RPC races by saving the change attribute */ 1063 /* Protect against RPC races by saving the change attribute */
1046 verifier = nfs_save_change_attribute(inode); 1064 verifier = nfs_save_change_attribute(inode);
@@ -1052,7 +1070,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
1052 if (status == -ESTALE) { 1070 if (status == -ESTALE) {
1053 nfs_zap_caches(inode); 1071 nfs_zap_caches(inode);
1054 if (!S_ISDIR(inode->i_mode)) 1072 if (!S_ISDIR(inode->i_mode))
1055 NFS_FLAGS(inode) |= NFS_INO_STALE; 1073 set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
1056 } 1074 }
1057 goto out; 1075 goto out;
1058 } 1076 }
@@ -1083,9 +1101,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
1083 inode->i_sb->s_id, 1101 inode->i_sb->s_id,
1084 (long long)NFS_FILEID(inode)); 1102 (long long)NFS_FILEID(inode));
1085 1103
1086out: 1104 out:
1087 NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; 1105 nfs_wake_up_inode(inode);
1088 wake_up(&nfsi->nfs_i_wait); 1106
1089 out_nowait: 1107 out_nowait:
1090 unlock_kernel(); 1108 unlock_kernel();
1091 return status; 1109 return status;
@@ -1404,7 +1422,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
1404 */ 1422 */
1405 nfs_invalidate_inode(inode); 1423 nfs_invalidate_inode(inode);
1406 out_err: 1424 out_err:
1407 NFS_FLAGS(inode) |= NFS_INO_STALE; 1425 set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
1408 return -ESTALE; 1426 return -ESTALE;
1409} 1427}
1410 1428
@@ -1996,7 +2014,6 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
1996 nfsi->ndirty = 0; 2014 nfsi->ndirty = 0;
1997 nfsi->ncommit = 0; 2015 nfsi->ncommit = 0;
1998 nfsi->npages = 0; 2016 nfsi->npages = 0;
1999 init_waitqueue_head(&nfsi->nfs_i_wait);
2000 nfs4_init_once(nfsi); 2017 nfs4_init_once(nfsi);
2001 } 2018 }
2002} 2019}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 229a1755842a..deef9567788a 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -112,8 +112,8 @@ struct nfs_inode {
112 /* 112 /*
113 * Various flags 113 * Various flags
114 */ 114 */
115 unsigned int flags; 115 unsigned long flags; /* atomic bit ops */
116 unsigned long cache_validity; 116 unsigned long cache_validity; /* bit mask */
117 117
118 /* 118 /*
119 * read_cache_jiffies is when we started read-caching this inode, 119 * read_cache_jiffies is when we started read-caching this inode,
@@ -175,8 +175,6 @@ struct nfs_inode {
175 /* Open contexts for shared mmap writes */ 175 /* Open contexts for shared mmap writes */
176 struct list_head open_files; 176 struct list_head open_files;
177 177
178 wait_queue_head_t nfs_i_wait;
179
180#ifdef CONFIG_NFS_V4 178#ifdef CONFIG_NFS_V4
181 struct nfs4_cached_acl *nfs4_acl; 179 struct nfs4_cached_acl *nfs4_acl;
182 /* NFSv4 state */ 180 /* NFSv4 state */
@@ -199,11 +197,11 @@ struct nfs_inode {
199#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ 197#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */
200 198
201/* 199/*
202 * Legal values of flags field 200 * Bit offsets in flags field
203 */ 201 */
204#define NFS_INO_REVALIDATING 0x0001 /* revalidating attrs */ 202#define NFS_INO_REVALIDATING (0) /* revalidating attrs */
205#define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */ 203#define NFS_INO_ADVISE_RDPLUS (1) /* advise readdirplus */
206#define NFS_INO_STALE 0x0004 /* possible stale inode */ 204#define NFS_INO_STALE (2) /* possible stale inode */
207 205
208static inline struct nfs_inode *NFS_I(struct inode *inode) 206static inline struct nfs_inode *NFS_I(struct inode *inode)
209{ 207{
@@ -229,8 +227,7 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
229#define NFS_ATTRTIMEO_UPDATE(inode) (NFS_I(inode)->attrtimeo_timestamp) 227#define NFS_ATTRTIMEO_UPDATE(inode) (NFS_I(inode)->attrtimeo_timestamp)
230 228
231#define NFS_FLAGS(inode) (NFS_I(inode)->flags) 229#define NFS_FLAGS(inode) (NFS_I(inode)->flags)
232#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING) 230#define NFS_STALE(inode) (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode)))
233#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE)
234 231
235#define NFS_FILEID(inode) (NFS_I(inode)->fileid) 232#define NFS_FILEID(inode) (NFS_I(inode)->fileid)
236 233
@@ -252,7 +249,7 @@ static inline int nfs_server_capable(struct inode *inode, int cap)
252 249
253static inline int NFS_USE_READDIRPLUS(struct inode *inode) 250static inline int NFS_USE_READDIRPLUS(struct inode *inode)
254{ 251{
255 return NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS; 252 return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
256} 253}
257 254
258/** 255/**