コード例 #1
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
/* perform a delayed copyup of a read-write file on a read-only branch */
static int do_delayed_copyup(struct file *file, struct dentry *parent)
{
	int bindex, bstart, bend, err = 0;
	struct dentry *dentry = file->f_path.dentry;
	struct inode *parent_inode = parent->d_inode;

	bstart = fbstart(file);
	bend = fbend(file);

	BUG_ON(!S_ISREG(dentry->d_inode->i_mode));

	unionfs_check_file(file);
	for (bindex = bstart - 1; bindex >= 0; bindex--) {
		if (!d_deleted(dentry))
			err = copyup_file(parent_inode, file, bstart,
					  bindex,
					  i_size_read(dentry->d_inode));
		else
			err = copyup_deleted_file(file, dentry, parent,
						  bstart, bindex);
		/* if succeeded, set lower open-file flags and break */
		if (!err) {
			struct file *lower_file;
			lower_file = unionfs_lower_file_idx(file, bindex);
			lower_file->f_flags = file->f_flags;
			break;
		}
	}
	if (err || (bstart <= fbstart(file)))
		goto out;
	bend = fbend(file);
	for (bindex = bstart; bindex <= bend; bindex++) {
		if (unionfs_lower_file_idx(file, bindex)) {
			branchput(dentry->d_sb, bindex);
			fput(unionfs_lower_file_idx(file, bindex));
			unionfs_set_lower_file_idx(file, bindex, NULL);
		}
	}
	path_put_lowers(dentry, bstart, bend, false);
	iput_lowers(dentry->d_inode, bstart, bend, false);
	/* for reg file, we only open it "once" */
	fbend(file) = fbstart(file);
	dbend(dentry) = dbstart(dentry);
	ibend(dentry->d_inode) = ibstart(dentry->d_inode);

out:
	unionfs_check_file(file);
	return err;
}
コード例 #2
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
/* unionfs_open helper function: open a directory */
static int __open_dir(struct inode *inode, struct file *file)
{
	struct dentry *lower_dentry;
	struct file *lower_file;
	int bindex, bstart, bend;
	struct vfsmount *mnt;

	bstart = fbstart(file) = dbstart(file->f_path.dentry);
	bend = fbend(file) = dbend(file->f_path.dentry);

	for (bindex = bstart; bindex <= bend; bindex++) {
		lower_dentry =
			unionfs_lower_dentry_idx(file->f_path.dentry, bindex);
		if (!lower_dentry)
			continue;

		dget(lower_dentry);
		unionfs_mntget(file->f_path.dentry, bindex);
		mnt = unionfs_lower_mnt_idx(file->f_path.dentry, bindex);
		lower_file = dentry_open(lower_dentry, mnt, file->f_flags,
					 current_cred());
		if (IS_ERR(lower_file))
			return PTR_ERR(lower_file);

		unionfs_set_lower_file_idx(file, bindex, lower_file);

		/*
		 * The branchget goes after the open, because otherwise
		 * we would miss the reference on release.
		 */
		branchget(inode->i_sb, bindex);
	}

	return 0;
}
コード例 #3
0
ファイル: file.c プロジェクト: kizukukoto/WDN900_GPL
int unionfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
	int bindex, bstart, bend;
	struct file *lower_file;
	struct dentry *lower_dentry;
	struct dentry *parent;
	struct inode *lower_inode, *inode;
	int err = -EINVAL;

	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
	parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
	unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);

	err = unionfs_file_revalidate(file, parent, true);
	if (unlikely(err))
		goto out;
	unionfs_check_file(file);

	bstart = fbstart(file);
	bend = fbend(file);
	if (bstart < 0 || bend < 0)
		goto out;

	inode = dentry->d_inode;
	if (unlikely(!inode)) {
		printk(KERN_ERR
		       "unionfs: null lower inode in unionfs_fsync\n");
		goto out;
	}
	for (bindex = bstart; bindex <= bend; bindex++) {
		lower_inode = unionfs_lower_inode_idx(inode, bindex);
		if (!lower_inode || !lower_inode->i_fop->fsync)
			continue;
		lower_file = unionfs_lower_file_idx(file, bindex);
		lower_dentry = unionfs_lower_dentry_idx(dentry, bindex);
		mutex_lock(&lower_inode->i_mutex);
		err = lower_inode->i_fop->fsync(lower_file,
						lower_dentry,
						datasync);
		if (!err && bindex == bstart)
			fsstack_copy_attr_times(inode, lower_inode);
		mutex_unlock(&lower_inode->i_mutex);
		if (err)
			goto out;
	}

