diff options
| author | J. Bruce Fields <bfields@citi.umich.edu> | 2009-02-22 17:51:34 -0500 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-03-18 17:38:38 -0400 |
| commit | 8b671b80707e4fc76adfe4387df07b3be1007c1e (patch) | |
| tree | d9dafb3a1174dfeb84f72ba56a04625204aab415 | |
| parent | d7fdcfe0aaaf6dffca6fa857bab374182fe7ca8b (diff) | |
nfsd4: remove use of mutex for file_hashtable
As part of reducing the scope of the client_mutex, and in order to
remove the need for mutexes from the callback code (so that callbacks
can be done as asynchronous rpc calls), move manipulations of the
file_hashtable under the recall_lock.
Update the relevant comments while we're here.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Cc: Alexandros Batsakis <batsakis@netapp.com>
Reviewed-by: Benny Halevy <bhalevy@panasas.com>
| -rw-r--r-- | fs/nfsd/nfs4callback.c | 2 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 47 | ||||
| -rw-r--r-- | include/linux/nfsd/state.h | 2 |
3 files changed, 24 insertions, 27 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 3fd7136321ca..5dcd38e5f138 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
| @@ -491,8 +491,6 @@ out_put_cred: | |||
| 491 | * or deleg_return. | 491 | * or deleg_return. |
| 492 | */ | 492 | */ |
| 493 | put_nfs4_client(clp); | 493 | put_nfs4_client(clp); |
| 494 | nfs4_lock_state(); | ||
| 495 | nfs4_put_delegation(dp); | 494 | nfs4_put_delegation(dp); |
| 496 | nfs4_unlock_state(); | ||
| 497 | return; | 495 | return; |
| 498 | } | 496 | } |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 89e575e7daea..54651aa45790 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -78,14 +78,18 @@ static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, state | |||
| 78 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | 78 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
| 79 | static void nfs4_set_recdir(char *recdir); | 79 | static void nfs4_set_recdir(char *recdir); |
| 80 | 80 | ||
| 81 | /* Locking: | 81 | /* Locking: */ |
| 82 | * | 82 | |
| 83 | * client_mutex: | 83 | /* Currently used for almost all code touching nfsv4 state: */ |
| 84 | * protects clientid_hashtbl[], clientstr_hashtbl[], | ||
| 85 | * unconfstr_hashtbl[], uncofid_hashtbl[]. | ||
| 86 | */ | ||
| 87 | static DEFINE_MUTEX(client_mutex); | 84 | static DEFINE_MUTEX(client_mutex); |
| 88 | 85 | ||
| 86 | /* | ||
| 87 | * Currently used for the del_recall_lru and file hash table. In an | ||
| 88 | * effort to decrease the scope of the client_mutex, this spinlock may | ||
| 89 | * eventually cover more: | ||
| 90 | */ | ||
| 91 | static DEFINE_SPINLOCK(recall_lock); | ||
| 92 | |||
| 89 | static struct kmem_cache *stateowner_slab = NULL; | 93 | static struct kmem_cache *stateowner_slab = NULL; |
| 90 | static struct kmem_cache *file_slab = NULL; | 94 | static struct kmem_cache *file_slab = NULL; |
| 91 | static struct kmem_cache *stateid_slab = NULL; | 95 | static struct kmem_cache *stateid_slab = NULL; |
| @@ -116,33 +120,23 @@ opaque_hashval(const void *ptr, int nbytes) | |||
| 116 | return x; | 120 | return x; |
| 117 | } | 121 | } |
| 118 | 122 | ||
| 119 | /* | ||
| 120 | * Delegation state | ||
| 121 | */ | ||
| 122 | |||
| 123 | /* recall_lock protects the del_recall_lru */ | ||
| 124 | static DEFINE_SPINLOCK(recall_lock); | ||
| 125 | static struct list_head del_recall_lru; | 123 | static struct list_head del_recall_lru; |
| 126 | 124 | ||
| 127 | static void | ||
| 128 | free_nfs4_file(struct kref *kref) | ||
| 129 | { | ||
| 130 | struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref); | ||
| 131 | list_del(&fp->fi_hash); | ||
| 132 | iput(fp->fi_inode); | ||
| 133 | kmem_cache_free(file_slab, fp); | ||
| 134 | } | ||
| 135 | |||
| 136 | static inline void | 125 | static inline void |
| 137 | put_nfs4_file(struct nfs4_file *fi) | 126 | put_nfs4_file(struct nfs4_file *fi) |
| 138 | { | 127 | { |
| 139 | kref_put(&fi->fi_ref, free_nfs4_file); | 128 | if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) { |
| 129 | list_del(&fi->fi_hash); | ||
| 130 | spin_unlock(&recall_lock); | ||
| 131 | iput(fi->fi_inode); | ||
| 132 | kmem_cache_free(file_slab, fi); | ||
| 133 | } | ||
| 140 | } | 134 | } |
| 141 | 135 | ||
| 142 | static inline void | 136 | static inline void |
| 143 | get_nfs4_file(struct nfs4_file *fi) | 137 | get_nfs4_file(struct nfs4_file *fi) |
| 144 | { | 138 | { |
| 145 | kref_get(&fi->fi_ref); | 139 | atomic_inc(&fi->fi_ref); |
| 146 | } | 140 | } |
| 147 | 141 | ||
| 148 | static int num_delegations; | 142 | static int num_delegations; |
| @@ -1000,11 +994,13 @@ alloc_init_file(struct inode *ino) | |||
| 1000 | 994 | ||
| 1001 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); | 995 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); |
| 1002 | if (fp) { | 996 | if (fp) { |
| 1003 | kref_init(&fp->fi_ref); | 997 | atomic_set(&fp->fi_ref, 1); |
| 1004 | INIT_LIST_HEAD(&fp->fi_hash); | 998 | INIT_LIST_HEAD(&fp->fi_hash); |
| 1005 | INIT_LIST_HEAD(&fp->fi_stateids); | 999 | INIT_LIST_HEAD(&fp->fi_stateids); |
| 1006 | INIT_LIST_HEAD(&fp->fi_delegations); | 1000 | INIT_LIST_HEAD(&fp->fi_delegations); |
| 1001 | spin_lock(&recall_lock); | ||
| 1007 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 1002 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
| 1003 | spin_unlock(&recall_lock); | ||
| 1008 | fp->fi_inode = igrab(ino); | 1004 | fp->fi_inode = igrab(ino); |
| 1009 | fp->fi_id = current_fileid++; | 1005 | fp->fi_id = current_fileid++; |
| 1010 | fp->fi_had_conflict = false; | 1006 | fp->fi_had_conflict = false; |
| @@ -1177,12 +1173,15 @@ find_file(struct inode *ino) | |||
| 1177 | unsigned int hashval = file_hashval(ino); | 1173 | unsigned int hashval = file_hashval(ino); |
| 1178 | struct nfs4_file *fp; | 1174 | struct nfs4_file *fp; |
| 1179 | 1175 | ||
| 1176 | spin_lock(&recall_lock); | ||
| 1180 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { | 1177 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { |
| 1181 | if (fp->fi_inode == ino) { | 1178 | if (fp->fi_inode == ino) { |
| 1182 | get_nfs4_file(fp); | 1179 | get_nfs4_file(fp); |
| 1180 | spin_unlock(&recall_lock); | ||
| 1183 | return fp; | 1181 | return fp; |
| 1184 | } | 1182 | } |
| 1185 | } | 1183 | } |
| 1184 | spin_unlock(&recall_lock); | ||
| 1186 | return NULL; | 1185 | return NULL; |
| 1187 | } | 1186 | } |
| 1188 | 1187 | ||
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 503b6bb53a56..a6e4a00fa392 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
| @@ -214,7 +214,7 @@ struct nfs4_stateowner { | |||
| 214 | * share_acces, share_deny on the file. | 214 | * share_acces, share_deny on the file. |
| 215 | */ | 215 | */ |
| 216 | struct nfs4_file { | 216 | struct nfs4_file { |
| 217 | struct kref fi_ref; | 217 | atomic_t fi_ref; |
| 218 | struct list_head fi_hash; /* hash by "struct inode *" */ | 218 | struct list_head fi_hash; /* hash by "struct inode *" */ |
| 219 | struct list_head fi_stateids; | 219 | struct list_head fi_stateids; |
| 220 | struct list_head fi_delegations; | 220 | struct list_head fi_delegations; |
