head	1.1;
access;
symbols
	LKML-branch:1.1.0.2;
locks; strict;
comment	@# @;


1.1
date	2006.10.24.06.14.17;	author jsipek;	state dead;
branches
	1.1.2.1;
next	;

1.1.2.1
date	2006.10.24.06.14.17;	author jsipek;	state Exp;
branches;
next	1.1.2.2;

1.1.2.2
date	2006.11.07.06.13.33;	author jsipek;	state Exp;
branches;
next	1.1.2.3;

1.1.2.3
date	2006.12.03.21.49.41;	author jsipek;	state Exp;
branches;
next	1.1.2.4;

1.1.2.4
date	2006.12.04.00.47.21;	author jsipek;	state Exp;
branches;
next	1.1.2.5;

1.1.2.5
date	2006.12.11.14.23.59;	author jsipek;	state Exp;
branches;
next	1.1.2.6;

1.1.2.6
date	2007.01.21.23.59.13;	author jsipek;	state Exp;
branches;
next	;


desc
@@


1.1
log
@file commonfops was initially added on branch LKML-branch.
@
text
@@


1.1.2.1
log
@Move unionfs specific bits into a subdir
@
text
@a0 588
Unionfs: Common file operations

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

This patch contains helper functions used through the rest of the code which
pertains to files.

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>

