All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Blunck <jblunck@suse.de>
To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org
Cc: viro@zeniv.linux.org.uk, bharata@in.ibm.com, dwmw2@infradead.org,
	mszeredi@suse.cz, vaurora@redhat.com
Subject: [PATCH 32/32] union-mount: Copy up directory entries on first readdir()
Date: Mon, 18 May 2009 18:09:28 +0200	[thread overview]
Message-ID: <1242662968-11684-33-git-send-email-jblunck@suse.de> (raw)
In-Reply-To: <1242662968-11684-1-git-send-email-jblunck@suse.de>

From: Valerie Aurora (Henson) <vaurora@redhat.com>

readdir() in union mounts is implemented by copying up all visible
directory entries from the lower level directories to the topmost
directory.  Directory entries that refer to lower level file system
objects are marked as "fallthru" in the topmost directory.

Signed-off-by: Valerie Aurora (Henson) <vaurora@redhat.com>
---
 fs/readdir.c          |   16 +++++
 fs/union.c            |  166 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/union.h |    2 +
 3 files changed, 184 insertions(+), 0 deletions(-)

diff --git a/fs/readdir.c b/fs/readdir.c
index 3a48491..903104a 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -16,6 +16,7 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/unistd.h>
+#include <linux/union.h>
 
 #include <asm/uaccess.h>
 
@@ -36,9 +37,24 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
 
 	res = -ENOENT;
 	if (!IS_DEADDIR(inode)) {
+		/*
+		 * XXX Think harder about locking for
+		 * union_copyup_dir.  Currently we lock the topmost
+		 * directory and hold that lock while sequentially
+		 * acquiring and dropping locks for the directories
+		 * below this one in the union stack.
+		 */
+		if (is_unionized(file->f_path.dentry, file->f_path.mnt) &&
+		    !IS_OPAQUE(inode)) {
+			res = union_copyup_dir(&file->f_path);
+			if (res)
+				goto out_unlock;
+		}
+
 		res = file->f_op->readdir(file, buf, filler);
 		file_accessed(file);
 	}
+out_unlock:
 	mutex_unlock(&inode->i_mutex);
 out:
 	return res;
diff --git a/fs/union.c b/fs/union.c
index d21fe5f..0c3c000 100644
--- a/fs/union.c
+++ b/fs/union.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2007-2009 Novell Inc.
  *
  *   Author(s): Jan Blunck (j.blunck@tu-harburg.de)
+ *              Valerie Aurora <vaurora@redhat.com>
  *
  * 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
@@ -780,3 +781,168 @@ void detach_mnt_union(struct vfsmount *mnt)
 	union_put(um);
 	return;
 }
