login
Header Space

 
 

[PATCH 29/42] Unionfs: miscellaneous helper routines

Score:
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
To: <hch@...>, <viro@...>, <akpm@...>
Cc: <linux-kernel@...>, <linux-fsdevel@...>, Erez Zadok <ezk@...>
Date: Sunday, December 9, 2007 - 10:42 pm

Mostly related to whiteouts.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
---
 fs/unionfs/subr.c |  242 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 242 insertions(+), 0 deletions(-)
 create mode 100644 fs/unionfs/subr.c

diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
new file mode 100644
index 0000000..1a26c57
--- /dev/null
+++ b/fs/unionfs/subr.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2003-2007 Erez Zadok
+ * Copyright (c) 2003-2006 Charles P. Wright
+ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
+ * Copyright (c) 2005-2006 Junjiro Okajima
+ * Copyright (c) 2005      Arun M. Krishnakumar
+ * Copyright (c) 2004-2006 David P. Quigley
+ * Copyright (c) 2003-2004 Mohammad Nayyer Zubair
+ * Copyright (c) 2003      Puja Gupta
+ * Copyright (c) 2003      Harikesavan Krishnan
+ * Copyright (c) 2003-2007 Stony Brook University
+ * Copyright (c) 2003-2007 The Research Foundation of SUNY
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "union.h"
+
+/*
+ * Pass an unionfs dentry and an index.  It will try to create a whiteout
+ * for the filename in dentry, and will try in branch 'index'.  On error,
+ * it will proceed to a branch to the left.
+ */
+int create_whiteout(struct dentry *dentry, int start)
+{
+	int bstart, bend, bindex;
+	struct dentry *lower_dir_dentry;
+	struct dentry *lower_dentry;
+	struct dentry *lower_wh_dentry;
+	struct nameidata nd;
+	char *name = NULL;
+	int err = -EINVAL;
+
+	verify_locked(dentry);
+
+	bstart = dbstart(dentry);
+	bend = dbend(dentry);
+
+	/* create dentry's whiteout equivalent */
+	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
+	if (unlikely(IS_ERR(name))) {
+		err = PTR_ERR(name);
+		goto out;
+	}
+
+	for (bindex = start; bindex >= 0; bindex--) {
+		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+
+		if (!lower_dentry) {
+			/*
+			 * if lower dentry is not present, create the
+			 * entire lower dentry directory structure and go
+			 * ahead.  Since we want to just create whiteout, we
+			 * only want the parent dentry, and hence get rid of
+			 * this dentry.
+			 */
+			lower_dentry = create_parents(dentry->d_inode,
+						      dentry,
+						      dentry->d_name.name,
+						      bindex);
+			if (!lower_dentry || IS_ERR(lower_dentry)) {
+				int ret = PTR_ERR(lower_dentry);
+				if (!IS_COPYUP_ERR(ret))
+					printk(KERN_ERR
+					       "unionfs: create_parents for "
+					       "whiteout failed: bindex=%d "
+					       "err=%d\n", bindex, ret);
+				continue;
+			}
+		}
+
+		lower_wh_dentry =
+			lookup_one_len(name, lower_dentry->d_parent,
+				       dentry->d_name.len + UNIONFS_WHLEN);
+		if (IS_ERR(lower_wh_dentry))
+			continue;
+
+		/*
+		 * The whiteout already exists. This used to be impossible,
+		 * but now is possible because of opaqueness.
+		 */
+		if (lower_wh_dentry->d_inode) {
+			dput(lower_wh_dentry);
+			err = 0;
+			goto out;
+		}
+
+		err = init_lower_nd(&nd, LOOKUP_CREATE);
+		if (unlikely(err < 0))
+			goto out;
+		lower_dir_dentry = lock_parent(lower_wh_dentry);
+		err = is_robranch_super(dentry->d_sb, bindex);
+		if (!err)
+			err = vfs_create(lower_dir_dentry->d_inode,
+					 lower_wh_dentry,
+					 ~current->fs->umask & S_IRWXUGO,
+					 &nd);
+		unlock_dir(lower_dir_dentry);
+		dput(lower_wh_dentry);
+		release_lower_nd(&nd, err);
+
+		if (!err || !IS_COPYUP_ERR(err))
+			break;
+	}
+
+	/* set dbopaque so that lookup will not proceed after this branch */
+	if (!err)
+		set_dbopaque(dentry, bindex);
+
+out:
+	kfree(name);
+	return err;
+}
+
+/*
+ * This is a helper function for rename, which ends up with hosed over
+ * dentries when it needs to revert.
+ */
+int unionfs_refresh_lower_dentry(struct dentry *dentry, int bindex)
+{
+	struct dentry *lower_dentry;
+	struct dentry *lower_parent;
+	int err = 0;
+
+	verify_locked(dentry);
+
+	unionfs_lock_dentry(dentry->d_parent);
+	lower_parent = unionfs_lower_dentry_idx(dentry->d_parent, bindex);
+	unionfs_unlock_dentry(dentry->d_parent);
+
+	BUG_ON(!S_ISDIR(lower_parent->d_inode->i_mode));
+
+	lower_dentry = lookup_one_len(dentry->d_name.name, lower_parent,
+				      dentry->d_name.len);
+	if (IS_ERR(lower_dentry)) {
+		err = PTR_ERR(lower_dentry);
+		goto out;
+	}
+
+	dput(unionfs_lower_dentry_idx(dentry, bindex));
+	iput(unionfs_lower_inode_idx(dentry->d_inode, bindex));
+	unionfs_set_lower_inode_idx(dentry->d_inode, bindex, NULL);
+
+	if (!lower_dentry->d_inode) {
+		dput(lower_dentry);
+		unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
+	} else {
+		unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry);
+		unionfs_set_lower_inode_idx(dentry->d_inode, bindex,
+					    igrab(lower_dentry->d_inode));
+	}
+
+out:
+	return err;
+}
+
+int make_dir_opaque(struct dentry *dentry, int bindex)
+{
+	int err = 0;
+	struct dentry *lower_dentry, *diropq;
+	struct inode *lower_dir;
+	struct nameidata nd;
+	kernel_cap_t orig_cap;
+
+	/*
+	 * Opaque directory whiteout markers are special files (like regular
+	 * whiteouts), and should appear to the users as if they don't
+	 * exist.  They should be created/deleted regardless of directory
+	 * search/create permissions, but only for the duration of this
+	 * creation of the .wh.__dir_opaque: file.  Note, this does not
+	 * circumvent normal ->permission).
+	 */
+	orig_cap = current->cap_effective;
+	cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH);
+	cap_raise(current->cap_effective, CAP_DAC_OVERRIDE);
+
+	lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
+	lower_dir = lower_dentry->d_inode;
+	BUG_ON(!S_ISDIR(dentry->d_inode->i_mode) ||
+	       !S_ISDIR(lower_dir->i_mode));
+
+	mutex_lock(&lower_dir->i_mutex);
+	diropq = lookup_one_len(UNIONFS_DIR_OPAQUE, lower_dentry,
+				sizeof(UNIONFS_DIR_OPAQUE) - 1);
+	if (IS_ERR(diropq)) {
+		err = PTR_ERR(diropq);
+		goto out;
+	}
+
+	err = init_lower_nd(&nd, LOOKUP_CREATE);
+	if (unlikely(err < 0))
+		goto out;
+	if (!diropq->d_inode)
+		err = vfs_create(lower_dir, diropq, S_IRUGO, &nd);
+	if (!err)
+		set_dbopaque(dentry, bindex);
+	release_lower_nd(&nd, err);
+
+	dput(diropq);
+
+out:
+	mutex_unlock(&lower_dir->i_mutex);
+	current->cap_effective = orig_cap;
+	return err;
+}
+
+/*
+ * returns the right n_link value based on the inode type
+ */
+int unionfs_get_nlinks(const struct inode *inode)
+{
+	/* don't bother to do all the work since we're unlinked */
+	if (inode->i_nlink == 0)
+		return 0;
+
+	if (!S_ISDIR(inode->i_mode))
+		return unionfs_lower_inode(inode)->i_nlink;
+
+	/*
+	 * For directories, we return 1. The only place that could cares
+	 * about links is readdir, and there's d_type there so even that
+	 * doesn't matter.
+	 */
+	return 1;
+}
+
+/* construct whiteout filename */
+char *alloc_whname(const char *name, int len)
+{
+	char *buf;
+
+	buf = kmalloc(len + UNIONFS_WHLEN + 1, GFP_KERNEL);
+	if (unlikely(!buf))
+		return ERR_PTR(-ENOMEM);
+
+	strcpy(buf, UNIONFS_WHPFX);
+	strlcat(buf, name, len + UNIONFS_WHLEN + 1);
+
+	return buf;
+}
-- 
1.5.2.2

