diff options
author | Jeff Layton <jlayton@primarydata.com> | 2014-07-30 08:27:23 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-08-05 10:55:09 -0400 |
commit | 98d5c7c5bd378aa1a22549200f49de3ed79d4d0a (patch) | |
tree | fd03989e734c5554461d1964e7fff3e2cd4e5d11 | |
parent | 82e05efaec9b5b1528771b30c27d060961576827 (diff) |
nfsd: add more granular locking to *_delegations fault injectors
...instead of relying on the client_mutex.
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | fs/nfsd/fault_inject.c | 16 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 175 | ||||
-rw-r--r-- | fs/nfsd/state.h | 11 |
3 files changed, 162 insertions, 40 deletions
diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index d4472cd19807..2479dba71c3c 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c | |||
@@ -152,19 +152,15 @@ static struct nfsd_fault_inject_op inject_ops[] = { | |||
152 | }, | 152 | }, |
153 | { | 153 | { |
154 | .file = "forget_delegations", | 154 | .file = "forget_delegations", |
155 | .get = nfsd_inject_get, | 155 | .get = nfsd_inject_print_delegations, |
156 | .set_val = nfsd_inject_set, | 156 | .set_val = nfsd_inject_forget_delegations, |
157 | .set_clnt = nfsd_inject_set_client, | 157 | .set_clnt = nfsd_inject_forget_client_delegations, |
158 | .forget = nfsd_forget_client_delegations, | ||
159 | .print = nfsd_print_client_delegations, | ||
160 | }, | 158 | }, |
161 | { | 159 | { |
162 | .file = "recall_delegations", | 160 | .file = "recall_delegations", |
163 | .get = nfsd_inject_get, | 161 | .get = nfsd_inject_print_delegations, |
164 | .set_val = nfsd_inject_set, | 162 | .set_val = nfsd_inject_recall_delegations, |
165 | .set_clnt = nfsd_inject_set_client, | 163 | .set_clnt = nfsd_inject_recall_client_delegations, |
166 | .forget = nfsd_recall_client_delegations, | ||
167 | .print = nfsd_print_client_delegations, | ||
168 | }, | 164 | }, |
169 | }; | 165 | }; |
170 | 166 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 20bffa8c976c..d18bbb1e334d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -6102,9 +6102,13 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, | |||
6102 | struct list_head *victims) | 6102 | struct list_head *victims) |
6103 | { | 6103 | { |
6104 | struct nfs4_delegation *dp, *next; | 6104 | struct nfs4_delegation *dp, *next; |
6105 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, | ||
6106 | nfsd_net_id); | ||
6105 | u64 count = 0; | 6107 | u64 count = 0; |
6106 | 6108 | ||
6107 | lockdep_assert_held(&state_lock); | 6109 | lockdep_assert_held(&nn->client_lock); |
6110 | |||
6111 | spin_lock(&state_lock); | ||
6108 | list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { | 6112 | list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { |
6109 | if (victims) { | 6113 | if (victims) { |
6110 | /* | 6114 | /* |
@@ -6116,62 +6120,180 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, | |||
6116 | if (dp->dl_time != 0) | 6120 | if (dp->dl_time != 0) |
6117 | continue; | 6121 | continue; |
6118 | 6122 | ||
6123 | atomic_inc(&clp->cl_refcount); | ||
6119 | unhash_delegation_locked(dp); | 6124 | unhash_delegation_locked(dp); |
6120 | list_add(&dp->dl_recall_lru, victims); | 6125 | list_add(&dp->dl_recall_lru, victims); |
6121 | } | 6126 | } |
6122 | if (++count == max) | 6127 | ++count; |
6128 | /* | ||
6129 | * Despite the fact that these functions deal with | ||
6130 | * 64-bit integers for "count", we must ensure that | ||
6131 | * it doesn't blow up the clp->cl_refcount. Throw a | ||
6132 | * warning if we start to approach INT_MAX here. | ||
6133 | */ | ||
6134 | WARN_ON_ONCE(count == (INT_MAX / 2)); | ||
6135 | if (count == max) | ||
6123 | break; | 6136 | break; |
6124 | } | 6137 | } |
6138 | spin_unlock(&state_lock); | ||
6125 | return count; | 6139 | return count; |
6126 | } | 6140 | } |
6127 | 6141 | ||
6128 | u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) | 6142 | static u64 |
6143 | nfsd_print_client_delegations(struct nfs4_client *clp) | ||
6129 | { | 6144 | { |
6130 | struct nfs4_delegation *dp, *next; | 6145 | u64 count = nfsd_find_all_delegations(clp, 0, NULL); |
6131 | LIST_HEAD(victims); | ||
6132 | u64 count; | ||
6133 | 6146 | ||
6134 | spin_lock(&state_lock); | 6147 | nfsd_print_count(clp, count, "delegations"); |
6135 | count = nfsd_find_all_delegations(clp, max, &victims); | 6148 | return count; |
6136 | spin_unlock(&state_lock); | 6149 | } |
6150 | |||
6151 | u64 | ||
6152 | nfsd_inject_print_delegations(struct nfsd_fault_inject_op *op) | ||
6153 | { | ||
6154 | struct nfs4_client *clp; | ||
6155 | u64 count = 0; | ||
6156 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, | ||
6157 | nfsd_net_id); | ||
6158 | |||
6159 | if (!nfsd_netns_ready(nn)) | ||
6160 | return 0; | ||
6137 | 6161 | ||
6138 | list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) { | 6162 | spin_lock(&nn->client_lock); |
6163 | list_for_each_entry(clp, &nn->client_lru, cl_lru) | ||
6164 | count += nfsd_print_client_delegations(clp); | ||
6165 | spin_unlock(&nn->client_lock); | ||
6166 | |||
6167 | return count; | ||
6168 | } | ||
6169 | |||
6170 | static void | ||
6171 | nfsd_forget_delegations(struct list_head *reaplist) | ||
6172 | { | ||
6173 | struct nfs4_client *clp; | ||
6174 | struct nfs4_delegation *dp, *next; | ||
6175 | |||
6176 | list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { | ||
6139 | list_del_init(&dp->dl_recall_lru); | 6177 | list_del_init(&dp->dl_recall_lru); |
6178 | clp = dp->dl_stid.sc_client; | ||
6140 | revoke_delegation(dp); | 6179 | revoke_delegation(dp); |
6180 | put_client(clp); | ||
6141 | } | 6181 | } |
6182 | } | ||
6183 | |||
6184 | u64 | ||
6185 | nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *op, | ||
6186 | struct sockaddr_storage *addr, size_t addr_size) | ||
6187 | { | ||
6188 | u64 count = 0; | ||
6189 | struct nfs4_client *clp; | ||
6190 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, | ||
6191 | nfsd_net_id); | ||
6192 | LIST_HEAD(reaplist); | ||
6193 | |||
6194 | if (!nfsd_netns_ready(nn)) | ||
6195 | return count; | ||
6196 | |||
6197 | spin_lock(&nn->client_lock); | ||
6198 | clp = nfsd_find_client(addr, addr_size); | ||
6199 | if (clp) | ||
6200 | count = nfsd_find_all_delegations(clp, 0, &reaplist); | ||
6201 | spin_unlock(&nn->client_lock); | ||
6202 | |||
6203 | nfsd_forget_delegations(&reaplist); | ||
6204 | return count; | ||
6205 | } | ||
6142 | 6206 | ||
6207 | u64 | ||
6208 | nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *op, u64 max) | ||
6209 | { | ||
6210 | u64 count = 0; | ||
6211 | struct nfs4_client *clp; | ||
6212 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, | ||
6213 | nfsd_net_id); | ||
6214 | LIST_HEAD(reaplist); | ||
6215 | |||
6216 | if (!nfsd_netns_ready(nn)) | ||
6217 | return count; | ||
6218 | |||
6219 | spin_lock(&nn->client_lock); | ||
6220 | list_for_each_entry(clp, &nn->client_lru, cl_lru) { | ||
6221 | count += nfsd_find_all_delegations(clp, max - count, &reaplist); | ||
6222 | if (max != 0 && count >= max) | ||
6223 | break; | ||
6224 | } | ||
6225 | spin_unlock(&nn->client_lock); | ||
6226 | nfsd_forget_delegations(&reaplist); | ||
6143 | return count; | 6227 | return count; |
6144 | } | 6228 | } |
6145 | 6229 | ||
6146 | u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) | 6230 | static void |
6231 | nfsd_recall_delegations(struct list_head *reaplist) | ||
6147 | { | 6232 | { |
6148 | struct nfs4_delegation *dp; | 6233 | struct nfs4_client *clp; |
6149 | LIST_HEAD(victims); | 6234 | struct nfs4_delegation *dp, *next; |
6150 | u64 count; | ||
6151 | 6235 | ||
6152 | spin_lock(&state_lock); | 6236 | list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { |
6153 | count = nfsd_find_all_delegations(clp, max, &victims); | ||
6154 | while (!list_empty(&victims)) { | ||
6155 | dp = list_first_entry(&victims, struct nfs4_delegation, | ||
6156 | dl_recall_lru); | ||
6157 | list_del_init(&dp->dl_recall_lru); | 6237 | list_del_init(&dp->dl_recall_lru); |
6238 | clp = dp->dl_stid.sc_client; | ||
6239 | /* | ||
6240 | * We skipped all entries that had a zero dl_time before, | ||
6241 | * so we can now reset the dl_time back to 0. If a delegation | ||
6242 | * break comes in now, then it won't make any difference since | ||
6243 | * we're recalling it either way. | ||
6244 | */ | ||
6245 | spin_lock(&state_lock); | ||
6158 | dp->dl_time = 0; | 6246 | dp->dl_time = 0; |
6247 | spin_unlock(&state_lock); | ||
6159 | nfsd_break_one_deleg(dp); | 6248 | nfsd_break_one_deleg(dp); |
6249 | put_client(clp); | ||
6160 | } | 6250 | } |
6161 | spin_unlock(&state_lock); | 6251 | } |
6162 | 6252 | ||
6253 | u64 | ||
6254 | nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *op, | ||
6255 | struct sockaddr_storage *addr, | ||
6256 | size_t addr_size) | ||
6257 | { | ||
6258 | u64 count = 0; | ||
6259 | struct nfs4_client *clp; | ||
6260 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, | ||
6261 | nfsd_net_id); | ||
6262 | LIST_HEAD(reaplist); | ||
6263 | |||
6264 | if (!nfsd_netns_ready(nn)) | ||
6265 | return count; | ||
6266 | |||
6267 | spin_lock(&nn->client_lock); | ||
6268 | clp = nfsd_find_client(addr, addr_size); | ||
6269 | if (clp) | ||
6270 | count = nfsd_find_all_delegations(clp, 0, &reaplist); | ||
6271 | spin_unlock(&nn->client_lock); | ||
6272 | |||
6273 | nfsd_recall_delegations(&reaplist); | ||
6163 | return count; | 6274 | return count; |
6164 | } | 6275 | } |
6165 | 6276 | ||
6166 | u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) | 6277 | u64 |
6278 | nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *op, u64 max) | ||
6167 | { | 6279 | { |
6168 | u64 count = 0; | 6280 | u64 count = 0; |
6281 | struct nfs4_client *clp, *next; | ||
6282 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, | ||
6283 | nfsd_net_id); | ||
6284 | LIST_HEAD(reaplist); | ||
6169 | 6285 | ||
6170 | spin_lock(&state_lock); | 6286 | if (!nfsd_netns_ready(nn)) |
6171 | count = nfsd_find_all_delegations(clp, max, NULL); | 6287 | return count; |
6172 | spin_unlock(&state_lock); | ||
6173 | 6288 | ||
6174 | nfsd_print_count(clp, count, "delegations"); | 6289 | spin_lock(&nn->client_lock); |
6290 | list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { | ||
6291 | count += nfsd_find_all_delegations(clp, max - count, &reaplist); | ||
6292 | if (max != 0 && ++count >= max) | ||
6293 | break; | ||
6294 | } | ||
6295 | spin_unlock(&nn->client_lock); | ||
6296 | nfsd_recall_delegations(&reaplist); | ||
6175 | return count; | 6297 | return count; |
6176 | } | 6298 | } |
6177 | 6299 | ||
@@ -6179,7 +6301,8 @@ u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) | |||
6179 | { | 6301 | { |
6180 | struct nfs4_client *clp, *next; | 6302 | struct nfs4_client *clp, *next; |
6181 | u64 count = 0; | 6303 | u64 count = 0; |
6182 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); | 6304 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, |
6305 | nfsd_net_id); | ||
6183 | 6306 | ||
6184 | if (!nfsd_netns_ready(nn)) | 6307 | if (!nfsd_netns_ready(nn)) |
6185 | return 0; | 6308 | return 0; |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index faaf6af7b28d..0a35e7bea5f7 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -493,10 +493,13 @@ u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *, | |||
493 | struct sockaddr_storage *, size_t); | 493 | struct sockaddr_storage *, size_t); |
494 | u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64); | 494 | u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64); |
495 | 495 | ||
496 | u64 nfsd_forget_client_delegations(struct nfs4_client *, u64); | 496 | u64 nfsd_inject_print_delegations(struct nfsd_fault_inject_op *); |
497 | u64 nfsd_recall_client_delegations(struct nfs4_client *, u64); | 497 | u64 nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *, |
498 | 498 | struct sockaddr_storage *, size_t); | |
499 | u64 nfsd_print_client_delegations(struct nfs4_client *, u64); | 499 | u64 nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *, u64); |
500 | u64 nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *, | ||
501 | struct sockaddr_storage *, size_t); | ||
502 | u64 nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *, u64); | ||
500 | #else /* CONFIG_NFSD_FAULT_INJECTION */ | 503 | #else /* CONFIG_NFSD_FAULT_INJECTION */ |
501 | static inline int nfsd_fault_inject_init(void) { return 0; } | 504 | static inline int nfsd_fault_inject_init(void) { return 0; } |
502 | static inline void nfsd_fault_inject_cleanup(void) {} | 505 | static inline void nfsd_fault_inject_cleanup(void) {} |