diff options
author | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:49:40 -0500 |
---|---|---|
committer | Nick Piggin <npiggin@kernel.dk> | 2011-01-07 01:50:23 -0500 |
commit | 61f3dee4af09528997a970280da240577bf60721 (patch) | |
tree | 8c916d7c1965303a37f1051aa5d42d8e2b7b115a /fs/dcache.c | |
parent | 58db63d086790eec2ed433f9d8c4962239809cf8 (diff) |
fs: dcache reduce dput locking
It is possible to run dput without taking data structure locks up-front. In
many cases where we don't kill the dentry anyway, these locks are not required.
Signed-off-by: Nick Piggin <npiggin@kernel.dk>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 52 |
1 files changed, 23 insertions, 29 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index bf6294a20f0e..98a05696593e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -323,35 +323,16 @@ repeat: | |||
323 | if (dentry->d_count == 1) | 323 | if (dentry->d_count == 1) |
324 | might_sleep(); | 324 | might_sleep(); |
325 | spin_lock(&dentry->d_lock); | 325 | spin_lock(&dentry->d_lock); |
326 | if (IS_ROOT(dentry)) | 326 | BUG_ON(!dentry->d_count); |
327 | parent = NULL; | 327 | if (dentry->d_count > 1) { |
328 | else | 328 | dentry->d_count--; |
329 | parent = dentry->d_parent; | ||
330 | if (dentry->d_count == 1) { | ||
331 | if (!spin_trylock(&dcache_inode_lock)) { | ||
332 | drop2: | ||
333 | spin_unlock(&dentry->d_lock); | ||
334 | goto repeat; | ||
335 | } | ||
336 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
337 | spin_unlock(&dcache_inode_lock); | ||
338 | goto drop2; | ||
339 | } | ||
340 | } | ||
341 | dentry->d_count--; | ||
342 | if (dentry->d_count) { | ||
343 | spin_unlock(&dentry->d_lock); | 329 | spin_unlock(&dentry->d_lock); |
344 | if (parent) | ||
345 | spin_unlock(&parent->d_lock); | ||
346 | return; | 330 | return; |
347 | } | 331 | } |
348 | 332 | ||
349 | /* | ||
350 | * AV: ->d_delete() is _NOT_ allowed to block now. | ||
351 | */ | ||
352 | if (dentry->d_op && dentry->d_op->d_delete) { | 333 | if (dentry->d_op && dentry->d_op->d_delete) { |
353 | if (dentry->d_op->d_delete(dentry)) | 334 | if (dentry->d_op->d_delete(dentry)) |
354 | goto unhash_it; | 335 | goto kill_it; |
355 | } | 336 | } |
356 | 337 | ||
357 | /* Unreachable? Get rid of it */ | 338 | /* Unreachable? Get rid of it */ |
@@ -362,17 +343,30 @@ drop2: | |||
362 | dentry->d_flags |= DCACHE_REFERENCED; | 343 | dentry->d_flags |= DCACHE_REFERENCED; |
363 | dentry_lru_add(dentry); | 344 | dentry_lru_add(dentry); |
364 | 345 | ||
365 | spin_unlock(&dentry->d_lock); | 346 | dentry->d_count--; |
366 | if (parent) | 347 | spin_unlock(&dentry->d_lock); |
367 | spin_unlock(&parent->d_lock); | ||
368 | spin_unlock(&dcache_inode_lock); | ||
369 | return; | 348 | return; |
370 | 349 | ||
371 | unhash_it: | ||
372 | __d_drop(dentry); | ||
373 | kill_it: | 350 | kill_it: |
351 | if (!spin_trylock(&dcache_inode_lock)) { | ||
352 | relock: | ||
353 | spin_unlock(&dentry->d_lock); | ||
354 | cpu_relax(); | ||
355 | goto repeat; | ||
356 | } | ||
357 | if (IS_ROOT(dentry)) | ||
358 | parent = NULL; | ||
359 | else | ||
360 | parent = dentry->d_parent; | ||
361 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
362 | spin_unlock(&dcache_inode_lock); | ||
363 | goto relock; | ||
364 | } | ||
365 | dentry->d_count--; | ||
374 | /* if dentry was on the d_lru list delete it from there */ | 366 | /* if dentry was on the d_lru list delete it from there */ |
375 | dentry_lru_del(dentry); | 367 | dentry_lru_del(dentry); |
368 | /* if it was on the hash (d_delete case), then remove it */ | ||
369 | __d_drop(dentry); | ||
376 | dentry = d_kill(dentry, parent); | 370 | dentry = d_kill(dentry, parent); |
377 | if (dentry) | 371 | if (dentry) |
378 | goto repeat; | 372 | goto repeat; |