[PATCH 29/76] union-mount: Free union stack on removal of topmost dentry from dcache
From: David Howells <dhowells@redhat.com>
Date: 2011-06-17 16:04:53
Subsystem:
filesystems (vfs and infrastructure), the rest · Maintainers:
Alexander Viro, Christian Brauner, Linus Torvalds
From: Jan Blunck <redacted> If a dentry is removed from dentry cache because its usage count drops to zero, its union stack is freed too. --- fs/dcache.c | 11 +++++++++++ fs/namespace.c | 2 ++ 2 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 05b0a8b..4848d8b 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c@@ -37,6 +37,7 @@ #include <linux/rculist_bl.h> #include <linux/prefetch.h> #include "internal.h" +#include "union.h" /* * Usage:
@@ -293,6 +294,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) if (parent) spin_unlock(&parent->d_lock); dentry_iput(dentry); + d_free_unions(dentry); /* * dentry_iput drops the locks, at which point nobody (except * transient RCU lookups) can reach this dentry.
@@ -949,6 +951,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) iput(inode); } + d_free_unions(dentry); d_free(dentry); /* finished when we fall off the top of the tree,
@@ -2059,6 +2062,7 @@ again: } dentry->d_flags &= ~DCACHE_CANT_MOUNT; dentry_unlink_inode(dentry); + d_free_unions(dentry); fsnotify_nameremove(dentry, isdir); return; }
@@ -2068,6 +2072,13 @@ again: spin_unlock(&dentry->d_lock); + /* + * Remove any associated unions. While someone still has this + * directory open (ref count > 0), we could not have deleted + * it unless it was empty, and therefore has no references to + * directories below it. So we don't need the unions. + */ + d_free_unions(dentry); fsnotify_nameremove(dentry, isdir); } EXPORT_SYMBOL(d_delete);
diff --git a/fs/namespace.c b/fs/namespace.c
index 06819db..dbb32f4 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c@@ -35,6 +35,7 @@ #include <asm/unistd.h> #include "pnode.h" #include "internal.h" +#include "union.h" #define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) #define HASH_SIZE (1UL << HASH_SHIFT)
@@ -1284,6 +1285,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) propagate_umount(&tmp_list); list_for_each_entry(p, &tmp_list, mnt_hash) { + d_free_unions(p->mnt_root); list_del_init(&p->mnt_expire); list_del_init(&p->mnt_list); __touch_mnt_namespace(p->mnt_ns);