diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-08-10 11:58:57 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-08-24 15:51:00 -0400 |
commit | 01df9c5e918ae5559f2d96da0143f8bfbb9e6171 (patch) | |
tree | 1716c3caf8c5d6c10aa139bdbb75d93af30fc0b2 /fs/lockd/svcsubs.c | |
parent | 8f8e7a50f450fcb86a5b2ffb94543c57a14f8260 (diff) |
LOCKD: Fix a deadlock in nlm_traverse_files()
nlm_traverse_files() is not allowed to hold the nlm_file_mutex while calling
nlm_inspect file, since it may end up calling nlm_release_file() when
releaseing the blocks.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
(cherry picked from e558d3cde986e04f68afe8c790ad68ef4b94587a commit)
Diffstat (limited to 'fs/lockd/svcsubs.c')
-rw-r--r-- | fs/lockd/svcsubs.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 2a4df9b3779a..01b4db9e5466 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -237,19 +237,22 @@ static int | |||
237 | nlm_traverse_files(struct nlm_host *host, int action) | 237 | nlm_traverse_files(struct nlm_host *host, int action) |
238 | { | 238 | { |
239 | struct nlm_file *file, **fp; | 239 | struct nlm_file *file, **fp; |
240 | int i; | 240 | int i, ret = 0; |
241 | 241 | ||
242 | mutex_lock(&nlm_file_mutex); | 242 | mutex_lock(&nlm_file_mutex); |
243 | for (i = 0; i < FILE_NRHASH; i++) { | 243 | for (i = 0; i < FILE_NRHASH; i++) { |
244 | fp = nlm_files + i; | 244 | fp = nlm_files + i; |
245 | while ((file = *fp) != NULL) { | 245 | while ((file = *fp) != NULL) { |
246 | file->f_count++; | ||
247 | mutex_unlock(&nlm_file_mutex); | ||
248 | |||
246 | /* Traverse locks, blocks and shares of this file | 249 | /* Traverse locks, blocks and shares of this file |
247 | * and update file->f_locks count */ | 250 | * and update file->f_locks count */ |
248 | if (nlm_inspect_file(host, file, action)) { | 251 | if (nlm_inspect_file(host, file, action)) |
249 | mutex_unlock(&nlm_file_mutex); | 252 | ret = 1; |
250 | return 1; | ||
251 | } | ||
252 | 253 | ||
254 | mutex_lock(&nlm_file_mutex); | ||
255 | file->f_count--; | ||
253 | /* No more references to this file. Let go of it. */ | 256 | /* No more references to this file. Let go of it. */ |
254 | if (!file->f_blocks && !file->f_locks | 257 | if (!file->f_blocks && !file->f_locks |
255 | && !file->f_shares && !file->f_count) { | 258 | && !file->f_shares && !file->f_count) { |
@@ -262,7 +265,7 @@ nlm_traverse_files(struct nlm_host *host, int action) | |||
262 | } | 265 | } |
263 | } | 266 | } |
264 | mutex_unlock(&nlm_file_mutex); | 267 | mutex_unlock(&nlm_file_mutex); |
265 | return 0; | 268 | return ret; |
266 | } | 269 | } |
267 | 270 | ||
268 | /* | 271 | /* |