diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 248 |
1 files changed, 174 insertions, 74 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index ee127f9ab274..a661247a20d5 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -47,6 +47,8 @@ | |||
47 | * - d_lru | 47 | * - d_lru |
48 | * - d_count | 48 | * - d_count |
49 | * - d_unhashed() | 49 | * - d_unhashed() |
50 | * - d_parent and d_subdirs | ||
51 | * - childrens' d_child and d_parent | ||
50 | * | 52 | * |
51 | * Ordering: | 53 | * Ordering: |
52 | * dcache_lock | 54 | * dcache_lock |
@@ -223,24 +225,22 @@ static void dentry_lru_move_tail(struct dentry *dentry) | |||
223 | * | 225 | * |
224 | * If this is the root of the dentry tree, return NULL. | 226 | * If this is the root of the dentry tree, return NULL. |
225 | * | 227 | * |
226 | * dcache_lock and d_lock must be held by caller, are dropped by d_kill. | 228 | * dcache_lock and d_lock and d_parent->d_lock must be held by caller, and |
229 | * are dropped by d_kill. | ||
227 | */ | 230 | */ |
228 | static struct dentry *d_kill(struct dentry *dentry) | 231 | static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) |
229 | __releases(dentry->d_lock) | 232 | __releases(dentry->d_lock) |
233 | __releases(parent->d_lock) | ||
230 | __releases(dcache_lock) | 234 | __releases(dcache_lock) |
231 | { | 235 | { |
232 | struct dentry *parent; | ||
233 | |||
234 | list_del(&dentry->d_u.d_child); | 236 | list_del(&dentry->d_u.d_child); |
237 | if (parent) | ||
238 | spin_unlock(&parent->d_lock); | ||
235 | dentry_iput(dentry); | 239 | dentry_iput(dentry); |
236 | /* | 240 | /* |
237 | * dentry_iput drops the locks, at which point nobody (except | 241 | * dentry_iput drops the locks, at which point nobody (except |
238 | * transient RCU lookups) can reach this dentry. | 242 | * transient RCU lookups) can reach this dentry. |
239 | */ | 243 | */ |
240 | if (IS_ROOT(dentry)) | ||
241 | parent = NULL; | ||
242 | else | ||
243 | parent = dentry->d_parent; | ||
244 | d_free(dentry); | 244 | d_free(dentry); |
245 | return parent; | 245 | return parent; |
246 | } | 246 | } |
@@ -312,6 +312,7 @@ EXPORT_SYMBOL(d_drop); | |||
312 | 312 | ||
313 | void dput(struct dentry *dentry) | 313 | void dput(struct dentry *dentry) |
314 | { | 314 | { |
315 | struct dentry *parent; | ||
315 | if (!dentry) | 316 | if (!dentry) |
316 | return; | 317 | return; |
317 | 318 | ||
@@ -319,6 +320,10 @@ repeat: | |||
319 | if (dentry->d_count == 1) | 320 | if (dentry->d_count == 1) |
320 | might_sleep(); | 321 | might_sleep(); |
321 | spin_lock(&dentry->d_lock); | 322 | spin_lock(&dentry->d_lock); |
323 | if (IS_ROOT(dentry)) | ||
324 | parent = NULL; | ||
325 | else | ||
326 | parent = dentry->d_parent; | ||
322 | if (dentry->d_count == 1) { | 327 | if (dentry->d_count == 1) { |
323 | if (!spin_trylock(&dcache_lock)) { | 328 | if (!spin_trylock(&dcache_lock)) { |
324 | /* | 329 | /* |
@@ -330,10 +335,17 @@ repeat: | |||
330 | spin_unlock(&dentry->d_lock); | 335 | spin_unlock(&dentry->d_lock); |
331 | goto repeat; | 336 | goto repeat; |
332 | } | 337 | } |
338 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
339 | spin_unlock(&dentry->d_lock); | ||
340 | spin_unlock(&dcache_lock); | ||
341 | goto repeat; | ||
342 | } | ||
333 | } | 343 | } |
334 | dentry->d_count--; | 344 | dentry->d_count--; |
335 | if (dentry->d_count) { | 345 | if (dentry->d_count) { |
336 | spin_unlock(&dentry->d_lock); | 346 | spin_unlock(&dentry->d_lock); |
347 | if (parent) | ||
348 | spin_unlock(&parent->d_lock); | ||
337 | spin_unlock(&dcache_lock); | 349 | spin_unlock(&dcache_lock); |
338 | return; | 350 | return; |
339 | } | 351 | } |
@@ -355,6 +367,8 @@ repeat: | |||
355 | dentry_lru_add(dentry); | 367 | dentry_lru_add(dentry); |
356 | 368 | ||
357 | spin_unlock(&dentry->d_lock); | 369 | spin_unlock(&dentry->d_lock); |
370 | if (parent) | ||
371 | spin_unlock(&parent->d_lock); | ||
358 | spin_unlock(&dcache_lock); | 372 | spin_unlock(&dcache_lock); |
359 | return; | 373 | return; |
360 | 374 | ||
@@ -363,7 +377,7 @@ unhash_it: | |||
363 | kill_it: | 377 | kill_it: |
364 | /* if dentry was on the d_lru list delete it from there */ | 378 | /* if dentry was on the d_lru list delete it from there */ |
365 | dentry_lru_del(dentry); | 379 | dentry_lru_del(dentry); |
366 | dentry = d_kill(dentry); | 380 | dentry = d_kill(dentry, parent); |
367 | if (dentry) | 381 | if (dentry) |
368 | goto repeat; | 382 | goto repeat; |
369 | } | 383 | } |
@@ -584,12 +598,13 @@ EXPORT_SYMBOL(d_prune_aliases); | |||
584 | * quadratic behavior of shrink_dcache_parent(), but is also expected | 598 | * quadratic behavior of shrink_dcache_parent(), but is also expected |
585 | * to be beneficial in reducing dentry cache fragmentation. | 599 | * to be beneficial in reducing dentry cache fragmentation. |
586 | */ | 600 | */ |
587 | static void prune_one_dentry(struct dentry * dentry) | 601 | static void prune_one_dentry(struct dentry *dentry, struct dentry *parent) |
588 | __releases(dentry->d_lock) | 602 | __releases(dentry->d_lock) |
603 | __releases(parent->d_lock) | ||
589 | __releases(dcache_lock) | 604 | __releases(dcache_lock) |
590 | { | 605 | { |
591 | __d_drop(dentry); | 606 | __d_drop(dentry); |
592 | dentry = d_kill(dentry); | 607 | dentry = d_kill(dentry, parent); |
593 | 608 | ||
594 | /* | 609 | /* |
595 | * Prune ancestors. Locking is simpler than in dput(), | 610 | * Prune ancestors. Locking is simpler than in dput(), |
@@ -597,9 +612,20 @@ static void prune_one_dentry(struct dentry * dentry) | |||
597 | */ | 612 | */ |
598 | while (dentry) { | 613 | while (dentry) { |
599 | spin_lock(&dcache_lock); | 614 | spin_lock(&dcache_lock); |
615 | again: | ||
600 | spin_lock(&dentry->d_lock); | 616 | spin_lock(&dentry->d_lock); |
617 | if (IS_ROOT(dentry)) | ||
618 | parent = NULL; | ||
619 | else | ||
620 | parent = dentry->d_parent; | ||
621 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
622 | spin_unlock(&dentry->d_lock); | ||
623 | goto again; | ||
624 | } | ||
601 | dentry->d_count--; | 625 | dentry->d_count--; |
602 | if (dentry->d_count) { | 626 | if (dentry->d_count) { |
627 | if (parent) | ||
628 | spin_unlock(&parent->d_lock); | ||
603 | spin_unlock(&dentry->d_lock); | 629 | spin_unlock(&dentry->d_lock); |
604 | spin_unlock(&dcache_lock); | 630 | spin_unlock(&dcache_lock); |
605 | return; | 631 | return; |
@@ -607,7 +633,7 @@ static void prune_one_dentry(struct dentry * dentry) | |||
607 | 633 | ||
608 | dentry_lru_del(dentry); | 634 | dentry_lru_del(dentry); |
609 | __d_drop(dentry); | 635 | __d_drop(dentry); |
610 | dentry = d_kill(dentry); | 636 | dentry = d_kill(dentry, parent); |
611 | } | 637 | } |
612 | } | 638 | } |
613 | 639 | ||
@@ -616,29 +642,40 @@ static void shrink_dentry_list(struct list_head *list) | |||
616 | struct dentry *dentry; | 642 | struct dentry *dentry; |
617 | 643 | ||
618 | while (!list_empty(list)) { | 644 | while (!list_empty(list)) { |
645 | struct dentry *parent; | ||
646 | |||
619 | dentry = list_entry(list->prev, struct dentry, d_lru); | 647 | dentry = list_entry(list->prev, struct dentry, d_lru); |
620 | 648 | ||
621 | if (!spin_trylock(&dentry->d_lock)) { | 649 | if (!spin_trylock(&dentry->d_lock)) { |
650 | relock: | ||
622 | spin_unlock(&dcache_lru_lock); | 651 | spin_unlock(&dcache_lru_lock); |
623 | cpu_relax(); | 652 | cpu_relax(); |
624 | spin_lock(&dcache_lru_lock); | 653 | spin_lock(&dcache_lru_lock); |
625 | continue; | 654 | continue; |
626 | } | 655 | } |
627 | 656 | ||
628 | __dentry_lru_del(dentry); | ||
629 | |||
630 | /* | 657 | /* |
631 | * We found an inuse dentry which was not removed from | 658 | * We found an inuse dentry which was not removed from |
632 | * the LRU because of laziness during lookup. Do not free | 659 | * the LRU because of laziness during lookup. Do not free |
633 | * it - just keep it off the LRU list. | 660 | * it - just keep it off the LRU list. |
634 | */ | 661 | */ |
635 | if (dentry->d_count) { | 662 | if (dentry->d_count) { |
663 | __dentry_lru_del(dentry); | ||
636 | spin_unlock(&dentry->d_lock); | 664 | spin_unlock(&dentry->d_lock); |
637 | continue; | 665 | continue; |
638 | } | 666 | } |
667 | if (IS_ROOT(dentry)) | ||
668 | parent = NULL; | ||
669 | else | ||
670 | parent = dentry->d_parent; | ||
671 | if (parent && !spin_trylock(&parent->d_lock)) { | ||
672 | spin_unlock(&dentry->d_lock); | ||
673 | goto relock; | ||
674 | } | ||
675 | __dentry_lru_del(dentry); | ||
639 | spin_unlock(&dcache_lru_lock); | 676 | spin_unlock(&dcache_lru_lock); |
640 | 677 | ||
641 | prune_one_dentry(dentry); | 678 | prune_one_dentry(dentry, parent); |
642 | /* dcache_lock and dentry->d_lock dropped */ | 679 | /* dcache_lock and dentry->d_lock dropped */ |
643 | spin_lock(&dcache_lock); | 680 | spin_lock(&dcache_lock); |
644 | spin_lock(&dcache_lru_lock); | 681 | spin_lock(&dcache_lru_lock); |
@@ -833,14 +870,16 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
833 | /* this is a branch with children - detach all of them | 870 | /* this is a branch with children - detach all of them |
834 | * from the system in one go */ | 871 | * from the system in one go */ |
835 | spin_lock(&dcache_lock); | 872 | spin_lock(&dcache_lock); |
873 | spin_lock(&dentry->d_lock); | ||
836 | list_for_each_entry(loop, &dentry->d_subdirs, | 874 | list_for_each_entry(loop, &dentry->d_subdirs, |
837 | d_u.d_child) { | 875 | d_u.d_child) { |
838 | spin_lock(&loop->d_lock); | 876 | spin_lock_nested(&loop->d_lock, |
877 | DENTRY_D_LOCK_NESTED); | ||
839 | dentry_lru_del(loop); | 878 | dentry_lru_del(loop); |
840 | __d_drop(loop); | 879 | __d_drop(loop); |
841 | spin_unlock(&loop->d_lock); | 880 | spin_unlock(&loop->d_lock); |
842 | cond_resched_lock(&dcache_lock); | ||
843 | } | 881 | } |
882 | spin_unlock(&dentry->d_lock); | ||
844 | spin_unlock(&dcache_lock); | 883 | spin_unlock(&dcache_lock); |
845 | 884 | ||
846 | /* move to the first child */ | 885 | /* move to the first child */ |
@@ -868,16 +907,17 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
868 | BUG(); | 907 | BUG(); |
869 | } | 908 | } |
870 | 909 | ||
871 | if (IS_ROOT(dentry)) | 910 | if (IS_ROOT(dentry)) { |
872 | parent = NULL; | 911 | parent = NULL; |
873 | else { | 912 | list_del(&dentry->d_u.d_child); |
913 | } else { | ||
874 | parent = dentry->d_parent; | 914 | parent = dentry->d_parent; |
875 | spin_lock(&parent->d_lock); | 915 | spin_lock(&parent->d_lock); |
876 | parent->d_count--; | 916 | parent->d_count--; |
917 | list_del(&dentry->d_u.d_child); | ||
877 | spin_unlock(&parent->d_lock); | 918 | spin_unlock(&parent->d_lock); |
878 | } | 919 | } |
879 | 920 | ||
880 | list_del(&dentry->d_u.d_child); | ||
881 | detached++; | 921 | detached++; |
882 | 922 | ||
883 | inode = dentry->d_inode; | 923 | inode = dentry->d_inode; |
@@ -958,6 +998,7 @@ int have_submounts(struct dentry *parent) | |||
958 | spin_lock(&dcache_lock); | 998 | spin_lock(&dcache_lock); |
959 | if (d_mountpoint(parent)) | 999 | if (d_mountpoint(parent)) |
960 | goto positive; | 1000 | goto positive; |
1001 | spin_lock(&this_parent->d_lock); | ||
961 | repeat: | 1002 | repeat: |
962 | next = this_parent->d_subdirs.next; | 1003 | next = this_parent->d_subdirs.next; |
963 | resume: | 1004 | resume: |
@@ -965,22 +1006,34 @@ resume: | |||
965 | struct list_head *tmp = next; | 1006 | struct list_head *tmp = next; |
966 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 1007 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
967 | next = tmp->next; | 1008 | next = tmp->next; |
1009 | |||
1010 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
968 | /* Have we found a mount point ? */ | 1011 | /* Have we found a mount point ? */ |
969 | if (d_mountpoint(dentry)) | 1012 | if (d_mountpoint(dentry)) { |
1013 | spin_unlock(&dentry->d_lock); | ||
1014 | spin_unlock(&this_parent->d_lock); | ||
970 | goto positive; | 1015 | goto positive; |
1016 | } | ||
971 | if (!list_empty(&dentry->d_subdirs)) { | 1017 | if (!list_empty(&dentry->d_subdirs)) { |
1018 | spin_unlock(&this_parent->d_lock); | ||
1019 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
972 | this_parent = dentry; | 1020 | this_parent = dentry; |
1021 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
973 | goto repeat; | 1022 | goto repeat; |
974 | } | 1023 | } |
1024 | spin_unlock(&dentry->d_lock); | ||
975 | } | 1025 | } |
976 | /* | 1026 | /* |
977 | * All done at this level ... ascend and resume the search. | 1027 | * All done at this level ... ascend and resume the search. |
978 | */ | 1028 | */ |
979 | if (this_parent != parent) { | 1029 | if (this_parent != parent) { |
980 | next = this_parent->d_u.d_child.next; | 1030 | next = this_parent->d_u.d_child.next; |
1031 | spin_unlock(&this_parent->d_lock); | ||
981 | this_parent = this_parent->d_parent; | 1032 | this_parent = this_parent->d_parent; |
1033 | spin_lock(&this_parent->d_lock); | ||
982 | goto resume; | 1034 | goto resume; |
983 | } | 1035 | } |
1036 | spin_unlock(&this_parent->d_lock); | ||
984 | spin_unlock(&dcache_lock); | 1037 | spin_unlock(&dcache_lock); |
985 | return 0; /* No mount points found in tree */ | 1038 | return 0; /* No mount points found in tree */ |
986 | positive: | 1039 | positive: |
@@ -1010,6 +1063,7 @@ static int select_parent(struct dentry * parent) | |||
1010 | int found = 0; | 1063 | int found = 0; |
1011 | 1064 | ||
1012 | spin_lock(&dcache_lock); | 1065 | spin_lock(&dcache_lock); |
1066 | spin_lock(&this_parent->d_lock); | ||
1013 | repeat: | 1067 | repeat: |
1014 | next = this_parent->d_subdirs.next; | 1068 | next = this_parent->d_subdirs.next; |
1015 | resume: | 1069 | resume: |
@@ -1017,8 +1071,9 @@ resume: | |||
1017 | struct list_head *tmp = next; | 1071 | struct list_head *tmp = next; |
1018 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 1072 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
1019 | next = tmp->next; | 1073 | next = tmp->next; |
1074 | BUG_ON(this_parent == dentry); | ||
1020 | 1075 | ||
1021 | spin_lock(&dentry->d_lock); | 1076 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1022 | 1077 | ||
1023 | /* | 1078 | /* |
1024 | * move only zero ref count dentries to the end | 1079 | * move only zero ref count dentries to the end |
@@ -1031,33 +1086,44 @@ resume: | |||
1031 | dentry_lru_del(dentry); | 1086 | dentry_lru_del(dentry); |
1032 | } | 1087 | } |
1033 | 1088 | ||
1034 | spin_unlock(&dentry->d_lock); | ||
1035 | |||
1036 | /* | 1089 | /* |
1037 | * We can return to the caller if we have found some (this | 1090 | * We can return to the caller if we have found some (this |
1038 | * ensures forward progress). We'll be coming back to find | 1091 | * ensures forward progress). We'll be coming back to find |
1039 | * the rest. | 1092 | * the rest. |
1040 | */ | 1093 | */ |
1041 | if (found && need_resched()) | 1094 | if (found && need_resched()) { |
1095 | spin_unlock(&dentry->d_lock); | ||
1042 | goto out; | 1096 | goto out; |
1097 | } | ||
1043 | 1098 | ||
1044 | /* | 1099 | /* |
1045 | * Descend a level if the d_subdirs list is non-empty. | 1100 | * Descend a level if the d_subdirs list is non-empty. |
1046 | */ | 1101 | */ |
1047 | if (!list_empty(&dentry->d_subdirs)) { | 1102 | if (!list_empty(&dentry->d_subdirs)) { |
1103 | spin_unlock(&this_parent->d_lock); | ||
1104 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
1048 | this_parent = dentry; | 1105 | this_parent = dentry; |
1106 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
1049 | goto repeat; | 1107 | goto repeat; |
1050 | } | 1108 | } |
1109 | |||
1110 | spin_unlock(&dentry->d_lock); | ||
1051 | } | 1111 | } |
1052 | /* | 1112 | /* |
1053 | * All done at this level ... ascend and resume the search. | 1113 | * All done at this level ... ascend and resume the search. |
1054 | */ | 1114 | */ |
1055 | if (this_parent != parent) { | 1115 | if (this_parent != parent) { |
1116 | struct dentry *tmp; | ||
1056 | next = this_parent->d_u.d_child.next; | 1117 | next = this_parent->d_u.d_child.next; |
1057 | this_parent = this_parent->d_parent; | 1118 | tmp = this_parent->d_parent; |
1119 | spin_unlock(&this_parent->d_lock); | ||
1120 | BUG_ON(tmp == this_parent); | ||
1121 | this_parent = tmp; | ||
1122 | spin_lock(&this_parent->d_lock); | ||
1058 | goto resume; | 1123 | goto resume; |
1059 | } | 1124 | } |
1060 | out: | 1125 | out: |
1126 | spin_unlock(&this_parent->d_lock); | ||
1061 | spin_unlock(&dcache_lock); | 1127 | spin_unlock(&dcache_lock); |
1062 | return found; | 1128 | return found; |
1063 | } | 1129 | } |
@@ -1155,18 +1221,19 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1155 | INIT_LIST_HEAD(&dentry->d_lru); | 1221 | INIT_LIST_HEAD(&dentry->d_lru); |
1156 | INIT_LIST_HEAD(&dentry->d_subdirs); | 1222 | INIT_LIST_HEAD(&dentry->d_subdirs); |
1157 | INIT_LIST_HEAD(&dentry->d_alias); | 1223 | INIT_LIST_HEAD(&dentry->d_alias); |
1224 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
1158 | 1225 | ||
1159 | if (parent) { | 1226 | if (parent) { |
1160 | dentry->d_parent = dget(parent); | 1227 | spin_lock(&dcache_lock); |
1228 | spin_lock(&parent->d_lock); | ||
1229 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
1230 | dentry->d_parent = dget_dlock(parent); | ||
1161 | dentry->d_sb = parent->d_sb; | 1231 | dentry->d_sb = parent->d_sb; |
1162 | } else { | ||
1163 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
1164 | } | ||
1165 | |||
1166 | spin_lock(&dcache_lock); | ||
1167 | if (parent) | ||
1168 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); | 1232 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); |
1169 | spin_unlock(&dcache_lock); | 1233 | spin_unlock(&dentry->d_lock); |
1234 | spin_unlock(&parent->d_lock); | ||
1235 | spin_unlock(&dcache_lock); | ||
1236 | } | ||
1170 | 1237 | ||
1171 | this_cpu_inc(nr_dentry); | 1238 | this_cpu_inc(nr_dentry); |
1172 | 1239 | ||
@@ -1684,13 +1751,18 @@ int d_validate(struct dentry *dentry, struct dentry *dparent) | |||
1684 | struct dentry *child; | 1751 | struct dentry *child; |
1685 | 1752 | ||
1686 | spin_lock(&dcache_lock); | 1753 | spin_lock(&dcache_lock); |
1754 | spin_lock(&dparent->d_lock); | ||
1687 | list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) { | 1755 | list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) { |
1688 | if (dentry == child) { | 1756 | if (dentry == child) { |
1689 | __dget_locked(dentry); | 1757 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1758 | __dget_locked_dlock(dentry); | ||
1759 | spin_unlock(&dentry->d_lock); | ||
1760 | spin_unlock(&dparent->d_lock); | ||
1690 | spin_unlock(&dcache_lock); | 1761 | spin_unlock(&dcache_lock); |
1691 | return 1; | 1762 | return 1; |
1692 | } | 1763 | } |
1693 | } | 1764 | } |
1765 | spin_unlock(&dparent->d_lock); | ||
1694 | spin_unlock(&dcache_lock); | 1766 | spin_unlock(&dcache_lock); |
1695 | 1767 | ||
1696 | return 0; | 1768 | return 0; |
@@ -1802,17 +1874,6 @@ void dentry_update_name_case(struct dentry *dentry, struct qstr *name) | |||
1802 | } | 1874 | } |
1803 | EXPORT_SYMBOL(dentry_update_name_case); | 1875 | EXPORT_SYMBOL(dentry_update_name_case); |
1804 | 1876 | ||
1805 | /* | ||
1806 | * When switching names, the actual string doesn't strictly have to | ||
1807 | * be preserved in the target - because we're dropping the target | ||
1808 | * anyway. As such, we can just do a simple memcpy() to copy over | ||
1809 | * the new name before we switch. | ||
1810 | * | ||
1811 | * Note that we have to be a lot more careful about getting the hash | ||
1812 | * switched - we have to switch the hash value properly even if it | ||
1813 | * then no longer matches the actual (corrupted) string of the target. | ||
1814 | * The hash value has to match the hash queue that the dentry is on.. | ||
1815 | */ | ||
1816 | static void switch_names(struct dentry *dentry, struct dentry *target) | 1877 | static void switch_names(struct dentry *dentry, struct dentry *target) |
1817 | { | 1878 | { |
1818 | if (dname_external(target)) { | 1879 | if (dname_external(target)) { |
@@ -1854,18 +1915,53 @@ static void switch_names(struct dentry *dentry, struct dentry *target) | |||
1854 | swap(dentry->d_name.len, target->d_name.len); | 1915 | swap(dentry->d_name.len, target->d_name.len); |
1855 | } | 1916 | } |
1856 | 1917 | ||
1918 | static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) | ||
1919 | { | ||
1920 | /* | ||
1921 | * XXXX: do we really need to take target->d_lock? | ||
1922 | */ | ||
1923 | if (IS_ROOT(dentry) || dentry->d_parent == target->d_parent) | ||
1924 | spin_lock(&target->d_parent->d_lock); | ||
1925 | else { | ||
1926 | if (d_ancestor(dentry->d_parent, target->d_parent)) { | ||
1927 | spin_lock(&dentry->d_parent->d_lock); | ||
1928 | spin_lock_nested(&target->d_parent->d_lock, | ||
1929 | DENTRY_D_LOCK_NESTED); | ||
1930 | } else { | ||
1931 | spin_lock(&target->d_parent->d_lock); | ||
1932 | spin_lock_nested(&dentry->d_parent->d_lock, | ||
1933 | DENTRY_D_LOCK_NESTED); | ||
1934 | } | ||
1935 | } | ||
1936 | if (target < dentry) { | ||
1937 | spin_lock_nested(&target->d_lock, 2); | ||
1938 | spin_lock_nested(&dentry->d_lock, 3); | ||
1939 | } else { | ||
1940 | spin_lock_nested(&dentry->d_lock, 2); | ||
1941 | spin_lock_nested(&target->d_lock, 3); | ||
1942 | } | ||
1943 | } | ||
1944 | |||
1945 | static void dentry_unlock_parents_for_move(struct dentry *dentry, | ||
1946 | struct dentry *target) | ||
1947 | { | ||
1948 | if (target->d_parent != dentry->d_parent) | ||
1949 | spin_unlock(&dentry->d_parent->d_lock); | ||
1950 | if (target->d_parent != target) | ||
1951 | spin_unlock(&target->d_parent->d_lock); | ||
1952 | } | ||
1953 | |||
1857 | /* | 1954 | /* |
1858 | * We cannibalize "target" when moving dentry on top of it, | 1955 | * When switching names, the actual string doesn't strictly have to |
1859 | * because it's going to be thrown away anyway. We could be more | 1956 | * be preserved in the target - because we're dropping the target |
1860 | * polite about it, though. | 1957 | * anyway. As such, we can just do a simple memcpy() to copy over |
1861 | * | 1958 | * the new name before we switch. |
1862 | * This forceful removal will result in ugly /proc output if | 1959 | * |
1863 | * somebody holds a file open that got deleted due to a rename. | 1960 | * Note that we have to be a lot more careful about getting the hash |
1864 | * We could be nicer about the deleted file, and let it show | 1961 | * switched - we have to switch the hash value properly even if it |
1865 | * up under the name it had before it was deleted rather than | 1962 | * then no longer matches the actual (corrupted) string of the target. |
1866 | * under the original name of the file that was moved on top of it. | 1963 | * The hash value has to match the hash queue that the dentry is on.. |
1867 | */ | 1964 | */ |
1868 | |||
1869 | /* | 1965 | /* |
1870 | * d_move_locked - move a dentry | 1966 | * d_move_locked - move a dentry |
1871 | * @dentry: entry to move | 1967 | * @dentry: entry to move |
@@ -1879,20 +1975,12 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target) | |||
1879 | if (!dentry->d_inode) | 1975 | if (!dentry->d_inode) |
1880 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); | 1976 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); |
1881 | 1977 | ||
1978 | BUG_ON(d_ancestor(dentry, target)); | ||
1979 | BUG_ON(d_ancestor(target, dentry)); | ||
1980 | |||
1882 | write_seqlock(&rename_lock); | 1981 | write_seqlock(&rename_lock); |
1883 | /* | 1982 | |
1884 | * XXXX: do we really need to take target->d_lock? | 1983 | dentry_lock_for_move(dentry, target); |
1885 | */ | ||
1886 | if (d_ancestor(dentry, target)) { | ||
1887 | spin_lock(&dentry->d_lock); | ||
1888 | spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED); | ||
1889 | } else if (d_ancestor(target, dentry) || target < dentry) { | ||
1890 | spin_lock(&target->d_lock); | ||
1891 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
1892 | } else { | ||
1893 | spin_lock(&dentry->d_lock); | ||
1894 | spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED); | ||
1895 | } | ||
1896 | 1984 | ||
1897 | /* Move the dentry to the target hash queue, if on different bucket */ | 1985 | /* Move the dentry to the target hash queue, if on different bucket */ |
1898 | spin_lock(&dcache_hash_lock); | 1986 | spin_lock(&dcache_hash_lock); |
@@ -1924,6 +2012,8 @@ static void d_move_locked(struct dentry * dentry, struct dentry * target) | |||
1924 | } | 2012 | } |
1925 | 2013 | ||
1926 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); | 2014 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); |
2015 | |||
2016 | dentry_unlock_parents_for_move(dentry, target); | ||
1927 | spin_unlock(&target->d_lock); | 2017 | spin_unlock(&target->d_lock); |
1928 | fsnotify_d_move(dentry); | 2018 | fsnotify_d_move(dentry); |
1929 | spin_unlock(&dentry->d_lock); | 2019 | spin_unlock(&dentry->d_lock); |
@@ -2013,17 +2103,20 @@ out_err: | |||
2013 | /* | 2103 | /* |
2014 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a | 2104 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a |
2015 | * named dentry in place of the dentry to be replaced. | 2105 | * named dentry in place of the dentry to be replaced. |
2106 | * returns with anon->d_lock held! | ||
2016 | */ | 2107 | */ |
2017 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | 2108 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) |
2018 | { | 2109 | { |
2019 | struct dentry *dparent, *aparent; | 2110 | struct dentry *dparent, *aparent; |
2020 | 2111 | ||
2021 | switch_names(dentry, anon); | 2112 | dentry_lock_for_move(anon, dentry); |
2022 | swap(dentry->d_name.hash, anon->d_name.hash); | ||
2023 | 2113 | ||
2024 | dparent = dentry->d_parent; | 2114 | dparent = dentry->d_parent; |
2025 | aparent = anon->d_parent; | 2115 | aparent = anon->d_parent; |
2026 | 2116 | ||
2117 | switch_names(dentry, anon); | ||
2118 | swap(dentry->d_name.hash, anon->d_name.hash); | ||
2119 | |||
2027 | dentry->d_parent = (aparent == anon) ? dentry : aparent; | 2120 | dentry->d_parent = (aparent == anon) ? dentry : aparent; |
2028 | list_del(&dentry->d_u.d_child); | 2121 | list_del(&dentry->d_u.d_child); |
2029 | if (!IS_ROOT(dentry)) | 2122 | if (!IS_ROOT(dentry)) |
@@ -2038,6 +2131,10 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | |||
2038 | else | 2131 | else |
2039 | INIT_LIST_HEAD(&anon->d_u.d_child); | 2132 | INIT_LIST_HEAD(&anon->d_u.d_child); |
2040 | 2133 | ||
2134 | dentry_unlock_parents_for_move(anon, dentry); | ||
2135 | spin_unlock(&dentry->d_lock); | ||
2136 | |||
2137 | /* anon->d_lock still locked, returns locked */ | ||
2041 | anon->d_flags &= ~DCACHE_DISCONNECTED; | 2138 | anon->d_flags &= ~DCACHE_DISCONNECTED; |
2042 | } | 2139 | } |
2043 | 2140 | ||
@@ -2073,7 +2170,6 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2073 | /* Is this an anonymous mountpoint that we could splice | 2170 | /* Is this an anonymous mountpoint that we could splice |
2074 | * into our tree? */ | 2171 | * into our tree? */ |
2075 | if (IS_ROOT(alias)) { | 2172 | if (IS_ROOT(alias)) { |
2076 | spin_lock(&alias->d_lock); | ||
2077 | __d_materialise_dentry(dentry, alias); | 2173 | __d_materialise_dentry(dentry, alias); |
2078 | __d_drop(alias); | 2174 | __d_drop(alias); |
2079 | goto found; | 2175 | goto found; |
@@ -2558,6 +2654,7 @@ void d_genocide(struct dentry *root) | |||
2558 | struct list_head *next; | 2654 | struct list_head *next; |
2559 | 2655 | ||
2560 | spin_lock(&dcache_lock); | 2656 | spin_lock(&dcache_lock); |
2657 | spin_lock(&this_parent->d_lock); | ||
2561 | repeat: | 2658 | repeat: |
2562 | next = this_parent->d_subdirs.next; | 2659 | next = this_parent->d_subdirs.next; |
2563 | resume: | 2660 | resume: |
@@ -2571,8 +2668,10 @@ resume: | |||
2571 | continue; | 2668 | continue; |
2572 | } | 2669 | } |
2573 | if (!list_empty(&dentry->d_subdirs)) { | 2670 | if (!list_empty(&dentry->d_subdirs)) { |
2574 | spin_unlock(&dentry->d_lock); | 2671 | spin_unlock(&this_parent->d_lock); |
2672 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
2575 | this_parent = dentry; | 2673 | this_parent = dentry; |
2674 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
2576 | goto repeat; | 2675 | goto repeat; |
2577 | } | 2676 | } |
2578 | dentry->d_count--; | 2677 | dentry->d_count--; |
@@ -2580,12 +2679,13 @@ resume: | |||
2580 | } | 2679 | } |
2581 | if (this_parent != root) { | 2680 | if (this_parent != root) { |
2582 | next = this_parent->d_u.d_child.next; | 2681 | next = this_parent->d_u.d_child.next; |
2583 | spin_lock(&this_parent->d_lock); | ||
2584 | this_parent->d_count--; | 2682 | this_parent->d_count--; |
2585 | spin_unlock(&this_parent->d_lock); | 2683 | spin_unlock(&this_parent->d_lock); |
2586 | this_parent = this_parent->d_parent; | 2684 | this_parent = this_parent->d_parent; |
2685 | spin_lock(&this_parent->d_lock); | ||
2587 | goto resume; | 2686 | goto resume; |
2588 | } | 2687 | } |
2688 | spin_unlock(&this_parent->d_lock); | ||
2589 | spin_unlock(&dcache_lock); | 2689 | spin_unlock(&dcache_lock); |
2590 | } | 2690 | } |
2591 | 2691 | ||