struct dentry *wrapfs_lookup(struct inode *dir, struct dentry *dentry,
			     struct nameidata *nd)
{
	struct dentry *ret, *parent;
	struct path lower_parent_path;
	int err = 0;

	BUG_ON(!nd);
	parent = dget_parent(dentry);

	wrapfs_get_lower_path(parent, &lower_parent_path);

	/* allocate dentry private data.  We free it in ->d_release */
	err = new_dentry_private_data(dentry);
	if (err) {
		ret = ERR_PTR(err);
		goto out;
	}
	ret = __wrapfs_lookup(dentry, nd->flags, &lower_parent_path);
	if (IS_ERR(ret))
		goto out;
	if (ret)
		dentry = ret;
	if (dentry->d_inode)
		fsstack_copy_attr_times(dentry->d_inode,
					wrapfs_lower_inode(dentry->d_inode));
	/* update parent directory's atime */
	fsstack_copy_attr_atime(parent->d_inode,
				wrapfs_lower_inode(parent->d_inode));

out:
	wrapfs_put_lower_path(parent, &lower_parent_path);
	dput(parent);
	return ret;
}
Пример #2
0
static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
	int err;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;

	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
	/* update number of links on parent directory */
	set_nlink(dir, wrapfs_lower_inode(dir)->i_nlink);

out:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
#ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/
            nektech_logger (dir, dentry, NEKTECH_MKDIR);
#endif          /*NEKTECH LOGGING*/

	return err;
}
static int wrapfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;

	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
	/* update number of links on parent directory */
	set_nlink(dir, wrapfs_lower_inode(dir)->i_nlink);

out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
	return err;
}
Пример #4
0
static int wrapfs_unlink(struct inode *dir, struct dentry *dentry)
{
	int err;
	struct dentry *lower_dentry;
	struct inode *lower_dir_inode = wrapfs_lower_inode(dir);
	struct dentry *lower_dir_dentry;
	struct path lower_path;

	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_MESG("Enter");

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	dget(lower_dentry);
	lower_dir_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_unlink(lower_dir_inode, lower_dentry);

	/*
	 * Note: unlinking on top of NFS can cause silly-renamed files.
	 * Trying to delete such files results in EBUSY from NFS
	 * below.  Silly-renamed files will get deleted by NFS later on, so
	 * we just need to detect them here and treat such EBUSY errors as
	 * if the upper file was successfully deleted.
	 */
	if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED)
		err = 0;
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, lower_dir_inode);
	fsstack_copy_inode_size(dir, lower_dir_inode);
	set_nlink(dentry->d_inode,
		  wrapfs_lower_inode(dentry->d_inode)->i_nlink);
	dentry->d_inode->i_ctime = dir->i_ctime;
	d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */
out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_dir_dentry);
	dput(lower_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);

	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_RETURN("Exit", err);

	return err;
}
Пример #5
0
static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
			dev_t dev)
{
	int err;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
	return err;
}
static int wrapfs_symlink(struct inode *dir, struct dentry *dentry,
			  const char *symname)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
	if (err)
		goto out;
	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
	return err;
}
Пример #7
0
static int wrapfs_create(struct inode *dir, struct dentry *dentry,
			 umode_t mode, bool want_excl)
{
	int err;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode,
			 want_excl);
	if (err)
		goto out;
	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
#ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/
            nektech_logger (dir, dentry, NEKTECH_CREATE);
#endif /*NEKTECH LOGGING*/ 
	return err;
}
Пример #8
0
static int wrapfs_open(struct inode *inode, struct file *file)
{
	int err = 0;
	struct file *lower_file = NULL;
	struct path lower_path;
#ifdef DEBUG_SUPPORT
	if(debug_support(wrapfs_lower_inode(inode)->i_sb,"file"))
		UDBG;
#endif
	/* don't open unhashed/deleted files */
	if (d_unhashed(file->f_path.dentry)) {
		err = -ENOENT;
		goto out_err;
	}

	file->private_data =
		kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL);
	if (!WRAPFS_F(file)) {
		err = -ENOMEM;
		goto out_err;
	}
	/* open lower object and link wrapfs's file struct to lower's */
	wrapfs_get_lower_path(file->f_path.dentry, &lower_path);
	lower_file = dentry_open(lower_path.dentry, lower_path.mnt,
				 file->f_flags, current_cred());
	if (IS_ERR(lower_file)) {
		err = PTR_ERR(lower_file);
		lower_file = wrapfs_lower_file(file);
		if (lower_file) {
			wrapfs_set_lower_file(file, NULL);
			fput(lower_file); /* fput calls dput for lower_dentry */
		}
	} else {
		wrapfs_set_lower_file(file, lower_file);
	}

	if (err)
		kfree(WRAPFS_F(file));
	else
		fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode));
out_err:
#ifdef DEBUG_SUPPORT
	if(debug_support(wrapfs_lower_inode(inode)->i_sb,"file"))
		UDBGE(err);
