linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Josef "Jeff" Sipek <jsipek@cs.sunysb.edu>
To: linux-kernel@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org, torvalds@osdl.org, akpm@osdl.org,
	hch@infradead.org, viro@ftp.linux.org.uk
Subject: [PATCH 5 of 23] Unionfs: Copyup Functionality
Date: Sat, 07 Oct 2006 01:07:24 -0400	[thread overview]
Message-ID: <2bae4a1f2233e373f4f3.1160197644@thor.fsl.cs.sunysb.edu> (raw)
In-Reply-To: <patchbomb.1160197639@thor.fsl.cs.sunysb.edu>

From: Josef "Jeff" Sipek <jsipek@cs.sunysb.edu>

This patch contains the functions used to perform copyup operations in unionfs.

Signed-off-by: Josef "Jeff" Sipek <jsipek@cs.sunysb.edu>
Signed-off-by: David Quigley <dquigley@fsl.cs.sunysb.edu>
Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>

---

1 file changed, 657 insertions(+)
fs/unionfs/copyup.c |  657 +++++++++++++++++++++++++++++++++++++++++++++++++++

diff -r fd7639f798f9 -r 2bae4a1f2233 fs/unionfs/copyup.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fs/unionfs/copyup.c	Sat Oct 07 00:46:18 2006 -0400
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2003-2006 Erez Zadok
+ * Copyright (c) 2003-2006 Charles P. Wright
+ * Copyright (c) 2005-2006 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-2006 Stony Brook University
+ * Copyright (c) 2003-2006 The Research Foundation of State University of New York*
+ *
+ * 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"
+
+/* Determine the mode based on the copyup flags, and the existing dentry. */
+static int copyup_permissions(struct super_block *sb,
+			      struct dentry *old_hidden_dentry,
+			      struct dentry *new_hidden_dentry)
+{
+	struct inode *i = old_hidden_dentry->d_inode;
+	struct iattr newattrs;
+	int err;
+
+	newattrs.ia_atime = i->i_atime;
+	newattrs.ia_mtime = i->i_mtime;
+	newattrs.ia_ctime = i->i_ctime;
+
+	newattrs.ia_gid = i->i_gid;
+	newattrs.ia_uid = i->i_uid;
+
+	newattrs.ia_mode = i->i_mode;
+
+	newattrs.ia_valid = ATTR_CTIME | ATTR_ATIME | ATTR_MTIME |
+	    ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_FORCE |
+	    ATTR_GID | ATTR_UID | ATTR_MODE;
+
+	err = notify_change(new_hidden_dentry, &newattrs);
+
+	return err;
+}
+
+int copyup_dentry(struct inode *dir, struct dentry *dentry,
+		  int bstart, int new_bindex,
+		  struct file **copyup_file, loff_t len)
+{
+	return copyup_named_dentry(dir, dentry, bstart, new_bindex,
+				   dentry->d_name.name,
+				   dentry->d_name.len, copyup_file, len);
+}
+
+/* create the new device/file/directory - use copyup_permission to copyup
+ * times, and mode
+ *
+ * if the object being copied up is a regular file, the file is only created,
+ * the contents have to be copied up separately
+ */
+static inline int __copyup_ndentry(struct dentry *old_hidden_dentry,
+				   struct dentry *new_hidden_dentry,
+				   struct dentry *new_hidden_parent_dentry,
+				   char *symbuf)
+{
+	int err = 0;
+	umode_t old_mode = old_hidden_dentry->d_inode->i_mode;
+	struct sioq_args args;
+
+	if (S_ISDIR(old_mode)) {
+		args.u.mkdir.parent = new_hidden_parent_dentry->d_inode;
+		args.u.mkdir.dentry = new_hidden_dentry;
+		args.u.mkdir.mode = old_mode;
+
+		run_sioq(__unionfs_mkdir, &args);
+		err = args.err;
+	} else if (S_ISLNK(old_mode)) {
+		args.u.symlink.parent = new_hidden_parent_dentry->d_inode;
+		args.u.symlink.dentry = new_hidden_dentry;
+		args.u.symlink.symbuf = symbuf;
+		args.u.symlink.mode = old_mode;
+
+		run_sioq(__unionfs_symlink, &args);
+		err = args.err;
+	} else if (S_ISBLK(old_mode)
+		   || S_ISCHR(old_mode)
+		   || S_ISFIFO(old_mode)
+		   || S_ISSOCK(old_mode)) {
+		args.u.mknod.parent = new_hidden_parent_dentry->d_inode;
+		args.u.mknod.dentry = new_hidden_dentry;
+		args.u.mknod.mode = old_mode;
+		args.u.mknod.dev = old_hidden_dentry->d_inode->i_rdev;
+
+		run_sioq(__unionfs_mknod, &args);
+		err = args.err;
+	} else if (S_ISREG(old_mode)) {
+		args.u.create.parent = new_hidden_parent_dentry->d_inode;
+		args.u.create.dentry = new_hidden_dentry;
+		args.u.create.mode = old_mode;
+		args.u.create.nd = NULL;
+
+		run_sioq(__unionfs_create, &args);
+		err = args.err;
+	} else {
+		printk(KERN_ERR "Unknown inode type %d\n",
+				old_mode);
+		BUG();
+	}
+
+	return err;
+}
+
+static inline int __copyup_reg_data(struct dentry *dentry,
+				    struct dentry *new_hidden_dentry,
+				    int new_bindex,
+				    struct dentry *old_hidden_dentry,
+				    int old_bindex,
+				    struct file **copyup_file,
+				    loff_t len)
+{
+	struct super_block *sb = dentry->d_sb;
+	struct file *input_file;
+	struct file *output_file;
+	mm_segment_t old_fs;
+	char *buf = NULL;
+	ssize_t read_bytes, write_bytes;
+	ssize_t size;
+	int err = 0;
+
+	/* open old file */
+	mntget(dtohm_index(dentry, old_bindex));
+	branchget(sb, old_bindex);
+	input_file = dentry_open(old_hidden_dentry,
+			dtohm_index(dentry, old_bindex), O_RDONLY);
+	if (IS_ERR(input_file)) {
+		dput(old_hidden_dentry);
+		err = PTR_ERR(input_file);
+		goto out;
+	}
+	if (!input_file->f_op || !input_file->f_op->read) {
+		err = -EINVAL;
+		goto out_close_in;
+	}
+
+	/* open new file */
+	dget(new_hidden_dentry);
+	mntget(dtohm_index(dentry, new_bindex));
+	branchget(sb, new_bindex);
+	output_file = dentry_open(new_hidden_dentry,
+			dtohm_index(dentry, new_bindex), O_WRONLY);
+	if (IS_ERR(output_file)) {
+		err = PTR_ERR(output_file);
+		goto out_close_in2;
+	}
+	if (!output_file->f_op || !output_file->f_op->write) {
+		err = -EINVAL;
+		goto out_close_out;
+	}
+
+	/* allocating a buffer */
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf) {
+		err = -ENOMEM;
+		goto out_close_out;
+	}
+
+	input_file->f_pos = 0;
+	output_file->f_pos = 0;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	size = len;
+	err = 0;
+	do {
+		if (len >= PAGE_SIZE)
+			size = PAGE_SIZE;
+		else if ((len < PAGE_SIZE) && (len > 0))
+			size = len;
+
+		len -= PAGE_SIZE;
+
+		read_bytes =
+		    input_file->f_op->read(input_file,
+					   (char __user *)buf, size,
+					   &input_file->f_pos);
+		if (read_bytes <= 0) {
+			err = read_bytes;
+			break;
+		}
+
+		write_bytes =
+		    output_file->f_op->write(output_file,
+					     (char __user *)buf,
+					     read_bytes,
+					     &output_file->f_pos);
+		if (write_bytes < 0 || (write_bytes < read_bytes)) {
+			err = write_bytes;
+			break;
+		}
+	} while ((read_bytes > 0) && (len > 0));
+
+	set_fs(old_fs);
+
+	kfree(buf);
+
+	if (err)
+		goto out_close_out;
+	if (copyup_file) {
+		*copyup_file = output_file;
+		goto out_close_in;
+	}
+
+out_close_out:
+	fput(output_file);
+
+out_close_in2:
+	branchput(sb, new_bindex);
+
+out_close_in:
+	fput(input_file);
+
+out:
+	branchput(sb, old_bindex);
+
+	return err;
+}
+
+static inline void __clear(struct dentry *dentry,
+			   struct dentry *old_hidden_dentry,
+			   int old_bstart, int old_bend,
+			   struct dentry *new_hidden_dentry,
+			   int new_bindex)
+{
+	/* get rid of the hidden dentry and all its traces */
+	set_dtohd_index(dentry, new_bindex, NULL);
+	set_dbstart(dentry, old_bstart);
+	set_dbend(dentry, old_bend);
+
+	dput(new_hidden_dentry);
+	dput(old_hidden_dentry);
+}
+
+int copyup_named_dentry(struct inode *dir, struct dentry *dentry,
+			int bstart, int new_bindex, const char *name,
+			int namelen, struct file **copyup_file, loff_t len)
+{
+	struct dentry *new_hidden_dentry;
+	struct dentry *old_hidden_dentry = NULL;
+	struct super_block *sb;
+	int err = 0;
+	int old_bindex;
+	int old_bstart;
+	int old_bend;
+	struct dentry *new_hidden_parent_dentry = NULL;
+	mm_segment_t oldfs;
+	char *symbuf = NULL;
+
+	verify_locked(dentry);
+
+	old_bindex = bstart;
+	old_bstart = dbstart(dentry);
+	old_bend = dbend(dentry);
+
+	BUG_ON(new_bindex < 0);
+	BUG_ON(new_bindex >= old_bindex);
+
+	sb = dir->i_sb;
+
+	unionfs_read_lock(sb);
+
+	if ((err = is_robranch_super(sb, new_bindex))) {
+		dput(old_hidden_dentry);
+		goto out;
+	}
+
+	/* Create the directory structure above this dentry. */
+	new_hidden_dentry = create_parents_named(dir, dentry, name, new_bindex);
+	if (IS_ERR(new_hidden_dentry)) {
+		dput(old_hidden_dentry);
+		err = PTR_ERR(new_hidden_dentry);
+		goto out;
+	}
+
+	old_hidden_dentry = dtohd_index(dentry, old_bindex);
+	dget(old_hidden_dentry);
+
+	/* For symlinks, we must read the link before we lock the directory. */
+	if (S_ISLNK(old_hidden_dentry->d_inode->i_mode)) {
+
+		symbuf = kmalloc(PATH_MAX, GFP_KERNEL);
+		if (!symbuf) {
+			__clear(dentry, old_hidden_dentry,
+				old_bstart, old_bend,
+				new_hidden_dentry, new_bindex);
+			err = -ENOMEM;
+			goto out_free;
+		}
+
+		oldfs = get_fs();
+		set_fs(KERNEL_DS);
+		err = old_hidden_dentry->d_inode->i_op->readlink(
+					old_hidden_dentry,
+					(char __user *)symbuf,
+					PATH_MAX);
+		set_fs(oldfs);
+		if (err) {
+			__clear(dentry, old_hidden_dentry,
+				old_bstart, old_bend,
+				new_hidden_dentry, new_bindex);
+			goto out_free;
+		}
+		symbuf[err] = '\0';
+	}
+
+	/* Now we lock the parent, and create the object in the new branch. */
+	new_hidden_parent_dentry = lock_parent(new_hidden_dentry);
+
+	/* create the new inode */
+	err = __copyup_ndentry(old_hidden_dentry, new_hidden_dentry,
+			       new_hidden_parent_dentry, symbuf);
+
+	if (err) {
+		__clear(dentry, old_hidden_dentry,
+			old_bstart, old_bend,
+			new_hidden_dentry, new_bindex);
+		goto out_unlock;
+	}
+
+	/* We actually copyup the file here. */
+	if (S_ISREG(old_hidden_dentry->d_inode->i_mode))
+		err = __copyup_reg_data(dentry, new_hidden_dentry, new_bindex,
+				old_hidden_dentry, old_bindex, copyup_file, len);
+	if (err)
+		goto out_unlink;
+
+	/* Set permissions. */
+	if ((err = copyup_permissions(sb, old_hidden_dentry, new_hidden_dentry)))
+		goto out_unlink;
+
+	/* do not allow files getting deleted to be reinterposed */
+	if (!d_deleted(dentry))
+		unionfs_reinterpose(dentry);
+
+	goto out_unlock;
+	/****/
+
+out_unlink:
+	/* copyup failed, because we possibly ran out of space or
+	 * quota, or something else happened so let's unlink; we don't
+	 * really care about the return value of vfs_unlink */
+	vfs_unlink(new_hidden_parent_dentry->d_inode, new_hidden_dentry);
+
+	if (copyup_file) {
+		/* need to close the file */
+
+		fput(*copyup_file);
+		branchput(sb, new_bindex);
+	}
+
+	/* TODO: should we reset the error to something like -EIO? */
+
+out_unlock:
+	unlock_dir(new_hidden_parent_dentry);
+
+out_free:
+	kfree(symbuf);
+
+out:
+	unionfs_read_unlock(sb);
+
+	return err;
+}
+
+/* This function creates a copy of a file represented by 'file' which currently
+ * resides in branch 'bstart' to branch 'new_bindex.'  The copy will be named
+ * "name".  */
+int copyup_named_file(struct inode *dir, struct file *file, char *name,
+		      int bstart, int new_bindex, loff_t len)
+{
+	int err = 0;
+	struct file *output_file = NULL;
+
+	err = copyup_named_dentry(dir, file->f_dentry, bstart,
+				  new_bindex, name, strlen(name), &output_file,
+				  len);
+	if (!err) {
+		fbstart(file) = new_bindex;
+		set_ftohf_index(file, new_bindex, output_file);
+	}
+
+	return err;
+}
+
+/* This function creates a copy of a file represented by 'file' which currently
+ * resides in branch 'bstart' to branch 'new_bindex'.
+ */
+int copyup_file(struct inode *dir, struct file *file, int bstart,
+		int new_bindex, loff_t len)
+{
+	int err = 0;
+	struct file *output_file = NULL;
+
+	err = copyup_dentry(dir, file->f_dentry, bstart, new_bindex,
+			    &output_file, len);
+	if (!err) {
+		fbstart(file) = new_bindex;
+		set_ftohf_index(file, new_bindex, output_file);
+	}
+
+	return err;
+}
+
+/* This function replicates the directory structure upto given dentry
+ * in the bindex branch. Can create directory structure recursively to the right
+ * also.
+ */
+struct dentry *create_parents(struct inode *dir, struct dentry *dentry,
+			      int bindex)
+{
+	return create_parents_named(dir, dentry, dentry->d_name.name, bindex);
+}
+
+static inline void __cleanup_dentry(struct dentry * dentry, int bindex,
+					int old_bstart, int old_bend)
+{
+	int loop_start;
+	int loop_end;
+	int new_bstart = -1;
+	int new_bend = -1;
+	int i;
+
+	loop_start = min(old_bstart, bindex);
+	loop_end = max(old_bend, bindex);
+
+	/* This loop sets the bstart and bend for the new
+	 * dentry by traversing from left to right.
+	 * It also dputs all negative dentries except
+	 * bindex (the newly looked dentry
+	 */
+	for (i = loop_start; i <= loop_end; i++) {
+		if (!dtohd_index(dentry, i))
+			continue;
+
+		if (i == bindex) {
+			new_bend = i;
+			if (new_bstart < 0)
+				new_bstart = i;
+			continue;
+		}
+
+		if (!dtohd_index(dentry, i)->d_inode) {
+			dput(dtohd_index(dentry, i));
+			set_dtohd_index(dentry, i, NULL);
+		} else {
+			if (new_bstart < 0)
+				new_bstart = i;
+			new_bend = i;
+		}
+	}
+
+	if (new_bstart < 0)
+		new_bstart = bindex;
+	if (new_bend < 0)
+		new_bend = bindex;
+	set_dbstart(dentry, new_bstart);
+	set_dbend(dentry, new_bend);
+
+}
+static inline void __set_inode(struct dentry * upper, struct dentry * lower,
+				int bindex)
+{
+	set_itohi_index(upper->d_inode, bindex,
+			igrab(lower->d_inode));
+	if (likely(ibstart(upper->d_inode) > bindex))
+		ibstart(upper->d_inode) = bindex;
+	if (likely(ibend(upper->d_inode) < bindex))
+		ibend(upper->d_inode) = bindex;
+
+}
+static inline void __set_dentry(struct dentry * upper, struct dentry * lower,
+				int bindex)
+{
+	set_dtohd_index(upper, bindex, lower);
+	if (likely(dbstart(upper) > bindex))
+		set_dbstart(upper, bindex);
+	if (likely(dbend(upper) < bindex))
+		set_dbend(upper, bindex);
+}
+/* This function replicates the directory structure upto given dentry
+ * in the bindex branch.  */
+struct dentry *create_parents_named(struct inode *dir, struct dentry *dentry,
+				    const char *name, int bindex)
+{
+	int err;
+	struct dentry *child_dentry;
+	struct dentry *parent_dentry;
+	struct dentry *hidden_parent_dentry = NULL;
+	struct dentry *hidden_dentry = NULL;
+	const char *childname;
+	unsigned int childnamelen;
+
+	int old_kmalloc_size;
+	int kmalloc_size;
+	int num_dentry;
+	int count;
+
+	int old_bstart;
+	int old_bend;
+	struct dentry **path = NULL;
+	struct dentry **tmp_path;
+	struct super_block *sb;
+
+	verify_locked(dentry);
+
+	/* There is no sense allocating any less than the minimum. */
+	kmalloc_size = malloc_sizes[0].cs_size;
+	num_dentry = kmalloc_size / sizeof(struct dentry *);
+
+	if ((err = is_robranch_super(dir->i_sb, bindex))) {
+		hidden_dentry = ERR_PTR(err);
+		goto out;
+	}
+
+	old_bstart = dbstart(dentry);
+	old_bend = dbend(dentry);
+
+	hidden_dentry = ERR_PTR(-ENOMEM);
+	path = kzalloc(kmalloc_size, GFP_KERNEL);
+	if (!path)
+		goto out;
+
+	/* assume the negative dentry of unionfs as the parent dentry */
+	parent_dentry = dentry;
+
+	count = 0;
+	/* This loop finds the first parent that exists in the given branch.
+	 * We start building the directory structure from there.  At the end
+	 * of the loop, the following should hold:
+	 *      child_dentry is the first nonexistent child
+	 *      parent_dentry is the first existent parent
+	 *      path[0] is the = deepest child
+	 *      path[count] is the first child to create
+	 */
+	do {
+		child_dentry = parent_dentry;
+
+		/* find the parent directory dentry in unionfs */
+		parent_dentry = child_dentry->d_parent;
+		lock_dentry(parent_dentry);
+
+		/* find out the hidden_parent_dentry in the given branch */
+		hidden_parent_dentry = dtohd_index(parent_dentry, bindex);
+
+		/* store the child dentry */
+		path[count++] = child_dentry;
+
+		/* grow path table */
+		if (count == num_dentry) {
+			old_kmalloc_size = kmalloc_size;
+			kmalloc_size *= 2;
+			num_dentry = kmalloc_size / sizeof(struct dentry *);
+
+			tmp_path = kzalloc(kmalloc_size, GFP_KERNEL);
+			if (!tmp_path) {
+				hidden_dentry = ERR_PTR(-ENOMEM);
+				goto out;
+			}
+			memcpy(tmp_path, path, old_kmalloc_size);
+			kfree(path);
+			path = tmp_path;
+			tmp_path = NULL;
+		}
+
+	} while (!hidden_parent_dentry);
+	count--;
+
+	sb = dentry->d_sb;
+
+	/* This is basically while(child_dentry != dentry).  This loop is
+	 * horrible to follow and should be replaced with cleaner code. */
+	while (1) {
+		// get hidden parent dir in the current branch
+		hidden_parent_dentry = dtohd_index(parent_dentry, bindex);
+		unlock_dentry(parent_dentry);
+
+		// init the values to lookup
+		childname = child_dentry->d_name.name;
+		childnamelen = child_dentry->d_name.len;
+
+		if (child_dentry != dentry) {
+			// lookup child in the underlying file system
+			hidden_dentry =
+			    lookup_one_len(childname, hidden_parent_dentry,
+					   childnamelen);
+			if (IS_ERR(hidden_dentry))
+				goto out;
+		} else {
+
+			/* is the name a whiteout of the childname ? */
+			//lookup the whiteout child in the underlying file system
+			hidden_dentry =
+			    lookup_one_len(name, hidden_parent_dentry,
+					   strlen(name));
+			if (IS_ERR(hidden_dentry))
+				goto out;
+
+			/* Replace the current dentry (if any) with the new one. */
+			dput(dtohd_index(dentry, bindex));
+			set_dtohd_index(dentry, bindex, hidden_dentry);
+
+			__cleanup_dentry(dentry, bindex, old_bstart, old_bend);
+			break;
+		}
+
+		if (hidden_dentry->d_inode) {
+			/* since this already exists we dput to avoid
+			 * multiple references on the same dentry */
+			dput(hidden_dentry);
+		} else {
+			struct sioq_args args;
+
+			/* its a negative dentry, create a new dir */
+			hidden_parent_dentry = lock_parent(hidden_dentry);
+
+			args.u.mkdir.parent = hidden_parent_dentry->d_inode;
+			args.u.mkdir.dentry = hidden_dentry;
+			args.u.mkdir.mode = child_dentry->d_inode->i_mode;
+
+			run_sioq(__unionfs_mkdir, &args);
+			err = args.err;
+
+			if (!err)
+				err = copyup_permissions(dir->i_sb,
+						child_dentry, hidden_dentry);
+			unlock_dir(hidden_parent_dentry);
+			if (err) {
+				dput(hidden_dentry);
+				hidden_dentry = ERR_PTR(err);
+				goto out;
+			}
+
+		}
+
+		__set_inode(child_dentry, hidden_dentry, bindex);
+		__set_dentry(child_dentry, hidden_dentry, bindex);
+
+		parent_dentry = child_dentry;
+		child_dentry = path[--count];
+	}
+out:
+	kfree(path);
+	return hidden_dentry;
+}
+



  parent reply	other threads:[~2006-10-07  5:56 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-10-07  5:07 [PATCH 0 of 23] Unionfs: Stackable Namespace Unification Filesystem Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 1 of 23] Unionfs: Documentation Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 2 of 23] lookup_one_len_nd - lookup_one_len with nameidata argument Josef Jeff Sipek
