diff options
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 86 |
1 files changed, 21 insertions, 65 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 0a38ef8d7f00..6055d61811d3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -88,35 +88,6 @@ EXPORT_SYMBOL(rename_lock); | |||
| 88 | 88 | ||
| 89 | static struct kmem_cache *dentry_cache __read_mostly; | 89 | static struct kmem_cache *dentry_cache __read_mostly; |
| 90 | 90 | ||
| 91 | /** | ||
| 92 | * read_seqbegin_or_lock - begin a sequence number check or locking block | ||
| 93 | * @lock: sequence lock | ||
| 94 | * @seq : sequence number to be checked | ||
| 95 | * | ||
| 96 | * First try it once optimistically without taking the lock. If that fails, | ||
| 97 | * take the lock. The sequence number is also used as a marker for deciding | ||
| 98 | * whether to be a reader (even) or writer (odd). | ||
| 99 | * N.B. seq must be initialized to an even number to begin with. | ||
| 100 | */ | ||
| 101 | static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq) | ||
| 102 | { | ||
| 103 | if (!(*seq & 1)) /* Even */ | ||
| 104 | *seq = read_seqbegin(lock); | ||
| 105 | else /* Odd */ | ||
| 106 | read_seqlock_excl(lock); | ||
| 107 | } | ||
| 108 | |||
| 109 | static inline int need_seqretry(seqlock_t *lock, int seq) | ||
| 110 | { | ||
| 111 | return !(seq & 1) && read_seqretry(lock, seq); | ||
| 112 | } | ||
| 113 | |||
| 114 | static inline void done_seqretry(seqlock_t *lock, int seq) | ||
| 115 | { | ||
| 116 | if (seq & 1) | ||
| 117 | read_sequnlock_excl(lock); | ||
| 118 | } | ||
| 119 | |||
| 120 | /* | 91 | /* |
| 121 | * This is the single most critical data structure when it comes | 92 | * This is the single most critical data structure when it comes |
| 122 | * to the dcache: the hashtable for lookups. Somebody should try | 93 | * to the dcache: the hashtable for lookups. Somebody should try |
| @@ -125,8 +96,6 @@ static inline void done_seqretry(seqlock_t *lock, int seq) | |||
| 125 | * This hash-function tries to avoid losing too many bits of hash | 96 | * This hash-function tries to avoid losing too many bits of hash |
| 126 | * information, yet avoid using a prime hash-size or similar. | 97 | * information, yet avoid using a prime hash-size or similar. |
| 127 | */ | 98 | */ |
| 128 | #define D_HASHBITS d_hash_shift | ||
| 129 | #define D_HASHMASK d_hash_mask | ||
| 130 | 99 | ||
| 131 | static unsigned int d_hash_mask __read_mostly; | 100 | static unsigned int d_hash_mask __read_mostly; |
| 132 | static unsigned int d_hash_shift __read_mostly; | 101 | static unsigned int d_hash_shift __read_mostly; |
| @@ -137,8 +106,8 @@ static inline struct hlist_bl_head *d_hash(const struct dentry *parent, | |||
| 137 | unsigned int hash) | 106 | unsigned int hash) |
| 138 | { | 107 | { |
| 139 | hash += (unsigned long) parent / L1_CACHE_BYTES; | 108 | hash += (unsigned long) parent / L1_CACHE_BYTES; |
| 140 | hash = hash + (hash >> D_HASHBITS); | 109 | hash = hash + (hash >> d_hash_shift); |
| 141 | return dentry_hashtable + (hash & D_HASHMASK); | 110 | return dentry_hashtable + (hash & d_hash_mask); |
| 142 | } | 111 | } |
| 143 | 112 | ||
| 144 | /* Statistics gathering. */ | 113 | /* Statistics gathering. */ |
| @@ -223,7 +192,7 @@ static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char | |||
| 223 | if (!tcount) | 192 | if (!tcount) |
| 224 | return 0; | 193 | return 0; |
| 225 | } | 194 | } |
| 226 | mask = ~(~0ul << tcount*8); | 195 | mask = bytemask_from_count(tcount); |
| 227 | return unlikely(!!((a ^ b) & mask)); | 196 | return unlikely(!!((a ^ b) & mask)); |
| 228 | } | 197 | } |
| 229 | 198 | ||
| @@ -469,7 +438,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) | |||
| 469 | { | 438 | { |
| 470 | list_del(&dentry->d_u.d_child); | 439 | list_del(&dentry->d_u.d_child); |
| 471 | /* | 440 | /* |
| 472 | * Inform try_to_ascend() that we are no longer attached to the | 441 | * Inform d_walk() that we are no longer attached to the |
| 473 | * dentry tree | 442 | * dentry tree |
| 474 | */ | 443 | */ |
| 475 | dentry->d_flags |= DCACHE_DENTRY_KILLED; | 444 | dentry->d_flags |= DCACHE_DENTRY_KILLED; |
| @@ -1069,34 +1038,6 @@ void shrink_dcache_sb(struct super_block *sb) | |||
| 1069 | } | 1038 | } |
| 1070 | EXPORT_SYMBOL(shrink_dcache_sb); | 1039 | EXPORT_SYMBOL(shrink_dcache_sb); |
| 1071 | 1040 | ||
| 1072 | /* | ||
| 1073 | * This tries to ascend one level of parenthood, but | ||
| 1074 | * we can race with renaming, so we need to re-check | ||
| 1075 | * the parenthood after dropping the lock and check | ||
| 1076 | * that the sequence number still matches. | ||
| 1077 | */ | ||
| 1078 | static struct dentry *try_to_ascend(struct dentry *old, unsigned seq) | ||
| 1079 | { | ||
| 1080 | struct dentry *new = old->d_parent; | ||
| 1081 | |||
| 1082 | rcu_read_lock(); | ||
| 1083 | spin_unlock(&old->d_lock); | ||
| 1084 | spin_lock(&new->d_lock); | ||
| 1085 | |||
| 1086 | /* | ||
| 1087 | * might go back up the wrong parent if we have had a rename | ||
| 1088 | * or deletion | ||
| 1089 | */ | ||
| 1090 | if (new != old->d_parent || | ||
| 1091 | (old->d_flags & DCACHE_DENTRY_KILLED) || | ||
| 1092 | need_seqretry(&rename_lock, seq)) { | ||
| 1093 | spin_unlock(&new->d_lock); | ||
| 1094 | new = NULL; | ||
| 1095 | } | ||
| 1096 | rcu_read_unlock(); | ||
| 1097 | return new; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | /** | 1041 | /** |
| 1101 | * enum d_walk_ret - action to talke during tree walk | 1042 | * enum d_walk_ret - action to talke during tree walk |
| 1102 | * @D_WALK_CONTINUE: contrinue walk | 1043 | * @D_WALK_CONTINUE: contrinue walk |
| @@ -1185,9 +1126,24 @@ resume: | |||
| 1185 | */ | 1126 | */ |
| 1186 | if (this_parent != parent) { | 1127 | if (this_parent != parent) { |
| 1187 | struct dentry *child = this_parent; | 1128 | struct dentry *child = this_parent; |
| 1188 | this_parent = try_to_ascend(this_parent, seq); | 1129 | this_parent = child->d_parent; |
| 1189 | if (!this_parent) | 1130 | |
| 1131 | rcu_read_lock(); | ||
| 1132 | spin_unlock(&child->d_lock); | ||
| 1133 | spin_lock(&this_parent->d_lock); | ||
| 1134 | |||
| 1135 | /* | ||
| 1136 | * might go back up the wrong parent if we have had a rename | ||
| 1137 | * or deletion | ||
| 1138 | */ | ||
| 1139 | if (this_parent != child->d_parent || | ||
| 1140 | (child->d_flags & DCACHE_DENTRY_KILLED) || | ||
| 1141 | need_seqretry(&rename_lock, seq)) { | ||
| 1142 | spin_unlock(&this_parent->d_lock); | ||
| 1143 | rcu_read_unlock(); | ||
| 1190 | goto rename_retry; | 1144 | goto rename_retry; |
| 1145 | } | ||
| 1146 | rcu_read_unlock(); | ||
| 1191 | next = child->d_u.d_child.next; | 1147 | next = child->d_u.d_child.next; |
| 1192 | goto resume; | 1148 | goto resume; |
| 1193 | } | 1149 | } |
