aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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 /fs
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/dir.c4
-rw-r--r--fs/nfs/inode.c69
2 files changed, 45 insertions, 28 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}