2006-10-07 17:03   ` Daniel Walker
2006-10-07 18:23     ` Josef Sipek
2006-10-07 18:37       ` Daniel Walker
2006-10-07  5:07 ` [PATCH 3 of 23] Unionfs: Branch management functionality Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 4 of 23] Unionfs: Common file operations Josef Jeff Sipek
2006-10-07  5:07 ` Josef Jeff Sipek [this message]
2006-10-07  5:07 ` [PATCH 6 of 23] Unionfs: Dentry operations Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 7 of 23] Unionfs: File operations Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 8 of 23] Unionfs: Directory file operations Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 9 of 23] Unionfs: Directory manipulation helper functions Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 10 of 23] Unionfs: Inode operations Josef Jeff Sipek
2006-10-13  8:53   ` Pekka Enberg
2006-10-07  5:07 ` [PATCH 11 of 23] Unionfs: Lookup helper functions Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 12 of 23] Unionfs: Main module functions Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 13 of 23] Unionfs: Readdir state Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 14 of 23] Unionfs: Rename Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 15 of 23] Unionfs: Privileged operations workqueue Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 16 of 23] Unionfs: Handling of stale inodes Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 17 of 23] Unionfs: Miscellaneous helper functions Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 18 of 23] Unionfs: Superblock operations Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 19 of 23] Unionfs: Helper macros/inlines Josef Jeff Sipek
2006-10-13  8:23   ` Pekka Enberg
2006-10-07  5:07 ` [PATCH 20 of 23] Unionfs: Internal include file Josef Jeff Sipek
2006-10-13  8:02   ` Pekka Enberg
2006-10-13  8:05     ` Pekka Enberg
2006-10-07  5:07 ` [PATCH 21 of 23] Unionfs: Include file Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 22 of 23] Unionfs: Unlink Josef Jeff Sipek
2006-10-07  5:07 ` [PATCH 23 of 23] Unionfs: Kconfig and Makefile Josef Jeff Sipek

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=2bae4a1f2233e373f4f3.1160197644@thor.fsl.cs.sunysb.edu \
    --to=jsipek@cs.sunysb.edu \
    --cc=akpm@osdl.org \
    --cc=hch@infradead.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@osdl.org \
    --cc=viro@ftp.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;
as well as URLs for NNTP newsgroup(s).