[PATCH 21/73] union-mount: Create union_stack structure [ver #2]

From: David Howells
Date: Tue Feb 21 2012 - 14:59:29 EST


From: Valerie Aurora <vaurora@xxxxxxxxxx>

struct union_stack records the stack of directories unioned at this
directory. A union_stack is an array of struct paths, dynamically
allocated when the dentry for the topmost directory is created. The
topmost dentry contains a pointer to the union_stack.

Signed-off-by: Valerie Aurora <vaurora@xxxxxxxxxx>
Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
---

fs/dcache.c | 3 +++
fs/union.h | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/dcache.h | 25 ++++++++++++++++++++++-
3 files changed, 80 insertions(+), 1 deletions(-)
create mode 100644 fs/union.h

diff --git a/fs/dcache.c b/fs/dcache.c
index 238684a..326a432 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1222,6 +1222,9 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
dentry->d_sb = sb;
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
+#ifdef CONFIG_UNION_MOUNT
+ dentry->d_union_stack = NULL;
+#endif
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
diff --git a/fs/union.h b/fs/union.h
new file mode 100644
index 0000000..d42dc09
--- /dev/null
+++ b/fs/union.h
@@ -0,0 +1,53 @@
+/*
+ * VFS-based union mounts for Linux
+ *
+ * Copyright (C) 2004-2007 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2007-2009 Novell Inc.
+ * Copyright (C) 2009-2010 Red Hat, Inc.
+ *
+ * Author(s): Jan Blunck (j.blunck@xxxxxxxxxxxxx)
+ * Valerie Aurora <vaurora@xxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifdef CONFIG_UNION_MOUNT
+
+#include <linux/mount.h>
+#include <linux/dcache.h>
+#include <linux/path.h>
+
+/*
+ * WARNING! Confusing terminology alert.
+ *
+ * Note that the directions "up" and "down" in union mounts are the
+ * opposite of "up" and "down" in normal VFS operation terminology.
+ * "up" in the rest of the VFS means "towards the root of the mount
+ * tree." If you mount B on top of A, following B "up" will get you
+ * A. In union mounts, "up" means "towards the most recently mounted
+ * layer of the union stack." If you union mount B on top of A,
+ * following A "up" will get you to B. Another way to put it is that
+ * "up" in the VFS means going from this mount towards the direction
+ * of its mnt->mnt_parent pointer, but "up" in union mounts means
+ * going in the opposite direction (until you run out of union
+ * layers).
+ */
+
+/*
+ * The union_stack structure. It is an array of struct paths of
+ * directories below the topmost directory in a unioned directory, The
+ * topmost dentry has a pointer to this structure. The topmost dentry
+ * can only be part of one union, so we can reference it from the
+ * dentry, but lower dentries can be part of multiple union stacks.
+ *
+ * The number of dirs actually allocated is kept in the superblock,
+ * s_union_count.
+ */
+struct union_stack {
+ struct path u_dirs[0];
+};
+
+#endif /* CONFIG_UNION_MOUNT */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index cc0181b..e2d44e1 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -102,16 +102,36 @@ full_name_hash(const unsigned char *name, unsigned int len)
* Try to keep struct dentry aligned on 64 byte cachelines (this will
* give reasonable cacheline footprint with larger lines without the
* large memory footprint increase).
+ *
+ * XXX DNAME_INLINE_LEN_MIN is kind of pitiful on 64bit + union
+ * mounts. May be worth tuning up, but either we go to 256 bytes and
+ * a wasteful 88 bytes of d_iname, or we lose 64-byte aligment.
*/
#ifdef CONFIG_64BIT
+
+#ifdef CONFIG_UNION_MOUNT
+# define DNAME_INLINE_LEN 24 /* 192 bytes */
+#else
# define DNAME_INLINE_LEN 32 /* 192 bytes */
+#endif /* CONFIG_UNION_MOUNT */
+
+#else
+
+#ifdef CONFIG_UNION_MOUNT
+# ifdef CONFIG_SMP
+# define DNAME_INLINE_LEN 32 /* 128 bytes */
+# else
+# define DNAME_INLINE_LEN 36 /* 128 bytes */
+# endif
#else
# ifdef CONFIG_SMP
# define DNAME_INLINE_LEN 36 /* 128 bytes */
# else
# define DNAME_INLINE_LEN 40 /* 128 bytes */
# endif
-#endif
+#endif /* CONFIG_UNION_MOUNT */
+
+#endif /* CONFIG_64BIT */

struct dentry {
/* RCU lookup touched fields */
@@ -132,6 +152,9 @@ struct dentry {
unsigned long d_time; /* used by d_revalidate */
void *d_fsdata; /* fs-specific data */

+#ifdef CONFIG_UNION_MOUNT
+ struct union_stack *d_union_stack; /* dirs in union stack */
+#endif
struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/