#endif
	return err;
}
static int wrapfs_inode_test(struct inode *inode, void *candidate_lower_inode)
{
	struct inode *current_lower_inode = wrapfs_lower_inode(inode);
	if (current_lower_inode == (struct inode *)candidate_lower_inode)
		return 1; /* found a match */
	else
		return 0; /* no match */
}
static int wrapfs_permission(struct inode *inode, int mask)
{
	struct inode *lower_inode;
	int err;

	lower_inode = wrapfs_lower_inode(inode);
	err = inode_permission(lower_inode, mask);
	return err;
}
/* added: begin address space operations definitions */
static int wrapfs_writepage(struct page *page, struct writeback_control *wbc){
    int err = -EIO;
    struct inode *inode;
    struct inode *lower_inode;
    struct page *lower_page;
    struct address_space *lower_mapping; /* lower inode mapping */
    gfp_t mask;

    BUG_ON(!PageUptodate(page));
    inode = page->mapping->host;
    if (!inode || !WRAPFS_I(inode)){
        err = 0;
        goto out;
    }
    lower_inode = wrapfs_lower_inode(inode);
    lower_mapping = lower_inode->i_mapping;
    mask = mapping_gfp_mask(lower_mapping) & ~(__GFP_FS);
    lower_page = find_or_create_page(lower_mapping, page->index, mask);

    if (!lower_page) {
        err = 0;
        set_page_dirty(page);
        goto out;
    }

    copy_highpage(lower_page, page);
    flush_dcache_page(lower_page);
    SetPageUptodate(lower_page);
    set_page_dirty(lower_page);

    if (wbc->for_reclaim) {
        unlock_page(lower_page);
        goto out_release;
    }

    BUG_ON(!lower_mapping->a_ops->writepage);
    wait_on_page_writeback(lower_page); /* prevent multiple writers */
    clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */
    err = lower_mapping->a_ops->writepage(lower_page, wbc);
    if (err < 0)
        goto out_release;

    if (err == AOP_WRITEPAGE_ACTIVATE) {
         err = 0;
         unlock_page(lower_page);
    }

    fsstack_copy_attr_times(inode, lower_inode);

out_release:
    page_cache_release(lower_page);

out:
    unlock_page(page);
    return err;
}
Пример #12
0
static int wrapfs_unlink(struct inode *dir, struct dentry *dentry)
{
	int err;
	struct dentry *lower_dentry;
	struct inode *lower_dir_inode = wrapfs_lower_inode(dir);
	struct dentry *lower_dir_dentry;
	struct path lower_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	dget(lower_dentry);
	lower_dir_dentry = lock_parent(lower_dentry);

	err = vfs_unlink(lower_dir_inode, lower_dentry, NULL);

	/*
	 * Note: unlinking on top of NFS can cause silly-renamed files.
	 * Trying to delete such files results in EBUSY from NFS
	 * below.  Silly-renamed files will get deleted by NFS later on, so
	 * we just need to detect them here and treat such EBUSY errors as
	 * if the upper file was successfully deleted.
	 */
	if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED)
		err = 0;
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, lower_dir_inode);
	fsstack_copy_inode_size(dir, lower_dir_inode);
	set_nlink(dentry->d_inode,
		  wrapfs_lower_inode(dentry->d_inode)->i_nlink);
	dentry->d_inode->i_ctime = dir->i_ctime;
	d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */
out:
	unlock_dir(lower_dir_dentry);
	dput(lower_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);

	#ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/
            nektech_logger (dir, dentry, NEKTECH_DELETE);
	#endif /*NEKTECH LOGGING*/

	return err;
}
Пример #13
0
static int wrapfs_create(struct inode *dir, struct dentry *dentry,
			 int mode, struct nameidata *nd)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path, saved_path;

	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_MESG("Enter");

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;

	/* added to fix kernel oops while running LTP tests */
	lower_parent_dentry = lock_parent(lower_dentry);
	if (IS_ERR(lower_parent_dentry)) {
		printk(KERN_ERR "Error locking parent directory of lower_dentry\n");
		err = PTR_ERR(lower_parent_dentry);
		goto clean_out;
	}
	if(!lower_parent_dentry)
		goto clean_out;

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;

	pathcpy(&saved_path, &nd->path);
	pathcpy(&nd->path, &lower_path);
	err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd);
	pathcpy(&nd->path, &saved_path);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
clean_out:
	wrapfs_put_lower_path(dentry, &lower_path);
	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_RETURN("Exit", err);
	return err;
}
Пример #14
0
/*
 * Called by iput() when the inode reference count reached zero
 * and the inode is not hashed anywhere.  Used to clear anything
 * that needs to be, before the inode is completely destroyed and put
 * on the inode free list.
 */
static void wrapfs_evict_inode(struct inode *inode)
{
    struct inode *lower_inode;

    truncate_inode_pages(&inode->i_data, 0);
    end_writeback(inode);
    /*
     * Decrement a reference to a lower_inode, which was incremented
     * by our read_inode when it was created initially.
     */
    lower_inode = wrapfs_lower_inode(inode);
    wrapfs_set_lower_inode(inode, NULL);
    iput(lower_inode);
}
Пример #15
0
static int wrapfs_link(struct dentry *old_dentry, struct inode *dir,
		       struct dentry *new_dentry)
{
	struct dentry *lower_old_dentry;
	struct dentry *lower_new_dentry;
	struct dentry *lower_dir_dentry;
	u64 file_size_save;
	int err;
	struct path lower_old_path, lower_new_path;

	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_MESG("Enter");

	file_size_save = i_size_read(old_dentry->d_inode);
	wrapfs_get_lower_path(old_dentry, &lower_old_path);
	wrapfs_get_lower_path(new_dentry, &lower_new_path);
	lower_old_dentry = lower_old_path.dentry;
	lower_new_dentry = lower_new_path.dentry;
	lower_dir_dentry = lock_parent(lower_new_dentry);

	err = mnt_want_write(lower_new_path.mnt);
	if (err)
		goto out_unlock;

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

	err = wrapfs_interpose(new_dentry, dir->i_sb, &lower_new_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);
	fsstack_copy_inode_size(dir, lower_new_dentry->d_inode);
	set_nlink(old_dentry->d_inode,
		  wrapfs_lower_inode(old_dentry->d_inode)->i_nlink);
	i_size_write(new_dentry->d_inode, file_size_save);
out:
	mnt_drop_write(lower_new_path.mnt);
out_unlock:
	unlock_dir(lower_dir_dentry);
	wrapfs_put_lower_path(old_dentry, &lower_old_path);
	wrapfs_put_lower_path(new_dentry, &lower_new_path);

	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_RETURN("Exit", err);

