diff options
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/svclock.c | 119 | ||||
-rw-r--r-- | fs/lockd/svcsubs.c | 5 |
2 files changed, 59 insertions, 65 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 3127ae9e435c..7209712f3832 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -40,7 +40,7 @@ | |||
40 | 40 | ||
41 | static void nlmsvc_release_block(struct nlm_block *block); | 41 | static void nlmsvc_release_block(struct nlm_block *block); |
42 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); | 42 | static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); |
43 | static int nlmsvc_remove_block(struct nlm_block *block); | 43 | static void nlmsvc_remove_block(struct nlm_block *block); |
44 | 44 | ||
45 | static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); | 45 | static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); |
46 | static void nlmsvc_freegrantargs(struct nlm_rqst *call); | 46 | static void nlmsvc_freegrantargs(struct nlm_rqst *call); |
@@ -49,7 +49,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops; | |||
49 | /* | 49 | /* |
50 | * The list of blocked locks to retry | 50 | * The list of blocked locks to retry |
51 | */ | 51 | */ |
52 | static struct nlm_block * nlm_blocked; | 52 | static LIST_HEAD(nlm_blocked); |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Insert a blocked lock into the global list | 55 | * Insert a blocked lock into the global list |
@@ -57,48 +57,44 @@ static struct nlm_block * nlm_blocked; | |||
57 | static void | 57 | static void |
58 | nlmsvc_insert_block(struct nlm_block *block, unsigned long when) | 58 | nlmsvc_insert_block(struct nlm_block *block, unsigned long when) |
59 | { | 59 | { |
60 | struct nlm_block **bp, *b; | 60 | struct nlm_block *b; |
61 | struct list_head *pos; | ||
61 | 62 | ||
62 | dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); | 63 | dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when); |
63 | kref_get(&block->b_count); | 64 | if (list_empty(&block->b_list)) { |
64 | if (block->b_queued) | 65 | kref_get(&block->b_count); |
65 | nlmsvc_remove_block(block); | 66 | } else { |
66 | bp = &nlm_blocked; | 67 | list_del_init(&block->b_list); |
68 | } | ||
69 | |||
70 | pos = &nlm_blocked; | ||
67 | if (when != NLM_NEVER) { | 71 | if (when != NLM_NEVER) { |
68 | if ((when += jiffies) == NLM_NEVER) | 72 | if ((when += jiffies) == NLM_NEVER) |
69 | when ++; | 73 | when ++; |
70 | while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER) | 74 | list_for_each(pos, &nlm_blocked) { |
71 | bp = &b->b_next; | 75 | b = list_entry(pos, struct nlm_block, b_list); |
72 | } else | 76 | if (time_after(b->b_when,when) || b->b_when == NLM_NEVER) |
73 | while ((b = *bp) != 0) | 77 | break; |
74 | bp = &b->b_next; | 78 | } |
79 | /* On normal exit from the loop, pos == &nlm_blocked, | ||
80 | * so we will be adding to the end of the list - good | ||
81 | */ | ||
82 | } | ||
75 | 83 | ||
76 | block->b_queued = 1; | 84 | list_add_tail(&block->b_list, pos); |
77 | block->b_when = when; | 85 | block->b_when = when; |
78 | block->b_next = b; | ||
79 | *bp = block; | ||
80 | } | 86 | } |
81 | 87 | ||
82 | /* | 88 | /* |
83 | * Remove a block from the global list | 89 | * Remove a block from the global list |
84 | */ | 90 | */ |
85 | static int | 91 | static inline void |
86 | nlmsvc_remove_block(struct nlm_block *block) | 92 | nlmsvc_remove_block(struct nlm_block *block) |
87 | { | 93 | { |
88 | struct nlm_block **bp, *b; | 94 | if (!list_empty(&block->b_list)) { |
89 | 95 | list_del_init(&block->b_list); | |
90 | if (!block->b_queued) | 96 | nlmsvc_release_block(block); |
91 | return 1; | ||
92 | for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) { | ||
93 | if (b == block) { | ||
94 | *bp = block->b_next; | ||
95 | block->b_queued = 0; | ||
96 | nlmsvc_release_block(block); | ||
97 | return 1; | ||
98 | } | ||
99 | } | 97 | } |
100 | |||
101 | return 0; | ||
102 | } | 98 | } |
103 | 99 | ||
104 | /* | 100 | /* |
@@ -107,14 +103,14 @@ nlmsvc_remove_block(struct nlm_block *block) | |||
107 | static struct nlm_block * | 103 | static struct nlm_block * |
108 | nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) | 104 | nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) |
109 | { | 105 | { |
110 | struct nlm_block **head, *block; | 106 | struct nlm_block *block; |
111 | struct file_lock *fl; | 107 | struct file_lock *fl; |
112 | 108 | ||
113 | dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n", | 109 | dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n", |
114 | file, lock->fl.fl_pid, | 110 | file, lock->fl.fl_pid, |
115 | (long long)lock->fl.fl_start, | 111 | (long long)lock->fl.fl_start, |
116 | (long long)lock->fl.fl_end, lock->fl.fl_type); | 112 | (long long)lock->fl.fl_end, lock->fl.fl_type); |
117 | for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) { | 113 | list_for_each_entry(block, &nlm_blocked, b_list) { |
118 | fl = &block->b_call->a_args.lock.fl; | 114 | fl = &block->b_call->a_args.lock.fl; |
119 | dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", | 115 | dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", |
120 | block->b_file, fl->fl_pid, | 116 | block->b_file, fl->fl_pid, |
@@ -147,16 +143,16 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) | |||
147 | { | 143 | { |
148 | struct nlm_block *block; | 144 | struct nlm_block *block; |
149 | 145 | ||
150 | for (block = nlm_blocked; block; block = block->b_next) { | 146 | list_for_each_entry(block, &nlm_blocked, b_list) { |
151 | dprintk("cookie: head of blocked queue %p, block %p\n", | ||
152 | nlm_blocked, block); | ||
153 | if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie) | 147 | if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie) |
154 | && nlm_cmp_addr(sin, &block->b_host->h_addr)) | 148 | && nlm_cmp_addr(sin, &block->b_host->h_addr)) |
155 | break; | 149 | goto found; |
156 | } | 150 | } |
157 | 151 | ||
158 | if (block != NULL) | 152 | return NULL; |
159 | kref_get(&block->b_count); | 153 | |
154 | found: | ||
155 | kref_get(&block->b_count); | ||
160 | return block; | 156 | return block; |
161 | } | 157 | } |
162 | 158 | ||
@@ -192,6 +188,8 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | |||
192 | if (block == NULL) | 188 | if (block == NULL) |
193 | goto failed; | 189 | goto failed; |
194 | kref_init(&block->b_count); | 190 | kref_init(&block->b_count); |
191 | INIT_LIST_HEAD(&block->b_list); | ||
192 | INIT_LIST_HEAD(&block->b_flist); | ||
195 | 193 | ||
196 | if (!nlmsvc_setgrantargs(call, lock)) | 194 | if (!nlmsvc_setgrantargs(call, lock)) |
197 | goto failed_free; | 195 | goto failed_free; |
@@ -210,8 +208,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file, | |||
210 | file->f_count++; | 208 | file->f_count++; |
211 | 209 | ||
212 | /* Add to file's list of blocks */ | 210 | /* Add to file's list of blocks */ |
213 | block->b_fnext = file->f_blocks; | 211 | list_add(&block->b_flist, &file->f_blocks); |
214 | file->f_blocks = block; | ||
215 | 212 | ||
216 | /* Set up RPC arguments for callback */ | 213 | /* Set up RPC arguments for callback */ |
217 | block->b_call = call; | 214 | block->b_call = call; |
@@ -248,18 +245,12 @@ static void nlmsvc_free_block(struct kref *kref) | |||
248 | { | 245 | { |
249 | struct nlm_block *block = container_of(kref, struct nlm_block, b_count); | 246 | struct nlm_block *block = container_of(kref, struct nlm_block, b_count); |
250 | struct nlm_file *file = block->b_file; | 247 | struct nlm_file *file = block->b_file; |
251 | struct nlm_block **bp; | ||
252 | 248 | ||
253 | dprintk("lockd: freeing block %p...\n", block); | 249 | dprintk("lockd: freeing block %p...\n", block); |
254 | 250 | ||
255 | down(&file->f_sema); | ||
256 | /* Remove block from file's list of blocks */ | 251 | /* Remove block from file's list of blocks */ |
257 | for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) { | 252 | down(&file->f_sema); |
258 | if (*bp == block) { | 253 | list_del_init(&block->b_flist); |
259 | *bp = block->b_fnext; | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | up(&file->f_sema); | 254 | up(&file->f_sema); |
264 | 255 | ||
265 | nlmsvc_freegrantargs(block->b_call); | 256 | nlmsvc_freegrantargs(block->b_call); |
@@ -279,21 +270,23 @@ static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file) | |||
279 | struct nlm_block *block; | 270 | struct nlm_block *block; |
280 | 271 | ||
281 | down(&file->f_sema); | 272 | down(&file->f_sema); |
282 | for (block = file->f_blocks; block != NULL; block = block->b_fnext) | 273 | list_for_each_entry(block, &file->f_blocks, b_flist) |
283 | block->b_host->h_inuse = 1; | 274 | block->b_host->h_inuse = 1; |
284 | up(&file->f_sema); | 275 | up(&file->f_sema); |
285 | } | 276 | } |
286 | 277 | ||
287 | static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file) | 278 | static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file) |
288 | { | 279 | { |
289 | struct nlm_block *block; | 280 | struct nlm_block *block, *next; |
290 | 281 | ||
291 | restart: | 282 | restart: |
292 | down(&file->f_sema); | 283 | down(&file->f_sema); |
293 | for (block = file->f_blocks; block != NULL; block = block->b_fnext) { | 284 | list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) { |
294 | if (host != NULL && host != block->b_host) | 285 | if (host != NULL && host != block->b_host) |
295 | continue; | 286 | continue; |
296 | if (!block->b_queued) | 287 | /* Do not destroy blocks that are not on |
288 | * the global retry list - why? */ | ||
289 | if (list_empty(&block->b_list)) | ||
297 | continue; | 290 | continue; |
298 | kref_get(&block->b_count); | 291 | kref_get(&block->b_count); |
299 | up(&file->f_sema); | 292 | up(&file->f_sema); |
@@ -528,10 +521,10 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) | |||
528 | static void | 521 | static void |
529 | nlmsvc_notify_blocked(struct file_lock *fl) | 522 | nlmsvc_notify_blocked(struct file_lock *fl) |
530 | { | 523 | { |
531 | struct nlm_block **bp, *block; | 524 | struct nlm_block *block; |
532 | 525 | ||
533 | dprintk("lockd: VFS unblock notification for block %p\n", fl); | 526 | dprintk("lockd: VFS unblock notification for block %p\n", fl); |
534 | for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) { | 527 | list_for_each_entry(block, &nlm_blocked, b_list) { |
535 | if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { | 528 | if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) { |
536 | nlmsvc_insert_block(block, 0); | 529 | nlmsvc_insert_block(block, 0); |
537 | svc_wake_up(block->b_daemon); | 530 | svc_wake_up(block->b_daemon); |
@@ -697,16 +690,19 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status | |||
697 | unsigned long | 690 | unsigned long |
698 | nlmsvc_retry_blocked(void) | 691 | nlmsvc_retry_blocked(void) |
699 | { | 692 | { |
700 | struct nlm_block *block; | 693 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; |
694 | struct nlm_block *block; | ||
695 | |||
696 | while (!list_empty(&nlm_blocked)) { | ||
697 | block = list_entry(nlm_blocked.next, struct nlm_block, b_list); | ||
701 | 698 | ||
702 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", | ||
703 | nlm_blocked, | ||
704 | nlm_blocked? nlm_blocked->b_when : 0); | ||
705 | while ((block = nlm_blocked) != 0) { | ||
706 | if (block->b_when == NLM_NEVER) | 699 | if (block->b_when == NLM_NEVER) |
707 | break; | 700 | break; |
708 | if (time_after(block->b_when,jiffies)) | 701 | if (time_after(block->b_when,jiffies)) { |
702 | timeout = block->b_when - jiffies; | ||
709 | break; | 703 | break; |
704 | } | ||
705 | |||
710 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", | 706 | dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", |
711 | block, block->b_when); | 707 | block, block->b_when); |
712 | kref_get(&block->b_count); | 708 | kref_get(&block->b_count); |
@@ -714,8 +710,5 @@ nlmsvc_retry_blocked(void) | |||
714 | nlmsvc_release_block(block); | 710 | nlmsvc_release_block(block); |
715 | } | 711 | } |
716 | 712 | ||
717 | if ((block = nlm_blocked) && block->b_when != NLM_NEVER) | 713 | return timeout; |
718 | return (block->b_when - jiffies); | ||
719 | |||
720 | return MAX_SCHEDULE_TIMEOUT; | ||
721 | } | 714 | } |
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index c8308bccd319..a92fc5813144 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -107,6 +107,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, | |||
107 | memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); | 107 | memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); |
108 | file->f_hash = hash; | 108 | file->f_hash = hash; |
109 | init_MUTEX(&file->f_sema); | 109 | init_MUTEX(&file->f_sema); |
110 | INIT_LIST_HEAD(&file->f_blocks); | ||
110 | 111 | ||
111 | /* Open the file. Note that this must not sleep for too long, else | 112 | /* Open the file. Note that this must not sleep for too long, else |
112 | * we would lock up lockd:-) So no NFS re-exports, folks. | 113 | * we would lock up lockd:-) So no NFS re-exports, folks. |
@@ -220,7 +221,7 @@ nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action) | |||
220 | { | 221 | { |
221 | if (action == NLM_ACT_CHECK) { | 222 | if (action == NLM_ACT_CHECK) { |
222 | /* Fast path for mark and sweep garbage collection */ | 223 | /* Fast path for mark and sweep garbage collection */ |
223 | if (file->f_count || file->f_blocks || file->f_shares) | 224 | if (file->f_count || list_empty(&file->f_blocks) || file->f_shares) |
224 | return 1; | 225 | return 1; |
225 | } else { | 226 | } else { |
226 | nlmsvc_traverse_blocks(host, file, action); | 227 | nlmsvc_traverse_blocks(host, file, action); |
@@ -253,7 +254,7 @@ nlm_traverse_files(struct nlm_host *host, int action) | |||
253 | mutex_lock(&nlm_file_mutex); | 254 | mutex_lock(&nlm_file_mutex); |
254 | file->f_count--; | 255 | file->f_count--; |
255 | /* No more references to this file. Let go of it. */ | 256 | /* No more references to this file. Let go of it. */ |
256 | if (!file->f_blocks && !file->f_locks | 257 | if (list_empty(&file->f_blocks) && !file->f_locks |
257 | && !file->f_shares && !file->f_count) { | 258 | && !file->f_shares && !file->f_count) { |
258 | *fp = file->f_next; | 259 | *fp = file->f_next; |
259 | nlmsvc_ops->fclose(file->f_file); | 260 | nlmsvc_ops->fclose(file->f_file); |