* [patch 0/5] union-directory implementation
@ 2009-05-21 9:22 Miklos Szeredi
2009-05-21 9:22 ` [patch 1/5] union-directory: Introduce MNT_UNION and MS_UNION flags Miklos Szeredi
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Miklos Szeredi @ 2009-05-21 9:22 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: jblunck, bharata, vaurora, viro
This patchset implements the simplest form of union mounts (called
union directories here). This is somewhat similar to Plan9 union
mounts. The patches are derived from Jan Blunck's work.
Also available from git:
git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git union-dir
Features:
- top level directory unification only
- no copy up
- no whiteouts, opaque dir, etc...
- create/rename/unlink only work on top layer
- write works on any layer (without copy up)
- directory entry deduplication in kernel
- supports directory seeking (that hell from POSIX)
Shortcomings:
- directory reading is O(n^2), needs optimization
- weird create/unlink semantics due to ignoring union
I'm posting these patches in a hope that
a) they may be useful on their own (after further development),
b) they may help with the full fledged union-mount implementation
Comments?
Thanks,
Miklos
--
Jan Blunck (5):
union-directory: Introduce MNT_UNION and MS_UNION flags
union-directory: Support for traversing the layers of a union-directory
union-directory: Some checks during namespace changes
union-directory: Make lookup continue in overlayed directories
union-directory: Simple union-mount readdir implementation
---
fs/Kconfig | 8 ++
fs/Makefile | 2 +
fs/file_table.c | 1 +
fs/namei.c | 49 +++++++++++
fs/namespace.c | 25 +++++-
fs/readdir.c | 21 +++--
fs/union.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++
fs/union.h | 26 ++++++
include/linux/fs.h | 18 ++++
include/linux/mount.h | 1 +
10 files changed, 369 insertions(+), 11 deletions(-)
create mode 100644 fs/union.c
create mode 100644 fs/union.h
^ permalink raw reply [flat|nested] 7+ messages in thread
* [patch 1/5] union-directory: Introduce MNT_UNION and MS_UNION flags
2009-05-21 9:22 [patch 0/5] union-directory implementation Miklos Szeredi
@ 2009-05-21 9:22 ` Miklos Szeredi
2009-05-21 9:22 ` [patch 2/5] union-directory: Support for traversing the layers of a union-directory Miklos Szeredi
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Miklos Szeredi @ 2009-05-21 9:22 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: jblunck, bharata, vaurora, viro
[-- Attachment #1: union-mount-mount_flag.diff --]
[-- Type: text/plain, Size: 2694 bytes --]
From: Jan Blunck <jblunck@suse.de>
Add per mountpoint flag for Union Mount support. You need additional patches
to util-linux for that to work (ftp.suse.com/pub/people/jblunck/union-mount).
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
fs/namespace.c | 5 ++++-
include/linux/fs.h | 1 +
include/linux/mount.h | 1 +
3 files changed, 6 insertions(+), 1 deletion(-)
Index: linux-2.6/fs/namespace.c
===================================================================
--- linux-2.6.orig/fs/namespace.c 2009-05-20 15:05:15.000000000 +0200
+++ linux-2.6/fs/namespace.c 2009-05-20 15:07:46.000000000 +0200
@@ -796,6 +796,7 @@ static void show_mnt_opts(struct seq_fil
{ MNT_NODIRATIME, ",nodiratime" },
{ MNT_RELATIME, ",relatime" },
{ MNT_STRICTATIME, ",strictatime" },
+ { MNT_UNION, ",union" },
{ 0, NULL }
};
const struct proc_fs_info *fs_infop;
@@ -1952,10 +1953,12 @@ long do_mount(char *dev_name, char *dir_
mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
if (flags & MS_RDONLY)
mnt_flags |= MNT_READONLY;
+ if (flags & MS_UNION)
+ mnt_flags |= MNT_UNION;
flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT |
- MS_STRICTATIME);
+ MS_STRICTATIME | MS_UNION);
/* ... and get the mountpoint */
retval = kern_path(dir_name, LOOKUP_FOLLOW, &path);
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h 2009-05-20 15:05:15.000000000 +0200
+++ linux-2.6/include/linux/fs.h 2009-05-20 15:07:46.000000000 +0200
@@ -188,6 +188,7 @@ struct inodes_stat_t {
#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
+#define MS_UNION 256
#define MS_NOATIME 1024 /* Do not update access times. */
#define MS_NODIRATIME 2048 /* Do not update directory access times */
#define MS_BIND 4096
Index: linux-2.6/include/linux/mount.h
===================================================================
--- linux-2.6.orig/include/linux/mount.h 2009-05-20 15:05:15.000000000 +0200
+++ linux-2.6/include/linux/mount.h 2009-05-20 15:07:46.000000000 +0200
@@ -35,6 +35,7 @@ struct mnt_namespace;
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
#define MNT_PNODE_MASK 0x3000 /* propagation flag mask */
+#define MNT_UNION 0x4000 /* if the vfsmount is a union mount */
struct vfsmount {
struct list_head mnt_hash;
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [patch 2/5] union-directory: Support for traversing the layers of a union-directory
2009-05-21 9:22 [patch 0/5] union-directory implementation Miklos Szeredi
2009-05-21 9:22 ` [patch 1/5] union-directory: Introduce MNT_UNION and MS_UNION flags Miklos Szeredi
@ 2009-05-21 9:22 ` Miklos Szeredi
2009-05-21 9:22 ` [patch 3/5] union-directory: Some checks during namespace changes Miklos Szeredi
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Miklos Szeredi @ 2009-05-21 9:22 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: jblunck, bharata, vaurora, viro
[-- Attachment #1: union-directory-stack.diff --]
[-- Type: text/plain, Size: 3897 bytes --]
From: Jan Blunck <jblunck@suse.de>
This adds follow_union_up() to travers from one layer to the next overlayed
mountpoint if given an union mounted mountpoint. This is basically the invert
of what follow_mount() is doing.
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
fs/Kconfig | 8 ++++++++
fs/Makefile | 2 ++
fs/union.c | 34 ++++++++++++++++++++++++++++++++++
fs/union.h | 25 +++++++++++++++++++++++++
4 files changed, 69 insertions(+)
Index: linux-2.6/fs/Kconfig
===================================================================
--- linux-2.6.orig/fs/Kconfig 2009-05-20 15:05:15.000000000 +0200
+++ linux-2.6/fs/Kconfig 2009-05-20 15:09:52.000000000 +0200
@@ -62,6 +62,14 @@ source "fs/autofs/Kconfig"
source "fs/autofs4/Kconfig"
source "fs/fuse/Kconfig"
+config UNION_MOUNT
+ bool "Union mount support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ If you say Y here, you will be able to mount file systems as
+ union mount stacks. This is a VFS based implementation and
+ should work with all file systems. If unsure, say N.
+
config GENERIC_ACL
bool
select FS_POSIX_ACL
Index: linux-2.6/fs/Makefile
===================================================================
--- linux-2.6.orig/fs/Makefile 2009-05-20 15:05:15.000000000 +0200
+++ linux-2.6/fs/Makefile 2009-05-20 15:09:52.000000000 +0200
@@ -51,6 +51,8 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.
obj-$(CONFIG_NFS_COMMON) += nfs_common/
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
+obj-$(CONFIG_UNION_MOUNT) += union.o
+
obj-y += quota/
obj-$(CONFIG_PROC_FS) += proc/
Index: linux-2.6/fs/union.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/fs/union.c 2009-05-20 15:09:52.000000000 +0200
@@ -0,0 +1,34 @@
+/*
+ * VFS based union mount for Linux
+ *
+ * Copyright (C) 2004-2007 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2007 Novell Inc.
+ *
+ * Author(s): Jan Blunck (j.blunck@tu-harburg.de)
+ *
+ * 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; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include "union.h"
+
+/*
+ * follow_union_up - follow the union stack one layer "up"
+ *
+ * This is called to traverse the union stack from one layer to the next
+ * overlayed one. follow_union_up() is called by various lookup functions
+ * that are aware of union mounts.
+ *
+ * Returns non zero if followed to the next layer, zero otherwise.
+ */
+int follow_union_up(struct path *path)
+{
+ if (IS_MNT_UNION(path->mnt) && path->dentry == path->mnt->mnt_root)
+ return follow_up(&path->mnt, &path->dentry);
+
+ return 0;
+}
Index: linux-2.6/fs/union.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/fs/union.h 2009-05-20 15:09:52.000000000 +0200
@@ -0,0 +1,25 @@
+/*
+ * VFS based union mount for Linux
+ *
+ * Copyright (C) 2004-2007 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright (C) 2007 Novell Inc.
+ * Author(s): Jan Blunck (j.blunck@tu-harburg.de)
+ *
+ * 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; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <linux/mount.h>
+
+struct path;
+
+extern int follow_union_up(struct path *path);
+
+#ifdef CONFIG_UNION_MOUNT
+#define IS_MNT_UNION(mnt) ((mnt)->mnt_flags & MNT_UNION)
+#else
+#define IS_MNT_UNION(x) (0)
+#endif
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [patch 3/5] union-directory: Some checks during namespace changes
2009-05-21 9:22 [patch 0/5] union-directory implementation Miklos Szeredi
2009-05-21 9:22 ` [patch 1/5] union-directory: Introduce MNT_UNION and MS_UNION flags Miklos Szeredi
2009-05-21 9:22 ` [patch 2/5] union-directory: Support for traversing the layers of a union-directory Miklos Szeredi
@ 2009-05-21 9:22 ` Miklos Szeredi
2009-05-21 9:22 ` [patch 4/5] union-directory: Make lookup continue in overlayed directories Miklos Szeredi
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Miklos Szeredi @ 2009-05-21 9:22 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: jblunck, bharata, vaurora, viro
[-- Attachment #1: union-directory-mount.diff --]
[-- Type: text/plain, Size: 2515 bytes --]
From: Jan Blunck <jblunck@suse.de>
Add some additional checks when mounting something into an union.
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
fs/namespace.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
Index: linux-2.6/fs/namespace.c
===================================================================
--- linux-2.6.orig/fs/namespace.c 2009-05-20 15:07:46.000000000 +0200
+++ linux-2.6/fs/namespace.c 2009-05-20 15:10:05.000000000 +0200
@@ -32,6 +32,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)
@@ -1456,6 +1457,10 @@ static int do_change_type(struct path *p
if (path->dentry != path->mnt->mnt_root)
return -EINVAL;
+ /* Don't change the type of union mounts */
+ if (IS_MNT_UNION(path->mnt))
+ return -EINVAL;
+
down_write(&namespace_sem);
if (type == MS_SHARED) {
err = invent_group_ids(mnt, recurse);
@@ -1477,7 +1482,7 @@ static int do_change_type(struct path *p
* do loopback mount.
*/
static int do_loopback(struct path *path, char *old_name,
- int recurse)
+ int recurse, int mnt_flags)
{
struct path old_path;
struct vfsmount *mnt = NULL;
@@ -1507,6 +1512,9 @@ static int do_loopback(struct path *path
if (!mnt)
goto out;
+ if (mnt_flags & MNT_UNION)
+ mnt->mnt_flags |= MNT_UNION;
+
err = graft_tree(mnt, path);
if (err) {
LIST_HEAD(umount_list);
@@ -1600,6 +1608,13 @@ static int do_move_mount(struct path *pa
if (err)
return err;
+ /* moving to or from a union mount is not supported */
+ err = -EINVAL;
+ if (IS_MNT_UNION(path->mnt))
+ goto exit;
+ if (IS_MNT_UNION(old_path.mnt))
+ goto exit;
+
down_write(&namespace_sem);
while (d_mountpoint(path->dentry) &&
follow_down(&path->mnt, &path->dentry))
@@ -1657,6 +1672,7 @@ out:
up_write(&namespace_sem);
if (!err)
path_put(&parent_path);
+exit:
path_put(&old_path);
return err;
}
@@ -1974,7 +1990,7 @@ long do_mount(char *dev_name, char *dir_
retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags,
data_page);
else if (flags & MS_BIND)
- retval = do_loopback(&path, dev_name, flags & MS_REC);
+ retval = do_loopback(&path, dev_name, flags & MS_REC, mnt_flags);
else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
retval = do_change_type(&path, flags);
else if (flags & MS_MOVE)
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [patch 4/5] union-directory: Make lookup continue in overlayed directories
2009-05-21 9:22 [patch 0/5] union-directory implementation Miklos Szeredi
` (2 preceding siblings ...)
2009-05-21 9:22 ` [patch 3/5] union-directory: Some checks during namespace changes Miklos Szeredi
@ 2009-05-21 9:22 ` Miklos Szeredi
2009-05-21 9:22 ` [patch 5/5] union-directory: Simple union-mount readdir implementation Miklos Szeredi
2009-05-21 9:56 ` [patch 0/5] union-directory implementation Miklos Szeredi
5 siblings, 0 replies; 7+ messages in thread
From: Miklos Szeredi @ 2009-05-21 9:22 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: jblunck, bharata, vaurora, viro
[-- Attachment #1: union-directory-lookup.diff --]
[-- Type: text/plain, Size: 2450 bytes --]
From: Jan Blunck <jblunck@suse.de>
This patch lets adds support for union-directory lookup to lookups from dentry
cache and real lookups. On union-directories a lookup must continue on
overlayed directories of the union. The lookup continues until the first
no-negative dentry is found. Otherwise the topmost negative dentry is
returned.
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
fs/namei.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
Index: linux-2.6/fs/namei.c
===================================================================
--- linux-2.6.orig/fs/namei.c 2009-05-20 15:05:15.000000000 +0200
+++ linux-2.6/fs/namei.c 2009-05-20 15:10:09.000000000 +0200
@@ -34,6 +34,7 @@
#include <linux/device_cgroup.h>
#include <linux/fs_struct.h>
#include <asm/uaccess.h>
+#include "union.h"
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
@@ -778,6 +779,49 @@ static __always_inline void follow_dotdo
follow_mount(&nd->path.mnt, &nd->path.dentry);
}
+static int do_lookup_union(struct nameidata *nd, struct qstr *name,
+ struct path *path)
+{
+ int err;
+ struct path save;
+
+ save = nd->path;
+ path_get(&save);
+ while (follow_union_up(&nd->path)) {
+ struct dentry *dentry;
+
+ dentry = d_hash_and_lookup(nd->path.dentry, name);
+ if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
+ dentry = do_revalidate(dentry, nd);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out;
+ }
+ if (!dentry) {
+ dentry = real_lookup(nd->path.dentry, name, nd);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out;
+ }
+ if (dentry->d_inode) {
+ dput(path->dentry);
+ path->dentry = dentry;
+ path->mnt = mntget(nd->path.mnt);
+ follow_mount(&path->mnt, &path->dentry);
+ err = 0;
+ goto out;
+ }
+ dput(dentry);
+ }
+ __follow_mount(path);
+ err = 0;
+out:
+ path_put(&nd->path);
+ nd->path = save;
+
+ return err;
+}
+
/*
* It's more convoluted than I'd like it to be, but... it's still fairly
* small and for now I'd prefer to have fast path as straight as possible.
@@ -796,6 +840,11 @@ static int do_lookup(struct nameidata *n
done:
path->mnt = mnt;
path->dentry = dentry;
+ if (IS_MNT_UNION(mnt) && !dentry->d_inode &&
+ nd->path.dentry == nd->path.mnt->mnt_root) {
+ return do_lookup_union(nd, name, path);
+ }
+
__follow_mount(path);
return 0;
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* [patch 5/5] union-directory: Simple union-mount readdir implementation
2009-05-21 9:22 [patch 0/5] union-directory implementation Miklos Szeredi
` (3 preceding siblings ...)
2009-05-21 9:22 ` [patch 4/5] union-directory: Make lookup continue in overlayed directories Miklos Szeredi
@ 2009-05-21 9:22 ` Miklos Szeredi
2009-05-21 9:56 ` [patch 0/5] union-directory implementation Miklos Szeredi
5 siblings, 0 replies; 7+ messages in thread
From: Miklos Szeredi @ 2009-05-21 9:22 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel
Cc: jblunck, bharata, vaurora, viro, Bharata B Rao
[-- Attachment #1: union-directory-readdir.diff --]
[-- Type: text/plain, Size: 8642 bytes --]
From: Jan Blunck <jblunck@suse.de>
This is a very simple union mount readdir implementation. It modifies
the readdir routine to merge the entries of union mounted directories
and eliminate duplicates while walking the union stack. All
filesystem types are supported.
There can be multiple calls to readdir/getdents routines for reading
the entries of a single directory, the union directory cache is
maitained across these calls. The cache is stored in the struct file.
The cache is cleared on final fput() and when the file is rewound to
the zero position.
This implementation supports seeking in the directory. A simple
counter is used as offset in the cached list of entries.
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: Bharata B Rao <bharata@linux.vnet.ibm.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
fs/file_table.c | 1
fs/readdir.c | 21 +++--
fs/union.c | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/union.h | 1
include/linux/fs.h | 17 ++++
5 files changed, 227 insertions(+), 8 deletions(-)
Index: linux-2.6/fs/readdir.c
===================================================================
--- linux-2.6.orig/fs/readdir.c 2009-05-20 18:15:58.000000000 +0200
+++ linux-2.6/fs/readdir.c 2009-05-20 18:16:26.000000000 +0200
@@ -18,6 +18,7 @@
#include <linux/unistd.h>
#include <asm/uaccess.h>
+#include "union.h"
int vfs_readdir(struct file *file, filldir_t filler, void *buf)
{
@@ -30,16 +31,20 @@ int vfs_readdir(struct file *file, filld
if (res)
goto out;
- res = mutex_lock_killable(&inode->i_mutex);
- if (res)
- goto out;
+ if (IS_MNT_UNION(file->f_path.mnt)) {
+ res = readdir_union(file, buf, filler);
+ } else {
+ res = mutex_lock_killable(&inode->i_mutex);
+ if (res)
+ goto out;
- res = -ENOENT;
- if (!IS_DEADDIR(inode)) {
- res = file->f_op->readdir(file, buf, filler);
- file_accessed(file);
+ res = -ENOENT;
+ if (!IS_DEADDIR(inode)) {
+ res = file->f_op->readdir(file, buf, filler);
+ file_accessed(file);
+ }
+ mutex_unlock(&inode->i_mutex);
}
- mutex_unlock(&inode->i_mutex);
out:
return res;
}
Index: linux-2.6/fs/union.c
===================================================================
--- linux-2.6.orig/fs/union.c 2009-05-20 18:16:26.000000000 +0200
+++ linux-2.6/fs/union.c 2009-05-20 19:51:29.000000000 +0200
@@ -14,6 +14,9 @@
#include <linux/fs.h>
#include <linux/namei.h>
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/sched.h>
#include "union.h"
/*
@@ -32,3 +35,195 @@ int follow_union_up(struct path *path)
return 0;
}
+
+
+/*
+ * Union mounts support for readdir.
+ */
+
+/* The readdir union cache object */
+struct union_cache_entry {
+ struct union_cache_entry *next;
+ struct qstr name;
+ unsigned int type;
+ u64 ino;
+};
+
+struct union_cache_callback {
+ struct union_cache_entry *list; /* head of list */
+ struct union_cache_entry **endp; /* pointer to tail of list */
+ int count;
+};
+
+static int union_cache_add_entry(struct union_cache_callback *cb,
+ const char *name, int namelen, u64 ino,
+ unsigned int d_type)
+{
+ struct union_cache_entry *p;
+
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->name.name = kstrndup(name, namelen, GFP_KERNEL);
+ if (!p->name.name) {
+ kfree(p);
+ return -ENOMEM;
+ }
+ p->name.len = namelen;
+ p->name.hash = 0;
+ p->type = d_type;
+ p->ino = ino;
+ p->next = NULL;
+ *cb->endp = p;
+ cb->endp = &p->next;
+
+ return 0;
+}
+
+void __union_cache_free(struct union_cache_entry *p)
+{
+ while (p) {
+ struct union_cache_entry *next = p->next;
+
+ kfree(p->name.name);
+ kfree(p);
+ p = next;
+ }
+}
+
+static int union_cache_find_entry(struct union_cache_entry *start,
+ const char *name, int namelen)
+{
+ struct union_cache_entry *p;
+ int ret = 0;
+
+ for (p = start; p; p = p->next) {
+ if (p->name.len != namelen)
+ continue;
+ if (strncmp(p->name.name, name, namelen) == 0) {
+ ret = 1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int union_filldir(void *buf, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
+{
+ struct union_cache_callback *cb = buf;
+
+ cb->count++;
+ if (!union_cache_find_entry(cb->list, name, namlen))
+ union_cache_add_entry(cb, name, namlen, ino, d_type);
+
+ return 0;
+}
+
+static int read_union_cache(struct file *file, struct union_cache_callback *cb)
+{
+ struct inode *inode;
+ struct path path;
+ int res;
+
+ cb->list = NULL;
+ cb->endp = &cb->list;
+
+ path = file->f_path;
+ path_get(&path);
+ do {
+ struct file *ftmp;
+
+ path_get(&path);
+ ftmp = dentry_open(path.dentry, path.mnt,
+ O_RDONLY | O_DIRECTORY, current_cred());
+ if (IS_ERR(ftmp)) {
+ res = PTR_ERR(ftmp);
+ break;
+ }
+
+ inode = path.dentry->d_inode;
+ mutex_lock(&inode->i_mutex);
+
+ res = -ENOENT;
+ if (!IS_DEADDIR(inode)) {
+ do {
+ cb->count = 0;
+ res = ftmp->f_op->readdir(ftmp, cb,
+ union_filldir);
+ } while (res >= 0 && cb->count);
+ if (res > 0)
+ res = 0;
+
+ file_accessed(ftmp);
+ }
+
+ mutex_unlock(&inode->i_mutex);
+ fput(ftmp);
+ } while (!res && follow_union_up(&path));
+ path_put(&path);
+
+ return res;
+}
+
+/*
+ * readdir_union - A wrapper around ->readdir()
+ *
+ * This is a wrapper around the filesystems readdir(), which is walking
+ * the union stack and calls ->readdir() for every directory in the stack.
+ * The directory entries are read into the union mounts readdir cache to
+ * support duplicate removal.
+ */
+int readdir_union(struct file *file, void *buf, filldir_t filler)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct union_cache_entry *p;
+ loff_t off;
+ int res = 0;
+
+ mutex_lock(&inode->i_mutex);
+ if (!file->f_pos && file->f_union_cache) {
+ __union_cache_free(file->f_union_cache);
+ file->f_union_cache = NULL;
+ }
+
+ if (!file->f_union_cache) {
+ struct union_cache_callback cb;
+
+ mutex_unlock(&inode->i_mutex);
+
+ res = read_union_cache(file, &cb);
+ if (res)
+ return res;
+
+ mutex_lock(&inode->i_mutex);
+
+ if (file->f_union_cache) {
+ /* Somebody else managed to fill it before us */
+ __union_cache_free(cb.list);
+ } else {
+ file->f_union_cache = cb.list;
+ }
+ }
+
+ off = 0;
+ for (p = file->f_union_cache; p; p = p->next) {
+ int over;
+
+ off++;
+ if (off <= file->f_pos)
+ continue;
+
+ over = filler(buf, p->name.name, p->name.len, off - 1,
+ p->ino, p->type);
+ if (over)
+ break;
+
+ file->f_pos = off;
+ }
+ mutex_unlock(&inode->i_mutex);
+
+ return res;
+}
Index: linux-2.6/fs/union.h
===================================================================
--- linux-2.6.orig/fs/union.h 2009-05-20 18:16:26.000000000 +0200
+++ linux-2.6/fs/union.h 2009-05-20 18:16:26.000000000 +0200
@@ -17,6 +17,7 @@
struct path;
extern int follow_union_up(struct path *path);
+extern int readdir_union(struct file *file, void *buf, filldir_t filler);
#ifdef CONFIG_UNION_MOUNT
#define IS_MNT_UNION(mnt) ((mnt)->mnt_flags & MNT_UNION)
Index: linux-2.6/fs/file_table.c
===================================================================
--- linux-2.6.orig/fs/file_table.c 2009-05-20 14:11:58.000000000 +0200
+++ linux-2.6/fs/file_table.c 2009-05-20 19:17:09.000000000 +0200
@@ -280,6 +280,7 @@ void __fput(struct file *file)
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
+ union_cache_free(file);
ima_file_free(file);
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h 2009-05-20 18:16:26.000000000 +0200
+++ linux-2.6/include/linux/fs.h 2009-05-20 19:19:38.000000000 +0200
@@ -934,6 +934,9 @@ struct file {
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
+#ifdef CONFIG_UNION_MOUNT
+ struct union_cache_entry *f_union_cache;
+#endif
};
extern spinlock_t files_lock;
#define file_list_lock() spin_lock(&files_lock);
@@ -985,6 +988,20 @@ static inline int file_check_writeable(s
}
#endif /* CONFIG_DEBUG_WRITECOUNT */
+#ifdef CONFIG_UNION_MOUNT
+extern void __union_cache_free(struct union_cache_entry *);
+
+static inline void union_cache_free(struct file *file)
+{
+ if (file->f_union_cache)
+ __union_cache_free(file->f_union_cache);
+}
+#else
+static inline void union_cache_free(struct file *file)
+{
+}
+#endif
+
#define MAX_NON_LFS ((1UL<<31) - 1)
/* Page cache limit. The filesystems should put that into their s_maxbytes
--
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [patch 0/5] union-directory implementation
2009-05-21 9:22 [patch 0/5] union-directory implementation Miklos Szeredi
` (4 preceding siblings ...)
2009-05-21 9:22 ` [patch 5/5] union-directory: Simple union-mount readdir implementation Miklos Szeredi
@ 2009-05-21 9:56 ` Miklos Szeredi
5 siblings, 0 replies; 7+ messages in thread
From: Miklos Szeredi @ 2009-05-21 9:56 UTC (permalink / raw)
To: linux-fsdevel, linux-kernel; +Cc: jblunck, bharata, vaurora, viro
On Thu, 21 May 2009, Miklos Szeredi wrote:
> Features:
>
> - top level directory unification only
> - no copy up
> - no whiteouts, opaque dir, etc...
> - create/rename/unlink only work on top layer
> - write works on any layer (without copy up)
> - directory entry deduplication in kernel
> - supports directory seeking (that hell from POSIX)
Forgot an important one:
- filesystem independent, any fs can be part of the union
Thanks,
Miklos
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-05-21 9:56 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-21 9:22 [patch 0/5] union-directory implementation Miklos Szeredi
2009-05-21 9:22 ` [patch 1/5] union-directory: Introduce MNT_UNION and MS_UNION flags Miklos Szeredi
2009-05-21 9:22 ` [patch 2/5] union-directory: Support for traversing the layers of a union-directory Miklos Szeredi
2009-05-21 9:22 ` [patch 3/5] union-directory: Some checks during namespace changes Miklos Szeredi
2009-05-21 9:22 ` [patch 4/5] union-directory: Make lookup continue in overlayed directories Miklos Szeredi
2009-05-21 9:22 ` [patch 5/5] union-directory: Simple union-mount readdir implementation Miklos Szeredi
2009-05-21 9:56 ` [patch 0/5] union-directory implementation Miklos Szeredi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).