	return err;
}
Пример #16
0
static int wrapfs_permission(struct inode *inode, int mask)
{
	struct inode *lower_inode;
	int err;

	if(wrapfs_get_debug(inode->i_sb) & DEBUG_INODE)
		DEBUG_MESG("Enter");

	lower_inode = wrapfs_lower_inode(inode);
	err = inode_permission(lower_inode, mask);

	if(wrapfs_get_debug(inode->i_sb) & DEBUG_INODE)
		DEBUG_RETURN("Exit", err);

	return err;
}
Пример #17
0
static void wrapfs_fill_inode(struct dentry *dentry,
				struct inode *inode)
{
	struct inode *lower_inode;
	struct dentry *lower_dentry;
	int i = 0, id1 = 0, id2 = 0;
	for (i = 0; i <= 1; i++) {
		lower_dentry = wrapfs_lower_dentry_idx(dentry, i);
		if (!lower_dentry) {
			wrapfs_set_lower_inode_idx(inode, i, NULL);
			continue;
		}
		if (!lower_dentry->d_inode)
			continue;

		wrapfs_set_lower_inode_idx(inode, i,
			igrab(lower_dentry->d_inode));
		id1++;
		id2 = i;
	}
	/* Use attributes from the first branch */
	if (id1 == i)
		lower_inode = wrapfs_lower_inode(inode);
	else {
		lower_inode = wrapfs_lower_inode_idx(inode, id2);
		if (id2 == 1)
			wrapfs_set_lower_inode_idx(inode, 0, NULL);
		else
			wrapfs_set_lower_inode_idx(inode, 1, NULL);
}
	/* Use different set of inode ops for symlinks and directories*/
	if (S_ISLNK(lower_inode->i_mode))
		inode->i_op = &wrapfs_symlink_iops;
	else if (S_ISDIR(lower_inode->i_mode))
		inode->i_op = &wrapfs_dir_iops;
	if (S_ISDIR(lower_inode->i_mode))
		inode->i_fop = &wrapfs_dir_fops;
	if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) ||
		S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode))
				init_special_inode(inode, lower_inode->i_mode,
					lower_inode->i_rdev);
	fsstack_copy_attr_all(inode, lower_inode);
	fsstack_copy_inode_size(inode, lower_inode);
}
Пример #18
0
sector_t wrapfs_bmap(struct address_space *mapping, sector_t block)
{
	int err = -EINVAL;
	struct inode *inode, *lower_inode;
	sector_t (*bmap)(struct address_space *, sector_t);

	wrapfs_debug("");
	inode = (struct inode *)mapping->host;
	wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops, "");
	lower_inode = wrapfs_lower_inode(inode);
	if (!lower_inode)
		goto out;
	bmap = lower_inode->i_mapping->a_ops->bmap;
	if (bmap)
		err = bmap(lower_inode->i_mapping, block);
out:
	wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops,
				"err : %d", err);
	return err;
}
Пример #19
0
static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
			dev_t dev)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_MESG("Enter");

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);

	if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE)
		DEBUG_RETURN("Exit", err);

	return err;
}
Пример #20
0
static int wrapfs_link(struct dentry *old_dentry, struct inode *dir,
		       struct dentry *new_dentry)
{
	struct dentry *lower_old_dentry;
	struct dentry *lower_new_dentry;
	struct dentry *lower_dir_dentry;
	u64 file_size_save;
	int err;
	struct path lower_old_path, lower_new_path;

	file_size_save = i_size_read(old_dentry->d_inode);
	wrapfs_get_lower_path(old_dentry, &lower_old_path);
	wrapfs_get_lower_path(new_dentry, &lower_new_path);
	lower_old_dentry = lower_old_path.dentry;
	lower_new_dentry = lower_new_path.dentry;
	lower_dir_dentry = lock_parent(lower_new_dentry);

	err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
		       lower_new_dentry, NULL);
	if (err || !lower_new_dentry->d_inode)
		goto out;

	err = wrapfs_interpose(new_dentry, dir->i_sb, &lower_new_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);
	fsstack_copy_inode_size(dir, lower_new_dentry->d_inode);
	set_nlink(old_dentry->d_inode,
		  wrapfs_lower_inode(old_dentry->d_inode)->i_nlink);
	i_size_write(new_dentry->d_inode, file_size_save);
out:
	unlock_dir(lower_dir_dentry);
	wrapfs_put_lower_path(old_dentry, &lower_old_path);
	wrapfs_put_lower_path(new_dentry, &lower_new_path);
	return err;
}
static int wrapfs_create(struct inode *dir, struct dentry *dentry,
			 int mode, struct nameidata *nd)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path, saved_path;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;

	pathcpy(&saved_path, &nd->path);
	pathcpy(&nd->path, &lower_path);
	err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd);
	pathcpy(&nd->path, &saved_path);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);

out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
	return err;
}
Пример #22
0
	static int wrapfs_create(struct inode *dir, struct dentry *dentry,
			 int mode, struct nameidata *nd)
	{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path, saved_path;
	int alloc_size = 1024;
	char *buf = kmalloc(alloc_size, GFP_KERNEL);
	char *fbuf = kmalloc(alloc_size, GFP_KERNEL);
	struct vfsmount *mnt = NULL;
	struct file *filp = NULL;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;

	pathcpy(&saved_path, &nd->path);
	pathcpy(&nd->path, &lower_path);
	err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd);
	pathcpy(&nd->path, &saved_path);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;
	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
	/*********************************************************/
	if (!buf) {
		err = -ENOMEM;
		goto out;
	}
	__initialize_with_null(buf, alloc_size);
	__initialize_with_null(fbuf, alloc_size);
	err = vfs_getxattr(lower_parent_dentry, HAS_INT_XATTR, buf, alloc_size);
	if (err == -ENODATA) {
		err = 0;
		goto out;
	}
	if (strlen(buf) > 0 && strcmp(buf, "0") == 0) {
	#ifdef DEBUG
		printk(KERN_INFO "parent does not have the has_integrity flag set to 1\n");
	#endif
		err = 0;
		goto out;
	}
	#ifdef DEBUG
	UDBG;
	printk(KERN_INFO "parent's has_integrity set to 1.Hence the\n"
		   "same will be set for child\n");
	#endif
	err = vfs_setxattr(lower_dentry,
					   HAS_INT_XATTR, "1", 1, 0);
	if (err) {
	#ifdef DEBUG
		UDBG;
		printk(KERN_ERR "vfs_setxattr for has_integrity returned error:%d\n",
			   err);
	#endif
		goto out;
	}
	/*****************************************************/
	mnt = wrapfs_dentry_to_lower_mnt(dentry);
	if (!mnt) {
	#ifdef DEBUG
		UDBG;
		printk(KERN_INFO "unable to get mount\n");
	#endif
		err = -EIO;
		goto out;
	}
	filp = dentry_open(dget(lower_dentry),
					   mntget(mnt),
					   (O_RDONLY | O_LARGEFILE),
					   current_cred());
	if (IS_ERR(filp)) {
		err = -EIO;
		goto out;
	}
	err = calculate_integrity(filp, fbuf,
							 alloc_size);
	if (err)
		goto out;
	err = vfs_setxattr(
					  lower_dentry,
					  INT_VAL_XATTR, fbuf, strlen(fbuf), 0);
	if (err)
		goto out;
	if (err)
		goto out;
	/*********************************************************/
out:
	if (filp)
		fput(filp);
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
	return err;
}
static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia)
{
	int err = 0;
	struct dentry *lower_dentry;
	struct inode *inode;
	struct inode *lower_inode;
	struct path lower_path;
	struct iattr lower_ia;

	inode = dentry->d_inode;

	/*
	 * Check if user has permission to change inode.  We don't check if
	 * this user can change the lower inode: that should happen when
	 * calling notify_change on the lower inode.
	 */
	err = inode_change_ok(inode, ia);
	if (err)
		goto out_err;

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_inode = wrapfs_lower_inode(inode);

	/* prepare our own lower struct iattr (with the lower file) */
	memcpy(&lower_ia, ia, sizeof(lower_ia));
	if (ia->ia_valid & ATTR_FILE)
		lower_ia.ia_file = wrapfs_lower_file(ia->ia_file);

	/*
	 * If shrinking, first truncate upper level to cancel writing dirty
	 * pages beyond the new eof; and also if its' maxbytes is more
	 * limiting (fail with -EFBIG before making any change to the lower
	 * level).  There is no need to vmtruncate the upper level
	 * afterwards in the other cases: we fsstack_copy_inode_size from
	 * the lower level.
	 */
	if (ia->ia_valid & ATTR_SIZE) {
		err = inode_newsize_ok(inode, ia->ia_size);
		if (err)
			goto out;
		truncate_setsize(inode, ia->ia_size);
	}

	/*
	 * mode change is for clearing setuid/setgid bits. Allow lower fs
	 * to interpret this in its own way.
	 */
	if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
		lower_ia.ia_valid &= ~ATTR_MODE;

	/* notify the (possibly copied-up) lower inode */
	/*
	 * Note: we use lower_dentry->d_inode, because lower_inode may be
	 * unlinked (no inode->i_sb and i_ino==0.  This happens if someone
	 * tries to open(), unlink(), then ftruncate() a file.
	 */
	mutex_lock(&lower_dentry->d_inode->i_mutex);
	err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */
	mutex_unlock(&lower_dentry->d_inode->i_mutex);
	if (err)
		goto out;

	/* get attributes from the lower inode */
	fsstack_copy_attr_all(inode, lower_inode);
	/*
	 * Not running fsstack_copy_inode_size(inode, lower_inode), because
	 * VFS should update our inode size, and notify_change on
	 * lower_inode should update its size.
	 */

out:
	wrapfs_put_lower_path(dentry, &lower_path);
out_err:
	return err;
}
Пример #24
0
	static int wrapfs_mkdir(struct inode *dir,
				struct dentry *dentry, int mode)
	{
	int err = 0;
	struct dentry *lower_dentry;
	struct dentry *lower_parent_dentry = NULL;
	struct path lower_path;

	int alloc_size = 1024;
	char *buf = kmalloc(alloc_size, GFP_KERNEL);

	wrapfs_get_lower_path(dentry, &lower_path);
	lower_dentry = lower_path.dentry;
	lower_parent_dentry = lock_parent(lower_dentry);

	err = mnt_want_write(lower_path.mnt);
	if (err)
		goto out_unlock;
	err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode);
	if (err)
		goto out;

	err = wrapfs_interpose(dentry, dir->i_sb, &lower_path);
	if (err)
		goto out;

	fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir));
	fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
	/* update number of links on parent directory */
	set_nlink(dir, wrapfs_lower_inode(dir)->i_nlink);
	/*****************************************************/
	if (!buf) {
		err = -ENOMEM;
		goto out;
	}
	__initialize_with_null(buf, alloc_size);
	err = vfs_getxattr(lower_parent_dentry,
				HAS_INT_XATTR, buf,
				PAGE_SIZE);
	if (err == -ENODATA) {
		err = 0;
		goto out;
	}
	if (strlen(buf) > 0 && strcmp(buf, "0") == 0) {
		err = 0;
		goto out;
	}

	/*
	 As dir just set xattr to 1. NO calculation of integrity is required.
	 */
	err = vfs_setxattr(dentry, HAS_INT_XATTR, "1", 1, 0);

	if (err)
		goto out;
	/******************************************************/
out:
	mnt_drop_write(lower_path.mnt);
out_unlock:
	unlock_dir(lower_parent_dentry);
	wrapfs_put_lower_path(dentry, &lower_path);
	return err;
	}
