From: Ian Kent <raven@themaw.net>
To: Valerie Aurora <vaurora@redhat.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>,
Miklos Szeredi <miklos@szeredi.hu>, Jan Blunck <jblunck@suse.de>,
Christoph Hellwig <hch@infradead.org>,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
Felix Fietkau <nbd@openwrt.org>
Subject: Re: [PATCH 24/38] union-mount: Copy up directory entries on first readdir()
Date: Tue, 13 Jul 2010 12:51:57 +0800 [thread overview]
Message-ID: <20100713045156.GH3949@zeus.themaw.net> (raw)
In-Reply-To: <1276627208-17242-25-git-send-email-vaurora@redhat.com>
On Tue, Jun 15, 2010 at 11:39:54AM -0700, Valerie Aurora wrote:
> 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.
>
> Thanks to Felix Fietkau <nbd@openwrt.org> for a bug fix.
>
> XXX - How to deal with fallthrus in lower layers?
>
> Signed-off-by: Valerie Aurora <vaurora@redhat.com>
> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> ---
> fs/readdir.c | 9 +++
> fs/union.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> fs/union.h | 2 +
> 3 files changed, 168 insertions(+), 0 deletions(-)
>
> diff --git a/fs/readdir.c b/fs/readdir.c
> index 3a48491..dd3eae1 100644
> --- a/fs/readdir.c
> +++ b/fs/readdir.c
> @@ -19,6 +19,8 @@
>
> #include <asm/uaccess.h>
>
> +#include "union.h"
> +
> int vfs_readdir(struct file *file, filldir_t filler, void *buf)
> {
> struct inode *inode = file->f_path.dentry->d_inode;
> @@ -36,9 +38,16 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
>
> res = -ENOENT;
> if (!IS_DEADDIR(inode)) {
> + if (IS_DIR_UNIONED(file->f_path.dentry) && !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 c089c02..76a6c34 100644
> --- a/fs/union.c
> +++ b/fs/union.c
> @@ -22,6 +22,8 @@
> #include <linux/fs_struct.h>
> #include <linux/slab.h>
> #include <linux/namei.h>
> +#include <linux/file.h>
> +#include <linux/security.h>
>
> #include "union.h"
>
> @@ -211,3 +213,158 @@ int union_create_topmost_dir(struct path *parent, struct qstr *name,
>
> return res;
> }
> +
> +/**
> + * 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_WARNING "%s: error looking up %s\n", __func__,
> + dentry->d_name.name);
> + err = PTR_ERR(dentry);
> + 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))
> + 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.
> + */
> + err = topmost_dentry->d_inode->i_op->fallthru(topmost_dentry->d_inode,
> + dentry);
There's a bit of indirection going on here so it isn't clear to me if
it is possible for i_op->fallthru() to ever be NULL?
> +out_dput:
> + dput(dentry);
> +out:
> + return err;
> +}
> +
> +/**
> + * 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.
> + *
> + * Locking strategy: We hold the topmost dir's i_mutex on entry. We
> + * grab the i_mutex on lower directories one by one. So the locking
> + * order is:
> + *
> + * Writable/topmost layers > Read-only/lower layers
> + *
> + * So there is no problem with lock ordering for union stacks with
> + * multiple lower layers. E.g.:
> + *
> + * (topmost) A->B->C (bottom)
> + * (topmost) D->C->B (bottom)
> + *
> + * (Not that we support more than two layers at the moment.)
> + */
> +
> +int union_copyup_dir(struct path *topmost_path)
> +{
> + struct dentry *topmost_dentry = topmost_path->dentry;
> + struct union_dir *ud;
> + int res = 0;
> +
> + BUG_ON(IS_OPAQUE(topmost_dentry->d_inode));
> +
> + res = mnt_want_write(topmost_path->mnt);
> + if (res)
> + return res;
> + /*
> + * 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.
> + */
> + topmost_dentry->d_inode->i_flags |= S_OPAQUE;
> + mark_inode_dirty(topmost_dentry->d_inode);
> +
> + for (ud = topmost_path->dentry->d_union_dir; ud != NULL; ud = ud->u_lower) {
> + struct file * ftmp;
> + struct inode * inode;
> + struct path path;
> +
> + BUG_ON(ud->u_this.dentry->d_count.counter == 0);
> + path = ud->u_this;
> + /* 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));
> + path_put(&path);
> + 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;
> +
> + /* XXX Should process directories below an opaque
> + * directory in case there are fallthrus in it */
> + if (IS_OPAQUE(path.dentry->d_inode))
> + break;
> +
> + }
> + mnt_drop_write(topmost_path->mnt);
> + return res;
> +}
> diff --git a/fs/union.h b/fs/union.h
> index 505f132..80c2421 100644
> --- a/fs/union.h
> +++ b/fs/union.h
> @@ -58,6 +58,7 @@ extern void d_free_unions(struct dentry *);
> int needs_lookup_union(struct path *, struct path *);
> int union_create_topmost_dir(struct path *, struct qstr *, struct path *,
> struct path *);
> +extern int union_copyup_dir(struct path *);
>
> #else /* CONFIG_UNION_MOUNT */
>
> @@ -67,6 +68,7 @@ int union_create_topmost_dir(struct path *, struct qstr *, struct path *,
> #define d_free_unions(x) do { } while (0)
> #define needs_lookup_union(x, y) ({ (0); })
> #define union_create_topmost_dir(w, x, y, z) ({ BUG(); (NULL); })
> +#define union_copyup_dir(x) ({ BUG(); (0); })
>
> #endif /* CONFIG_UNION_MOUNT */
> #endif /* __KERNEL__ */
> --
> 1.6.3.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
next prev parent reply other threads:[~2010-07-13 4:52 UTC|newest]
Thread overview: 105+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-15 18:39 [PATCH 00/38] Union mounts - union stack as linked list Valerie Aurora
2010-06-15 18:39 ` [PATCH 01/38] VFS: Comment follow_mount() and friends Valerie Aurora
2010-06-15 18:39 ` [PATCH 02/38] VFS: Make lookup_hash() return a struct path Valerie Aurora
2010-06-15 18:39 ` [PATCH 03/38] VFS: Add read-only users count to superblock Valerie Aurora
2010-06-15 18:39 ` [PATCH 04/38] autofs4: Save autofs trigger's vfsmount in super block info Valerie Aurora
2010-06-16 4:04 ` [autofs] " Ian Kent
2010-06-16 23:14 ` Valerie Aurora
2010-06-17 2:04 ` Ian Kent
2010-06-21 3:39 ` Ian Kent
2010-06-21 13:06 ` Miklos Szeredi
2010-06-21 13:24 ` Ian Kent
2010-06-22 4:46 ` Ian Kent
2010-06-22 5:49 ` J. R. Okajima
2010-06-22 13:11 ` Ian Kent
2010-06-23 1:23 ` Ian Kent
2010-06-23 2:07 ` J. R. Okajima
2010-06-23 2:37 ` Ian Kent
2010-06-24 1:35 ` Ian Kent
2010-06-24 5:16 ` Ian Kent
2010-06-15 18:39 ` [PATCH 05/38] whiteout/NFSD: Don't return information about whiteouts to userspace Valerie Aurora
2010-06-15 18:39 ` [PATCH 06/38] whiteout: Add vfs_whiteout() and whiteout inode operation Valerie Aurora
2010-07-13 3:52 ` Ian Kent
2010-07-16 19:50 ` Valerie Aurora
2010-06-15 18:39 ` [PATCH 07/38] whiteout: Set S_OPAQUE inode flag when creating directories Valerie Aurora
2010-07-13 4:05 ` Ian Kent
2010-07-16 20:12 ` Valerie Aurora
2010-07-17 4:14 ` Ian Kent
2010-06-15 18:39 ` [PATCH 08/38] whiteout: Allow removal of a directory with whiteouts Valerie Aurora
2010-06-15 18:39 ` [PATCH 09/38] whiteout: tmpfs whiteout support Valerie Aurora
2010-06-15 18:39 ` [PATCH 10/38] whiteout: Split of ext2_append_link() from ext2_add_link() Valerie Aurora
2010-06-15 18:39 ` [PATCH 11/38] whiteout: ext2 whiteout support Valerie Aurora
2010-07-13 4:24 ` Ian Kent
2010-07-19 22:14 ` Valerie Aurora
2010-06-15 18:39 ` [PATCH 12/38] whiteout: jffs2 " Valerie Aurora
2010-06-15 18:39 ` [PATCH 13/38] fallthru: Basic fallthru definitions Valerie Aurora
2010-06-15 18:39 ` [PATCH 14/38] fallthru: ext2 fallthru support Valerie Aurora
2010-07-13 4:30 ` Ian Kent
2010-08-04 14:44 ` Miklos Szeredi
2010-08-04 22:48 ` Valerie Aurora
2010-08-05 10:36 ` Miklos Szeredi
2010-08-05 23:30 ` Valerie Aurora
2010-08-06 8:15 ` Miklos Szeredi
2010-08-06 17:16 ` Valerie Aurora
2010-08-06 17:44 ` Miklos Szeredi
2010-08-04 23:04 ` Valerie Aurora
2010-08-05 11:13 ` Miklos Szeredi
2010-08-06 17:12 ` Valerie Aurora
2010-08-17 22:27 ` Valerie Aurora
2010-08-18 8:26 ` Miklos Szeredi
2010-06-15 18:39 ` [PATCH 15/38] fallthru: jffs2 " Valerie Aurora
2010-06-15 18:39 ` [PATCH 16/38] fallthru: tmpfs " Valerie Aurora
2010-06-15 18:39 ` [PATCH 17/38] union-mount: Union mounts documentation Valerie Aurora
2010-06-17 8:01 ` Alex Riesen
2010-06-17 18:39 ` Valerie Aurora
2010-06-17 20:32 ` Alex Riesen
2010-06-18 21:06 ` Valerie Aurora
2010-06-21 13:14 ` Miklos Szeredi
2010-06-21 23:17 ` Valerie Aurora
2010-06-23 8:43 ` Alex Riesen
2010-06-15 18:39 ` [PATCH 18/38] union-mount: Introduce MNT_UNION and MS_UNION flags Valerie Aurora
2010-06-15 18:39 ` [PATCH 19/38] union-mount: Introduce union_dir structure and basic operations Valerie Aurora
2010-07-13 4:39 ` Ian Kent
2010-07-16 20:51 ` Valerie Aurora
2010-08-04 14:51 ` Miklos Szeredi
2010-08-04 19:47 ` Valerie Aurora
2010-08-05 10:28 ` Miklos Szeredi
2010-08-06 17:09 ` Valerie Aurora
2010-06-15 18:39 ` [PATCH 20/38] union-mount: Free union dirs on removal from dcache Valerie Aurora
2010-06-15 18:39 ` [PATCH 21/38] union-mount: Support for mounting union mount file systems Valerie Aurora
2010-07-13 4:47 ` Ian Kent
2010-07-16 21:02 ` Valerie Aurora
2010-07-20 3:12 ` Ian Kent
2010-08-04 21:59 ` Valerie Aurora
2010-08-05 10:34 ` Miklos Szeredi
2010-08-06 16:33 ` Valerie Aurora
2010-07-16 21:05 ` Valerie Aurora
2010-08-04 14:55 ` Miklos Szeredi
2010-08-04 19:50 ` Valerie Aurora
2010-08-05 4:26 ` Valerie Aurora
2010-06-15 18:39 ` [PATCH 22/38] union-mount: Implement union lookup Valerie Aurora
2010-07-13 4:49 ` Ian Kent
2010-07-19 21:58 ` Valerie Aurora
2010-06-15 18:39 ` [PATCH 23/38] union-mount: Call do_whiteout() on unlink and rmdir in unions Valerie Aurora
2010-06-15 18:39 ` [PATCH 24/38] union-mount: Copy up directory entries on first readdir() Valerie Aurora
2010-07-13 4:51 ` Ian Kent [this message]
2010-06-15 18:39 ` [PATCH 25/38] VFS: Split inode_permission() and create path_permission() Valerie Aurora
2010-06-15 18:39 ` [PATCH 26/38] VFS: Create user_path_nd() to lookup both parent and target Valerie Aurora
2010-06-15 18:39 ` [PATCH 27/38] union-mount: In-kernel file copyup routines Valerie Aurora
2010-07-13 4:56 ` Ian Kent
2010-07-19 22:41 ` Valerie Aurora
2010-08-04 15:26 ` Miklos Szeredi
2010-08-05 19:54 ` Valerie Aurora
2010-06-15 18:39 ` [PATCH 28/38] union-mount: Implement union-aware access()/faccessat() Valerie Aurora
2010-06-15 18:39 ` [PATCH 29/38] union-mount: Implement union-aware link() Valerie Aurora
2010-06-15 18:40 ` [PATCH 30/38] union-mount: Implement union-aware rename() Valerie Aurora
2010-06-15 18:40 ` [PATCH 31/38] union-mount: Implement union-aware writable open() Valerie Aurora
2010-06-15 18:40 ` [PATCH 32/38] union-mount: Implement union-aware chown() Valerie Aurora
2010-06-15 18:40 ` [PATCH 33/38] union-mount: Implement union-aware truncate() Valerie Aurora
2010-06-15 18:40 ` [PATCH 34/38] union-mount: Implement union-aware chmod()/fchmodat() Valerie Aurora
2010-06-15 18:40 ` [PATCH 35/38] union-mount: Implement union-aware lchown() Valerie Aurora
2010-06-15 18:40 ` [PATCH 36/38] union-mount: Implement union-aware utimensat() Valerie Aurora
2010-06-15 18:40 ` [PATCH 37/38] union-mount: Implement union-aware setxattr() Valerie Aurora
2010-06-15 18:40 ` [PATCH 38/38] union-mount: Implement union-aware lsetxattr() Valerie Aurora
2010-06-25 19:04 [PATCH 00/38] Union mounts - multiple layers and submounts Valerie Aurora
2010-06-25 19:05 ` [PATCH 24/38] union-mount: Copy up directory entries on first readdir() Valerie Aurora
2010-08-06 22:34 [PATCH 00/38] VFS union mounts - Add MS_FALLTHRU Valerie Aurora
2010-08-06 22:35 ` [PATCH 24/38] union-mount: Copy up directory entries on first readdir() 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=20100713045156.GH3949@zeus.themaw.net \
--to=raven@themaw.net \
--cc=hch@infradead.org \
--cc=jblunck@suse.de \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=nbd@openwrt.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome