Exemple #1
0
STATIC int
base0fs_mknod(inode_t *dir, struct dentry *dentry, int mode, dev_t dev)
{
        int err;
        struct dentry *lower_dentry;
        struct dentry *lower_dir_dentry;

        print_entry_location();
        lower_dentry = base0fs_lower_dentry(dentry);	/* CPW: Moved below print_entry_location */
        fist_checkinode(dir, "base0fs_mknod-dir");

        lower_dir_dentry = base0fs_lock_parent(lower_dentry);

        err = VFS_MKNOD(lower_dir_dentry->d_inode,
                        lower_dentry,
                        mode,
                        dev);
        if (err || !lower_dentry->d_inode)
                goto out;

        err = base0fs_interpose(lower_dentry, dentry, dir->i_sb, 0);
        if (err)
                goto out;
        fist_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);

out:
        unlock_dir(lower_dir_dentry);
        if (!dentry->d_inode)
                d_drop(dentry);

        fist_checkinode(dir, "post base0fs_mknod-dir");
        print_exit_status(err);
        return err;
}
Exemple #2
0
STATIC int
base0fs_link(struct dentry *old_dentry, inode_t *dir, struct dentry *new_dentry)
{
        int err;
        struct dentry *lower_old_dentry;
        struct dentry *lower_new_dentry;
        struct dentry *lower_dir_dentry;

        print_entry_location();
        lower_old_dentry = base0fs_lower_dentry(old_dentry);	/* CPW: Moved below print_entry_location */
        lower_new_dentry = base0fs_lower_dentry(new_dentry);

        fist_checkinode(dir, "base0fs_link-dir");
        fist_checkinode(old_dentry->d_inode, "base0fs_link-oldinode");

        dget(lower_old_dentry);
        dget(lower_new_dentry);
        lower_dir_dentry = base0fs_lock_parent(lower_new_dentry);


        err = VFS_LINK(lower_old_dentry,
                       lower_dir_dentry->d_inode,
                       lower_new_dentry);
        if (err || !lower_new_dentry->d_inode)
                goto out_lock;

        err = base0fs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
        if (err)
                goto out_lock;

        fist_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
        /* propagate number of hard-links */
        old_dentry->d_inode->i_nlink = INODE_TO_LOWER(old_dentry->d_inode)->i_nlink;

out_lock:
        unlock_dir(lower_dir_dentry);
        dput(lower_new_dentry);
        dput(lower_old_dentry);
        if (!new_dentry->d_inode)
                d_drop(new_dentry);

        print_exit_status(err);
        return err;
}
Exemple #3
0
STATIC int
base0fs_create(inode_t *dir, struct dentry *dentry, int mode, struct nameidata *nd)
{
        int err;
        struct dentry *lower_dentry;
	struct vfsmount *lower_mount;
        struct dentry *lower_dir_dentry;
	FIST_ND_DECLARATIONS;

        print_entry_location();
        lower_dentry = base0fs_lower_dentry(dentry);
        BUG_ON(!lower_dentry);
        fist_checkinode(dir, "base0fs_create");
	lower_mount = DENTRY_TO_LVFSMNT(dentry);

        lower_dir_dentry = base0fs_lock_parent(lower_dentry);
        err = PTR_ERR(lower_dir_dentry);
        if (IS_ERR(lower_dir_dentry))
                goto out;

	FIST_ND_SAVE_ARGS(dentry, lower_dentry, lower_mount);
        err = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, nd);
	FIST_ND_RESTORE_ARGS;
        /* XXX this could potentially return a negative lower_dentry! */
        if (err)
                goto out_lock;

        err = base0fs_interpose(lower_dentry, dentry, dir->i_sb, 0);
        if (err)
                goto out_lock;

        fist_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);


out_lock:
        unlock_dir(lower_dir_dentry);