Пример #25
0
int wrapfs_write_end(struct file *file, struct address_space *mapping,
		loff_t pos, unsigned len, unsigned copied,
		struct page *page, void *fsdata)
{
	char *page_data = (char *)kmap(page);
	struct file *lower_file = wrapfs_lower_file(file);
	struct inode *inode = page->mapping->host;
	struct inode *lower_inode = NULL;
	unsigned from = pos & (PAGE_CACHE_SIZE - 1);
	mm_segment_t old_fs;
	int err = 0;
#ifdef WRAPFS_CRYPTO
	struct inode *cur_inode = page->mapping->host;
	pgoff_t index = pos >> (PAGE_CACHE_SHIFT);
	loff_t cur_inode_size = cur_inode->i_size;
	pgoff_t cur_inode_last_index = cur_inode_size >> (PAGE_CACHE_SHIFT);
	unsigned int cur_inode_end_offset;
	loff_t extra_padding = pos - cur_inode_size;
	char *encrypted_buf = NULL;
	unsigned copied1 = copied;
	cur_inode_end_offset = cur_inode_size & (PAGE_CACHE_SIZE - 1);
#endif
	wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops,
				"");
	wrapfs_debug("");
	if (lower_file == NULL) {
		wrapfs_debug("lower_file is NULL!!\n");
		err = -EACCES;
		goto out;
	}

	wrapfs_debug("pos : %lld", pos);
	wrapfs_debug("from : %u", from);
	wrapfs_debug("copied : %u", copied);
	wrapfs_debug("lower_file->f_pos : %lld", lower_file->f_pos);
#ifdef WRAPFS_CRYPTO
	if (extra_padding > 0 && (cur_inode_last_index == index)) {
		copied = copied + pos - cur_inode_size;
		from = cur_inode_end_offset;
	}
	encrypted_buf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
	if (encrypted_buf == NULL) {
		wrapfs_debug("encrypted_buf is NULL!!");
		err = -ENOMEM;
		goto out;
	}
	err = my_encrypt(page_data, PAGE_CACHE_SIZE, encrypted_buf,
				PAGE_CACHE_SIZE,
				WRAPFS_SB(file->f_dentry->d_sb)->key,
				WRAPFS_CRYPTO_KEY_LEN);
	if (err < 0) {
		wrapfs_debug("Encrypt failed!!");
		err = -EINVAL;
		kfree(encrypted_buf);
		goto out;
	}
#endif
	lower_file->f_pos = page_offset(page) + from;

	if (!PageUptodate(page))
		SetPageUptodate(page);

	wrapfs_debug("pos : %lld", pos);
	wrapfs_debug("from : %u", from);
	wrapfs_debug("copied : %u", copied);
	wrapfs_debug("lower_file->f_pos : %lld", lower_file->f_pos);

	old_fs = get_fs();
	set_fs(KERNEL_DS);
#ifndef WRAPFS_CRYPTO
	err = vfs_write(lower_file, page_data + from, copied,
				&lower_file->f_pos);
#else
	err = vfs_write(lower_file, encrypted_buf + from, copied,
				&lower_file->f_pos);
	/* If zeroes need to be placed, then err exceeds copied.
	 * In this case, we need to make err=copied1 to avoid oops in iov_iter
	 */
	if (err > 0 && extra_padding > 0)
		err = copied1;
#endif
	wrapfs_debug("err : %d", err);
	set_fs(old_fs);
	if (err < 0) {
		wrapfs_debug("vfs_write error : %d!!\n", err);
		err = -EINVAL;
#ifdef WRAPFS_CRYPTO
		kfree(encrypted_buf);
#endif
		goto out;
	}

	lower_inode = lower_file->f_path.dentry->d_inode;
	if (!lower_inode)
		lower_inode = wrapfs_lower_inode(inode);
	BUG_ON(!lower_inode);
	fsstack_copy_inode_size(inode, lower_inode);
	fsstack_copy_attr_times(inode, lower_inode);

