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. --- fs/dcache.c | 3 +++ fs/union.h | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/dcache.h | 25 +++++++++++++++++++++- 3 files changed, 81 insertions(+), 1 deletions(-) create mode 100644 fs/union.h diff --git a/fs/dcache.c b/fs/dcache.c index 039a243..05b0a8b 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1300,6 +1300,9 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) INIT_LIST_HEAD(&dentry->d_subdirs); INIT_LIST_HEAD(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_u.d_child); +#ifdef CONFIG_UNION_MOUNT + dentry->d_union_stack = NULL; +#endif if (parent) { spin_lock(&parent->d_lock); diff --git a/fs/union.h b/fs/union.h new file mode 100644 index 0000000..38b26fd --- /dev/null +++ b/fs/union.h @@ -0,0 +1,54 @@ + /* + * 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. + */ +#ifndef __LINUX_UNION_H +#define __LINUX_UNION_H +#ifdef __KERNEL__ + +#ifdef CONFIG_UNION_MOUNT + +/* + * 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 */ +#endif /* __KERNEL__ */ +#endif /* __LINUX_UNION_H */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 1c4ad1b..eb8fbf8 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-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html