out:
	if (!err)
		unionfs_check_file(file);
	unionfs_unlock_dentry(dentry);
	unionfs_unlock_parent(dentry, parent);
	unionfs_read_unlock(dentry->d_sb);
	return err;
}
コード例 #4
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
/*
 * put all references held by upper struct file and free lower file pointer
 * array
 */
static void cleanup_file(struct file *file)
{
	int bindex, bstart, bend;
	struct file **lower_files;
	struct file *lower_file;
	struct super_block *sb = file->f_path.dentry->d_sb;

	lower_files = UNIONFS_F(file)->lower_files;
	bstart = fbstart(file);
	bend = fbend(file);

	for (bindex = bstart; bindex <= bend; bindex++) {
		int i;	/* holds (possibly) updated branch index */
		int old_bid;

		lower_file = unionfs_lower_file_idx(file, bindex);
		if (!lower_file)
			continue;

		/*
		 * Find new index of matching branch with an open
		 * file, since branches could have been added or
		 * deleted causing the one with open files to shift.
		 */
		old_bid = UNIONFS_F(file)->saved_branch_ids[bindex];
		i = branch_id_to_idx(sb, old_bid);
		if (unlikely(i < 0)) {
			printk(KERN_ERR "unionfs: no superblock for "
			       "file %p\n", file);
			continue;
		}

		/* decrement count of open files */
		branchput(sb, i);
		/*
		 * fput will perform an mntput for us on the correct branch.
		 * Although we're using the file's old branch configuration,
		 * bindex, which is the old index, correctly points to the
		 * right branch in the file's branch list.  In other words,
		 * we're going to mntput the correct branch even if branches
		 * have been added/removed.
		 */
		fput(lower_file);
		UNIONFS_F(file)->lower_files[bindex] = NULL;
		UNIONFS_F(file)->saved_branch_ids[bindex] = -1;
	}

	UNIONFS_F(file)->lower_files = NULL;
	kfree(lower_files);
	kfree(UNIONFS_F(file)->saved_branch_ids);
	/* set to NULL because caller needs to know if to kfree on error */
	UNIONFS_F(file)->saved_branch_ids = NULL;
}
コード例 #5
0
ファイル: file.c プロジェクト: BackupTheBerlios/dss-svn
/* this unionfs_write() does not modify data pages! */
ssize_t unionfs_write(struct file * file, const char *buf, size_t count,
		      loff_t * ppos)
{
	int err = -EINVAL;
	struct file *hidden_file = NULL;
	struct inode *inode;
	struct inode *hidden_inode;
	loff_t pos = *ppos;
	int bstart, bend;

	print_entry_location();

	if ((err = unionfs_file_revalidate(file, 1)))
		goto out;

	inode = file->f_dentry->d_inode;

	bstart = fbstart(file);
	bend = fbend(file);

	ASSERT(bstart != -1);
	PASSERT(ftopd(file));
	PASSERT(ftohf(file));

	hidden_file = ftohf(file);
	hidden_inode = hidden_file->f_dentry->d_inode;

	if (!hidden_file->f_op || !hidden_file->f_op->write)
		goto out;

	/* adjust for append -- seek to the end of the file */
	if (file->f_flags & O_APPEND)
		pos = inode->i_size;

	err = hidden_file->f_op->write(hidden_file, buf, count, &pos);

	/*
	 * copy ctime and mtime from lower layer attributes
	 * atime is unchanged for both layers
	 */
	if (err >= 0)
		fist_copy_attr_times(inode, hidden_inode);

	*ppos = pos;

	/* update this inode's size */
	if (pos > inode->i_size)
		inode->i_size = pos;

      out:
	print_exit_status(err);
	return err;
}
コード例 #6
0
ファイル: file.c プロジェクト: fullstory-morgue/aufs
int au_reopen_nondir(struct file *file)
{
	int err;
	struct dentry *dentry;
	aufs_bindex_t bstart, bindex, bend;
	struct file *hidden_file, *h_file_tmp;

	dentry = file->f_dentry;
	LKTRTrace("%.*s\n", DLNPair(dentry));
	DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode)
		 || !au_h_dptr(dentry)->d_inode);
	bstart = dbstart(dentry);

	h_file_tmp = NULL;
	if (fbstart(file) == bstart) {
		hidden_file = au_h_fptr(file);
		if (file->f_mode == hidden_file->f_mode)
			return 0; /* success */
		h_file_tmp = hidden_file;
		get_file(h_file_tmp);
		set_h_fptr(file, bstart, NULL);
	}
	DEBUG_ON(fbstart(file) < bstart
		 || ftofi(file)->fi_hfile[0 + bstart].hf_file);

	hidden_file = hidden_open(dentry, bstart, file->f_flags & ~O_TRUNC);
	//if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bstart));
	//hidden_file = ERR_PTR(-1);}
	err = PTR_ERR(hidden_file);
	if (IS_ERR(hidden_file))
		goto out; // close all?
	err = 0;
	//cpup_file_flags(hidden_file, file);
	set_fbstart(file, bstart);
	set_h_fptr(file, bstart, hidden_file);
	memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(file->f_ra)); //??

	/* close lower files */
	bend = fbend(file);
	for (bindex = bstart + 1; bindex <= bend; bindex++)
		set_h_fptr(file, bindex, NULL);
	set_fbend(file, bstart);

 out:
	if (h_file_tmp)
		fput(h_file_tmp);
	TraceErr(err);
	return err;
}
コード例 #7
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
int unionfs_flush(struct file *file, fl_owner_t id)
{
	int err = 0;
	struct file *lower_file = NULL;
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *parent;
	int bindex, bstart, bend;

	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
	parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
	unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);

	err = unionfs_file_revalidate(file, parent,
				      UNIONFS_F(file)->wrote_to_file);
	if (unlikely(err))
		goto out;
	unionfs_check_file(file);

	bstart = fbstart(file);
	bend = fbend(file);
	for (bindex = bstart; bindex <= bend; bindex++) {
		lower_file = unionfs_lower_file_idx(file, bindex);

		if (lower_file && lower_file->f_op &&
		    lower_file->f_op->flush) {
			err = lower_file->f_op->flush(lower_file, id);
			if (err)
				goto out;
		}

	}