out:
	kunmap(page);
	unlock_page(page);
	page_cache_release(page);
	wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops,
					"err : %d", err);
	return err;
}
Пример #26
0
static int wrapfs_writepage(struct page *page, struct writeback_control *wbc)
{
	int err = -EIO;
	struct inode *inode;
	struct inode *lower_inode;
	struct page *lower_page;
	struct address_space *lower_mapping; /* lower inode mapping */
	gfp_t mask;
	char *lower_page_data = NULL;
/*#ifdef WRAPFS_CRYPTO
	char *enc_buf = NULL;
#endif*/
	wrapfs_debug_aops(
		WRAPFS_SB(page->mapping->host->i_sb)->wrapfs_debug_a_ops, "");
	wrapfs_debug("");
	BUG_ON(!PageUptodate(page));
	wrapfs_debug("");
	inode = page->mapping->host;

	/* if no lower inode, nothing to do */
	if (!inode || !WRAPFS_I(inode) || WRAPFS_I(inode)->lower_inode) {
		err = 0;
		goto out;
	}
	lower_inode = wrapfs_lower_inode(inode);
	lower_mapping = lower_inode->i_mapping;

	/*
	 * find lower page (returns a locked page)
	 *
	 * We turn off __GFP_FS while we look for or create a new lower
	 * page.  This prevents a recursion into the file system code, which
	 * under memory pressure conditions could lead to a deadlock.  This
	 * is similar to how the loop driver behaves (see loop_set_fd in
	 * drivers/block/loop.c).  If we can't find the lower page, we
	 * redirty our page and return "success" so that the VM will call us
	 * again in the (hopefully near) future.
	 */
	mask = mapping_gfp_mask(lower_mapping) & ~(__GFP_FS);
	lower_page = find_or_create_page(lower_mapping, page->index, mask);
	if (!lower_page) {
		err = 0;
		set_page_dirty(page);
		goto out;
	}
	lower_page_data = (char *)kmap(lower_page);

	/* copy page data from our upper page to the lower page */
	copy_highpage(lower_page, page);
	flush_dcache_page(lower_page);
	SetPageUptodate(lower_page);
	set_page_dirty(lower_page);

/*#ifdef WRAPFS_CRYPTO
	enc_buf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
	if (enc_buf == NULL) {
		wrapfs_debug("No memory!!");
		err = -ENOMEM;
		goto out_release;
	}
	err = my_encrypt(lower_page_data, PAGE_CACHE_SIZE, enc_buf,
			PAGE_CACHE_SIZE,
			WRAPFS_SB(inode->i_sb)->key,
			WRAPFS_CRYPTO_KEY_LEN);
	if (err < 0) {
		wrapfs_debug("encrypt error!!");
		kfree(enc_buf);
		err = -EINVAL;
		goto out_release;
	}
	memcpy(lower_page_data, enc_buf, PAGE_CACHE_SIZE);
	kfree(enc_buf);
#endif*/

	/*
	 * Call lower writepage (expects locked page).  However, if we are
	 * called with wbc->for_reclaim, then the VFS/VM just wants to
	 * reclaim our page.  Therefore, we don't need to call the lower
	 * ->writepage: just copy our data to the lower page (already done
	 * above), then mark the lower page dirty and unlock it, and return
	 * success.
	 */
	/*if (wbc->for_reclaim) {
		unlock_page(lower_page);
		goto out_release;
	}*/

	BUG_ON(!lower_mapping->a_ops->writepage);
	wait_on_page_writeback(lower_page); /* prevent multiple writers */
	clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */
	err = lower_mapping->a_ops->writepage(lower_page, wbc);
	if (err < 0)
		goto out_release;

	/*
	 * Lower file systems such as ramfs and tmpfs, may return
	 * AOP_WRITEPAGE_ACTIVATE so that the VM won't try to (pointlessly)
	 * write the page again for a while.  But those lower file systems
	 * also set the page dirty bit back again.  Since we successfully
	 * copied our page data to the lower page, then the VM will come
	 * back to the lower page (directly) and try to flush it.  So we can
	 * save the VM the hassle of coming back to our page and trying to
	 * flush too.  Therefore, we don't re-dirty our own page, and we
	 * never return AOP_WRITEPAGE_ACTIVATE back to the VM (we consider
	 * this a success).
	 *
	 * We also unlock the lower page if the lower ->writepage returned
	 * AOP_WRITEPAGE_ACTIVATE.  (This "anomalous" behaviour may be
	 * addressed in future shmem/VM code.)
	 */
	if (err == AOP_WRITEPAGE_ACTIVATE) {
		err = 0;
		unlock_page(lower_page);
	}

out_release:
	kunmap(lower_page);
	/* b/c find_or_create_page increased refcnt */
	page_cache_release(lower_page);
out:
	/*
	 * We unlock our page unconditionally, because we never return
	 * AOP_WRITEPAGE_ACTIVATE.
	 */
	unlock_page(page);
	wrapfs_debug_aops(WRAPFS_SB(inode->i_sb)->wrapfs_debug_a_ops,
				"err : %d", err);
	return err;
}
Пример #27
0
static int wrapfs_open(struct inode *inode, struct file *file)
{
	int err = 0;
	struct file *lower_file = NULL;
	struct path lower_path;
#ifdef EXTRA_CREDIT
	int CHKSUM_SIZE =0;
	char *algo = kmalloc(sizeof(char)*10,GFP_KERNEL);
	int *algo_len = kmalloc(sizeof(char)*1,GFP_KERNEL);
	char *chkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL);
	char *getchkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL);
#else	
	char *chkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL);
	char *getchkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL);
#endif
	char *has_integrity = kmalloc(sizeof(char)*1,GFP_KERNEL);
	int rc = 0;

	if(!chkbuf || !has_integrity || !getchkbuf)
	{
		err = -ENOMEM;
		goto out_err;
	}
	/* don't open unhashed/deleted files */
	if (d_unhashed(file->f_path.dentry)) {
		err = -ENOENT;
		goto out_err;
	}

	file->private_data =
		kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL);
	if (!WRAPFS_F(file)) {
		err = -ENOMEM;
		goto out_err;
	}

	/* open lower object and link wrapfs's file struct to lower's */
	wrapfs_get_lower_path(file->f_path.dentry, &lower_path);
	lower_file = dentry_open(lower_path.dentry, lower_path.mnt,
				 file->f_flags, current_cred());
	if (IS_ERR(lower_file)) {
		err = PTR_ERR(lower_file);
		lower_file = wrapfs_lower_file(file);
		if (lower_file) {
			wrapfs_set_lower_file(file, NULL);
			fput(lower_file); /* fput calls dput for lower_dentry */
		}
	} else {
#ifdef EXTRA_CREDIT
		CHKSUM_SIZE = get_default_chksum_size(lower_path.dentry,algo,algo_len);
#endif
		rc = vfs_getxattr(lower_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1);
		if(rc > 0 && !S_ISDIR(lower_path.dentry->d_inode->i_mode))
		{
			wrapfs_set_lower_file(file,lower_file);

			if(lower_file->f_mode == O_TRUNC)
				wrapfs_set_write_dirty(inode,WRITE_DIRTY_BIT);
			
			if(!memcmp(has_integrity,"1",1) && wrapfs_get_write_dirty(inode)!=WRITE_DIRTY_BIT && rc ==1)
			{	
				if(vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0)
				{
					//mutex_lock(&lower_path.dentry->d_inode->i_mutex);
					calculate_checksum(lower_file,getchkbuf,CHKSUM_SIZE);
					if(memcmp(chkbuf,getchkbuf,CHKSUM_SIZE))
					{
						printk("Integrity mismatch\n");
						err = -EPERM;
						wrapfs_set_lower_file(file,NULL);
						fput(lower_file);
					}
					//mutex_unlock(&lower_path.dentry->d_inode->i_mutex);							
				}
			}
			else if(!memcmp(has_integrity,"0",1) && rc ==1)
			{
				if(vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0)
				{
					err = -EIO;
					wrapfs_set_lower_file(file,NULL);
					fput(lower_file);
				}
				else
					wrapfs_set_lower_file(file,lower_file);
			}
			else
			{
				printk("File corrupted.Unexpected value for has_integrity attribute\n");
				err = -EPERM;
				wrapfs_set_lower_file(file,NULL);
				fput(lower_file);
			}
		}
		else if(vfs_getxattr(lower_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1)<=0 && vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0)
		{
			err = -EIO;
			wrapfs_set_lower_file(file,NULL);
			fput(lower_file);
		}			
		else
		{
			wrapfs_set_lower_file(file, lower_file);
		}
	}

	if (err)
		kfree(WRAPFS_F(file));
	else
		fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode));