+
+/**
+ * union_copyup_dir_one - copy up a single directory entry
+ *
+ * Individual directory entry copyup function for union_copyup_dir.
+ * We get the entries from higher level layers first.
+ */
+
+static int union_copyup_dir_one(void *buf, const char *name, int namlen,
+				loff_t offset, u64 ino, unsigned int d_type)
+{
+	struct dentry *topmost_dentry = (struct dentry *) buf;
+	struct dentry *dentry;
+	int err = 0;
+
+	switch (namlen) {
+	case 2:
+		if (name[1] != '.')
+			break;
+	case 1:
+		if (name[0] != '.')
+			break;
+		return 0;
+	}
+
+	/* Lookup this entry in the topmost directory */
+	dentry = lookup_one_len(name, topmost_dentry, namlen);
+
+	if (IS_ERR(dentry)) {
+		printk(KERN_INFO "error looking up %s\n", dentry->d_name.name);
+		goto out;
+	}
+
+	/*
+	 * If the entry already exists, one of the following is true:
+	 * it was already copied up (due to an earlier lookup), an
+	 * entry with the same name already exists on the topmost file
+	 * system, it is a whiteout, or it is a fallthru.  In each
+	 * case, the top level entry masks any entries from lower file
+	 * systems, so don't copy up this entry.
+	 */
+	if (dentry->d_inode || d_is_whiteout(dentry) ||
+	    d_is_fallthru(dentry)) {
+		printk(KERN_INFO "skipping copy of %s\n", dentry->d_name.name);
+		goto out_dput;
+	}
+
+	/*
+	 * If the entry doesn't exist, create a fallthru entry in the
+	 * topmost file system.  All possible directory types are
+	 * used, so each file system must implement its own way of
+	 * storing a fallthru entry.
+	 */
+	printk(KERN_INFO "creating fallthru for %s\n", dentry->d_name.name);
+	err = topmost_dentry->d_inode->i_op->fallthru(topmost_dentry->d_inode,
+						      dentry);
+	/* FIXME */
+	BUG_ON(err);
+	/*
+	 * At this point, we have a negative dentry marked as fallthru
+	 * in the cache.  We could potentially lookup the entry lower
+	 * level file system and turn this into a positive dentry
+	 * right now, but it is not clear that would be a performance
+	 * win and adds more opportunities to fail.
+	 */
+out_dput:
+	dput(dentry);
+out:
+	return 0;
+}
+
+/**
+ * union_copyup_dir - copy up low-level directory entries to topmost dir
+ *
+ * readdir() is difficult to support on union file systems for two
+ * reasons: We must eliminate duplicates and apply whiteouts, and we
+ * must return something in f_pos that lets us restart in the same
+ * place when we return.  Our solution is to, on first readdir() of
+ * the directory, copy up all visible entries from the low-level file
+ * systems and mark the entries that refer to low-level file system
+ * objects as "fallthru" entries.
+ */
+
+int union_copyup_dir(struct path *topmost_path)
+{
+	struct dentry *topmost_dentry = topmost_path->dentry;
+	struct path path = *topmost_path;
+	int res = 0;
+
+	/*
+	 * Skip opaque dirs.
+	 */
+	if (IS_OPAQUE(topmost_dentry->d_inode))
+		return 0;
+
+	/*
+	 * Mark this dir opaque to show that we have already copied up
+	 * the lower entries.  Only fallthru entries pass through to
+	 * the underlying file system.
+	 *
+	 * XXX Deal with the lower file system changing.  This could
+	 * be through running a tool over the top level file system to
+	 * make directories transparent again, or we could check the
+	 * mtime of the underlying directory.
+	 */
+
+	topmost_dentry->d_inode->i_flags |= S_OPAQUE;
+	mark_inode_dirty(topmost_dentry->d_inode);
+
+	/*
+	 * Loop through each dir on each level copying up the entries
+	 * to the topmost.
+	 */
+
+	/* Don't drop the caller's reference to the topmost path */
+	path_get(&path);
+	while (follow_union_down(&path.mnt, &path.dentry)) {
+		struct file * ftmp;
+		struct inode * inode;
+
+		/* XXX Permit fallthrus on lower-level? Would need to
+		 * pass in opaque flag to union_copyup_dir_one() and
+		 * only copy up fallthru entries there.  We allow
+		 * fallthrus in lower level opaque directories on
+		 * lookup, so for consistency we should do one or the
+		 * other in both places. */
+		if (IS_OPAQUE(path.dentry->d_inode))
+			break;
+
+		/* dentry_open() doesn't get a path reference itself */
+		path_get(&path);
+		ftmp = dentry_open(path.dentry, path.mnt,
+				   O_RDONLY | O_DIRECTORY | O_NOATIME,
+				   current_cred());
+		if (IS_ERR(ftmp)) {
+			printk (KERN_ERR "unable to open dir %s for "
+				"directory copyup: %ld\n",
+				path.dentry->d_name.name, PTR_ERR(ftmp));
+			continue;
+		}
+
+		inode = path.dentry->d_inode;
+		mutex_lock(&inode->i_mutex);
+
+		res = -ENOENT;
+		if (IS_DEADDIR(inode))
+			goto out_fput;
+		/*
+		 * Read the whole directory, calling our directory
+		 * entry copyup function on each entry.  Pass in the
+		 * topmost dentry as our private data so we can create
+		 * new entries in the topmost directory.
+		 */
+		res = ftmp->f_op->readdir(ftmp, topmost_dentry,
+					  union_copyup_dir_one);
+out_fput:
+		mutex_unlock(&inode->i_mutex);
+		fput(ftmp);
+
+		if (res)
+			break;
+	}
+	path_put(&path);
+	return res;
+}
diff --git a/include/linux/union.h b/include/linux/union.h
index 405baa9..a0656b3 100644
--- a/include/linux/union.h
+++ b/include/linux/union.h
@@ -57,6 +57,7 @@ extern struct dentry *union_create_topmost(struct nameidata *, struct qstr *,
 					   struct path *);
 extern int __union_copyup(struct path *, struct nameidata *, struct path *);
 extern int union_copyup(struct nameidata *, int);