out:
	if (!err)
		unionfs_check_file(file);
	unionfs_unlock_dentry(dentry);
	unionfs_unlock_parent(dentry, parent);
	unionfs_read_unlock(dentry->d_sb);
	return err;
}
コード例 #8
0
ファイル: dirfops.c プロジェクト: mayli/unionfs-2.6.32.y
static int unionfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
	int err = 0;
	struct file *lower_file = NULL;
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *parent;
	struct inode *inode = NULL;
	struct unionfs_getdents_callback buf;
	struct unionfs_dir_state *uds;
	int bend;
	loff_t offset;

	unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_PARENT);
	parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
	unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);

	err = unionfs_file_revalidate(file, parent, false);
	if (unlikely(err))
		goto out;

	inode = dentry->d_inode;

	uds = UNIONFS_F(file)->rdstate;
	if (!uds) {
		if (file->f_pos == DIREOF) {
			goto out;
		} else if (file->f_pos > 0) {
			uds = find_rdstate(inode, file->f_pos);
			if (unlikely(!uds)) {
				err = -ESTALE;
				goto out;
			}
			UNIONFS_F(file)->rdstate = uds;
		} else {
			init_rdstate(file);
			uds = UNIONFS_F(file)->rdstate;
		}
	}
	bend = fbend(file);

	while (uds->bindex <= bend) {
		lower_file = unionfs_lower_file_idx(file, uds->bindex);
		if (!lower_file) {
			uds->bindex++;
			uds->dirpos = 0;
			continue;
		}

		/* prepare callback buffer */
		buf.filldir_called = 0;
		buf.filldir_error = 0;
		buf.entries_written = 0;
		buf.dirent = dirent;
		buf.filldir = filldir;
		buf.rdstate = uds;
		buf.sb = inode->i_sb;

		/* Read starting from where we last left off. */
		offset = vfs_llseek(lower_file, uds->dirpos, SEEK_SET);
		if (offset < 0) {
			err = offset;
			goto out;
		}
		err = vfs_readdir(lower_file, unionfs_filldir, &buf);

		/* Save the position for when we continue. */
		offset = vfs_llseek(lower_file, 0, SEEK_CUR);
		if (offset < 0) {
			err = offset;
			goto out;
		}
		uds->dirpos = offset;

		/* Copy the atime. */
		fsstack_copy_attr_atime(inode,
					lower_file->f_path.dentry->d_inode);

		if (err < 0)
			goto out;

		if (buf.filldir_error)
			break;

		if (!buf.entries_written) {
			uds->bindex++;
			uds->dirpos = 0;
		}
	}

	if (!buf.filldir_error && uds->bindex >= bend) {
		/* Save the number of hash entries for next time. */
		UNIONFS_I(inode)->hashsize = uds->hashentries;
		free_rdstate(uds);
		UNIONFS_F(file)->rdstate = NULL;
		file->f_pos = DIREOF;
	} else {
		file->f_pos = rdstate2offset(uds);
	}

