From mboxrd@z Thu Jan 1 00:00:00 1970 From: Valerie Aurora Subject: [PATCH 33/74] union-mount: Add union_create_topmost_dir() Date: Tue, 22 Mar 2011 18:59:09 -0700 Message-ID: <1300845590-14184-34-git-send-email-valerie.aurora@gmail.com> References: <1300845590-14184-1-git-send-email-valerie.aurora@gmail.com> Cc: viro@zeniv.linux.org.uk, Valerie Aurora , Valerie Aurora To: linux-fsdevel@vger.kernel.org, linux@vger.kernel.org Return-path: Received: from mail-iy0-f174.google.com ([209.85.210.174]:60979 "EHLO mail-iy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756580Ab1CWCBr (ORCPT ); Tue, 22 Mar 2011 22:01:47 -0400 In-Reply-To: <1300845590-14184-1-git-send-email-valerie.aurora@gmail.com> Sender: linux-fsdevel-owner@vger.kernel.org List-ID: From: Valerie Aurora Union mounts design requires that the topmost directory exist for every single directory at the time lookup completes. This is so that we don't have to double back and create a whole path's worth of directories whenever we copy up a file in a directory for the first time. This greatly simplifies locking and error handling. Signed-off-by: Valerie Aurora --- fs/union.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/union.h | 3 +++ 2 files changed, 56 insertions(+), 0 deletions(-) diff --git a/fs/union.c b/fs/union.c index 45552f8..446116f 100644 --- a/fs/union.c +++ b/fs/union.c @@ -93,3 +93,56 @@ int union_add_dir(struct path *topmost, struct path *lower, *path = *lower; return 0; } + +/** + * union_create_topmost_dir - Create a matching dir in the topmost file system + * + * @parent - parent of target on topmost layer + * @name - name of target + * @topmost - path of target on topmost layer + * @lower - path of source on lower layer + * + * As we lookup each directory on the lower layer of a union, we + * create a matching directory on the topmost layer if it does not + * already exist. + * + * We don't use vfs_mkdir() for a few reasons: don't want to do the + * security check, don't want to make the dir opaque, don't need to + * sanitize the mode. + * + * XXX - owner is wrong, set credentials properly + * XXX - rmdir() directory on failure of xattr copyup + * XXX - not atomic w/ respect to crash + */ + +int union_create_topmost_dir(struct path *parent, struct qstr *name, + struct path *topmost, struct path *lower) +{ + struct inode *dir = parent->dentry->d_inode; + int mode = lower->dentry->d_inode->i_mode; + int error; + + BUG_ON(topmost->dentry->d_inode); + + /* XXX - Do we even need to check this? */ + if (!dir->i_op->mkdir) + return -EPERM; + + error = mnt_want_write(parent->mnt); + if (error) + return error; + + error = dir->i_op->mkdir(dir, topmost->dentry, mode); + if (error) + goto out; + + error = union_copyup_xattr(lower->dentry, topmost->dentry); + if (error) + dput(topmost->dentry); + + fsnotify_mkdir(dir, topmost->dentry); +out: + mnt_drop_write(parent->mnt); + + return error; +} diff --git a/fs/union.h b/fs/union.h index bd03d67..1692803 100644 --- a/fs/union.h +++ b/fs/union.h @@ -53,6 +53,8 @@ struct union_stack { extern void d_free_unions(struct dentry *); extern int union_add_dir(struct path *, struct path *, unsigned int); +extern int union_create_topmost_dir(struct path *, struct qstr *, struct path *, + struct path *); static inline struct path *union_find_dir(struct dentry *dentry, unsigned int layer) { @@ -67,6 +69,7 @@ static inline struct path *union_find_dir(struct dentry *dentry, #define d_free_unions(x) do { } while (0) #define union_add_dir(x, y, z) ({ BUG(); (0); }) #define union_find_dir(x, y) ({ BUG(); (NULL); }) +#define union_create_topmost_dir(w, x, y, z) ({ BUG(); (0); }) #endif /* CONFIG_UNION_MOUNT */ #endif /* __KERNEL__ */ -- 1.7.0.4