Exemple #1
0
/*
 * 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 int __copyup_ndentry(struct dentry *old_lower_dentry,
			    struct dentry *new_lower_dentry,
			    struct dentry *new_lower_parent_dentry,
			    char *symbuf)
{
	int err = 0;
	umode_t old_mode = old_lower_dentry->d_inode->i_mode;
	struct sioq_args args;

	if (S_ISDIR(old_mode)) {
		args.mkdir.parent = new_lower_parent_dentry->d_inode;
		args.mkdir.dentry = new_lower_dentry;
		args.mkdir.mode = old_mode;

		run_sioq(__unionfs_mkdir, &args);
		err = args.err;
	} else if (S_ISLNK(old_mode)) {
		args.symlink.parent = new_lower_parent_dentry->d_inode;
		args.symlink.dentry = new_lower_dentry;
		args.symlink.symbuf = symbuf;

		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.mknod.parent = new_lower_parent_dentry->d_inode;
		args.mknod.dentry = new_lower_dentry;
		args.mknod.mode = old_mode;
		args.mknod.dev = old_lower_dentry->d_inode->i_rdev;

		run_sioq(__unionfs_mknod, &args);
		err = args.err;
	} else if (S_ISREG(old_mode)) {
		struct nameidata nd;
		err = init_lower_nd(&nd, LOOKUP_CREATE);
		if (unlikely(err < 0))
			goto out;
		args.create.nd = &nd;
		args.create.parent = new_lower_parent_dentry->d_inode;
		args.create.dentry = new_lower_dentry;
		args.create.mode = old_mode;

		run_sioq(__unionfs_create, &args);
		err = args.err;
		release_lower_nd(&nd, err);
	} else {
		printk(KERN_CRIT "unionfs: unknown inode type %d\n",
		       old_mode);
		BUG();
	}

out:
	return err;
}
static int unionfs_create(struct inode *dir, struct dentry *dentry,
			  int mode, struct nameidata *nd_unused)
{
	int err = 0;
	struct dentry *lower_dentry = NULL;
	struct dentry *lower_parent_dentry = NULL;
	struct dentry *parent;
	int valid = 0;
	struct nameidata lower_nd;

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

	valid = __unionfs_d_revalidate(dentry, parent, false);
	if (unlikely(!valid)) {
		err = -ESTALE;	/* same as what real_lookup does */
		goto out;
	}

	lower_dentry = find_writeable_branch(dir, dentry);
	if (IS_ERR(lower_dentry)) {
		err = PTR_ERR(lower_dentry);
		goto out;
	}

	lower_parent_dentry = lock_parent(lower_dentry);
	if (IS_ERR(lower_parent_dentry)) {
		err = PTR_ERR(lower_parent_dentry);
		goto out_unlock;
	}

	err = init_lower_nd(&lower_nd, LOOKUP_CREATE);
	if (unlikely(err < 0))
		goto out_unlock;
	err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode,
			 &lower_nd);
	release_lower_nd(&lower_nd, err);

	if (!err) {
		err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
		if (!err) {
			unionfs_copy_attr_times(dir);
			fsstack_copy_inode_size(dir,
						lower_parent_dentry->d_inode);
			/* update no. of links on parent directory */
			dir->i_nlink = unionfs_get_nlinks(dir);
		}
	}

out_unlock:
	unlock_dir(lower_parent_dentry);
out:
	if (!err) {
		unionfs_postcopyup_setmnt(dentry);
		unionfs_check_inode(dir);
		unionfs_check_dentry(dentry);
	}
	unionfs_unlock_dentry(dentry);
	unionfs_unlock_parent(dentry, parent);
	unionfs_read_unlock(dentry->d_sb);
	return err;
}