out:
	if (!err)
		unionfs_check_file(file);
	unionfs_unlock_dentry(dentry);
	unionfs_unlock_parent(dentry, parent);
	unionfs_read_unlock(dentry->d_sb);
	return err;
}
コード例 #9
0
ファイル: debug.c プロジェクト: robacklin/ts7800
void __unionfs_check_file(const struct file *file,
			  const char *fname, const char *fxn, int line)
{
	int bindex;
	int dstart, dend, fstart, fend;
	struct dentry *dentry;
	struct file *lower_file;
	struct inode *inode;
	struct super_block *sb;
	int printed_caller = 0;

	BUG_ON(!file);
	dentry = file->f_path.dentry;
	sb = dentry->d_sb;
	dstart = dbstart(dentry);
	dend = dbend(dentry);
	BUG_ON(dstart > dend);
	fstart = fbstart(file);
	fend = fbend(file);
	BUG_ON(fstart > fend);

	if (unlikely((fstart == -1 && fend != -1) ||
		     (fstart != -1 && fend == -1))) {
		PRINT_CALLER(fname, fxn, line);
		pr_debug(" CF0: file/dentry=%p:%p fstart/end=%d:%d\n",
			 file, dentry, fstart, fend);
	}
	if (unlikely(fstart != dstart)) {
		PRINT_CALLER(fname, fxn, line);
		pr_debug(" CF1: file/dentry=%p:%p fstart=%d dstart=%d\n",
			 file, dentry, fstart, dstart);
	}
	if (unlikely(fend != dend)) {
		PRINT_CALLER(fname, fxn, line);
		pr_debug(" CF2: file/dentry=%p:%p fend=%d dend=%d\n",
			 file, dentry, fend, dend);
	}
	inode = dentry->d_inode;
	if (!S_ISDIR(inode->i_mode)) {
		if (unlikely(fend != fstart)) {
			PRINT_CALLER(fname, fxn, line);
			pr_debug(" CF3: file/inode=%p:%p fstart=%d fend=%d\n",
				 file, inode, fstart, fend);
		}
		if (unlikely(dend != dstart)) {
			PRINT_CALLER(fname, fxn, line);
			pr_debug(" CF4: file/dentry=%p:%p dstart=%d dend=%d\n",
				 file, dentry, dstart, dend);
		}
	}

	/*
	 * check for NULL dentries inside the start/end range, or
	 * non-NULL dentries outside the start/end range.
	 */
	for (bindex = sbstart(sb); bindex < sbmax(sb); bindex++) {
		lower_file = unionfs_lower_file_idx(file, bindex);
		if (lower_file) {
			if (unlikely(bindex < fstart || bindex > fend)) {
				PRINT_CALLER(fname, fxn, line);
				pr_debug(" CF5: file/lower=%p:%p bindex=%d "
					 "fstart/end=%d:%d\n", file,
					 lower_file, bindex, fstart, fend);
			}
		} else {	/* lower_file == NULL */
			if (bindex >= fstart && bindex <= fend) {
				/*
				 * directories can have NULL lower inodes in
				 * b/t start/end, but NOT if at the
				 * start/end range.
				 */
				if (unlikely(!(S_ISDIR(inode->i_mode) &&
					       bindex > fstart &&
					       bindex < fend))) {
					PRINT_CALLER(fname, fxn, line);
					pr_debug(" CF6: file/lower=%p:%p "
						 "bindex=%d fstart/end=%d:%d\n",
						 file, lower_file, bindex,
						 fstart, fend);
				}
			}
		}
	}

	__unionfs_check_dentry(dentry, fname, fxn, line);
}
コード例 #10
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
/*
 * release all lower object references & free the file info structure
 *
 * No need to grab sb info's rwsem.
 */