+extern int union_copyup_dir(struct path *path);
 
 #else /* CONFIG_UNION_MOUNT */
 
@@ -74,6 +75,7 @@ extern int union_copyup(struct nameidata *, int);
 #define union_create_topmost(x, y, z)	({ BUG(); (NULL); })
 #define __union_copyup(x, y, z)		({ BUG(); (0); })
 #define union_copyup(x, y)		({ (0); })
+#define union_copyup_dir(x)		({ BUG(); (0); })
 
 #endif	/* CONFIG_UNION_MOUNT */
 #endif	/* __KERNEL__ */
-- 
1.6.1.3


  parent reply	other threads:[~2009-05-18 16:11 UTC|newest]

Thread overview: 72+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-18 16:08 [PATCH 00/32] VFS based Union Mount (V3) Jan Blunck
2009-05-18 16:08 ` [PATCH 01/32] atomic: Only take lock when the counter drops to zero on UP as well Jan Blunck
2009-05-18 16:08 ` [PATCH 02/32] VFS: BUG() if somebody tries to rehash an already hashed dentry Jan Blunck
2009-05-18 16:08 ` [PATCH 03/32] VFS: propagate mnt_flags into do_loopback Jan Blunck
2009-05-18 16:09 ` [PATCH 04/32] VFS: Make lookup_hash() return a struct path Jan Blunck
2009-05-18 16:09 ` [PATCH 05/32] VFS: Remove unnecessary micro-optimization in cached_lookup() Jan Blunck
2009-05-18 16:09 ` [PATCH 06/32] VFS: Make real_lookup() return a struct path Jan Blunck
2009-05-18 16:09 ` [PATCH 07/32] VFS: Introduce dput() variant that maintains a kill-list Jan Blunck
2009-05-18 16:09 ` [PATCH 08/32] whiteout: Don't return information about whiteouts to userspace Jan Blunck
2009-05-18 16:09 ` [PATCH 09/32] whiteout: Add vfs_whiteout() and whiteout inode operation Jan Blunck
2009-05-18 16:09 ` [PATCH 10/32] whiteout: Set S_OPAQUE inode flag when creating directories Jan Blunck
2009-05-18 16:09 ` [PATCH 11/32] whiteout: Add whiteout support to tmpfs Jan Blunck
2009-05-18 16:09 ` [PATCH 12/32] whiteout: Split of ext2_append_link() from ext2_add_link() Jan Blunck
2009-05-18 16:09 ` [PATCH 13/32] whiteout: Add whiteout support to ext2 Jan Blunck
2009-05-18 16:09 ` [PATCH 14/32] whiteout: Add path_whiteout() helper Jan Blunck
2009-05-18 16:09 ` [PATCH 15/32] union-mount: Documentation Jan Blunck
2009-05-25  6:25   ` hooanon05
2009-05-25  8:03     ` Arnd Bergmann
2009-05-25  8:43       ` hooanon05
2009-06-18 19:05         ` Valerie Aurora
2009-06-19  1:53           ` hooanon05
2009-05-18 16:09 ` [PATCH 16/32] union-mount: Introduce MNT_UNION and MS_UNION flags Jan Blunck
2009-05-18 16:09 ` [PATCH 17/32] union-mount: Introduce union_mount structure Jan Blunck
2009-05-18 16:09 ` [PATCH 18/32] union-mount: Drive the union cache via dcache Jan Blunck
2009-05-18 16:09 ` [PATCH 19/32] union-mount: Some checks during namespace changes Jan Blunck
2009-05-18 16:09 ` [PATCH 20/32] union-mount: Changes to the namespace handling Jan Blunck
2009-05-18 16:09 ` [PATCH 21/32] union-mount: Make lookup work for union-mounted file systems Jan Blunck
2009-05-19 16:15   ` Miklos Szeredi
2009-05-19 17:30     ` Valerie Aurora
2009-05-20 10:21       ` Miklos Szeredi
2009-05-18 16:09 ` [PATCH 22/32] union-mount: stop lookup when directory has S_OPAQUE flag set Jan Blunck
2009-05-18 16:09 ` [PATCH 23/32] union-mount: stop lookup when finding a whiteout Jan Blunck
2009-05-18 16:09 ` [PATCH 24/32] union-mount: in-kernel file copy between union mounted filesystems Jan Blunck
2009-05-18 16:09 ` [PATCH 25/32] union-mount: check for logically empty directory (FIXME) Jan Blunck
2009-05-18 16:09 ` [PATCH 26/32] union-mount: call do_whiteout() on unlink and rmdir Jan Blunck
2009-05-18 16:09 ` [PATCH 27/32] union-mount: Always create topmost directory on open Jan Blunck
2009-05-18 16:09 ` [PATCH 28/32] union-mount: Basic fallthru definitions Jan Blunck
2009-05-18 16:09 ` [PATCH 29/32] union mount: Support for fallthru entries in union mount lookup Jan Blunck
2009-05-18 16:09 ` [PATCH 30/32] union mount: ext2 fallthru support Jan Blunck
2009-05-18 16:32   ` Andreas Dilger
2009-05-19  9:42     ` Jan Blunck
2009-05-19 14:05       ` Andreas Dilger
2009-05-19 16:13         ` Jan Blunck
2009-05-18 16:09 ` [PATCH 31/32] union-mount: tmpfs " Jan Blunck
2009-05-18 16:09 ` Jan Blunck [this message]
2009-05-18 20:40 ` [PATCH] Userland for VFS based Union Mount (V3) Valerie Aurora
2009-05-21 13:53   ` Andreas Dilger
2009-06-18  3:22     ` Valerie Aurora
2009-05-19  9:48 ` [PATCH 00/32] " Miklos Szeredi
2009-05-19 10:29   ` Jan Blunck
2009-05-19 10:35     ` Miklos Szeredi
2009-05-19 10:39       ` Jan Blunck
2009-05-19 11:54         ` Arnd Bergmann
2009-05-19 11:54           ` Arnd Bergmann
2009-05-19 12:15           ` Jan Blunck
2009-05-19 12:21             ` Arnd Bergmann
2009-05-19 13:10               ` Jan Blunck
2009-05-19 17:23   ` Valerie Aurora
2009-05-20  9:05     ` Miklos Szeredi
2009-06-08 19:44       ` Valerie Aurora
2009-06-16 15:19         ` Miklos Szeredi
2009-05-21 12:54 ` Jan Rekorajski
2009-06-08 19:57   ` Valerie Aurora
2009-06-08 19:57     ` Valerie Aurora
2009-06-08 22:44     ` Jan Rekorajski
2009-06-08 22:48       ` Valerie Aurora
2009-06-08 22:48         ` Valerie Aurora
2009-06-15  9:55         ` Jan Rekorajski
2009-06-18  3:23           ` Valerie Aurora
2009-06-18  3:23             ` Valerie Aurora
2009-06-04 11:38 ` Scott James Remnant
2009-06-09 22:15   ` Valerie Aurora

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1242662968-11684-33-git-send-email-jblunck@suse.de \
    --to=jblunck@suse.de \
    --cc=bharata@in.ibm.com \
    --cc=dwmw2@infradead.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mszeredi@suse.cz \
    --cc=vaurora@redhat.com \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.