diff -r 7cf21588bb5f fs/unionfs/commonfops.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fs/unionfs/commonfops.c	Tue Oct 10 02:27:13 2006 -0400
@@@@ -0,0 +1,573 @@@@
+/*
+ * 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"
+
+/* 1) Copyup the file
+ * 2) Rename the file to '.unionfs<original inode#><counter>' - obviously
+ * stolen from NFS's silly rename
+ */
+static int copyup_deleted_file(struct file *file, struct dentry *dentry,
+			       int bstart, int bindex)
+{
+	static unsigned int counter;
+	const int i_inosize = sizeof(dentry->d_inode->i_ino) * 2;
+	const int countersize = sizeof(counter) * 2;
+	const int nlen = sizeof(".unionfs") + i_inosize + countersize - 1;
+	char name[nlen + 1];
+
+	int err;
+	struct dentry *tmp_dentry = NULL;
+	struct dentry *hidden_dentry = NULL;
+	struct dentry *hidden_dir_dentry = NULL;
+
+	hidden_dentry = dtohd_index(dentry, bstart);
+
+	sprintf(name, ".unionfs%*.*lx",
+			i_inosize, i_inosize, hidden_dentry->d_inode->i_ino);
+
+	tmp_dentry = NULL;
+	do {
+		char *suffix = name + nlen - countersize;
+
+		dput(tmp_dentry);
+		counter++;
+		sprintf(suffix, "%*.*x", countersize, countersize, counter);
+
+		printk(KERN_DEBUG "unionfs: trying to rename %s to %s\n",
+				dentry->d_name.name, name);
+
+		tmp_dentry = lookup_one_len(name, hidden_dentry->d_parent,
+					    UNIONFS_TMPNAM_LEN);
+		if (IS_ERR(tmp_dentry)) {
+			err = PTR_ERR(tmp_dentry);
+			goto out;
+		}
+	} while (tmp_dentry->d_inode != NULL);	/* need negative dentry */
+
+	err = copyup_named_file(dentry->d_parent->d_inode, file, name, bstart,
+				bindex, file->f_dentry->d_inode->i_size);
+	if (err)
+		goto out;
+
+	/* bring it to the same state as an unlinked file */
+	hidden_dentry = dtohd_index(dentry, dbstart(dentry));
+	hidden_dir_dentry = lock_parent(hidden_dentry);
+	err = vfs_unlink(hidden_dir_dentry->d_inode, hidden_dentry);
+	unlock_dir(hidden_dir_dentry);
+
+out:
+	return err;
+}
+
+static void cleanup_file(struct file *file, struct dentry *dentry)
+{
+	int bindex, bstart, bend;
+
+	bstart = fbstart(file);
+	bend = fbend(file);
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		if (ftohf_index(file, bindex)) {
+			branchput(dentry->d_sb, bindex);
+			fput(ftohf_index(file, bindex));
+		}
+	}
+
+	if (ftohf_ptr(file)) {
+		kfree(ftohf_ptr(file));
+		ftohf_ptr(file) = NULL;
+	}
+}
+
+static int open_all_files(struct file *file, struct dentry *dentry)
+{
+	int bindex, bstart, bend, err = 0;
+	struct file *hidden_file;
+	struct dentry *hidden_dentry;
+	struct super_block *sb = dentry->d_sb;
+
+	bstart = dbstart(dentry);
+	bend = dbend(dentry);
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		hidden_dentry = dtohd_index(dentry, bindex);
+		if (!hidden_dentry)
+			continue;
+
+		dget(hidden_dentry);
+		mntget(dtohm_index(dentry, bindex));
+		branchget(sb, bindex);
+
+		hidden_file = dentry_open(hidden_dentry,
+				dtohm_index(dentry, bindex), file->f_flags);
+		if (IS_ERR(hidden_file)) {
+			err = PTR_ERR(hidden_file);
+			goto out;
+		} else
+			set_ftohf_index(file, bindex, hidden_file);
+	}
+out:
+	return err;
+}
+
+static int open_highest_file(struct file *file, struct dentry *dentry,
+			     int willwrite)
+{
+	int bindex, bstart, bend, err = 0;
+	struct file *hidden_file;
+	struct dentry *hidden_dentry;
+	struct inode *parent_inode = dentry->d_parent->d_inode;
+	size_t inode_size = file->f_dentry->d_inode->i_size;
+	struct super_block *sb = dentry->d_sb;
+
+	bstart = dbstart(dentry);
+	bend = dbend(dentry);
+
+	hidden_dentry = dtohd(dentry);
+	if (willwrite && IS_WRITE_FLAG(file->f_flags)
+	    && is_robranch(dentry)) {
+		for (bindex = bstart - 1; bindex >= 0; bindex--) {
+			err = copyup_file(parent_inode, file, bstart, bindex,
+					  inode_size);
+			if (!err)
+				break;
+
+		}
+		atomic_set(&ftopd(file)->ufi_generation,
+			atomic_read(&itopd(dentry->d_inode)->uii_generation));
+		goto out;
+	}
+
+	dget(hidden_dentry);
+	mntget(dtohm_index(dentry, bstart));
+	branchget(sb, bstart);
+	hidden_file = dentry_open(hidden_dentry,
+			dtohm_index(dentry, bstart), file->f_flags);
+	if (IS_ERR(hidden_file)) {
+		err = PTR_ERR(hidden_file);
+		goto out;
+	}
+	set_ftohf(file, hidden_file);
+	/* Fix up the position. */
+	hidden_file->f_pos = file->f_pos;
+
+	memcpy(&(hidden_file->f_ra), &(file->f_ra),
+	       sizeof(struct file_ra_state));
+out:
+	return err;
+}
+
+static int do_delayed_copyup(struct file *file, struct dentry *dentry)
+{
+	int bindex, bstart, bend, err = 0;
+	struct inode *parent_inode = dentry->d_parent->d_inode;
+	loff_t inode_size = file->f_dentry->d_inode->i_size;
+
+	bstart = fbstart(file);
+	bend = fbend(file);
+
+	BUG_ON(!S_ISREG(file->f_dentry->d_inode->i_mode));
+
+	for (bindex = bstart - 1; bindex >= 0; bindex--) {
+		if (!d_deleted(file->f_dentry))
+			err = copyup_file(parent_inode, file, bstart,
+					bindex, inode_size);
+		else
+			err = copyup_deleted_file(file, dentry, bstart, bindex);
+
+		if (!err)
+			break;
+	}
+	if (!err && (bstart > fbstart(file))) {
+		bend = fbend(file);
+		for (bindex = bstart; bindex <= bend; bindex++) {
+			if (ftohf_index(file, bindex)) {
+				branchput(dentry->d_sb, bindex);
+				fput(ftohf_index(file, bindex));
+				set_ftohf_index(file, bindex, NULL);
+			}
+		}
+		fbend(file) = bend;
+	}
+	return err;
+}
+
+int unionfs_file_revalidate(struct file *file, int willwrite)
+{
+	struct super_block *sb;
+	struct dentry *dentry;
+	int sbgen, fgen, dgen;
+	int bstart, bend;
+	int size;
+
+	int err = 0;
+
+	dentry = file->f_dentry;
+	lock_dentry(dentry);
+	sb = dentry->d_sb;
+	unionfs_read_lock(sb);
+	if (!unionfs_d_revalidate(dentry, NULL) && !d_deleted(dentry)) {
+		err = -ESTALE;
+		goto out;
+	}
+
+	sbgen = atomic_read(&stopd(sb)->usi_generation);
+	dgen = atomic_read(&dtopd(dentry)->udi_generation);
+	fgen = atomic_read(&ftopd(file)->ufi_generation);
+
+	BUG_ON(sbgen > dgen);
+
+	/* There are two cases we are interested in.  The first is if the
+	 * generation is lower than the super-block.  The second is if someone
+	 * has copied up this file from underneath us, we also need to refresh
+	 * things. */
+	if (!d_deleted(dentry) &&
+	    (sbgen > fgen || dbstart(dentry) != fbstart(file))) {
+		/* First we throw out the existing files. */
+		cleanup_file(file, dentry);
+
+		/* Now we reopen the file(s) as in unionfs_open. */
+		bstart = fbstart(file) = dbstart(dentry);
+		bend = fbend(file) = dbend(dentry);
+
+		size = sizeof(struct file *) * sbmax(sb);
+		ftohf_ptr(file) = kzalloc(size, GFP_KERNEL);
+		if (!ftohf_ptr(file)) {
+			err = -ENOMEM;
+			goto out;
+		}
+
+		if (S_ISDIR(dentry->d_inode->i_mode)) {
+			/* We need to open all the files. */
+			err = open_all_files(file, dentry);
+			if (err)
+				goto out;
+		} else {
+			/* We only open the highest priority branch. */
+			err = open_highest_file(file, dentry, willwrite);
+			if (err)
+				goto out;
+		}
+		atomic_set(&ftopd(file)->ufi_generation,
+			   atomic_read(&itopd(dentry->d_inode)->
+				       uii_generation));
+	}
+
+	/* Copyup on the first write to a file on a readonly branch. */
+	if (willwrite && IS_WRITE_FLAG(file->f_flags)
+	    && !IS_WRITE_FLAG(ftohf(file)->f_flags) && is_robranch(dentry)) {
+		printk(KERN_DEBUG
+		       "Doing delayed copyup of a read-write file on a read-only branch.\n");
+		err = do_delayed_copyup(file, dentry);
+	}
+
+out:
+	unlock_dentry(dentry);
+	unionfs_read_unlock(dentry->d_sb);
+	return err;
+}
+
+/* unionfs_open helper function: open a directory */
+static inline int __open_dir(struct inode *inode, struct file *file)
+{
+	struct dentry *hidden_dentry;
+	struct file *hidden_file;
+	int bindex, bstart, bend;
+
+	bstart = fbstart(file) = dbstart(file->f_dentry);
+	bend = fbend(file) = dbend(file->f_dentry);
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		hidden_dentry = dtohd_index(file->f_dentry, bindex);
+		if (!hidden_dentry)
+			continue;
+
+		dget(hidden_dentry);
+		mntget(dtohm_index(file->f_dentry, bindex));
+		hidden_file = dentry_open(hidden_dentry,
+					dtohm_index(file->f_dentry, bindex),
+					file->f_flags);
+		if (IS_ERR(hidden_file))
+			return PTR_ERR(hidden_file);
+
+		set_ftohf_index(file, bindex, hidden_file);
+
+		/* The branchget goes after the open, because otherwise
+		 * we would miss the reference on release. */
+		branchget(inode->i_sb, bindex);
+	}
+
+	return 0;
+}
+
+/* unionfs_open helper function: open a file */
+static inline int __open_file(struct inode *inode, struct file *file)
+{
+	struct dentry *hidden_dentry;
+	struct file *hidden_file;
+	int hidden_flags;
+	int bindex, bstart, bend;
+
+	hidden_dentry = dtohd(file->f_dentry);
+	hidden_flags = file->f_flags;
+
+	bstart = fbstart(file) = dbstart(file->f_dentry);
+	bend = fbend(file) = dbend(file->f_dentry);
+
+	/* check for the permission for hidden file.  If the error is COPYUP_ERR,
+	 * copyup the file.
+	 */
+	if (hidden_dentry->d_inode && is_robranch(file->f_dentry)) {
+		/* if the open will change the file, copy it up otherwise defer it. */
+		if (hidden_flags & O_TRUNC) {
+			int size = 0;
+			int err = -EROFS;
+
+			/* copyup the file */
+			for (bindex = bstart - 1; bindex >= 0; bindex--) {
+				err = copyup_file(file->f_dentry->d_parent->d_inode,
+						file, bstart, bindex, size);
+				if (!err)
+					break;
+			}
+			return err;
+		} else
+			hidden_flags &= ~(OPEN_WRITE_FLAGS);
+	}
+
+	dget(hidden_dentry);
+
+	/* dentry_open will decrement mnt refcnt if err.
+	 * otherwise fput() will do an mntput() for us upon file close.
+	 */
+	mntget(dtohm_index(file->f_dentry, bstart));
+	hidden_file = dentry_open(hidden_dentry,
+				  dtohm_index(file->f_dentry, bstart),
+				  hidden_flags);
+	if (IS_ERR(hidden_file))
+		return PTR_ERR(hidden_file);
+
+	set_ftohf(file, hidden_file);
+	branchget(inode->i_sb, bstart);
+
+	return 0;
+}
+
+int unionfs_open(struct inode *inode, struct file *file)
+{
+	int err = 0;
+	struct file *hidden_file = NULL;
+	struct dentry *dentry = NULL;
+	int bindex = 0, bstart = 0, bend = 0;
+	int size;
+
+	ftopd_lhs(file) = kzalloc(sizeof(struct unionfs_file_info), GFP_KERNEL);
+	if (!ftopd(file)) {
+		err = -ENOMEM;
+		goto out;
+	}
+	fbstart(file) = -1;
+	fbend(file) = -1;
+	atomic_set(&ftopd(file)->ufi_generation,
+		   atomic_read(&itopd(inode)->uii_generation));
+
+	size = sizeof(struct file *) * sbmax(inode->i_sb);
+	ftohf_ptr(file) = kzalloc(size, GFP_KERNEL);
+	if (!ftohf_ptr(file)) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	dentry = file->f_dentry;
+	lock_dentry(dentry);
+	unionfs_read_lock(inode->i_sb);
+
+	bstart = fbstart(file) = dbstart(dentry);
+	bend = fbend(file) = dbend(dentry);
+
+	/* increment, so that we can flush appropriately */
+	atomic_inc(&itopd(dentry->d_inode)->uii_totalopens);
+
+	/* open all directories and make the unionfs file struct point to these hidden file structs */
+	if (S_ISDIR(inode->i_mode))
+		err = __open_dir(inode, file);	/* open a dir */
+	else
+		err = __open_file(inode, file);	/* open a file */
+
+	/* freeing the allocated resources, and fput the opened files */
+	if (err) {
+		for (bindex = bstart; bindex <= bend; bindex++) {
+			hidden_file = ftohf_index(file, bindex);
+			if (!hidden_file)
+				continue;
+
+			branchput(file->f_dentry->d_sb, bindex);
+			/* fput calls dput for hidden_dentry */
+			fput(hidden_file);
+		}
+	}
+
+	unlock_dentry(dentry);
+	unionfs_read_unlock(inode->i_sb);
+
+out:
+	if (err) {
+		kfree(ftohf_ptr(file));
+		kfree(ftopd(file));
+	}
+
+	return err;
+}
+
+int unionfs_file_release(struct inode *inode, struct file *file)
+{
+	struct file *hidden_file = NULL;
+	int bindex, bstart, bend;
+	int fgen;
+
+	/* fput all the hidden files */
+	fgen = atomic_read(&ftopd(file)->ufi_generation);
+	bstart = fbstart(file);
+	bend = fbend(file);
+
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		hidden_file = ftohf_index(file, bindex);
+
+		if (hidden_file) {
+			fput(hidden_file);
+			unionfs_read_lock(inode->i_sb);
+			branchput(inode->i_sb, bindex);
+			unionfs_read_unlock(inode->i_sb);
+		}
+	}
+	kfree(ftohf_ptr(file));
+
+	if (ftopd(file)->rdstate) {
+		ftopd(file)->rdstate->uds_access = jiffies;
+		printk(KERN_DEBUG "Saving rdstate with cookie %u [%d.%lld]\n",
+		       ftopd(file)->rdstate->uds_cookie,
+		       ftopd(file)->rdstate->uds_bindex,
+		       (long long)ftopd(file)->rdstate->uds_dirpos);
+		spin_lock(&itopd(inode)->uii_rdlock);
+		itopd(inode)->uii_rdcount++;
+		list_add_tail(&ftopd(file)->rdstate->uds_cache,
+			      &itopd(inode)->uii_readdircache);
+		mark_inode_dirty(inode);
+		spin_unlock(&itopd(inode)->uii_rdlock);
+		ftopd(file)->rdstate = NULL;
+	}
+	kfree(ftopd(file));
+	return 0;
+}
+
+static inline long do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct file *hidden_file;
+	int err;
+
+	hidden_file = ftohf(file);
+
+	err = security_file_ioctl(hidden_file, cmd, arg);
+	if (err)
+		goto out;
+	err = -ENOTTY;
+	if (!hidden_file || !hidden_file->f_op)
+		goto out;
+	if (hidden_file->f_op->unlocked_ioctl) {
+		err = hidden_file->f_op->unlocked_ioctl(hidden_file, cmd, arg);
+	} else if (hidden_file->f_op->ioctl) {
+		lock_kernel();
+		err = hidden_file->f_op->ioctl(hidden_file->f_dentry->d_inode,
+					       hidden_file, cmd, arg);
+		unlock_kernel();
+	}
+
+out:
+	return err;
+}
+
+long unionfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long err = 0;		/* don't fail by default */
+
+	if ((err = unionfs_file_revalidate(file, 1)))
+		goto out;
+
+	/* check if asked for local commands */
+	switch (cmd) {
+		case UNIONFS_IOCTL_INCGEN:
+			if (!capable(CAP_SYS_ADMIN)) {
+				err = -EACCES;
+				goto out;
+			}
+			err = unionfs_ioctl_incgen(file, cmd, arg);
+			break;
+
+		case UNIONFS_IOCTL_QUERYFILE:
+			err = unionfs_ioctl_queryfile(file, cmd, arg);
+			break;
+
+		default:
+			err = do_ioctl(file, cmd, arg);
+			break;
+	}
+
+out:
+	return err;
+}
+
+int unionfs_flush(struct file *file, fl_owner_t id)
+{
+	int err = 0;		/* assume ok (see open.c:close_fp) */
+	struct file *hidden_file = NULL;
+	int bindex, bstart, bend;
+
+	if ((err = unionfs_file_revalidate(file, 1)))
+		goto out;
+	if (!atomic_dec_and_test
+	    (&itopd(file->f_dentry->d_inode)->uii_totalopens))
+		goto out;
+
+	lock_dentry(file->f_dentry);
+
+	bstart = fbstart(file);
+	bend = fbend(file);
+	for (bindex = bstart; bindex <= bend; bindex++) {
+		hidden_file = ftohf_index(file, bindex);
+
+		if (hidden_file && hidden_file->f_op
+		    && hidden_file->f_op->flush) {
+			err = hidden_file->f_op->flush(hidden_file, id);
+			if (err)
+				goto out_lock;
+
+			/* if there are no more references to the dentry, dput it */
+			if (d_deleted(file->f_dentry)) {
+				dput(dtohd_index(file->f_dentry, bindex));
+				set_dtohd_index(file->f_dentry, bindex, NULL);
+			}
+		}
+
+	}
+
+out_lock:
+	unlock_dentry(file->f_dentry);
+out:
+	return err;
+}
+
@