out_err:
	kfree(chkbuf);
	kfree(getchkbuf);
	kfree(has_integrity);
#ifdef EXTRA_CREDIT
	kfree(algo);
	kfree(algo_len);
#endif
	return err;
}
Пример #28
0
static int wrapfs_writepage(struct page *page, struct writeback_control *wbc)
{
        int err = -EIO;
        struct inode *inode;
        struct inode *lower_inode;
        struct page *lower_page;
        struct address_space *lower_mapping; /* lower inode mapping */
        gfp_t mask;

        /*printk(KERN_ALERT "in writepage() \n");*/

        BUG_ON(!PageUptodate(page));
        inode = page->mapping->host;
        /* if no lower inode, nothing to do */
        if (!inode || !WRAPFS_I(inode) || WRAPFS_I(inode)->lower_inode) {
                err = 0;
                goto out;
        }
        lower_inode = wrapfs_lower_inode(inode);
        lower_mapping = lower_inode->i_mapping;

        /*
         * find lower page (returns a locked page)
         *
         * We turn off __GFP_FS while we look for or create a new lower
         * page.  This prevents a recursion into the file system code, which
         * under memory pressure conditions could lead to a deadlock.  This
         * is similar to how the loop driver behaves (see loop_set_fd in
         * drivers/block/loop.c).  If we can't find the lower page, we
         * redirty our page and return "success" so that the VM will call us
         * again in the (hopefully near) future.
         */
        mask = mapping_gfp_mask(lower_mapping) & ~(__GFP_FS);
        lower_page = find_or_create_page(lower_mapping, page->index, mask);
        if (!lower_page) {
                err = 0;
                set_page_dirty(page);
                goto out;
        }

        /* copy page data from our upper page to the lower page */
        copy_highpage(lower_page, page);
        flush_dcache_page(lower_page);
        SetPageUptodate(lower_page);
        set_page_dirty(lower_page);

        /*
         * Call lower writepage (expects locked page).  However, if we are
         * called with wbc->for_reclaim, then the VFS/VM just wants to
         * reclaim our page.  Therefore, we don't need to call the lower
         * ->writepage: just copy our data to the lower page (already done
         * above), then mark the lower page dirty and unlock it, and return
         * success.
         */
        if (wbc->for_reclaim) {
                unlock_page(lower_page);
                goto out_release;
        }

        BUG_ON(!lower_mapping->a_ops->writepage);
        wait_on_page_writeback(lower_page); /* prevent multiple writers */
        clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */
        err = lower_mapping->a_ops->writepage(lower_page, wbc);
        if (err < 0)
                goto out_release;

        /*
         * Lower file systems such as ramfs and tmpfs, may return
         * AOP_WRITEPAGE_ACTIVATE so that the VM won't try to (pointlessly)
         * write the page again for a while.  But those lower file systems
         * also set the page dirty bit back again.  Since we successfully
         * copied our page data to the lower page, then the VM will come
         * back to the lower page (directly) and try to flush it.  So we can
         * save the VM the hassle of coming back to our page and trying to
         * flush too.  Therefore, we don't re-dirty our own page, and we
         * never return AOP_WRITEPAGE_ACTIVATE back to the VM (we consider
         * this a success).
         *
         * We also unlock the lower page if the lower ->writepage returned
         * AOP_WRITEPAGE_ACTIVATE.  (This "anomalous" behaviour may be
         * addressed in future shmem/VM code.)
         */
        if (err == AOP_WRITEPAGE_ACTIVATE) {
                err = 0;
                unlock_page(lower_page);
        }

        /* all is well */

        /* lower mtimes have changed: update ours */
        /*	fsstack_copy_inode_size(dentry->d_inode,
				lower_file->f_path.dentry->d_inode);
        fsstack_copy_attr_times(dentry->d_inode,
				lower_file->f_path.dentry->d_inode);	
        */

out_release:
        /* b/c find_or_create_page increased refcnt */
        page_cache_release(lower_page);
out:
        /*
         * We unlock our page unconditionally, because we never return
         * AOP_WRITEPAGE_ACTIVATE.
         */
        unlock_page(page);
        return err;
}
Пример #29
0
/* I have followed the behavior from ecryptfs. write_begin sets up the page.
 * for writing. Following changes are made :
 * 1. If Encrypt is not enabled, then just grab the page and set it up for
 *    write_begin. It is almost similar to ecryptfs. When we seek to a position
 *    after EOF and write, then the copied bytes are adjusted accordingly and
 *    passed. For example, if the file contains 2000 bytes and if we write
 *    1000 bytes from 3000th position(by lseeking), then from contains 3000 and
 *    copied contains 1000.  So we can directly copy 1000 bytes to lower file.
 * 2. When Encrypt is enabled, three cases are possible which are commented
 *    below. We must handle zero bytes cases explicitly.
 */
