linux/fs/unionfs/super.c

1031 lines
30 KiB
C

/*
* Copyright (c) 2003-2014 Erez Zadok
* Copyright (c) 2003-2006 Charles P. Wright
* Copyright (c) 2005-2007 Josef 'Jeff' Sipek
* Copyright (c) 2005-2006 Junjiro Okajima
* Copyright (c) 2005 Arun M. Krishnakumar
* Copyright (c) 2004-2006 David P. Quigley
* Copyright (c) 2003-2004 Mohammad Nayyer Zubair
* Copyright (c) 2003 Puja Gupta
* Copyright (c) 2003 Harikesavan Krishnan
* Copyright (c) 2003-2014 Stony Brook University
* Copyright (c) 2003-2014 The Research Foundation of SUNY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "union.h"
/*
* The inode cache is used with alloc_inode for both our inode info and the
* vfs inode.
*/
static struct kmem_cache *unionfs_inode_cachep;
struct inode *unionfs_iget(struct super_block *sb, unsigned long ino)
{
int size;
struct unionfs_inode_info *info;
struct inode *inode;
inode = iget_locked(sb, ino);
if (!inode)
return ERR_PTR(-ENOMEM);
if (!(inode->i_state & I_NEW))
return inode;
info = UNIONFS_I(inode);
memset(info, 0, offsetof(struct unionfs_inode_info, vfs_inode));
info->bstart = -1;
info->bend = -1;
atomic_set(&info->generation,
atomic_read(&UNIONFS_SB(inode->i_sb)->generation));
spin_lock_init(&info->rdlock);
info->rdcount = 1;
info->hashsize = -1;
INIT_LIST_HEAD(&info->readdircache);
size = sbmax(inode->i_sb) * sizeof(struct inode *);
info->lower_inodes = kzalloc(size, GFP_KERNEL);
if (unlikely(!info->lower_inodes)) {
printk(KERN_CRIT "unionfs: no kernel memory when allocating "
"lower-pointer array!\n");
iget_failed(inode);
return ERR_PTR(-ENOMEM);
}
inode->i_version++;
inode->i_op = &unionfs_main_iops;
inode->i_fop = &unionfs_main_fops;
inode->i_mapping->a_ops = &unionfs_aops;
/*
* reset times so unionfs_copy_attr_all can keep out time invariants
* right (upper inode time being the max of all lower ones).
*/
inode->i_atime.tv_sec = inode->i_atime.tv_nsec = 0;
inode->i_mtime.tv_sec = inode->i_mtime.tv_nsec = 0;
inode->i_ctime.tv_sec = inode->i_ctime.tv_nsec = 0;
unlock_new_inode(inode);
return inode;
}
/*
* final actions when unmounting a file system
*
* No need to lock rwsem.
*/
static void unionfs_put_super(struct super_block *sb)
{
int bindex, bstart, bend;
struct unionfs_sb_info *spd;
int leaks = 0;
spd = UNIONFS_SB(sb);
if (!spd)
return;
bstart = sbstart(sb);
bend = sbend(sb);
/* Make sure we have no leaks of branchget/branchput. */
for (bindex = bstart; bindex <= bend; bindex++)
if (unlikely(branch_count(sb, bindex) != 0)) {
printk(KERN_CRIT
"unionfs: branch %d has %d references left!\n",
bindex, branch_count(sb, bindex));
leaks = 1;
}
WARN_ON(leaks != 0);
/* decrement lower super references */
for (bindex = bstart; bindex <= bend; bindex++) {
struct super_block *s;
s = unionfs_lower_super_idx(sb, bindex);
unionfs_set_lower_super_idx(sb, bindex, NULL);
atomic_dec(&s->s_active);
}
kfree(spd->dev_name);
kfree(spd->data);
kfree(spd);
sb->s_fs_info = NULL;
}
/*
* Since people use this to answer the "How big of a file can I write?"
* question, we report the size of the highest priority branch as the size of
* the union.
*/
static int unionfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int err = 0;
struct super_block *sb;
struct dentry *lower_dentry;
struct dentry *parent;
struct path lower_path;
bool valid;
sb = dentry->d_sb;
unionfs_read_lock(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, 0);
if (unlikely(!valid)) {
err = -ESTALE;
goto out;
}
unionfs_check_dentry(dentry);
lower_dentry = unionfs_lower_dentry(sb->s_root);
lower_path.dentry = lower_dentry;
lower_path.mnt = unionfs_mntget(sb->s_root, 0);
err = vfs_statfs(&lower_path, buf);
mntput(lower_path.mnt);
/* set return buf to our f/s to avoid confusing user-level utils */
buf->f_type = UNIONFS_SUPER_MAGIC;
/*
* Our maximum file name can is shorter by a few bytes because every
* file name could potentially be whited-out.
*
* XXX: this restriction goes away with ODF.
*/
unionfs_set_max_namelen(&buf->f_namelen);
/*
* reset two fields to avoid confusing user-land.
* XXX: is this still necessary?
*/
memset(&buf->f_fsid, 0, sizeof(__kernel_fsid_t));
memset(&buf->f_spare, 0, sizeof(buf->f_spare));
out:
unionfs_check_dentry(dentry);
unionfs_unlock_dentry(dentry);
unionfs_unlock_parent(dentry, parent);
unionfs_read_unlock(sb);
return err;
}
/* handle mode changing during remount */
static noinline_for_stack int do_remount_mode_option(
char *optarg,
int cur_branches,
struct unionfs_data *new_data,
struct path *new_lower_paths)
{
int err = -EINVAL;
int perms, idx;
char *modename = strchr(optarg, '=');
struct path path;
/* by now, optarg contains the branch name */
if (!*optarg) {
printk(KERN_ERR
"unionfs: no branch specified for mode change\n");
goto out;
}
if (!modename) {
printk(KERN_ERR "unionfs: branch \"%s\" requires a mode\n",
optarg);
goto out;
}
*modename++ = '\0';
err = parse_branch_mode(modename, &perms);
if (err) {
printk(KERN_ERR "unionfs: invalid mode \"%s\" for \"%s\"\n",
modename, optarg);
goto out;
}
/*
* Find matching branch index. For now, this assumes that nothing
* has been mounted on top of this Unionfs stack. Once we have /odf
* and cache-coherency resolved, we'll address the branch-path
* uniqueness.
*/
err = kern_path(optarg, LOOKUP_FOLLOW, &path);
if (err) {
printk(KERN_ERR "unionfs: error accessing "
"lower directory \"%s\" (error %d)\n",
optarg, err);
goto out;
}
for (idx = 0; idx < cur_branches; idx++)
if (path.mnt == new_lower_paths[idx].mnt &&
path.dentry == new_lower_paths[idx].dentry)
break;
path_put(&path); /* no longer needed */
if (idx == cur_branches) {
err = -ENOENT; /* err may have been reset above */
printk(KERN_ERR "unionfs: branch \"%s\" "
"not found\n", optarg);
goto out;
}
/* check/change mode for existing branch */
/* we don't warn if perms==branchperms */
new_data[idx].branchperms = perms;
err = 0;
out:
return err;
}
/* handle branch deletion during remount */
static noinline_for_stack int do_remount_del_option(
char *optarg, int cur_branches,
struct unionfs_data *new_data,
struct path *new_lower_paths)
{
int err = -EINVAL;
int idx;
struct path path;
/* optarg contains the branch name to delete */
/*
* Find matching branch index. For now, this assumes that nothing
* has been mounted on top of this Unionfs stack. Once we have /odf
* and cache-coherency resolved, we'll address the branch-path
* uniqueness.
*/
err = kern_path(optarg, LOOKUP_FOLLOW, &path);
if (err) {
printk(KERN_ERR "unionfs: error accessing "
"lower directory \"%s\" (error %d)\n",
optarg, err);
goto out;
}
for (idx = 0; idx < cur_branches; idx++)
if (path.mnt == new_lower_paths[idx].mnt &&
path.dentry == new_lower_paths[idx].dentry)
break;
path_put(&path); /* no longer needed */
if (idx == cur_branches) {
printk(KERN_ERR "unionfs: branch \"%s\" "
"not found\n", optarg);
err = -ENOENT;
goto out;
}
/* check if there are any open files on the branch to be deleted */
if (atomic_read(&new_data[idx].open_files) > 0) {
err = -EBUSY;
goto out;
}
/*
* Now we have to delete the branch. First, release any handles it
* has. Then, move the remaining array indexes past "idx" in
* new_data and new_lower_paths one to the left. Finally, adjust
* cur_branches.
*/
path_put(&new_lower_paths[idx]);
if (idx < cur_branches - 1) {
/* if idx==cur_branches-1, we delete last branch: easy */
memmove(&new_data[idx], &new_data[idx+1],
(cur_branches - 1 - idx) *
sizeof(struct unionfs_data));
memmove(&new_lower_paths[idx], &new_lower_paths[idx+1],
(cur_branches - 1 - idx) * sizeof(struct path));
}
err = 0;
out:
return err;
}
/* handle branch insertion during remount */
static noinline_for_stack int do_remount_add_option(
char *optarg, int cur_branches,
struct unionfs_data *new_data,
struct path *new_lower_paths,
int *high_branch_id)
{
int err = -EINVAL;
int perms;
int idx = 0; /* default: insert at beginning */
char *new_branch , *modename = NULL;
struct path path;
/*
* optarg can be of several forms:
*
* /bar:/foo insert /foo before /bar
* /bar:/foo=ro insert /foo in ro mode before /bar
* /foo insert /foo in the beginning (prepend)
* :/foo insert /foo at the end (append)
*/
if (*optarg == ':') { /* append? */
new_branch = optarg + 1; /* skip ':' */
idx = cur_branches;
goto found_insertion_point;
}
new_branch = strchr(optarg, ':');
if (!new_branch) { /* prepend? */
new_branch = optarg;
goto found_insertion_point;
}
*new_branch++ = '\0'; /* holds path+mode of new branch */
/*
* Find matching branch index. For now, this assumes that nothing
* has been mounted on top of this Unionfs stack. Once we have /odf
* and cache-coherency resolved, we'll address the branch-path
* uniqueness.
*/
err = kern_path(optarg, LOOKUP_FOLLOW, &path);
if (err) {
printk(KERN_ERR "unionfs: error accessing "
"lower directory \"%s\" (error %d)\n",
optarg, err);
goto out;
}
for (idx = 0; idx < cur_branches; idx++)
if (path.mnt == new_lower_paths[idx].mnt &&
path.dentry == new_lower_paths[idx].dentry)
break;
path_put(&path); /* no longer needed */
if (idx == cur_branches) {
printk(KERN_ERR "unionfs: branch \"%s\" "
"not found\n", optarg);
err = -ENOENT;
goto out;
}
/*
* At this point idx will hold the index where the new branch should
* be inserted before.
*/
found_insertion_point:
/* find the mode for the new branch */
if (new_branch)
modename = strchr(new_branch, '=');
if (modename)
*modename++ = '\0';
if (!new_branch || !*new_branch) {
printk(KERN_ERR "unionfs: null new branch\n");
err = -EINVAL;
goto out;
}
err = parse_branch_mode(modename, &perms);
if (err) {
printk(KERN_ERR "unionfs: invalid mode \"%s\" for "
"branch \"%s\"\n", modename, new_branch);
goto out;
}
err = kern_path(new_branch, LOOKUP_FOLLOW, &path);
if (err) {
printk(KERN_ERR "unionfs: error accessing "
"lower directory \"%s\" (error %d)\n",
new_branch, err);
goto out;
}
/*
* It's probably safe to check_mode the new branch to insert. Note:
* we don't allow inserting branches which are unionfs's by
* themselves (check_branch returns EINVAL in that case). This is
* because this code base doesn't support stacking unionfs: the ODF
* code base supports that correctly.
*/
err = check_branch(&path);
if (err) {
printk(KERN_ERR "unionfs: lower directory "
"\"%s\" is not a valid branch\n", optarg);
path_put(&path);
goto out;
}
/*
* Now we have to insert the new branch. But first, move the bits
* to make space for the new branch, if needed. Finally, adjust
* cur_branches.
* We don't release nd here; it's kept until umount/remount.
*/
if (idx < cur_branches) {
/* if idx==cur_branches, we append: easy */
memmove(&new_data[idx+1], &new_data[idx],
(cur_branches - idx) * sizeof(struct unionfs_data));
memmove(&new_lower_paths[idx+1], &new_lower_paths[idx],
(cur_branches - idx) * sizeof(struct path));
}
new_lower_paths[idx].dentry = path.dentry;
new_lower_paths[idx].mnt = path.mnt;
new_data[idx].sb = path.dentry->d_sb;
atomic_set(&new_data[idx].open_files, 0);
new_data[idx].branchperms = perms;
new_data[idx].branch_id = ++*high_branch_id; /* assign new branch ID */
err = 0;
out:
return err;
}
/*
* Support branch management options on remount.
*
* See Documentation/filesystems/unionfs/ for details.
*
* @flags: numeric mount options
* @options: mount options string
*
* This function can rearrange a mounted union dynamically, adding and
* removing branches, including changing branch modes. Clearly this has to
* be done safely and atomically. Luckily, the VFS already calls this
* function with lock_super(sb) and lock_kernel() held, preventing
* concurrent mixing of new mounts, remounts, and unmounts. Moreover,
* do_remount_sb(), our caller function, already called shrink_dcache_sb(sb)
* to purge dentries/inodes from our superblock, and also called
* fsync_super(sb) to purge any dirty pages. So we're good.
*
* XXX: however, our remount code may also need to invalidate mapped pages
* so as to force them to be re-gotten from the (newly reconfigured) lower
* branches. This has to wait for proper mmap and cache coherency support
* in the VFS.
*
*/
static int unionfs_remount_fs(struct super_block *sb, int *flags,
char *options)
{
int err = 0;
int i;
char *optionstmp, *tmp_to_free; /* kstrdup'ed of "options" */
char *optname;
int cur_branches = 0; /* no. of current branches */
int new_branches = 0; /* no. of branches actually left in the end */
int add_branches; /* est. no. of branches to add */
int del_branches; /* est. no. of branches to del */
int max_branches; /* max possible no. of branches */
struct unionfs_data *new_data = NULL, *tmp_data = NULL;
struct path *new_lower_paths = NULL, *tmp_lower_paths = NULL;
struct inode **new_lower_inodes = NULL;
int new_high_branch_id; /* new high branch ID */
int size; /* memory allocation size, temp var */
int old_ibstart, old_ibend;
unionfs_write_lock(sb);
/*
* The VFS will take care of "ro" and "rw" flags, and we can safely
* ignore MS_SILENT, but anything else left over is an error. So we
* need to check if any other flags may have been passed (none are
* allowed/supported as of now).
*/
if ((*flags & ~(MS_RDONLY | MS_SILENT)) != 0) {
printk(KERN_ERR
"unionfs: remount flags 0x%x unsupported\n", *flags);
err = -EINVAL;
goto out_error;
}
/*
* If 'options' is NULL, it's probably because the user just changed
* the union to a "ro" or "rw" and the VFS took care of it. So
* nothing to do and we're done.
*/
if (!options || options[0] == '\0')
goto out_error;
/*
* Find out how many branches we will have in the end, counting
* "add" and "del" commands. Copy the "options" string because
* strsep modifies the string and we need it later.
*/
tmp_to_free = kstrdup(options, GFP_KERNEL);
optionstmp = tmp_to_free;
if (unlikely(!optionstmp)) {
err = -ENOMEM;
goto out_free;
}
cur_branches = sbmax(sb); /* current no. branches */
new_branches = sbmax(sb);
del_branches = 0;
add_branches = 0;
new_high_branch_id = sbhbid(sb); /* save current high_branch_id */
while ((optname = strsep(&optionstmp, ",")) != NULL) {
char *optarg;
if (!optname || !*optname)
continue;
optarg = strchr(optname, '=');
if (optarg)
*optarg++ = '\0';
if (!strcmp("add", optname))
add_branches++;
else if (!strcmp("del", optname))
del_branches++;
}
kfree(tmp_to_free);
/* after all changes, will we have at least one branch left? */
if ((new_branches + add_branches - del_branches) < 1) {
printk(KERN_ERR
"unionfs: no branches left after remount\n");
err = -EINVAL;
goto out_free;
}
/*
* Since we haven't actually parsed all the add/del options, nor
* have we checked them for errors, we don't know for sure how many
* branches we will have after all changes have taken place. In
* fact, the total number of branches left could be less than what
* we have now. So we need to allocate space for a temporary
* placeholder that is at least as large as the maximum number of
* branches we *could* have, which is the current number plus all
* the additions. Once we're done with these temp placeholders, we
* may have to re-allocate the final size, copy over from the temp,
* and then free the temps (done near the end of this function).
*/
max_branches = cur_branches + add_branches;
/* allocate space for new pointers to lower dentry */
tmp_data = kcalloc(max_branches,
sizeof(struct unionfs_data), GFP_KERNEL);
if (unlikely(!tmp_data)) {
err = -ENOMEM;
goto out_free;
}
/* allocate space for new pointers to lower paths */
tmp_lower_paths = kcalloc(max_branches,
sizeof(struct path), GFP_KERNEL);
if (unlikely(!tmp_lower_paths)) {
err = -ENOMEM;
goto out_free;
}
/* copy current info into new placeholders, incrementing refcnts */
memcpy(tmp_data, UNIONFS_SB(sb)->data,
cur_branches * sizeof(struct unionfs_data));
memcpy(tmp_lower_paths, UNIONFS_D(sb->s_root)->lower_paths,
cur_branches * sizeof(struct path));
for (i = 0; i < cur_branches; i++)
path_get(&tmp_lower_paths[i]); /* drop refs at end of fxn */
/*******************************************************************
* For each branch command, do kern_path on the requested branch,
* and apply the change to a temp branch list. To handle errors, we
* already dup'ed the old arrays (above), and increased the refcnts
* on various f/s objects. So now we can do all the kern_path'ss
* and branch-management commands on the new arrays. If it fail mid
* way, we free the tmp arrays and *put all objects. If we succeed,
* then we free old arrays and *put its objects, and then replace
* the arrays with the new tmp list (we may have to re-allocate the
* memory because the temp lists could have been larger than what we
* actually needed).
*******************************************************************/
while ((optname = strsep(&options, ",")) != NULL) {
char *optarg;
if (!optname || !*optname)
continue;
/*
* At this stage optname holds a comma-delimited option, but
* without the commas. Next, we need to break the string on
* the '=' symbol to separate CMD=ARG, where ARG itself can
* be KEY=VAL. For example, in mode=/foo=rw, CMD is "mode",
* KEY is "/foo", and VAL is "rw".
*/
optarg = strchr(optname, '=');
if (optarg)
*optarg++ = '\0';
/* incgen remount option (instead of old ioctl) */
if (!strcmp("incgen", optname)) {
err = 0;
goto out_no_change;
}
/*
* All of our options take an argument now. (Insert ones
* that don't above this check.) So at this stage optname
* contains the CMD part and optarg contains the ARG part.
*/
if (!optarg || !*optarg) {
printk(KERN_ERR "unionfs: all remount options require "
"an argument (%s)\n", optname);
err = -EINVAL;
goto out_release;
}
if (!strcmp("add", optname)) {
err = do_remount_add_option(optarg, new_branches,
tmp_data,
tmp_lower_paths,
&new_high_branch_id);
if (err)
goto out_release;
new_branches++;
if (new_branches > UNIONFS_MAX_BRANCHES) {
printk(KERN_ERR "unionfs: command exceeds "
"%d branches\n", UNIONFS_MAX_BRANCHES);
err = -E2BIG;
goto out_release;
}
continue;
}
if (!strcmp("del", optname)) {
err = do_remount_del_option(optarg, new_branches,
tmp_data,
tmp_lower_paths);
if (err)
goto out_release;
new_branches--;
continue;
}
if (!strcmp("mode", optname)) {
err = do_remount_mode_option(optarg, new_branches,
tmp_data,
tmp_lower_paths);
if (err)
goto out_release;
continue;
}
/*
* When you use "mount -o remount,ro", mount(8) will
* reportedly pass the original dirs= string from
* /proc/mounts. So for now, we have to ignore dirs= and
* not consider it an error, unless we want to allow users
* to pass dirs= in remount. Note that to allow the VFS to
* actually process the ro/rw remount options, we have to
* return 0 from this function.
*/
if (!strcmp("dirs", optname)) {
printk(KERN_WARNING
"unionfs: remount ignoring option \"%s\"\n",
optname);
continue;
}
err = -EINVAL;
printk(KERN_ERR
"unionfs: unrecognized option \"%s\"\n", optname);
goto out_release;
}
out_no_change:
/******************************************************************
* WE'RE ALMOST DONE: check if leftmost branch might be read-only,
* see if we need to allocate a small-sized new vector, copy the
* vectors to their correct place, release the refcnt of the older
* ones, and return. Also handle invalidating any pages that will
* have to be re-read.
*******************************************************************/
if (!(tmp_data[0].branchperms & MAY_WRITE)) {
printk(KERN_ERR "unionfs: leftmost branch cannot be read-only "
"(use \"remount,ro\" to create a read-only union)\n");
err = -EINVAL;
goto out_release;
}
/* (re)allocate space for new pointers to lower dentry */
size = new_branches * sizeof(struct unionfs_data);
new_data = krealloc(tmp_data, size, GFP_KERNEL);
if (unlikely(!new_data)) {
err = -ENOMEM;
goto out_release;
}
/* allocate space for new pointers to lower paths */
size = new_branches * sizeof(struct path);
new_lower_paths = krealloc(tmp_lower_paths, size, GFP_KERNEL);
if (unlikely(!new_lower_paths)) {
err = -ENOMEM;
goto out_release;
}
/* allocate space for new pointers to lower inodes */
new_lower_inodes = kcalloc(new_branches,
sizeof(struct inode *), GFP_KERNEL);
if (unlikely(!new_lower_inodes)) {
err = -ENOMEM;
goto out_release;
}
/*
* OK, just before we actually put the new set of branches in place,
* we need to ensure that our own f/s has no dirty objects left.
* Luckily, do_remount_sb() already calls shrink_dcache_sb(sb) and
* fsync_super(sb), taking care of dentries, inodes, and dirty
* pages. So all that's left is for us to invalidate any leftover
* (non-dirty) pages to ensure that they will be re-read from the
* new lower branches (and to support mmap).
*/
/*
* Once we finish the remounting successfully, our superblock
* generation number will have increased. This will be detected by
* our dentry-revalidation code upon subsequent f/s operations
* through unionfs. The revalidation code will rebuild the union of
* lower inodes for a given unionfs inode and invalidate any pages
* of such "stale" inodes (by calling our purge_inode_data
* function). This revalidation will happen lazily and
* incrementally, as users perform operations on cached inodes. We
* would like to encourage this revalidation to happen sooner if
* possible, so we like to try to invalidate as many other pages in
* our superblock as we can. We used to call drop_pagecache_sb() or
* a variant thereof, but either method was racy (drop_caches alone
* is known to be racy). So now we let the revalidation happen on a
* per file basis in ->d_revalidate.
*/
/* grab new lower super references; release old ones */
for (i = 0; i < new_branches; i++)
atomic_inc(&new_data[i].sb->s_active);
for (i = 0; i < sbmax(sb); i++)
atomic_dec(&UNIONFS_SB(sb)->data[i].sb->s_active);
/* copy new vectors into their correct place */
tmp_data = UNIONFS_SB(sb)->data;
UNIONFS_SB(sb)->data = new_data;
new_data = NULL; /* so don't free good pointers below */
tmp_lower_paths = UNIONFS_D(sb->s_root)->lower_paths;
UNIONFS_D(sb->s_root)->lower_paths = new_lower_paths;
new_lower_paths = NULL; /* so don't free good pointers below */
/* update our unionfs_sb_info and root dentry index of last branch */
i = sbmax(sb); /* save no. of branches to release at end */
sbend(sb) = new_branches - 1;
dbend(sb->s_root) = new_branches - 1;
old_ibstart = ibstart(sb->s_root->d_inode);
old_ibend = ibend(sb->s_root->d_inode);
ibend(sb->s_root->d_inode) = new_branches - 1;
UNIONFS_D(sb->s_root)->bcount = new_branches;
new_branches = i; /* no. of branches to release below */
/*
* Update lower inodes: 3 steps
* 1. grab ref on all new lower inodes
*/
for (i = dbstart(sb->s_root); i <= dbend(sb->s_root); i++) {
struct dentry *lower_dentry =
unionfs_lower_dentry_idx(sb->s_root, i);
igrab(lower_dentry->d_inode);
new_lower_inodes[i] = lower_dentry->d_inode;
}
/* 2. release reference on all older lower inodes */
iput_lowers(sb->s_root->d_inode, old_ibstart, old_ibend, true);
/* 3. update root dentry's inode to new lower_inodes array */
UNIONFS_I(sb->s_root->d_inode)->lower_inodes = new_lower_inodes;
new_lower_inodes = NULL;
/* maxbytes may have changed */
sb->s_maxbytes = unionfs_lower_super_idx(sb, 0)->s_maxbytes;
/* update high branch ID */
sbhbid(sb) = new_high_branch_id;
/* update our sb->generation for revalidating objects */
i = atomic_inc_return(&UNIONFS_SB(sb)->generation);
atomic_set(&UNIONFS_D(sb->s_root)->generation, i);
atomic_set(&UNIONFS_I(sb->s_root->d_inode)->generation, i);
if (!(*flags & MS_SILENT))
pr_info("unionfs: %s: new generation number %d\n",
UNIONFS_SB(sb)->dev_name, i);
/* finally, update the root dentry's times */
unionfs_copy_attr_times(sb->s_root->d_inode);
err = 0; /* reset to success */
/*
* The code above falls through to the next label, and releases the
* refcnts of the older ones (stored in tmp_*): if we fell through
* here, it means success. However, if we jump directly to this
* label from any error above, then an error occurred after we
* grabbed various refcnts, and so we have to release the
* temporarily constructed structures.
*/
out_release:
/* no need to cleanup/release anything in tmp_data */
if (tmp_lower_paths)
for (i = 0; i < new_branches; i++)
path_put(&tmp_lower_paths[i]);
out_free:
kfree(tmp_lower_paths);
kfree(tmp_data);
kfree(new_lower_paths);
kfree(new_data);
kfree(new_lower_inodes);
out_error:
unionfs_check_dentry(sb->s_root);
unionfs_write_unlock(sb);
return err;
}
/*
* 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.
*
* No need to lock sb info's rwsem.
*/
static void unionfs_evict_inode(struct inode *inode)
{
int bindex, bstart, bend;
struct inode *lower_inode;
struct list_head *pos, *n;
struct unionfs_dir_state *rdstate;
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
list_for_each_safe(pos, n, &UNIONFS_I(inode)->readdircache) {
rdstate = list_entry(pos, struct unionfs_dir_state, cache);
list_del(&rdstate->cache);
free_rdstate(rdstate);
}
/*
* Decrement a reference to a lower_inode, which was incremented
* by our read_inode when it was created initially.
*/
bstart = ibstart(inode);
bend = ibend(inode);
if (bstart >= 0) {
for (bindex = bstart; bindex <= bend; bindex++) {
lower_inode = unionfs_lower_inode_idx(inode, bindex);
if (!lower_inode)
continue;
unionfs_set_lower_inode_idx(inode, bindex, NULL);
/* see Documentation/filesystems/unionfs/issues.txt */
lockdep_off();
iput(lower_inode);
lockdep_on();
}
}
kfree(UNIONFS_I(inode)->lower_inodes);
UNIONFS_I(inode)->lower_inodes = NULL;
}
static struct inode *unionfs_alloc_inode(struct super_block *sb)
{
struct unionfs_inode_info *i;
i = kmem_cache_alloc(unionfs_inode_cachep, GFP_KERNEL);
if (unlikely(!i))
return NULL;
/* memset everything up to the inode to 0 */
memset(i, 0, offsetof(struct unionfs_inode_info, vfs_inode));
i->vfs_inode.i_version = 1;
return &i->vfs_inode;
}
static void unionfs_destroy_inode(struct inode *inode)
{
kmem_cache_free(unionfs_inode_cachep, UNIONFS_I(inode));
}
/* unionfs inode cache constructor */
static void init_once(void *obj)
{
struct unionfs_inode_info *i = obj;
inode_init_once(&i->vfs_inode);
}
int unionfs_init_inode_cache(void)
{
int err = 0;
unionfs_inode_cachep =
kmem_cache_create("unionfs_inode_cache",
sizeof(struct unionfs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT, init_once);
if (unlikely(!unionfs_inode_cachep))
err = -ENOMEM;
return err;
}
/* unionfs inode cache destructor */
void unionfs_destroy_inode_cache(void)
{
if (unionfs_inode_cachep)
kmem_cache_destroy(unionfs_inode_cachep);
}
/*
* Called when we have a dirty inode, right here we only throw out
* parts of our readdir list that are too old.
*
* No need to grab sb info's rwsem.
*/
static int unionfs_write_inode(struct inode *inode,
struct writeback_control *wbc)
{
struct list_head *pos, *n;
struct unionfs_dir_state *rdstate;
spin_lock(&UNIONFS_I(inode)->rdlock);
list_for_each_safe(pos, n, &UNIONFS_I(inode)->readdircache) {
rdstate = list_entry(pos, struct unionfs_dir_state, cache);
/* We keep this list in LRU order. */
if ((rdstate->access + RDCACHE_JIFFIES) > jiffies)
break;
UNIONFS_I(inode)->rdcount--;
list_del(&rdstate->cache);
free_rdstate(rdstate);
}
spin_unlock(&UNIONFS_I(inode)->rdlock);
return 0;
}
/*
* Used only in nfs, to kill any pending RPC tasks, so that subsequent
* code can actually succeed and won't leave tasks that need handling.
*/
static void unionfs_umount_begin(struct super_block *sb)
{
struct super_block *lower_sb;
int bindex, bstart, bend;
unionfs_read_lock(sb, UNIONFS_SMUTEX_CHILD);
bstart = sbstart(sb);
bend = sbend(sb);
for (bindex = bstart; bindex <= bend; bindex++) {
lower_sb = unionfs_lower_super_idx(sb, bindex);
if (lower_sb && lower_sb->s_op &&
lower_sb->s_op->umount_begin)
lower_sb->s_op->umount_begin(lower_sb);
}
unionfs_read_unlock(sb);
}
static int unionfs_show_options(struct seq_file *m, struct dentry *root)
{
struct super_block *sb = root->d_sb;
int ret = 0;
char *tmp_page;
char *path;
int bindex, bstart, bend;
int perms;
/* to prevent a silly lockdep warning with namespace_sem */
lockdep_off();
unionfs_read_lock(sb, UNIONFS_SMUTEX_CHILD);
unionfs_lock_dentry(sb->s_root, UNIONFS_DMUTEX_CHILD);
tmp_page = (char *) __get_free_page(GFP_KERNEL);
if (unlikely(!tmp_page)) {
ret = -ENOMEM;
goto out;
}
bstart = sbstart(sb);
bend = sbend(sb);
seq_printf(m, ",dirs=");
for (bindex = bstart; bindex <= bend; bindex++) {
struct path p;
p.dentry = unionfs_lower_dentry_idx(sb->s_root, bindex);
p.mnt = unionfs_lower_mnt_idx(sb->s_root, bindex);
path = d_path(&p, tmp_page, PAGE_SIZE);
if (IS_ERR(path)) {
ret = PTR_ERR(path);
goto out;
}
perms = branchperms(sb, bindex);
seq_printf(m, "%s=%s", path,
perms & MAY_WRITE ? "rw" : "ro");
if (bindex != bend)
seq_printf(m, ":");
}
out:
free_page((unsigned long) tmp_page);
unionfs_unlock_dentry(sb->s_root);
unionfs_read_unlock(sb);
lockdep_on();
return ret;
}
struct super_operations unionfs_sops = {
.put_super = unionfs_put_super,
.statfs = unionfs_statfs,
.remount_fs = unionfs_remount_fs,
.evict_inode = unionfs_evict_inode,
.umount_begin = unionfs_umount_begin,
.show_options = unionfs_show_options,
.write_inode = unionfs_write_inode,
.alloc_inode = unionfs_alloc_inode,
.destroy_inode = unionfs_destroy_inode,
};