int unionfs_file_release(struct inode *inode, struct file *file)
{
	struct file *lower_file = NULL;
	struct unionfs_file_info *fileinfo;
	struct unionfs_inode_info *inodeinfo;
	struct super_block *sb = inode->i_sb;
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *parent;
	int bindex, bstart, bend;
	int fgen, err = 0;

	/*
	 * Since mm/memory.c:might_fault() (under PROVE_LOCKING) was
	 * modified in 2.6.29-rc1 to call might_lock_read on mmap_sem, this
	 * has been causing false positives in file system stacking layers.
	 * In particular, our ->mmap is called after sys_mmap2 already holds
	 * mmap_sem, then we lock our own mutexes; but earlier, it's
	 * possible for lockdep to have locked our mutexes first, and then
	 * we call a lower ->readdir which could call might_fault.  The
	 * different ordering of the locks is what lockdep complains about
	 * -- unnecessarily.  Therefore, we have no choice but to tell
	 * lockdep to temporarily turn off lockdep here.  Note: the comments
	 * inside might_sleep also suggest that it would have been
	 * nicer to only annotate paths that needs that might_lock_read.
	 */
	lockdep_off();
	unionfs_read_lock(sb, UNIONFS_SMUTEX_PARENT);
	parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
	unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);

	/*
	 * We try to revalidate, but the VFS ignores return return values
	 * from file->release, so we must always try to succeed here,
	 * including to do the kfree and dput below.  So if revalidation
	 * failed, all we can do is print some message and keep going.
	 */
	err = unionfs_file_revalidate(file, parent,
				      UNIONFS_F(file)->wrote_to_file);
	if (!err)
		unionfs_check_file(file);
	fileinfo = UNIONFS_F(file);
	BUG_ON(file->f_path.dentry->d_inode != inode);
	inodeinfo = UNIONFS_I(inode);

	/* fput all the lower files */
	fgen = atomic_read(&fileinfo->generation);
	bstart = fbstart(file);
	bend = fbend(file);

	for (bindex = bstart; bindex <= bend; bindex++) {
		lower_file = unionfs_lower_file_idx(file, bindex);

		if (lower_file) {
			unionfs_set_lower_file_idx(file, bindex, NULL);
			fput(lower_file);
			branchput(sb, bindex);
		}

		/* if there are no more refs to the dentry, dput it */
		if (d_deleted(dentry)) {
			dput(unionfs_lower_dentry_idx(dentry, bindex));
			unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
		}
	}

	kfree(fileinfo->lower_files);
	kfree(fileinfo->saved_branch_ids);

	if (fileinfo->rdstate) {
		fileinfo->rdstate->access = jiffies;
		spin_lock(&inodeinfo->rdlock);
		inodeinfo->rdcount++;
		list_add_tail(&fileinfo->rdstate->cache,
			      &inodeinfo->readdircache);
		mark_inode_dirty(inode);
		spin_unlock(&inodeinfo->rdlock);
		fileinfo->rdstate = NULL;
	}
	kfree(fileinfo);

	unionfs_unlock_dentry(dentry);
	unionfs_unlock_parent(dentry, parent);
	unionfs_read_unlock(sb);
	lockdep_on();
	return err;
}
コード例 #11
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
int unionfs_open(struct inode *inode, struct file *file)
{
	int err = 0;
	struct file *lower_file = NULL;
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *parent;
	int bindex = 0, bstart = 0, bend = 0;
	int size;
	int valid = 0;

	unionfs_read_lock(inode->i_sb, UNIONFS_SMUTEX_PARENT);
	parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT);
	unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD);

	/* don't open unhashed/deleted files */
	if (d_deleted(dentry)) {
		err = -ENOENT;
		goto out_nofree;
	}

	/* XXX: should I change 'false' below to the 'willwrite' flag? */
	valid = __unionfs_d_revalidate(dentry, parent, false);
	if (unlikely(!valid)) {
		err = -ESTALE;
		goto out_nofree;
	}

	file->private_data =
		kzalloc(sizeof(struct unionfs_file_info), GFP_KERNEL);
	if (unlikely(!UNIONFS_F(file))) {
		err = -ENOMEM;
		goto out_nofree;
	}
	fbstart(file) = -1;
	fbend(file) = -1;
	atomic_set(&UNIONFS_F(file)->generation,
		   atomic_read(&UNIONFS_I(inode)->generation));

	size = sizeof(struct file *) * sbmax(inode->i_sb);
	UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
	if (unlikely(!UNIONFS_F(file)->lower_files)) {
		err = -ENOMEM;
		goto out;
	}
	size = sizeof(int) * sbmax(inode->i_sb);
	UNIONFS_F(file)->saved_branch_ids = kzalloc(size, GFP_KERNEL);
	if (unlikely(!UNIONFS_F(file)->saved_branch_ids)) {
		err = -ENOMEM;
		goto out;
	}

	bstart = fbstart(file) = dbstart(dentry);
	bend = fbend(file) = dbend(dentry);

	/*
	 * open all directories and make the unionfs file struct point to
	 * these lower file structs
	 */
	if (S_ISDIR(inode->i_mode))
		err = __open_dir(inode, file);	/* open a dir */
	else
		err = __open_file(inode, file, parent);	/* open a file */

	/* freeing the allocated resources, and fput the opened files */
	if (err) {
		for (bindex = bstart; bindex <= bend; bindex++) {
			lower_file = unionfs_lower_file_idx(file, bindex);
			if (!lower_file)
				continue;

			branchput(dentry->d_sb, bindex);
			/* fput calls dput for lower_dentry */
			fput(lower_file);
		}
	}

