예제 #1
0
static int __open_file(struct inode *inode, struct file *file,
			struct dentry *parent)
{
	struct dentry *lower_dentry;
	struct file *lower_file;
	struct vfsmount *lower_mnt;
	struct dentry *dentry  = file->f_path.dentry;
	int lower_flags;
	int i = 0, idx = 0;
	for (i = 0; i <= 1; i++) {
		lower_dentry = wrapfs_lower_dentry_idx(dentry, i);
		if (!lower_dentry  || !lower_dentry->d_inode)
			continue;
		lower_flags = file->f_flags;

		if (lower_dentry->d_inode && (i == 1)) {
			UDBG;
			if (lower_flags & O_TRUNC) {
				int size = 0;
				int err = -EROFS;
				UDBG;

				err = copyup_file(parent->d_inode, file,
						  i, 0, size);
				if (!err)
					break;
				return err;
			} else
				lower_flags &= ~(OPEN_WRITE_FLAGS);
		}
		dget(lower_dentry);
		lower_mnt = mntget(wrapfs_lower_mnt_idx(dentry, i));

		if (!lower_mnt)
			lower_mnt = mntget(wrapfs_lower_mnt_idx(parent, i));

		lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags,
					current_cred());

		if (IS_ERR(lower_file))
			return PTR_ERR(lower_file);

		wrapfs_set_lower_file(file, lower_file);
		branchget(inode->i_sb, i);
		idx = i;
		goto out;
	}
out:
	if (!wrapfs_lower_inode_idx(inode, idx))
		fsstack_copy_attr_all(inode,
			wrapfs_lower_inode_idx(inode, idx));
	return 0;
}
예제 #2
0
/* 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;
}
예제 #3
0
/* open the highest priority file for a given upper file */
static int open_highest_file(struct file *file, bool willwrite)
{
	int bindex, bstart, bend, err = 0;
	struct file *lower_file;
	struct dentry *lower_dentry;
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *parent = dget_parent(dentry);
	struct inode *parent_inode = parent->d_inode;
	struct super_block *sb = dentry->d_sb;

	bstart = dbstart(dentry);
	bend = dbend(dentry);

	lower_dentry = unionfs_lower_dentry(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,
					  i_size_read(dentry->d_inode));
			if (!err)
				break;
		}
		atomic_set(&UNIONFS_F(file)->generation,
			   atomic_read(&UNIONFS_I(dentry->d_inode)->
				       generation));
		goto out;
	}

	dget(lower_dentry);
	unionfs_mntget(dentry, bstart);
	lower_file = dentry_open(lower_dentry,
				 unionfs_lower_mnt_idx(dentry, bstart),
				 file->f_flags, current_cred());
	if (IS_ERR(lower_file)) {
		err = PTR_ERR(lower_file);
		goto out;
	}
	branchget(sb, bstart);
	unionfs_set_lower_file(file, lower_file);
	/* Fix up the position. */
	lower_file->f_pos = file->f_pos;

	memcpy(&lower_file->f_ra, &file->f_ra, sizeof(struct file_ra_state));
out:
	dput(parent);
	return err;
}
예제 #4
0
/* 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;
}