aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd')
-rw-r--r--fs/lockd/svclock.c33
-rw-r--r--fs/lockd/svcshare.c20
-rw-r--r--fs/lockd/svcsubs.c105
3 files changed, 93 insertions, 65 deletions
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 7209712f3832..1f91567a1b88 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -265,24 +265,20 @@ static void nlmsvc_release_block(struct nlm_block *block)
265 kref_put(&block->b_count, nlmsvc_free_block); 265 kref_put(&block->b_count, nlmsvc_free_block);
266} 266}
267 267
268static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file) 268/*
269{ 269 * Loop over all blocks and delete blocks held by
270 struct nlm_block *block; 270 * a matching host.
271 271 */
272 down(&file->f_sema); 272void nlmsvc_traverse_blocks(struct nlm_host *host,
273 list_for_each_entry(block, &file->f_blocks, b_flist) 273 struct nlm_file *file,
274 block->b_host->h_inuse = 1; 274 nlm_host_match_fn_t match)
275 up(&file->f_sema);
276}
277
278static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
279{ 275{
280 struct nlm_block *block, *next; 276 struct nlm_block *block, *next;
281 277
282restart: 278restart:
283 down(&file->f_sema); 279 down(&file->f_sema);
284 list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) { 280 list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
285 if (host != NULL && host != block->b_host) 281 if (!match(block->b_host, host))
286 continue; 282 continue;
287 /* Do not destroy blocks that are not on 283 /* Do not destroy blocks that are not on
288 * the global retry list - why? */ 284 * the global retry list - why? */
@@ -298,19 +294,6 @@ restart:
298} 294}
299 295
300/* 296/*
301 * Loop over all blocks and perform the action specified.
302 * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
303 */
304void
305nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
306{
307 if (action == NLM_ACT_MARK)
308 nlmsvc_act_mark(host, file);
309 else
310 nlmsvc_act_unlock(host, file);
311}
312
313/*
314 * Initialize arguments for GRANTED call. The nlm_rqst structure 297 * Initialize arguments for GRANTED call. The nlm_rqst structure
315 * has been cleared already. 298 * has been cleared already.
316 */ 299 */
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 27288c83da96..b9926ce8782e 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -85,24 +85,20 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
85} 85}
86 86
87/* 87/*
88 * Traverse all shares for a given file (and host). 88 * Traverse all shares for a given file, and delete
89 * NLM_ACT_CHECK is handled by nlmsvc_inspect_file. 89 * those owned by the given (type of) host
90 */ 90 */
91void 91void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
92nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action) 92 nlm_host_match_fn_t match)
93{ 93{
94 struct nlm_share *share, **shpp; 94 struct nlm_share *share, **shpp;
95 95
96 shpp = &file->f_shares; 96 shpp = &file->f_shares;
97 while ((share = *shpp) != NULL) { 97 while ((share = *shpp) != NULL) {
98 if (action == NLM_ACT_MARK) 98 if (match(share->s_host, host)) {
99 share->s_host->h_inuse = 1; 99 *shpp = share->s_next;
100 else if (action == NLM_ACT_UNLOCK) { 100 kfree(share);
101 if (host == NULL || host == share->s_host) { 101 continue;
102 *shpp = share->s_next;
103 kfree(share);
104 continue;
105 }
106 } 102 }
107 shpp = &share->s_next; 103 shpp = &share->s_next;
108 } 104 }
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 91731353dfa4..bb13a48210f5 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -165,7 +165,8 @@ nlm_delete_file(struct nlm_file *file)
165 * action. 165 * action.
166 */ 166 */
167static int 167static int
168nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action) 168nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
169 nlm_host_match_fn_t match)
169{ 170{
170 struct inode *inode = nlmsvc_file_inode(file); 171 struct inode *inode = nlmsvc_file_inode(file);
171 struct file_lock *fl; 172 struct file_lock *fl;
@@ -179,17 +180,11 @@ again:
179 180
180 /* update current lock count */ 181 /* update current lock count */
181 file->f_locks++; 182 file->f_locks++;
183
182 lockhost = (struct nlm_host *) fl->fl_owner; 184 lockhost = (struct nlm_host *) fl->fl_owner;
183 if (action == NLM_ACT_MARK) 185 if (match(lockhost, host)) {
184 lockhost->h_inuse = 1;
185 else if (action == NLM_ACT_CHECK)
186 return 1;
187 else if (action == NLM_ACT_UNLOCK) {
188 struct file_lock lock = *fl; 186 struct file_lock lock = *fl;
189 187
190 if (host && lockhost != host)
191 continue;
192
193 lock.fl_type = F_UNLCK; 188 lock.fl_type = F_UNLCK;
194 lock.fl_start = 0; 189 lock.fl_start = 0;
195 lock.fl_end = OFFSET_MAX; 190 lock.fl_end = OFFSET_MAX;
@@ -206,27 +201,42 @@ again:
206} 201}
207 202
208/* 203/*
209 * Operate on a single file 204 * Inspect a single file
205 */
206static inline int
207nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match)
208{
209 nlmsvc_traverse_blocks(host, file, match);
210 nlmsvc_traverse_shares(host, file, match);
211 return nlm_traverse_locks(host, file, match);
212}
213
214/*
215 * Quick check whether there are still any locks, blocks or
216 * shares on a given file.
210 */ 217 */
211static inline int 218static inline int
212nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action) 219nlm_file_inuse(struct nlm_file *file)
213{ 220{
214 if (action == NLM_ACT_CHECK) { 221 struct inode *inode = nlmsvc_file_inode(file);
215 /* Fast path for mark and sweep garbage collection */ 222 struct file_lock *fl;
216 if (file->f_count || list_empty(&file->f_blocks) || file->f_shares) 223
224 if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
225 return 1;
226
227 for (fl = inode->i_flock; fl; fl = fl->fl_next) {
228 if (fl->fl_lmops == &nlmsvc_lock_operations)
217 return 1; 229 return 1;
218 } else {
219 nlmsvc_traverse_blocks(host, file, action);
220 nlmsvc_traverse_shares(host, file, action);
221 } 230 }
222 return nlm_traverse_locks(host, file, action); 231 file->f_locks = 0;
232 return 0;
223} 233}
224 234
225/* 235/*
226 * Loop over all files in the file table. 236 * Loop over all files in the file table.
227 */ 237 */
228static int 238static int
229nlm_traverse_files(struct nlm_host *host, int action) 239nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
230{ 240{
231 struct hlist_node *pos, *next; 241 struct hlist_node *pos, *next;
232 struct nlm_file *file; 242 struct nlm_file *file;
@@ -240,7 +250,7 @@ nlm_traverse_files(struct nlm_host *host, int action)
240 250
241 /* Traverse locks, blocks and shares of this file 251 /* Traverse locks, blocks and shares of this file
242 * and update file->f_locks count */ 252 * and update file->f_locks count */
243 if (nlm_inspect_file(host, file, action)) 253 if (nlm_inspect_file(host, file, match))
244 ret = 1; 254 ret = 1;
245 255
246 mutex_lock(&nlm_file_mutex); 256 mutex_lock(&nlm_file_mutex);
@@ -277,23 +287,54 @@ nlm_release_file(struct nlm_file *file)
277 mutex_lock(&nlm_file_mutex); 287 mutex_lock(&nlm_file_mutex);
278 288
279 /* If there are no more locks etc, delete the file */ 289 /* If there are no more locks etc, delete the file */
280 if(--file->f_count == 0) { 290 if (--file->f_count == 0 && !nlm_file_inuse(file))
281 if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK)) 291 nlm_delete_file(file);
282 nlm_delete_file(file);
283 }
284 292
285 mutex_unlock(&nlm_file_mutex); 293 mutex_unlock(&nlm_file_mutex);
286} 294}
287 295
288/* 296/*
297 * Helpers function for resource traversal
298 *
299 * nlmsvc_mark_host:
300 * used by the garbage collector; simply sets h_inuse.
301 * Always returns 0.
302 *
303 * nlmsvc_same_host:
304 * returns 1 iff the two hosts match. Used to release
305 * all resources bound to a specific host.
306 *
307 * nlmsvc_is_client:
308 * returns 1 iff the host is a client.
309 * Used by nlmsvc_invalidate_all
310 */
311static int
312nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy)
313{
314 host->h_inuse = 1;
315 return 0;
316}
317
318static int
319nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other)
320{
321 return host == other;
322}
323
324static int
325nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy)
326{
327 return host->h_server;
328}
329
330/*
289 * Mark all hosts that still hold resources 331 * Mark all hosts that still hold resources
290 */ 332 */
291void 333void
292nlmsvc_mark_resources(void) 334nlmsvc_mark_resources(void)
293{ 335{
294 dprintk("lockd: nlmsvc_mark_resources\n"); 336 dprintk("lockd: nlmsvc_mark_resources\n");
295 337 nlm_traverse_files(NULL, nlmsvc_mark_host);
296 nlm_traverse_files(NULL, NLM_ACT_MARK);
297} 338}
298 339
299/* 340/*
@@ -304,7 +345,7 @@ nlmsvc_free_host_resources(struct nlm_host *host)
304{ 345{
305 dprintk("lockd: nlmsvc_free_host_resources\n"); 346 dprintk("lockd: nlmsvc_free_host_resources\n");
306 347
307 if (nlm_traverse_files(host, NLM_ACT_UNLOCK)) { 348 if (nlm_traverse_files(host, nlmsvc_same_host)) {
308 printk(KERN_WARNING 349 printk(KERN_WARNING
309 "lockd: couldn't remove all locks held by %s\n", 350 "lockd: couldn't remove all locks held by %s\n",
310 host->h_name); 351 host->h_name);
@@ -319,8 +360,16 @@ void
319nlmsvc_invalidate_all(void) 360nlmsvc_invalidate_all(void)
320{ 361{
321 struct nlm_host *host; 362 struct nlm_host *host;
363
364 /* Release all locks held by NFS clients.
365 * Previously, the code would call
366 * nlmsvc_free_host_resources for each client in
367 * turn, which is about as inefficient as it gets.
368 * Now we just do it once in nlm_traverse_files.
369 */
370 nlm_traverse_files(NULL, nlmsvc_is_client);
371
322 while ((host = nlm_find_client()) != NULL) { 372 while ((host = nlm_find_client()) != NULL) {
323 nlmsvc_free_host_resources(host);
324 host->h_expires = 0; 373 host->h_expires = 0;
325 host->h_killed = 1; 374 host->h_killed = 1;
326 nlm_release_host(host); 375 nlm_release_host(host);