out:
	if (err) {
		kfree(UNIONFS_F(file)->lower_files);
		kfree(UNIONFS_F(file)->saved_branch_ids);
		kfree(UNIONFS_F(file));
	}
out_nofree:
	if (!err) {
		unionfs_postcopyup_setmnt(dentry);
		unionfs_copy_attr_times(inode);
		unionfs_check_file(file);
		unionfs_check_inode(inode);
	}
	unionfs_unlock_dentry(dentry);
	unionfs_unlock_parent(dentry, parent);
	unionfs_read_unlock(inode->i_sb);
	return err;
}
コード例 #12
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
/* unionfs_open helper function: open a file */
static int __open_file(struct inode *inode, struct file *file,
		       struct dentry *parent)
{
	struct dentry *lower_dentry;
	struct file *lower_file;
	int lower_flags;
	int bindex, bstart, bend;

	lower_dentry = unionfs_lower_dentry(file->f_path.dentry);
	lower_flags = file->f_flags;

	bstart = fbstart(file) = dbstart(file->f_path.dentry);
	bend = fbend(file) = dbend(file->f_path.dentry);

	/*
	 * check for the permission for lower file.  If the error is
	 * COPYUP_ERR, copyup the file.
	 */
	if (lower_dentry->d_inode && is_robranch(file->f_path.dentry)) {
		/*
		 * if the open will change the file, copy it up otherwise
		 * defer it.
		 */
		if (lower_flags & O_TRUNC) {
			int size = 0;
			int err = -EROFS;

			/* copyup the file */
			for (bindex = bstart - 1; bindex >= 0; bindex--) {
				err = copyup_file(parent->d_inode, file,
						  bstart, bindex, size);
				if (!err) {
					/* only one regular file open */
					fbend(file) = fbstart(file);
					break;
				}
			}
			return err;
		} else {
			/*
			 * turn off writeable flags, to force delayed copyup
			 * by caller.
			 */
			lower_flags &= ~(OPEN_WRITE_FLAGS);
		}
	}

