|
@@ -301,6 +301,27 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
|
|
|
return parent;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Unhash a dentry without inserting an RCU walk barrier or checking that
|
|
|
+ * dentry->d_lock is locked. The caller must take care of that, if
|
|
|
+ * appropriate.
|
|
|
+ */
|
|
|
+static void __d_shrink(struct dentry *dentry)
|
|
|
+{
|
|
|
+ if (!d_unhashed(dentry)) {
|
|
|
+ struct hlist_bl_head *b;
|
|
|
+ if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
|
|
|
+ b = &dentry->d_sb->s_anon;
|
|
|
+ else
|
|
|
+ b = d_hash(dentry->d_parent, dentry->d_name.hash);
|
|
|
+
|
|
|
+ hlist_bl_lock(b);
|
|
|
+ __hlist_bl_del(&dentry->d_hash);
|
|
|
+ dentry->d_hash.pprev = NULL;
|
|
|
+ hlist_bl_unlock(b);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* d_drop - drop a dentry
|
|
|
* @dentry: dentry to drop
|
|
@@ -319,17 +340,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
|
|
|
void __d_drop(struct dentry *dentry)
|
|
|
{
|
|
|
if (!d_unhashed(dentry)) {
|
|
|
- struct hlist_bl_head *b;
|
|
|
- if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED))
|
|
|
- b = &dentry->d_sb->s_anon;
|
|
|
- else
|
|
|
- b = d_hash(dentry->d_parent, dentry->d_name.hash);
|
|
|
-
|
|
|
- hlist_bl_lock(b);
|
|
|
- __hlist_bl_del(&dentry->d_hash);
|
|
|
- dentry->d_hash.pprev = NULL;
|
|
|
- hlist_bl_unlock(b);
|
|
|
-
|
|
|
+ __d_shrink(dentry);
|
|
|
dentry_rcuwalk_barrier(dentry);
|
|
|
}
|
|
|
}
|
|
@@ -828,44 +839,24 @@ EXPORT_SYMBOL(shrink_dcache_sb);
|
|
|
static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
|
|
|
{
|
|
|
struct dentry *parent;
|
|
|
- unsigned detached = 0;
|
|
|
|
|
|
BUG_ON(!IS_ROOT(dentry));
|
|
|
|
|
|
- /* detach this root from the system */
|
|
|
- spin_lock(&dentry->d_lock);
|
|
|
- dentry_lru_del(dentry);
|
|
|
- __d_drop(dentry);
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
-
|
|
|
for (;;) {
|
|
|
/* descend to the first leaf in the current subtree */
|
|
|
- while (!list_empty(&dentry->d_subdirs)) {
|
|
|
- struct dentry *loop;
|
|
|
-
|
|
|
- /* this is a branch with children - detach all of them
|
|
|
- * from the system in one go */
|
|
|
- spin_lock(&dentry->d_lock);
|
|
|
- list_for_each_entry(loop, &dentry->d_subdirs,
|
|
|
- d_u.d_child) {
|
|
|
- spin_lock_nested(&loop->d_lock,
|
|
|
- DENTRY_D_LOCK_NESTED);
|
|
|
- dentry_lru_del(loop);
|
|
|
- __d_drop(loop);
|
|
|
- spin_unlock(&loop->d_lock);
|
|
|
- }
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
-
|
|
|
- /* move to the first child */
|
|
|
+ while (!list_empty(&dentry->d_subdirs))
|
|
|
dentry = list_entry(dentry->d_subdirs.next,
|
|
|
struct dentry, d_u.d_child);
|
|
|
- }
|
|
|
|
|
|
/* consume the dentries from this leaf up through its parents
|
|
|
* until we find one with children or run out altogether */
|
|
|
do {
|
|
|
struct inode *inode;
|
|
|
|
|
|
+ /* detach from the system */
|
|
|
+ dentry_lru_del(dentry);
|
|
|
+ __d_shrink(dentry);
|
|
|
+
|
|
|
if (dentry->d_count != 0) {
|
|
|
printk(KERN_ERR
|
|
|
"BUG: Dentry %p{i=%lx,n=%s}"
|
|
@@ -886,14 +877,10 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
|
|
|
list_del(&dentry->d_u.d_child);
|
|
|
} else {
|
|
|
parent = dentry->d_parent;
|
|
|
- spin_lock(&parent->d_lock);
|
|
|
parent->d_count--;
|
|
|
list_del(&dentry->d_u.d_child);
|
|
|
- spin_unlock(&parent->d_lock);
|
|
|
}
|
|
|
|
|
|
- detached++;
|
|
|
-
|
|
|
inode = dentry->d_inode;
|
|
|
if (inode) {
|
|
|
dentry->d_inode = NULL;
|
|
@@ -938,9 +925,7 @@ void shrink_dcache_for_umount(struct super_block *sb)
|
|
|
|
|
|
dentry = sb->s_root;
|
|
|
sb->s_root = NULL;
|
|
|
- spin_lock(&dentry->d_lock);
|
|
|
dentry->d_count--;
|
|
|
- spin_unlock(&dentry->d_lock);
|
|
|
shrink_dcache_for_umount_subtree(dentry);
|
|
|
|
|
|
while (!hlist_bl_empty(&sb->s_anon)) {
|