1.1.2.2
log
@Git generates slightly different diffs - same information, just little
different
@
text
@d12 3
a14 5
diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
new file mode 100644
index 0000000..71b6650
--- /dev/null
+++ b/fs/unionfs/commonfops.c
@


1.1.2.3
log
@Collapsed macro patch into unionfs proper
@
text
@d15 3
a17 5

diff -r 1fa4961c7465 fs/unionfs/commonfops.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fs/unionfs/commonfops.c	Sun Dec 03 16:35:09 2006 -0500
@@@@ -0,0 +1,587 @@@@
d56 1
a56 1
+	hidden_dentry = unionfs_lower_dentry_idx(dentry, bstart);
d86 1
a86 1
+	hidden_dentry = unionfs_lower_dentry_idx(dentry, dbstart(dentry));
d95 1
a95 3
+/* put all references held by upper struct file and free lower file pointer
+ * array */
+static void cleanup_file(struct file *file)
a97 1
+	struct file **lf;
a98 1
+	lf = UNIONFS_F(file)->lower_files;
a100 1
+
d102 3
a104 3
+		if (unionfs_lower_file_idx(file, bindex)) {
+			branchput(file->f_dentry->d_sb, bindex);
+			fput(unionfs_lower_file_idx(file, bindex));
d108 4
a111 2
+	UNIONFS_F(file)->lower_files = NULL;
+	kfree(lf);
d114 1
a114 2
+/* open all lower files for a given file */
+static int open_all_files(struct file *file)
a118 1
+	struct dentry *dentry = file->f_dentry;
d125 1
a125 1
+		hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
d130 1
a130 1
+		mntget(unionfs_lower_mnt_idx(dentry, bindex));
d134 1
a134 2
+				unionfs_lower_mnt_idx(dentry, bindex),
+				file->f_flags);
d139 1
a139 1
+			unionfs_set_lower_file_idx(file, bindex, hidden_file);
d145 2
a146 2
+/* open the highest priority file for a given upper file */
+static int open_highest_file(struct file *file, int willwrite)
a150 2
+
+	struct dentry *dentry = file->f_dentry;
d152 1
a153 1
+	size_t inode_size = dentry->d_inode->i_size;
d158 3
a160 2
+	hidden_dentry = unionfs_lower_dentry(dentry);
+	if (willwrite && IS_WRITE_FLAG(file->f_flags) && is_robranch(dentry)) {
d166 1
d168 2
a169 2
+		atomic_set(&UNIONFS_F(file)->generation,
+			atomic_read(&UNIONFS_I(dentry->d_inode)->generation));
d174 1
a174 1
+	mntget(unionfs_lower_mnt_idx(dentry, bstart));
d177 1
a177 1
+			unionfs_lower_mnt_idx(dentry, bstart), file->f_flags);
d182 1
a182 1
+	unionfs_set_lower_file(file, hidden_file);
d186 2
a187 1
+	memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(struct file_ra_state));
d216 1
a216 1
+			if (unionfs_lower_file_idx(file, bindex)) {
d218 2
a219 2
+				fput(unionfs_lower_file_idx(file, bindex));
+				unionfs_set_lower_file_idx(file, bindex, NULL);
a226 1
+/* revalidate the stuct file */
d246 3
a248 3
+	sbgen = atomic_read(&UNIONFS_SB(sb)->generation);
+	dgen = atomic_read(&UNIONFS_D(dentry)->generation);
+	fgen = atomic_read(&UNIONFS_F(file)->generation);
d259 1
a259 1
+		cleanup_file(file);
d266 2
a267 2
+		UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
+		if (!UNIONFS_F(file)->lower_files) {
d274 1
a274 1
+			err = open_all_files(file);
d279 1
a279 1
+			err = open_highest_file(file, willwrite);
d283 3
a285 3
+		atomic_set(&UNIONFS_F(file)->generation,
+			   atomic_read(&UNIONFS_I(dentry->d_inode)->
+				       generation));
d289 4
a292 5
+	if (willwrite && IS_WRITE_FLAG(file->f_flags) &&
+	    !IS_WRITE_FLAG(unionfs_lower_file(file)->f_flags) &&
+	    is_robranch(dentry)) {
+		printk(KERN_DEBUG "Doing delayed copyup of a read-write "
+				  "file on a read-only branch.\n");
d313 1
a313 1
+		hidden_dentry = unionfs_lower_dentry_idx(file->f_dentry, bindex);
d318 1
a318 1
+		mntget(unionfs_lower_mnt_idx(file->f_dentry, bindex));
d320 2
a321 2
+				unionfs_lower_mnt_idx(file->f_dentry, bindex),
+				file->f_flags);
d325 1
a325 1
+		unionfs_set_lower_file_idx(file, bindex, hidden_file);
d343 1
a343 1
+	hidden_dentry = unionfs_lower_dentry(file->f_dentry);
d375 1
a375 1
+	mntget(unionfs_lower_mnt_idx(file->f_dentry, bstart));
d377 1
a377 1
+				  unionfs_lower_mnt_idx(file->f_dentry, bstart),
d382 1
a382 1
+	unionfs_set_lower_file(file, hidden_file);
d396 2
a397 2
+	file->private_data = kzalloc(sizeof(struct unionfs_file_info), GFP_KERNEL);
+	if (!UNIONFS_F(file)) {
d403 2
a404 2
+	atomic_set(&UNIONFS_F(file)->generation,
+		   atomic_read(&UNIONFS_I(inode)->generation));
d407 2
a408 2
+	UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
+	if (!UNIONFS_F(file)->lower_files) {
d421 1
a421 1
+	atomic_inc(&UNIONFS_I(dentry->d_inode)->totalopens);
d423 1
a423 2
+	/* open all directories and make the unionfs file struct point to
+	 * these hidden file structs */
d432 1
a432 1
+			hidden_file = unionfs_lower_file_idx(file, bindex);
d447 2
a448 2
+		kfree(UNIONFS_F(file)->lower_files);
+		kfree(UNIONFS_F(file));
a453 1
+/* release all lower object references & free the file info structure */
a456 2
+	struct unionfs_file_info *fileinfo = UNIONFS_F(file);
+	struct unionfs_inode_info *inodeinfo = UNIONFS_I(inode);
d461 1
a461 1
+	fgen = atomic_read(&fileinfo->generation);
d466 1
a466 1
+		hidden_file = unionfs_lower_file_idx(file, bindex);
d475 1
a475 1
+	kfree(fileinfo->lower_files);
d477 2
a478 2
+	if (fileinfo->rdstate) {
+		fileinfo->rdstate->access = jiffies;
d480 7
a486 7
+		       fileinfo->rdstate->cookie,
+		       fileinfo->rdstate->bindex,
+		       (long long)fileinfo->rdstate->dirpos);
+		spin_lock(&inodeinfo->rdlock);
+		inodeinfo->rdcount++;
+		list_add_tail(&fileinfo->rdstate->cache,
+			      &inodeinfo->readdircache);
d488 2
a489 2
+		spin_unlock(&inodeinfo->rdlock);
+		fileinfo->rdstate = NULL;
d491 1
a491 1
+	kfree(fileinfo);
a494 1
+/* pass the ioctl to the lower fs */
d500 1
a500 1
+	hidden_file = unionfs_lower_file(file);
a504 1
+
d523 1
a523 1
+	long err;
d531 2
a532 3
+			/* Increment the superblock generation count */
+			err = -EACCES;
+			if (!capable(CAP_SYS_ADMIN))
d534 1
a538 1
+			/* Return list of branches containing the given file */
a542 1
+			/* pass the ioctl down */
d553 1
a553 1
+	int err = 0;
a554 1
+	struct dentry *dentry = file->f_dentry;
d559 2
a560 1
+	if (!atomic_dec_and_test(&UNIONFS_I(dentry->d_inode)->totalopens))
d563 1
a563 1
+	lock_dentry(dentry);
d568 1
a568 1
+		hidden_file = unionfs_lower_file_idx(file, bindex);
d570 2
a571 1
+		if (hidden_file && hidden_file->f_op && hidden_file->f_op->flush) {
d577 3
a579 3
+			if (d_deleted(dentry)) {
+				dput(unionfs_lower_dentry_idx(dentry, bindex));
+				unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
d586 1
a586 1
+	unlock_dentry(dentry);
@


1.1.2.4
log
@Remove git cruft and add 2 patch descriptions
@
text
@d12 4
@


1.1.2.5
log
@Folded unionfs-lkml-comments-jan
@
text
@d12 1
a12 1
diff -r 9b8b53d675ec fs/unionfs/commonfops.c
d14 2
a15 2
+++ b/fs/unionfs/commonfops.c	Mon Dec 11 09:01:13 2006 -0500
@@@@ -0,0 +1,593 @@@@
d94 1
a94 2
+ * array
+ */
d259 1
a259 2
+	 * things.
+	 */
d333 1
a333 2
+		 * we would miss the reference on release.
+		 */
d358 1
a358 3
+		/* if the open will change the file, copy it up otherwise
+		 * defer it.
+		 */
d429 1
a429 2
+	 * these hidden file structs
+	 */
@


1.1.2.6
log
@A. Bunk's patch, more akpm comments, new copyright
@
text
@d12 3
a14 5
diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
new file mode 100644
index 0000000..6226a34
--- /dev/null
+++ b/fs/unionfs/commonfops.c
d17 1
a17 1
+ * Copyright (c) 2003-2007 Erez Zadok
d19 1
a19 1
+ * Copyright (c) 2005-2007 Josef 'Jeff' Sipek
d26 2
a27 2
+ * Copyright (c) 2003-2007 Stony Brook University
+ * Copyright (c) 2003-2007 The Research Foundation of State University of New York
@