out:
        fist_checkinode(dir, "post base0fs_create");
        print_exit_status(err);
        return err;
}
Exemple #4
0
STATIC int
base0fs_symlink(inode_t *dir, struct dentry *dentry, const char *symname)
{
        int err;
        struct dentry *lower_dentry;
        struct dentry *lower_dir_dentry;
        umode_t	mode;

        print_entry_location();
        lower_dentry = base0fs_lower_dentry(dentry);	/* CPW: Moved below print_entry_location */
        fist_checkinode(dir, "base0fs_symlink-dir");

        dget(lower_dentry);
        lower_dir_dentry = base0fs_lock_parent(lower_dentry);

        mode = S_IALLUGO;


        err = VFS_SYMLINK(lower_dir_dentry->d_inode, lower_dentry, symname, mode);


        if (err || !lower_dentry->d_inode)
                goto out_lock;
        err = base0fs_interpose(lower_dentry, dentry, dir->i_sb, 0);
        if (err)
                goto out_lock;

        fist_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
        fist_checkinode(dir, "post base0fs_symlink-dir");

out_lock:
        unlock_dir(lower_dir_dentry);
        dput(lower_dentry);
        if (!dentry->d_inode)
                d_drop(dentry);

        print_exit_status(err);
        return err;
}
Exemple #5
0
STATIC int
base0fs_mkdir(inode_t *dir, struct dentry *dentry, int mode)
{
        int err;
        struct dentry *lower_dentry;
        struct dentry *lower_dir_dentry;

        print_entry_location();
        lower_dentry = base0fs_lower_dentry(dentry);	/* CPW: Moved below print_entry_location */
        fist_checkinode(dir, "base0fs_mkdir-dir");

        lower_dir_dentry = base0fs_lock_parent(lower_dentry);

        err = VFS_MKDIR(lower_dir_dentry->d_inode,
                        lower_dentry,
                        mode);
        if (err || !lower_dentry->d_inode)
                goto out;

        err = base0fs_interpose(lower_dentry, dentry, dir->i_sb, 0);
        if (err)
                goto out;

        fist_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
        /* update number of links on parent directory */
        dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;

        fist_checkinode(dir, "post base0fs_mkdir-dir");

out:
        unlock_dir(lower_dir_dentry);
        if (!dentry->d_inode)
                d_drop(dentry);

        print_exit_status(err);
        return err;
}
Exemple #6
0
int create_sto_reg_file(dentry_t *dentry, int mode)
#endif
{
	int err = 0;
	inode_t *dir;
	dentry_t *hidden_sto_dentry;
	dentry_t *hidden_sto_dir_dentry;

	if(exists_in_storage(dentry)) {
		printk(KERN_CRIT "mini_fo: create_sto_file: wrong type or state.\n");
		err = -EINVAL;
		goto out;
	}
	err = get_neg_sto_dentry(dentry);

	if (err) {
		printk(KERN_CRIT "mini_fo: create_sto_file: ERROR getting neg. sto dentry.\n");
		goto out;
	}

	dir = dentry->d_parent->d_inode;
	hidden_sto_dentry = dtohd2(dentry);

	/* lock parent */
	hidden_sto_dir_dentry = dget(hidden_sto_dentry->d_parent);

	err = PTR_ERR(hidden_sto_dir_dentry);
        if (IS_ERR(hidden_sto_dir_dentry))
                goto out;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
	err = vfs_create(hidden_sto_dir_dentry->d_inode,
			 hidden_sto_dentry,
			 mode, nd);
#else
	err = vfs_create(hidden_sto_dir_dentry->d_inode,
			 hidden_sto_dentry,
			 mode);
#endif
        if(err) {
		printk(KERN_CRIT "mini_fo: create_sto_file: ERROR creating sto file.\n");
                goto out_lock;
	}

	if(!dtohd2(dentry)->d_inode) {
		printk(KERN_CRIT "mini_fo: create_sto_file: ERROR creating sto file [2].\n");
                err = -EINVAL;
                goto out_lock;
        }

        /* interpose the new inode */
        if(dtost(dentry) == DELETED) {
                dtost(dentry) = DEL_REWRITTEN;
                err = mini_fo_tri_interpose(NULL, hidden_sto_dentry, dentry, dir->i_sb, 0);
                if(err)
                        goto out_lock;
        }
        else if(dtost(dentry) == NON_EXISTANT) {
                dtost(dentry) = CREATED;
                err = mini_fo_tri_interpose(dtohd(dentry), hidden_sto_dentry, dentry, dir->i_sb, 0);
                if(err)
                        goto out_lock;
        }
        else if(dtost(dentry) == UNMODIFIED) {
                dtost(dentry) = MODIFIED;
                /* interpose on new inode */
                if(itohi2(dentry->d_inode) != NULL) {
                        printk(KERN_CRIT "mini_fo: create_sto_file: invalid inode detected.\n");
                        err = -EINVAL;
                        goto out_lock;
                }
                itohi2(dentry->d_inode) = igrab(dtohd2(dentry)->d_inode);
	}
	fist_copy_attr_timesizes(dentry->d_parent->d_inode,
				 hidden_sto_dir_dentry->d_inode);

 out_lock:
        dput(hidden_sto_dir_dentry);
 out:
	return err;
}
Exemple #7
0
int create_sto_nod(dentry_t *dentry, int mode, int dev)
#endif
{
	int err = 0;
	inode_t *dir;
	dentry_t *hidden_sto_dentry;
	dentry_t *hidden_sto_dir_dentry;

	if(exists_in_storage(dentry)) {
		err = -EEXIST;
		goto out;
	}
	err = get_neg_sto_dentry(dentry);

	if (err) {
                printk(KERN_CRIT "mini_fo: create_sto_nod: ERROR getting neg. sto dentry.\n");
                goto out;
        }

	dir = dentry->d_parent->d_inode;
	hidden_sto_dentry = dtohd2(dentry);

	/* lock parent */
	hidden_sto_dir_dentry = dget(hidden_sto_dentry->d_parent);

	err = PTR_ERR(hidden_sto_dir_dentry);
	if (IS_ERR(hidden_sto_dir_dentry))
		goto out;

	err = vfs_mknod(hidden_sto_dir_dentry->d_inode, hidden_sto_dentry, mode, dev);
	if(err)
		goto out_lock;

	if(!dtohd2(dentry)->d_inode) {
		printk(KERN_CRIT "mini_fo: create_sto_nod: creating storage inode failed [1].\n");
		err = -EINVAL; /* return something indicating failure */
		goto out_lock;
	}

	/* interpose the new inode */
	if(dtost(dentry) == DELETED) {
		dtost(dentry) = DEL_REWRITTEN;
		err = mini_fo_tri_interpose(NULL, hidden_sto_dentry, dentry, dir->i_sb, 0);
		if(err)
			goto out_lock;
	}
	else if(dtost(dentry) == NON_EXISTANT) {
		dtost(dentry) = CREATED;
		err = mini_fo_tri_interpose(dtohd(dentry), hidden_sto_dentry, dentry, dir->i_sb, 0);
		if(err)
			goto out_lock;
	}
	else if(dtost(dentry) == UNMODIFIED) {
		dtost(dentry) = MODIFIED;
		/* interpose on new inode */
		if(itohi2(dentry->d_inode) != NULL) {
			printk(KERN_CRIT "mini_fo: create_sto_nod: error, invalid inode detected.\n");
			err = -EINVAL;
			goto out_lock;
		}
		itohi2(dentry->d_inode) = igrab(dtohd2(dentry)->d_inode);
	}

	fist_copy_attr_timesizes(dir, hidden_sto_dir_dentry->d_inode);

 out_lock:
	dput(hidden_sto_dir_dentry);
 out:
	return err;
}
Exemple #8
0
/* create the sto dir, setup states */
int create_sto_dir(dentry_t *dentry, int mode)
{
	int err = 0;
	inode_t *dir;
	dentry_t *hidden_sto_dentry;
        dentry_t *hidden_sto_dir_dentry;

	/* had to take the "!S_ISDIR(mode))" check out, because it failed */
	if(exists_in_storage(dentry)) {
                printk(KERN_CRIT "mini_fo: create_sto_dir: wrong type or state.\\
n");
                err = -EINVAL;
                goto out;
        }

	err = get_neg_sto_dentry(dentry);
	if(err) {
		err = -EINVAL;
		goto out;
	}

	dir = dentry->d_parent->d_inode;
	hidden_sto_dentry = dtohd2(dentry);

	/* was: hidden_sto_dir_dentry = lock_parent(hidden_sto_dentry); */
	hidden_sto_dir_dentry = dget(hidden_sto_dentry->d_parent);

	err = PTR_ERR(hidden_sto_dir_dentry);
	if (IS_ERR(hidden_sto_dir_dentry))
		goto out;

	err = vfs_mkdir(hidden_sto_dir_dentry->d_inode,
			hidden_sto_dentry,
			mode);
	if(err) {
		printk(KERN_CRIT "mini_fo: create_sto_dir: ERROR creating sto dir.\n");
		goto out_lock;
	}

	if(!dtohd2(dentry)->d_inode) {
		printk(KERN_CRIT "mini_fo: create_sto_dir: ERROR creating sto dir [2].\n");
		err = -EINVAL;
		goto out_lock;
	}

	/* interpose the new inode */
	if(dtost(dentry) == DELETED) {
		dtost(dentry) = DEL_REWRITTEN;
		err = mini_fo_tri_interpose(NULL, hidden_sto_dentry, dentry, dir->i_sb, 0);
		if(err)
			goto out_lock;
	}
	else if(dtopd(dentry)->state == NON_EXISTANT) {
		dtopd(dentry)->state = CREATED;
		err = mini_fo_tri_interpose(dtohd(dentry), hidden_sto_dentry, dentry, dir->i_sb, 0);
		if(err)
			goto out_lock;
	}
	else if(dtopd(dentry)->state == UNMODIFIED) {
		dtopd(dentry)->state = MODIFIED;
		/* interpose on new inode */
		if(itohi2(dentry->d_inode) != NULL) {
			printk(KERN_CRIT "mini_fo:  create_sto_dir: ERROR, invalid inode detected.\n");
			err = -EINVAL;
			goto out_lock;
		}
		itohi2(dentry->d_inode) = igrab(dtohd2(dentry)->d_inode);
	}

	fist_copy_attr_timesizes(dir, hidden_sto_dir_dentry->d_inode);

	/* initalize the wol list */
	itopd(dentry->d_inode)->deleted_list_size = -1;
	itopd(dentry->d_inode)->renamed_list_size = -1;
	meta_build_lists(dentry);


 out_lock:
	/* was: unlock_dir(hidden_sto_dir_dentry); */
	dput(hidden_sto_dir_dentry);
 out:
	return err;
}
Exemple #9
0
static int unionfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
			 dev_t dev)
{
	int err = 0;
	struct dentry *hidden_dentry = NULL, *whiteout_dentry = NULL;
	struct dentry *hidden_parent_dentry = NULL;
	int bindex = 0, bstart;
	char *name = NULL;
	int whiteout_unlinked = 0;

	print_entry_location();
	lock_dentry(dentry);
	fist_print_dentry("IN unionfs_mknod", dentry);
	bstart = dbstart(dentry);

	hidden_dentry = dtohd(dentry);

	// check if whiteout exists in this branch, i.e. lookup .wh.foo first
	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
	if (IS_ERR(name)) {
		err = PTR_ERR(name);
		goto out;
	}

	whiteout_dentry =
	    LOOKUP_ONE_LEN(name, hidden_dentry->d_parent,
			   dentry->d_name.len + WHLEN);
	if (IS_ERR(whiteout_dentry)) {
		err = PTR_ERR(whiteout_dentry);
		goto out;
	}

	if (!whiteout_dentry->d_inode) {
		DPUT(whiteout_dentry);
		whiteout_dentry = NULL;
	} else {
		/* found .wh.foo, unlink it */
		hidden_parent_dentry = lock_parent(whiteout_dentry);

		//found a.wh.foo entry, remove it then do vfs_mkdir
		if (!(err = is_robranch_super(dentry->d_sb, bstart)))
			err = vfs_unlink(hidden_parent_dentry->d_inode,
					 whiteout_dentry);
		DPUT(whiteout_dentry);

		unlock_dir(hidden_parent_dentry);

		if (err) {
			if (!IS_COPYUP_ERR(err))
				goto out;

			bstart--;
		} else {
			whiteout_unlinked = 1;
		}
	}

	for (bindex = bstart; bindex >= 0; bindex--) {
		hidden_dentry = dtohd_index(dentry, bindex);
		if (!hidden_dentry) {
			hidden_dentry = create_parents(dir, dentry, bindex);
			if (!hidden_dentry || IS_ERR(hidden_dentry)) {
				fist_dprint(8,
					    "hidden dentry NULL for bindex = %d\n",
					    bindex);
				continue;
			}
		}

		hidden_parent_dentry = lock_parent(hidden_dentry);
		if (IS_ERR(hidden_parent_dentry)) {
			err = PTR_ERR(hidden_parent_dentry);
			goto out;
		}
		if (!(err = is_robranch_super(dentry->d_sb, bindex))) {
			err = vfs_mknod(hidden_parent_dentry->d_inode,
					hidden_dentry, mode, dev);
		}
		/* XXX this could potentially return a negative hidden_dentry! */
		if (err || !hidden_dentry->d_inode) {
			unlock_dir(hidden_parent_dentry);
			/* break out of for, if error was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				break;
		} else {
			err = unionfs_interpose(dentry, dir->i_sb, 0);
			if (!err) {
				fist_copy_attr_timesizes(dir,
							 hidden_parent_dentry->
							 d_inode);
				/* update number of links on parent directory */
				dir->i_nlink = get_nlinks(dir);
			}
			unlock_dir(hidden_parent_dentry);

			break;
		}
	}

      out:
	if (!dentry->d_inode)
		d_drop(dentry);

	if (name) {
		KFREE(name);
	}

	fist_print_dentry("OUT unionfs_mknod :", dentry);
	unlock_dentry(dentry);
	print_exit_status(err);
	return err;
}
Exemple #10
0
static int unionfs_mkdir(struct inode *parent, struct dentry *dentry, int mode)
{
	int err = 0;
	struct dentry *hidden_dentry = NULL, *whiteout_dentry = NULL;
	struct dentry *hidden_parent_dentry = NULL;
	int bindex = 0, bstart;
	char *name = NULL;
	int whiteout_unlinked = 0;
	uid_t saved_uid = current->fsuid;
	gid_t saved_gid = current->fsgid;

	print_entry_location();
	lock_dentry(dentry);
	fist_print_dentry("IN unionfs_mkdir", dentry);
	bstart = dbstart(dentry);

	hidden_dentry = dtohd(dentry);

	// check if whiteout exists in this branch, i.e. lookup .wh.foo first
	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
	if (IS_ERR(name)) {
		err = PTR_ERR(name);
		goto out;
	}

	whiteout_dentry =
	    LOOKUP_ONE_LEN(name, hidden_dentry->d_parent,
			   dentry->d_name.len + WHLEN);
	if (IS_ERR(whiteout_dentry)) {
		err = PTR_ERR(whiteout_dentry);
		goto out;
	}

	if (!whiteout_dentry->d_inode) {
		DPUT(whiteout_dentry);
		whiteout_dentry = NULL;
	} else {
		hidden_parent_dentry = lock_parent(whiteout_dentry);

		/* Set the uid and gid to trick the fs into allowing us to create
		 * the file */
		current->fsuid = hidden_parent_dentry->d_inode->i_uid;
		current->fsgid = hidden_parent_dentry->d_inode->i_gid;
		//found a.wh.foo entry, remove it then do vfs_mkdir
		if (!(err = is_robranch_super(dentry->d_sb, bstart))) {
			err =
			    vfs_unlink(hidden_parent_dentry->d_inode,
				       whiteout_dentry);
		}
		DPUT(whiteout_dentry);

		current->fsuid = saved_uid;
		current->fsgid = saved_gid;

		unlock_dir(hidden_parent_dentry);

		if (err) {
			/* exit if the error returned was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				goto out;
			bstart--;
		} else {
			whiteout_unlinked = 1;
		}
	}
	
	for (bindex = bstart; bindex >= 0; bindex--) {
		hidden_dentry = dtohd_index(dentry, bindex);
		if (!hidden_dentry) {
			hidden_dentry = create_parents(parent, dentry, bindex);
			if (!hidden_dentry || IS_ERR(hidden_dentry)) {
				fist_dprint(8,
					    "hidden dentry NULL for bindex = %d\n",
					    bindex);
				continue;
			}
		}

		hidden_parent_dentry = lock_parent(hidden_dentry);
		if (IS_ERR(hidden_parent_dentry)) {
			err = PTR_ERR(hidden_parent_dentry);
			goto out;
		}
		if (!(err = is_robranch_super(dentry->d_sb, bindex))) {
			err =
			    vfs_mkdir(hidden_parent_dentry->d_inode,
				      hidden_dentry, mode);
		}
		unlock_dir(hidden_parent_dentry);

		/* XXX this could potentially return a negative hidden_dentry! */
		if (err || !hidden_dentry->d_inode) {
			/* break out of for loop if error returned was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				break;
		} else {
			int i;
			int bend = dbend(dentry);
			
			for (i = bindex + 1; i < bend; i++) {
				if (dtohd_index(dentry, i)) {
					DPUT(dtohd_index(dentry, i));
					set_dtohd_index(dentry, i, NULL);
				}
			}
			bend = bindex;
			set_dbend(dentry, bend);

			err = unionfs_interpose(dentry, parent->i_sb, 0);
			if (!err) {
				fist_copy_attr_timesizes(parent,
							 hidden_parent_dentry->
							 d_inode);
				/* update number of links on parent directory */
				parent->i_nlink = get_nlinks(parent);
			}
			whiteout_dentry = LOOKUP_ONE_LEN(UNIONFS_DIR_OPAQUE,
							 hidden_dentry,
							 sizeof
							 (UNIONFS_DIR_OPAQUE) -
							 1);
			if (IS_ERR(whiteout_dentry)) {
				err = PTR_ERR(whiteout_dentry);
				goto out;
			}
			down(&hidden_dentry->d_inode->i_sem);
			err = vfs_create(hidden_dentry->d_inode,
					 whiteout_dentry, 0600, NULL);
			up(&hidden_dentry->d_inode->i_sem);
			DPUT(whiteout_dentry);

			if (err) {
				fist_dprint(8,
					    "mkdir: error creating directory override entry: %d\n",
					    err);
				goto out;
			}
			break;
		}
	}

      out:
	if (!dentry->d_inode)
		d_drop(dentry);

	KFREE(name);

	fist_print_dentry("OUT unionfs_mkdir :", dentry);
	unlock_dentry(dentry);
	print_exit_status(err);
	return err;
}
Exemple #11
0
static int unionfs_create(struct inode *parent, struct dentry *dentry,
			  int mode, struct nameidata *nd)
{
	int err = 0;
	struct dentry *hidden_dentry = NULL;
	struct dentry *whiteout_dentry = NULL;
	struct dentry *new_hidden_dentry;
	struct dentry *hidden_parent_dentry = NULL;
	int bindex = 0, bstart;
	char *name = NULL;

	print_entry_location();
	lock_dentry(dentry);
	fist_print_dentry("IN unionfs_create", dentry);

	/* We start out in the leftmost branch. */
	bstart = dbstart(dentry);
	hidden_dentry = dtohd(dentry);

	/* check if whiteout exists in this branch, i.e. lookup .wh.foo first */
	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
	if (IS_ERR(name)) {
		err = PTR_ERR(name);
		goto out;
	}

	whiteout_dentry =
	    LOOKUP_ONE_LEN(name, hidden_dentry->d_parent,
			   dentry->d_name.len + WHLEN);
	if (IS_ERR(whiteout_dentry)) {
		err = PTR_ERR(whiteout_dentry);
		whiteout_dentry = NULL;
		goto out;
	}

	if (whiteout_dentry->d_inode) {
		/* .wh.foo has been found. */
		/* First truncate it and then rename it to foo (hence having
		 * the same overall effect as a normal create.
		 *
		 * XXX: This is not strictly correct.  If we have unlinked the
		 * file and it still has a reference count, then we should
		 * actually unlink the whiteout so that user's data isn't
		 * hosed over.
		 */
		struct dentry *hidden_dir_dentry;
		struct iattr newattrs;

		down(&whiteout_dentry->d_inode->i_sem);
		newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_ATIME
		    | ATTR_MTIME | ATTR_UID | ATTR_GID | ATTR_FORCE
		    | ATTR_KILL_SUID | ATTR_KILL_SGID;

		newattrs.ia_mode = mode & ~current->fs->umask;
		newattrs.ia_uid = current->fsuid;
		newattrs.ia_gid = current->fsgid;

		if (whiteout_dentry->d_inode->i_size != 0) {
			newattrs.ia_valid |= ATTR_SIZE;
			newattrs.ia_size = 0;
		}

		err = notify_change(whiteout_dentry, &newattrs);

		up(&whiteout_dentry->d_inode->i_sem);

		if (err)
			printk(KERN_WARNING
			       "unionfs: %s:%d: notify_change failed: %d, ignoring..\n",
			       __FILE__, __LINE__, err);

		new_hidden_dentry = dtohd(dentry);
		DGET(new_hidden_dentry);

		hidden_dir_dentry = GET_PARENT(whiteout_dentry);
		lock_rename(hidden_dir_dentry, hidden_dir_dentry);

		if (!(err = is_robranch_super(dentry->d_sb, bstart))) {
			err =
			    vfs_rename(hidden_dir_dentry->d_inode,
				       whiteout_dentry,
				       hidden_dir_dentry->d_inode,
				       new_hidden_dentry);
		}
		if (!err) {
			fist_copy_attr_timesizes(parent,
						 new_hidden_dentry->d_parent->
						 d_inode);
			parent->i_nlink = get_nlinks(parent);
		}

		unlock_rename(hidden_dir_dentry, hidden_dir_dentry);
		DPUT(hidden_dir_dentry);

		DPUT(new_hidden_dentry);

		if (err) {
			/* exit if the error returned was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				goto out;
			/* We were not able to create the file in this branch,
			 * so, we try to create it in one branch to left
			 */
			bstart--;
		} else {
			/* reset the unionfs dentry to point to the .wh.foo entry. */

			/* Discard any old reference. */
			DPUT(dtohd(dentry));

			/* Trade one reference to another. */
			set_dtohd_index(dentry, bstart, whiteout_dentry);
			whiteout_dentry = NULL;

			err = unionfs_interpose(dentry, parent->i_sb, 0);
			goto out;
		}
	}

	for (bindex = bstart; bindex >= 0; bindex--) {
		hidden_dentry = dtohd_index(dentry, bindex);
		if (!hidden_dentry) {
			/* if hidden_dentry is NULL, create the entire
			 * dentry directory structure in branch 'bindex'.
			 * hidden_dentry will NOT be null when bindex == bstart
			 * because lookup passed as a negative unionfs dentry
			 * pointing to a lone negative underlying dentry */
			hidden_dentry = create_parents(parent, dentry, bindex);
			if (!hidden_dentry || IS_ERR(hidden_dentry)) {
				if (IS_ERR(hidden_dentry))
					err = PTR_ERR(hidden_dentry);
				continue;
			}
		}

		fist_checkinode(parent, "unionfs_create");

		hidden_parent_dentry = lock_parent(hidden_dentry);
		if (IS_ERR(hidden_parent_dentry)) {
			err = PTR_ERR(hidden_parent_dentry);
			goto out;
		}
		/* We shouldn't create things in a read-only branch. */
		if (!(err = is_robranch_super(dentry->d_sb, bindex))) {
			//DQ: vfs_create has a different prototype in 2.6
			err = vfs_create(hidden_parent_dentry->d_inode,
					 hidden_dentry, mode, nd);
		}
		if (err || !hidden_dentry->d_inode) {
			unlock_dir(hidden_parent_dentry);

			/* break out of for loop if the error wasn't  -EROFS */
			if (!IS_COPYUP_ERR(err))
				break;
		} else {
			err = unionfs_interpose(dentry, parent->i_sb, 0);
			if (!err) {
				fist_copy_attr_timesizes(parent,
							 hidden_parent_dentry->
							 d_inode);
				/* update number of links on parent directory */
				parent->i_nlink = get_nlinks(parent);
			}
			unlock_dir(hidden_parent_dentry);
			break;
		}
	}

      out:
	DPUT(whiteout_dentry);
	KFREE(name);

	fist_print_dentry("OUT unionfs_create :", dentry);
	unlock_dentry(dentry);
	print_exit_status(err);
	return err;
}
Exemple #12
0
static int unionfs_symlink(struct inode *dir, struct dentry *dentry,
			   const char *symname)
{
	int err = 0;
	struct dentry *hidden_dentry = NULL;
	struct dentry *whiteout_dentry = NULL;
	struct dentry *hidden_dir_dentry = NULL;
	umode_t mode;
	int bindex = 0, bstart;
	char *name = NULL;

	print_entry_location();
	lock_dentry(dentry);
	fist_print_dentry("IN unionfs_symlink", dentry);

	/* We start out in the leftmost branch. */
	bstart = dbstart(dentry);

	hidden_dentry = dtohd(dentry);

	/* check if whiteout exists in this branch, i.e. lookup .wh.foo first. If present, delete it */
	name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
	if (IS_ERR(name)) {
		err = PTR_ERR(name);
		goto out;
	}

	whiteout_dentry =
	    LOOKUP_ONE_LEN(name, hidden_dentry->d_parent,
			   dentry->d_name.len + WHLEN);
	if (IS_ERR(whiteout_dentry)) {
		err = PTR_ERR(whiteout_dentry);
		goto out;
	}

	if (!whiteout_dentry->d_inode) {
		DPUT(whiteout_dentry);
		whiteout_dentry = NULL;
	} else {
		/* found a .wh.foo entry, unlink it and then call vfs_symlink() */
		hidden_dir_dentry = lock_parent(whiteout_dentry);

		fist_print_generic_dentry("HDD", hidden_dir_dentry);
		fist_print_generic_dentry("WD", whiteout_dentry);

		if (!(err = is_robranch_super(dentry->d_sb, bstart))) {
			err =
			    vfs_unlink(hidden_dir_dentry->d_inode,
				       whiteout_dentry);
		}
		DPUT(whiteout_dentry);

		fist_copy_attr_times(dir, hidden_dir_dentry->d_inode);
		/* propagate number of hard-links */
		dir->i_nlink = get_nlinks(dir);

		unlock_dir(hidden_dir_dentry);

		if (err) {
			/* exit if the error returned was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				goto out;
			/* should now try to create symlink in the another branch */
			bstart--;
		}
	}

	/* deleted whiteout if it was present, now do a normal vfs_symlink() with
	   possible recursive directory creation */
	for (bindex = bstart; bindex >= 0; bindex--) {
		hidden_dentry = dtohd_index(dentry, bindex);
		if (!hidden_dentry) {
			/* if hidden_dentry is NULL, create the entire
			 * dentry directory structure in branch 'bindex'. hidden_dentry will NOT be null when
			 * bindex == bstart because lookup passed as a negative unionfs dentry pointing to a
			 * lone negative underlying dentry */
			hidden_dentry = create_parents(dir, dentry, bindex);
			if (!hidden_dentry || IS_ERR(hidden_dentry)) {
				if (IS_ERR(hidden_dentry)) {
					err = PTR_ERR(hidden_dentry);
				}
				fist_dprint(8,
					    "hidden dentry NULL (or error) for bindex = %d\n",
					    bindex);
				continue;
			}
		}

		hidden_dir_dentry = lock_parent(hidden_dentry);

		if (!(err = is_robranch_super(dentry->d_sb, bindex))) {
			mode = S_IALLUGO;
			err =
			    vfs_symlink(hidden_dir_dentry->d_inode,
					hidden_dentry, symname, mode);
		}
		unlock_dir(hidden_dir_dentry);

		if (err || !hidden_dentry->d_inode) {
			/* break out of for loop if error returned was NOT -EROFS */
			if (!IS_COPYUP_ERR(err))
				break;
		} else {
			err = unionfs_interpose(dentry, dir->i_sb, 0);
			if (!err) {
				fist_copy_attr_timesizes(dir,
							 hidden_dir_dentry->
							 d_inode);
				/* update number of links on parent directory */
				dir->i_nlink = get_nlinks(dir);
			}
			break;
		}
	}

      out:
	if (!dentry->d_inode)
		d_drop(dentry);

	KFREE(name);
	fist_print_dentry("OUT unionfs_symlink :", dentry);
	unlock_dentry(dentry);
	print_exit_status(err);
	return err;
}