--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[UNIONFS] 00/42 Unionfs and related patches review, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 21/42] Unionfs: inode operations, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 30/42] Unionfs: debugging infrastructure, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 20/42] Unionfs: readdir state helpers, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 13/42] Unionfs: basic file operations, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 36/42] VFS: export drop_pagecache_sb, Erez Zadok, (Sun Dec 9, 10:42 pm)
Re: [PATCH 36/42] VFS: export drop_pagecache_sb, Nick Piggin, (Wed Dec 12, 1:38 am)
Re: [PATCH 36/42] VFS: export drop_pagecache_sb , Erez Zadok, (Thu Dec 13, 11:24 am)
Re: [PATCH 36/42] VFS: export drop_pagecache_sb, Nick Piggin, (Thu Dec 13, 6:47 pm)
[PATCH 11/42] Unionfs: main header file, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 25/42] Unionfs: super_block operations, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 16/42] Unionfs: lower-level lookup routines, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 10/42] Unionfs: fanout header definitions, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 17/42] Unionfs: rename method and helpers, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 34/42] VFS path get/put ops used by Unionfs, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 23/42] Unionfs: address-space operations, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 19/42] Unionfs: readdir helper functions, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 14/42] Unionfs: lower-level copyup routines, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 38/42] VFS: simplified fsstack_copy_attr_all, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 32/42] Unionfs file system magic number, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 37/42] VFS: export release_open_intent symbol, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 33/42] MM: extern for drop_pagecache_sb, Erez Zadok, (Sun Dec 9, 10:42 pm)
Re: [PATCH 33/42] MM: extern for drop_pagecache_sb, Adrian Bunk, (Mon Dec 10, 10:04 am)
Re: [PATCH 33/42] MM: extern for drop_pagecache_sb , Erez Zadok, (Thu Dec 13, 11:05 am)
[PATCH 29/42] Unionfs: miscellaneous helper routines, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 31/42] VFS: fs_stack header cleanups, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 15/42] Unionfs: dentry revalidation, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 22/42] Unionfs: unlink/rmdir operations, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 28/42] Unionfs: async I/O queue operations, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 27/42] Unionfs: async I/O queue headers, Erez Zadok, (Sun Dec 9, 10:42 pm)
[PATCH 09/42] Unionfs: main Makefile, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 08/42] Makefile: hook to compile unionfs, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 04/42] Unionfs: usage documentation for users, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 07/42] Unionfs maintainers, Erez Zadok, (Sun Dec 9, 10:41 pm)
[PATCH 02/42] Unionfs: unionfs documentation index, Erez Zadok, (Sun Dec 9, 10:41 pm)
Re: [PATCH 01/42] Unionfs: filesystems documentation index, Jan Engelhardt, (Mon Dec 10, 10:47 am)
speck-geostationary