	dget(lower_dentry);

	/*
	 * dentry_open will decrement mnt refcnt if err.
	 * otherwise fput() will do an mntput() for us upon file close.
	 */
	unionfs_mntget(file->f_path.dentry, bstart);
	lower_file =
		dentry_open(lower_dentry,
			    unionfs_lower_mnt_idx(file->f_path.dentry, bstart),
			    lower_flags, current_cred());
	if (IS_ERR(lower_file))
		return PTR_ERR(lower_file);

	unionfs_set_lower_file(file, lower_file);
	branchget(inode->i_sb, bstart);

	return 0;
}
コード例 #13
0
ファイル: commonfops.c プロジェクト: mayli/unionfs-2.6.32.y
/*
 * Helper function for unionfs_file_revalidate/locked.
 * Expects dentry/parent to be locked already, and revalidated.
 */
static int __unionfs_file_revalidate(struct file *file, struct dentry *dentry,
				     struct dentry *parent,
				     struct super_block *sb, int sbgen,
				     int dgen, bool willwrite)
{
	int fgen;
	int bstart, bend, orig_brid;
	int size;
	int err = 0;

	fgen = atomic_read(&UNIONFS_F(file)->generation);

	/*
	 * 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) &&
	     unionfs_lower_file(file)))
		goto out_may_copyup;

	/* save orig branch ID */
	orig_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];

	/* First we throw out the existing files. */
	cleanup_file(file);

	/* 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);
	UNIONFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL);
	if (unlikely(!UNIONFS_F(file)->lower_files)) {
		err = -ENOMEM;
		goto out;
	}
	size = sizeof(int) * sbmax(sb);
	UNIONFS_F(file)->saved_branch_ids = kzalloc(size, GFP_KERNEL);
	if (unlikely(!UNIONFS_F(file)->saved_branch_ids)) {
		err = -ENOMEM;
		goto out;
	}

	if (S_ISDIR(dentry->d_inode->i_mode)) {
		/* We need to open all the files. */
		err = open_all_files(file);
		if (err)
			goto out;
	} else {
		int new_brid;
		/* We only open the highest priority branch. */
		err = open_highest_file(file, willwrite);
		if (err)
			goto out;
		new_brid = UNIONFS_F(file)->saved_branch_ids[fbstart(file)];
		if (unlikely(new_brid != orig_brid && sbgen > fgen)) {
			/*
			 * If we re-opened the file on a different branch
			 * than the original one, and this was due to a new
			 * branch inserted, then update the mnt counts of
			 * the old and new branches accordingly.
			 */
			unionfs_mntget(dentry, bstart);
			unionfs_mntput(sb->s_root,
				       branch_id_to_idx(sb, orig_brid));
		}
		/* regular files have only one open lower file */
		fbend(file) = fbstart(file);
	}
	atomic_set(&UNIONFS_F(file)->generation,
		   atomic_read(&UNIONFS_I(dentry->d_inode)->generation));

out_may_copyup:
	/* Copyup on the first write to a file on a readonly branch. */
	if (willwrite && IS_WRITE_FLAG(file->f_flags) &&
	    !IS_WRITE_FLAG(unionfs_lower_file(file)->f_flags) &&
	    is_robranch(dentry)) {
		pr_debug("unionfs: do delay copyup of \"%s\"\n",
			 dentry->d_name.name);
		err = do_delayed_copyup(file, parent);
		/* regular files have only one open lower file */
		if (!err && !S_ISDIR(dentry->d_inode->i_mode))
			fbend(file) = fbstart(file);
	}

out:
	if (err) {
		kfree(UNIONFS_F(file)->lower_files);
		kfree(UNIONFS_F(file)->saved_branch_ids);
	}
	return err;
}