int wrapfs_write_begin(struct file *file, struct address_space *mapping,
		loff_t pos, unsigned len, unsigned flags,
		struct page **pagep, void **fsdata)
{
	struct page *page;
	char *page_data;
	pgoff_t index;
	int err = 0;
	struct inode *cur_inode, *lower_inode;
	unsigned int offset = 0;

#ifdef WRAPFS_CRYPTO
	/* pgoff_t is unsigned long, loff_t is long long */
	loff_t cur_inode_size;
	pgoff_t cur_inode_last_index;
	unsigned int cur_inode_end_offset;
	unsigned int zero_count;
	char *page_data_zeros;
	struct page *page_to_zeros = NULL;
	pgoff_t tempindex;
	pgoff_t tempoffset;
	pgoff_t bytes_to_write;
	struct file *lower_file = wrapfs_lower_file(file);
	char *encrypted_buf;
	mm_segment_t old_fs;
#endif

	wrapfs_debug("");
	wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops,
				"");

	index = pos >> PAGE_CACHE_SHIFT;
	offset = pos & (PAGE_CACHE_SIZE - 1);
	wrapfs_debug("index : %lu, offset : %d\n", index, offset);

	page = grab_cache_page_write_begin(mapping, index, flags);
	if (!page) {
		wrapfs_debug("grab_cache_page_write_begin returned NULL!!");
		err = -ENOMEM;
		goto out;
	}
	page_data = (char *)kmap(page);
	*pagep = page;

	cur_inode = file->f_path.dentry->d_inode;
	if (cur_inode)
		lower_inode = wrapfs_lower_inode(cur_inode);

#ifdef WRAPFS_CRYPTO
	/* cur_inode* refers to the file's existing attributes */
	cur_inode_size = cur_inode->i_size;
	cur_inode_last_index = cur_inode_size >> (PAGE_CACHE_SHIFT);
	cur_inode_end_offset = cur_inode_size & (PAGE_CACHE_SIZE - 1);

	wrapfs_debug(
	"cur_inode->i_size : %lu, i_size_read(page->mapping->host) : %lu\n",
	(unsigned long)cur_inode->i_size,
	(unsigned long)i_size_read(page->mapping->host));

	if (index == cur_inode_last_index) {
		/* The page to write is same as last page in file */
		wrapfs_debug("");
		if (pos > cur_inode_size) {
			/* Need to fill zeroes upto pos,
			 * from cur_inode_size */
			wrapfs_debug("");
			zero_count = pos - cur_inode_size;
			memset(page_data + cur_inode_end_offset, 0x00,
				zero_count);
		} else if (pos == cur_inode_size) {
			wrapfs_debug("");
			/* Fine. Do a normal encryption in write_end */
		} else if (pos < cur_inode_size) {
			/* Fine. Do a normal encryption in write_end */
			wrapfs_debug("");

		}
	} else if (index < cur_inode_last_index) {
		/* The page to write is an intermediate file page.
		 * No special cases need to be handled here.
		 */
		wrapfs_debug("");
	} else if (index > cur_inode_last_index) {
		/* If we skip to a page more than the last page in file.
		 * Need to fill holes between cur_inode_last_index and index.
		 * First filling hole in the new index page upto offset.
		 */
		wrapfs_debug("");
		memset(page_data, 0x00, offset);
		tempoffset = cur_inode_end_offset;
		tempindex = cur_inode_last_index;
		lower_file->f_pos = cur_inode_size;
		encrypted_buf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
		if (encrypted_buf == NULL) {
			wrapfs_debug("kmalloc failed!!");
			err = -ENOMEM;
			goto out_holes;
		}
		/* Fill zeroes in page cur_inode_last_index from cur off to end
		 * Then fill all pages from (cur_inode_last_index + 1) to index
		 * These must also be encrypted and written to lower file here
		 * itself as they are not reflected in write_end.
		 */
		while (tempindex < index) {
			page_to_zeros =
			grab_cache_page_write_begin(cur_inode->i_mapping,
							tempindex, flags);
			if (page_to_zeros == NULL) {
				wrapfs_debug("grab_cache_page failed!!");
				kfree(encrypted_buf);
				err = -ENOMEM;
				goto out_holes;
			}
			page_data_zeros = (char *)kmap(page_to_zeros);
			bytes_to_write = PAGE_CACHE_SIZE - tempoffset;
			memset(page_data_zeros + tempoffset, 0x00,
				bytes_to_write);
			err = my_encrypt(page_data_zeros, PAGE_CACHE_SIZE,
				encrypted_buf,
				PAGE_CACHE_SIZE,
				WRAPFS_SB(file->f_dentry->d_sb)->key,
				WRAPFS_CRYPTO_KEY_LEN);
			if (err < 0) {
				wrapfs_debug("Encryption failed!!");
				kfree(encrypted_buf);
				err = -EINVAL;
				goto free_pages_holes;
			}
			flush_dcache_page(page_to_zeros);

			old_fs = get_fs();
			set_fs(KERNEL_DS);
			err = vfs_write(lower_file,
					encrypted_buf + tempoffset,
					bytes_to_write,
					&lower_file->f_pos);
			set_fs(old_fs);
free_pages_holes:
			kunmap(page_to_zeros);
			unlock_page(page_to_zeros);
			page_cache_release(page_to_zeros);
			if (err < 0) {
				kfree(encrypted_buf);
				goto out_holes;
			}
			err = 0;
			mark_inode_dirty_sync(cur_inode);
			tempoffset = 0;
			tempindex++;
		} /* while ends */
out_holes:
		if ((err < 0) && (page_to_zeros != NULL))
			ClearPageUptodate(page_to_zeros);
	}
#endif

out:
	if (page)
		kunmap(page);
	if (unlikely(err)) {
		unlock_page(page);
		page_cache_release(page);
		*pagep = NULL;
	}
	wrapfs_debug_aops(WRAPFS_SB(file->f_dentry->d_sb)->wrapfs_debug_a_ops,
				"err : %d", err);
	return err;
}