コード例 #1
0
struct aufs_branch *stobr(struct super_block *sb, aufs_bindex_t bindex)
{
	SiMustAnyLock(sb);
	AuDebugOn(bindex < 0 || sbend(sb) < bindex
		  || !stosi(sb)->si_branch[0 + bindex]);
	return stosi(sb)->si_branch[0 + bindex];
}
コード例 #2
0
ファイル: super.c プロジェクト: BackupTheBerlios/dss-svn
/* final actions when unmounting a file system */
static void unionfs_put_super(struct super_block *sb)
{
	int bindex, bstart, bend;
	struct unionfs_sb_info *spd;

	print_entry_location();

	if ((spd = stopd(sb))) {
		/* XXX: Free persistent inode stuff. */

		bstart = sbstart(sb);
		bend = sbend(sb);
		for (bindex = bstart; bindex <= bend; bindex++)
			mntput(stohiddenmnt_index(sb, bindex));

		/* Make sure we have no leaks of branchget/branchput. */
		for (bindex = bstart; bindex <= bend; bindex++)
			ASSERT(branch_count(sb, bindex) == 0);

		KFREE(stohs_ptr(sb));
		KFREE(stohiddenmnt_ptr(sb));
		KFREE(spd->usi_sbcount_p);
		KFREE(spd->usi_branchperms_p);
		KFREE(spd->usi_putmaps);
		KFREE(spd);
		stopd_lhs(sb) = NULL;
	}
	fist_dprint(6, "unionfs: released super\n");

	print_exit_location();
}
コード例 #3
0
ファイル: branchman.c プロジェクト: BackupTheBerlios/dss-svn
int unionfs_ioctl_branchcount(struct file *file, unsigned int cmd,
			      unsigned long arg)
{
	int err = 0;
	int bstart, bend;
	int i;
	struct super_block *sb = file->f_dentry->d_sb;

	print_entry_location();

	bstart = sbstart(sb);
	bend = sbend(sb);

	err = bend + 1;
	if (!arg)
		goto out;

	for (i = bstart; i <= bend; i++) {
		if (put_user(branch_count(sb, i), ((int *)arg) + i)) {
			err = -EFAULT;
			goto out;
		}
	}

      out:
	print_exit_status(err);
	return err;
}
コード例 #4
0
static int make_xino(struct seq_file *seq, struct sysaufs_args *args,
		     int *do_size)
{
	int err;
	struct super_block *sb = args->sb;
	aufs_bindex_t bindex, bend;
	struct file *xf;
	struct inode *xi;

	TraceEnter();
	AuDebugOn(args->index != SysaufsSb_XINO);
	SiMustReadLock(sb);

	*do_size = 0;
	err = seq_printf(seq, "%lu %lu\n", (unsigned long)sizeof(struct xino),
			 (unsigned long)atomic_long_read(&stosi(sb)->si_xino));
	bend = sbend(sb);
	for (bindex = 0; !err && bindex <= bend; bindex++) {
		xf = stobr(sb, bindex)->br_xino;
		xi = xf->f_dentry->d_inode;
		err = seq_printf(seq, "%d: %d, %Lux%d %Ld\n",
				 bindex, file_count(xf),
				 (u64)xi->i_blocks, 1 << xi->i_blkbits,
				 i_size_read(xi));
	}
	return err;
}
コード例 #5
0
int find_bindex(struct super_block *sb, struct aufs_branch *br)
{
	aufs_bindex_t bindex, bend;

	bend = sbend(sb);
	for (bindex = 0; bindex <= bend; bindex++)
		if (stobr(sb, bindex) == br)
			return bindex;
	return -1;
}
コード例 #6
0
int unionfs_ioctl_rdwrbranch(struct inode *inode, unsigned int cmd,
			     unsigned long arg)
{
	int err;
	struct unionfs_rdwrbranch_args *rdwrargs = NULL;
	int gen;

	print_entry_location();

	unionfs_write_lock(inode->i_sb);
	lock_dentry(inode->i_sb->s_root);

	if ((err = newputmap(inode->i_sb)))
		goto out;

	err = -ENOMEM;
	rdwrargs = KMALLOC(sizeof(struct unionfs_rdwrbranch_args), GFP_KERNEL);
	if (!rdwrargs)
		goto out;

	err = -EFAULT;
	if (copy_from_user
	    (rdwrargs, (const void __user *)arg,
	     sizeof(struct unionfs_rdwrbranch_args)))
		goto out;

	err = -EINVAL;
	if (rdwrargs->rwb_branch < 0
	    || (rdwrargs->rwb_branch > (sbend(inode->i_sb) + 1)))
		goto out;
	if (rdwrargs->rwb_perms & ~(MAY_READ | MAY_WRITE | MAY_NFSRO))
		goto out;
	if (!(rdwrargs->rwb_perms & MAY_READ))
		goto out;

	set_branchperms(inode->i_sb, rdwrargs->rwb_branch, rdwrargs->rwb_perms);

	atomic_inc(&stopd(inode->i_sb)->usi_generation);
	gen = atomic_read(&stopd(inode->i_sb)->usi_generation);
	atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen);
	atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen);

	err = 0;

      out:
	unlock_dentry(inode->i_sb->s_root);
	unionfs_write_unlock(inode->i_sb);
	KFREE(rdwrargs);

	print_exit_status(err);

	return err;
}
コード例 #7
0
ファイル: debug.c プロジェクト: robacklin/ts7800
void __show_inode_counts(const struct inode *inode,
			const char *file, const char *fxn, int line)
{
	struct inode *lower_inode;
	int bindex;

	if (unlikely(!inode)) {
		pr_debug("SiC: Null inode\n");
		return;
	}
	for (bindex = sbstart(inode->i_sb); bindex <= sbend(inode->i_sb);
	     bindex++) {
		lower_inode = unionfs_lower_inode_idx(inode, bindex);
		if (unlikely(!lower_inode))
			continue;
		pr_debug("SIC(%lu:%d:%d): lc=%d %s:%s:%d\n",
			 inode->i_ino, bindex,
			 atomic_read(&(inode)->i_count),
			 atomic_read(&(lower_inode)->i_count),
			 file, fxn, line);
	}
}
コード例 #8
0
ファイル: super.c プロジェクト: BackupTheBerlios/dss-svn
static int unionfs_statfs(struct super_block *sb, struct kstatfs *buf)
{
	int err = 0;
	struct super_block *hidden_sb;
	struct kstatfs rsb;
	int bindex, bindex1, bstart, bend;

	print_entry_location();
	memset(buf, 0, sizeof(struct kstatfs));
	buf->f_type = UNIONFS_SUPER_MAGIC;

	buf->f_frsize = 0;
	buf->f_namelen = 0;

	bstart = sbstart(sb);
	bend = sbend(sb);

	for (bindex = bstart; bindex <= bend; bindex++) {
		int dup = 0;

		hidden_sb = stohs_index(sb, bindex);
		/* Ignore duplicate super blocks. */
		for (bindex1 = bstart; bindex1 < bindex; bindex1++) {
			if (hidden_sb == stohs_index(sb, bindex1)) {
				dup = 1;
				break;
			}
		}
		if (dup) {
			continue;
		}

		err = vfs_statfs(hidden_sb, &rsb);
		fist_dprint(8,
			    "adding values for bindex:%d bsize:%d blocks:%d bfree:%d bavail:%d\n",
			    bindex, (int)rsb.f_bsize, (int)rsb.f_blocks,
			    (int)rsb.f_bfree, (int)rsb.f_bavail);

		if (!buf->f_frsize)
			buf->f_frsize = rsb.f_frsize;
		if (!buf->f_namelen) {
			buf->f_namelen = rsb.f_namelen;
		} else {
			if (buf->f_namelen > rsb.f_namelen)
				buf->f_namelen = rsb.f_namelen;
		}
		if (!buf->f_bsize) {
			buf->f_bsize = rsb.f_bsize;
		} else {
			if (buf->f_bsize < rsb.f_bsize) {
				int shifter = 0;
				while (buf->f_bsize < rsb.f_bsize) {
					shifter++;
					rsb.f_bsize >>= 1;
				}
				rsb.f_blocks <<= shifter;
				rsb.f_bfree <<= shifter;
				rsb.f_bavail <<= shifter;
			} else {
				int shifter = 0;
				while (buf->f_bsize > rsb.f_bsize) {
					shifter++;
					rsb.f_bsize <<= 1;
				}
				rsb.f_blocks >>= shifter;
				rsb.f_bfree >>= shifter;
				rsb.f_bavail >>= shifter;
			}
		}
コード例 #9
0
ファイル: branchman.c プロジェクト: BackupTheBerlios/dss-svn
static int newputmap(struct super_block *sb)
{
	struct unionfs_sb_info *spd;
	struct putmap *newmap;
	int count = 0;
	int i;

	print_entry_location();

	spd = stopd(sb);

	i = sizeof(int) * (sbend(sb) + 1);
	newmap = KMALLOC(sizeof(struct putmap) + i, GFP_UNIONFS);
	if (!newmap) {
		print_exit_status(-ENOMEM);
		return -ENOMEM;
	}

	if (!spd->usi_firstputmap) {
		spd->usi_firstputmap = 1;
		spd->usi_lastputmap = 1;

		spd->usi_putmaps =
		    KMALLOC(sizeof(struct putmap *), GFP_UNIONFS);
		if (!spd->usi_putmaps) {
			KFREE(newmap);
			print_exit_status(-ENOMEM);
			return -ENOMEM;
		}
	} else {
		struct putmap **newlist;
		int newfirst = spd->usi_firstputmap;

		while (!spd->usi_putmaps[newfirst - spd->usi_firstputmap] &&
		       newfirst <= spd->usi_lastputmap) {
			newfirst++;
		}

		newlist =
		    KMALLOC(sizeof(struct putmap *) *
			    (1 + spd->usi_lastputmap - newfirst), GFP_UNIONFS);
		if (!newlist) {
			KFREE(newmap);
			print_exit_status(-ENOMEM);
			return -ENOMEM;
		}

		for (i = newfirst; i <= spd->usi_lastputmap; i++) {
			newlist[i - newfirst] =
			    spd->usi_putmaps[i - spd->usi_firstputmap];
		}

		KFREE(spd->usi_putmaps);
		spd->usi_putmaps = newlist;
		spd->usi_firstputmap = newfirst;
		spd->usi_lastputmap++;
	}

	newmap->bend = sbend(sb);
	for (i = 0; i <= sbend(sb); i++) {
		count += branch_count(sb, i);
		newmap->map[i] = i;
	}
	for (i = spd->usi_firstputmap; i < spd->usi_lastputmap; i++) {
		struct putmap *cur;
		cur = spd->usi_putmaps[i - spd->usi_firstputmap];
		if (!cur)
			continue;
		count -= atomic_read(&cur->count);
	}
	atomic_set(&newmap->count, count);
	spd->usi_putmaps[spd->usi_lastputmap - spd->usi_firstputmap] = newmap;

	print_exit_status(0);
	return 0;
}
コード例 #10
0
ファイル: branchman.c プロジェクト: BackupTheBerlios/dss-svn
/* This must be called with the super block already locked. */
int unionfs_ioctl_delbranch(struct super_block *sb, unsigned long arg)
{
	struct dentry *hidden_dentry;
	struct inode *hidden_inode;
	struct super_block *hidden_sb;
	struct vfsmount *hidden_mnt;
	struct dentry *root_dentry;
	struct inode *root_inode;
	int err = 0;
	int pmindex, i, gen;

	print_entry("branch = %lu ", arg);
	lock_dentry(sb->s_root);

	err = -EBUSY;
	if (sbmax(sb) == 1)
		goto out;
	err = -EINVAL;
	if (arg < 0 || arg > stopd(sb)->b_end)
		goto out;
	err = -EBUSY;
	if (branch_count(sb, arg))
		goto out;

	if ((err = newputmap(sb)))
		goto out;

	pmindex = stopd(sb)->usi_lastputmap;
	pmindex -= stopd(sb)->usi_firstputmap;

	atomic_inc(&stopd(sb)->usi_generation);
	gen = atomic_read(&stopd(sb)->usi_generation);

	root_dentry = sb->s_root;
	root_inode = sb->s_root->d_inode;

	hidden_dentry = dtohd_index(root_dentry, arg);
	hidden_mnt = stohiddenmnt_index(sb, arg);
	hidden_inode = itohi_index(root_inode, arg);
	hidden_sb = stohs_index(sb, arg);

	DPUT(hidden_dentry);
	iput(hidden_inode);
	mntput(hidden_mnt);

	for (i = arg; i <= (sbend(sb) - 1); i++) {
		set_branch_count(sb, i, branch_count(sb, i + 1));
		set_stohiddenmnt_index(sb, i, stohiddenmnt_index(sb, i + 1));
		set_stohs_index(sb, i, stohs_index(sb, i + 1));
		set_branchperms(sb, i, branchperms(sb, i + 1));
		set_dtohd_index(root_dentry, i,
				dtohd_index(root_dentry, i + 1));
		set_itohi_index(root_inode, i, itohi_index(root_inode, i + 1));
		stopd(sb)->usi_putmaps[pmindex]->map[i + 1] = i;
	}

	set_dtohd_index(root_dentry, sbend(sb), NULL);
	set_itohi_index(root_inode, sbend(sb), NULL);
	set_stohiddenmnt_index(sb, sbend(sb), NULL);
	set_stohs_index(sb, sbend(sb), NULL);

	stopd(sb)->b_end--;
	set_dbend(root_dentry, dbend(root_dentry) - 1);
	dtopd(root_dentry)->udi_bcount--;
	itopd(root_inode)->b_end--;

	atomic_set(&dtopd(root_dentry)->udi_generation, gen);
	atomic_set(&itopd(root_inode)->uii_generation, gen);

	fixputmaps(sb);

	/* This doesn't open a file, so we might have to free the map here. */
	if (atomic_read(&stopd(sb)->usi_putmaps[pmindex]->count) == 0) {
		KFREE(stopd(sb)->usi_putmaps[pmindex]);
		stopd(sb)->usi_putmaps[pmindex] = NULL;
	}

      out:
	unlock_dentry(sb->s_root);
	print_exit_status(err);

	return err;
}
コード例 #11
0
ファイル: branchman.c プロジェクト: BackupTheBerlios/dss-svn
int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd,
			    unsigned long arg)
{
	int err;
	struct unionfs_addbranch_args *addargs = NULL;
	struct nameidata nd;
	char *path = NULL;
	int gen;
	int i;
	int count;

	int pobjects;

	struct vfsmount **new_hidden_mnt = NULL;
	struct inode **new_uii_inode = NULL;
	struct dentry **new_udi_dentry = NULL;
	struct super_block **new_usi_sb = NULL;
	int *new_branchperms = NULL;
	atomic_t *new_counts = NULL;

	print_entry_location();

	err = -ENOMEM;
	addargs = KMALLOC(sizeof(struct unionfs_addbranch_args), GFP_UNIONFS);
	if (!addargs)
		goto out;

	err = -EFAULT;
	if (copy_from_user
	    (addargs, (void *)arg, sizeof(struct unionfs_addbranch_args)))
		goto out;

	err = -EINVAL;
	if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE))
		goto out;
	if (!(addargs->ab_perms & MAY_READ))
		goto out;

	err = -E2BIG;
	if (sbend(inode->i_sb) > FD_SETSIZE)
		goto out;

	err = -ENOMEM;
	if (!(path = getname(addargs->ab_path)))
		goto out;

	err = path_lookup(path, LOOKUP_FOLLOW, &nd);

	RECORD_PATH_LOOKUP(&nd);
	if (err)
		goto out;
	if ((err = check_branch(&nd))) {
		path_release(&nd);
		RECORD_PATH_RELEASE(&nd);
		goto out;
	}

	unionfs_write_lock(inode->i_sb);
	lock_dentry(inode->i_sb->s_root);

	err = -EINVAL;
	if (addargs->ab_branch < 0
	    || (addargs->ab_branch > (sbend(inode->i_sb) + 1)))
		goto out;

	if ((err = newputmap(inode->i_sb)))
		goto out;

	stopd(inode->i_sb)->b_end++;
	dtopd(inode->i_sb->s_root)->udi_bcount++;
	set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) + 1);
	itopd(inode->i_sb->s_root->d_inode)->b_end++;

	atomic_inc(&stopd(inode->i_sb)->usi_generation);
	gen = atomic_read(&stopd(inode->i_sb)->usi_generation);

	pobjects = (sbend(inode->i_sb) + 1) - UNIONFS_INLINE_OBJECTS;
	if (pobjects > 0) {
		/* Reallocate the dynamic structures. */
		new_hidden_mnt =
		    KMALLOC(sizeof(struct vfsmount *) * pobjects, GFP_UNIONFS);
		new_udi_dentry =
		    KMALLOC(sizeof(struct dentry *) * pobjects, GFP_UNIONFS);
		new_uii_inode =
		    KMALLOC(sizeof(struct inode *) * pobjects, GFP_UNIONFS);
		new_usi_sb =
		    KMALLOC(sizeof(struct super_block *) * pobjects,
			    GFP_UNIONFS);
		new_counts = KMALLOC(sizeof(atomic_t) * pobjects, GFP_UNIONFS);
		new_branchperms = KMALLOC(sizeof(int) * pobjects, GFP_UNIONFS);
		if (!new_hidden_mnt || !new_udi_dentry || !new_uii_inode
		    || !new_counts || !new_usi_sb || !new_branchperms) {
			err = -ENOMEM;
			goto out;
		}
		memset(new_hidden_mnt, 0, sizeof(struct vfsmount *) * pobjects);
		memset(new_udi_dentry, 0, sizeof(struct dentry *) * pobjects);
		memset(new_uii_inode, 0, sizeof(struct inode *) * pobjects);
		memset(new_usi_sb, 0, sizeof(struct super_block *) * pobjects);
		memset(new_branchperms, 0, sizeof(int) * pobjects);
	}

	/* Copy the in-place values to our new structure. */
	for (i = UNIONFS_INLINE_OBJECTS; i < addargs->ab_branch; i++) {
		int j = i - UNIONFS_INLINE_OBJECTS;

		count = branch_count(inode->i_sb, i);
		atomic_set(&(new_counts[j]), count);

		new_branchperms[j] = branchperms(inode->i_sb, i);
		new_hidden_mnt[j] = stohiddenmnt_index(inode->i_sb, i);

		new_usi_sb[j] = stohs_index(inode->i_sb, i);
		new_udi_dentry[j] = dtohd_index(inode->i_sb->s_root, i);
		new_uii_inode[j] = itohi_index(inode->i_sb->s_root->d_inode, i);
	}

	/* Shift the ends to the right (only handle reallocated bits). */
	for (i = sbend(inode->i_sb) - 1; i >= (int)addargs->ab_branch; i--) {
		int j = i + 1;
		int perms;
		struct vfsmount *hm;
		struct super_block *hs;
		struct dentry *hd;
		struct inode *hi;
		int pmindex;

		count = branch_count(inode->i_sb, i);
		perms = branchperms(inode->i_sb, i);
		hm = stohiddenmnt_index(inode->i_sb, i);
		hs = stohs_index(inode->i_sb, i);
		hd = dtohd_index(inode->i_sb->s_root, i);
		hi = itohi_index(inode->i_sb->s_root->d_inode, i);

		/* Update the newest putmap, so it is correct for later. */
		pmindex = stopd(inode->i_sb)->usi_lastputmap;
		pmindex -= stopd(inode->i_sb)->usi_firstputmap;
		stopd(inode->i_sb)->usi_putmaps[pmindex]->map[i] = j;

		if (j >= UNIONFS_INLINE_OBJECTS) {
			j -= UNIONFS_INLINE_OBJECTS;
			atomic_set(&(new_counts[j]), count);
			new_branchperms[j] = perms;
			new_hidden_mnt[j] = hm;
			new_usi_sb[j] = hs;
			new_udi_dentry[j] = hd;
			new_uii_inode[j] = hi;
		} else {
			set_branch_count(inode->i_sb, j, count);
			set_branchperms(inode->i_sb, j, perms);
			set_stohiddenmnt_index(inode->i_sb, j, hm);
			set_stohs_index(inode->i_sb, j, hs);
			set_dtohd_index(inode->i_sb->s_root, j, hd);
			set_itohi_index(inode->i_sb->s_root->d_inode, j, hi);
		}
	}

	/* Now we can free the old ones. */
	KFREE(dtopd(inode->i_sb->s_root)->udi_dentry_p);
	KFREE(itopd(inode->i_sb->s_root->d_inode)->uii_inode_p);
	KFREE(stopd(inode->i_sb)->usi_hidden_mnt_p);
	KFREE(stopd(inode->i_sb)->usi_sb_p);
	KFREE(stopd(inode->i_sb)->usi_sbcount_p);
	KFREE(stopd(inode->i_sb)->usi_branchperms_p);

	/* Update the real pointers. */
	dtohd_ptr(inode->i_sb->s_root) = new_udi_dentry;
	itohi_ptr(inode->i_sb->s_root->d_inode) = new_uii_inode;
	stohiddenmnt_ptr(inode->i_sb) = new_hidden_mnt;
	stohs_ptr(inode->i_sb) = new_usi_sb;
	stopd(inode->i_sb)->usi_sbcount_p = new_counts;
	stopd(inode->i_sb)->usi_branchperms_p = new_branchperms;

	/* Re-NULL the new ones so we don't try to free them. */
	new_hidden_mnt = NULL;
	new_udi_dentry = NULL;
	new_usi_sb = NULL;
	new_uii_inode = NULL;
	new_counts = NULL;
	new_branchperms = NULL;

	/* Put the new dentry information into it's slot. */
	set_dtohd_index(inode->i_sb->s_root, addargs->ab_branch, nd.dentry);
	set_itohi_index(inode->i_sb->s_root->d_inode, addargs->ab_branch,
			igrab(nd.dentry->d_inode));
	set_branchperms(inode->i_sb, addargs->ab_branch, addargs->ab_perms);
	set_branch_count(inode->i_sb, addargs->ab_branch, 0);
	set_stohiddenmnt_index(inode->i_sb, addargs->ab_branch, nd.mnt);
	set_stohs_index(inode->i_sb, addargs->ab_branch, nd.dentry->d_sb);

	atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen);
	atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen);

	fixputmaps(inode->i_sb);

      out:
	unlock_dentry(inode->i_sb->s_root);
	unionfs_write_unlock(inode->i_sb);

	KFREE(new_hidden_mnt);
	KFREE(new_udi_dentry);
	KFREE(new_uii_inode);
	KFREE(new_usi_sb);
	KFREE(new_counts);
	KFREE(new_branchperms);
	KFREE(addargs);
	if (path)
		putname(path);

	print_exit_status(err);

	return err;
}
コード例 #12
0
ファイル: main.c プロジェクト: mrtos/Logitech-Revue
/*
 * our custom d_alloc_root work-alike
 *
 * we can't use d_alloc_root if we want to use our own interpose function
 * unchanged, so we simply call our own "fake" d_alloc_root
 */
static struct dentry *unionfs_d_alloc_root(struct super_block *sb)
{
    struct dentry *ret = NULL;

    if (sb) {
        static const struct qstr name = {
            .name = "/",
            .len = 1
        };

        ret = d_alloc(NULL, &name);
        if (likely(ret)) {
            ret->d_op = &unionfs_dops;
            ret->d_sb = sb;
            ret->d_parent = ret;
        }
    }
    return ret;
}

/*
 * There is no need to lock the unionfs_super_info's rwsem as there is no
 * way anyone can have a reference to the superblock at this point in time.
 */
static int unionfs_read_super(struct super_block *sb, void *raw_data,
                              int silent)
{
    int err = 0;
    struct unionfs_dentry_info *lower_root_info = NULL;
    int bindex, bstart, bend;

    if (!raw_data) {
        printk(KERN_ERR
               "unionfs: read_super: missing data argument\n");
        err = -EINVAL;
        goto out;
    }

    /* Allocate superblock private data */
    sb->s_fs_info = kzalloc(sizeof(struct unionfs_sb_info), GFP_KERNEL);
    if (unlikely(!UNIONFS_SB(sb))) {
        printk(KERN_CRIT "unionfs: read_super: out of memory\n");
        err = -ENOMEM;
        goto out;
    }

    UNIONFS_SB(sb)->bend = -1;
    atomic_set(&UNIONFS_SB(sb)->generation, 1);
    init_rwsem(&UNIONFS_SB(sb)->rwsem);
    UNIONFS_SB(sb)->high_branch_id = -1; /* -1 == invalid branch ID */

    lower_root_info = unionfs_parse_options(sb, raw_data);
    if (IS_ERR(lower_root_info)) {
        printk(KERN_ERR
               "unionfs: read_super: error while parsing options "
               "(err = %ld)\n", PTR_ERR(lower_root_info));
        err = PTR_ERR(lower_root_info);
        lower_root_info = NULL;
        goto out_free;
    }
    if (lower_root_info->bstart == -1) {
        err = -ENOENT;
        goto out_free;
    }

    /* set the lower superblock field of upper superblock */
    bstart = lower_root_info->bstart;
    BUG_ON(bstart != 0);
    sbend(sb) = bend = lower_root_info->bend;
    for (bindex = bstart; bindex <= bend; bindex++) {
        struct dentry *d = lower_root_info->lower_paths[bindex].dentry;
        atomic_inc(&d->d_sb->s_active);
        unionfs_set_lower_super_idx(sb, bindex, d->d_sb);
    }

    /* max Bytes is the maximum bytes from highest priority branch */
    sb->s_maxbytes = unionfs_lower_super_idx(sb, 0)->s_maxbytes;

    /*
     * Our c/m/atime granularity is 1 ns because we may stack on file
     * systems whose granularity is as good.  This is important for our
     * time-based cache coherency.
     */
    sb->s_time_gran = 1;

    sb->s_op = &unionfs_sops;

    /* See comment next to the definition of unionfs_d_alloc_root */
    sb->s_root = unionfs_d_alloc_root(sb);
    if (unlikely(!sb->s_root)) {
        err = -ENOMEM;
        goto out_dput;
    }

    /* link the upper and lower dentries */
    sb->s_root->d_fsdata = NULL;
    err = new_dentry_private_data(sb->s_root, UNIONFS_DMUTEX_ROOT);
    if (unlikely(err))
        goto out_freedpd;

    /* Set the lower dentries for s_root */
    for (bindex = bstart; bindex <= bend; bindex++) {
        struct dentry *d;
        struct vfsmount *m;

        d = lower_root_info->lower_paths[bindex].dentry;
        m = lower_root_info->lower_paths[bindex].mnt;

        unionfs_set_lower_dentry_idx(sb->s_root, bindex, d);
        unionfs_set_lower_mnt_idx(sb->s_root, bindex, m);
    }
    dbstart(sb->s_root) = bstart;
    dbend(sb->s_root) = bend;

    /* Set the generation number to one, since this is for the mount. */
    atomic_set(&UNIONFS_D(sb->s_root)->generation, 1);

    /*
     * Call interpose to create the upper level inode.  Only
     * INTERPOSE_LOOKUP can return a value other than 0 on err.
     */
    err = PTR_ERR(unionfs_interpose(sb->s_root, sb, 0));
    unionfs_unlock_dentry(sb->s_root);
    if (!err)
        goto out;
    /* else fall through */

out_freedpd:
    if (UNIONFS_D(sb->s_root)) {
        kfree(UNIONFS_D(sb->s_root)->lower_paths);
        free_dentry_private_data(sb->s_root);
    }
    dput(sb->s_root);

out_dput:
    if (lower_root_info && !IS_ERR(lower_root_info)) {
        for (bindex = lower_root_info->bstart;
                bindex <= lower_root_info->bend; bindex++) {
            struct dentry *d;
            struct vfsmount *m;

            d = lower_root_info->lower_paths[bindex].dentry;
            m = lower_root_info->lower_paths[bindex].mnt;

            dput(d);
            /* initializing: can't use unionfs_mntput here */
            mntput(m);
            /* drop refs we took earlier */
            atomic_dec(&d->d_sb->s_active);
        }
        kfree(lower_root_info->lower_paths);
        kfree(lower_root_info);
        lower_root_info = NULL;
    }

out_free:
    kfree(UNIONFS_SB(sb)->data);
    kfree(UNIONFS_SB(sb));
    sb->s_fs_info = NULL;

out:
    if (lower_root_info && !IS_ERR(lower_root_info)) {
        kfree(lower_root_info->lower_paths);
        kfree(lower_root_info);
    }
    return err;
}
コード例 #13
0
int unionfs_ioctl_addbranch(struct inode *inode, unsigned int cmd,
			    unsigned long arg)
{
	int err;
	struct unionfs_addbranch_args *addargs = NULL;
	struct nameidata nd;
	char *path = NULL;
	int gen;
	int i;

	int pobjects;

	struct unionfs_usi_data *new_data = NULL;
	struct dentry **new_udi_dentry = NULL;
	struct inode **new_uii_inode = NULL;

	struct dentry *root = NULL;
	struct dentry *hidden_root = NULL;

	print_entry_location();

	err = -ENOMEM;
	addargs = KMALLOC(sizeof(struct unionfs_addbranch_args), GFP_KERNEL);
	if (!addargs)
		goto out;

	err = -EFAULT;
	if (copy_from_user
	    (addargs, (const void __user *)arg,
	     sizeof(struct unionfs_addbranch_args)))
		goto out;

	err = -EINVAL;
	if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE | MAY_NFSRO))
		goto out;
	if (!(addargs->ab_perms & MAY_READ))
		goto out;

	err = -E2BIG;
	if (sbend(inode->i_sb) > FD_SETSIZE)
		goto out;

	err = -ENOMEM;
	if (!(path = getname((const char __user *)addargs->ab_path)))
		goto out;

	err = path_lookup(path, LOOKUP_FOLLOW, &nd);

	RECORD_PATH_LOOKUP(&nd);
	if (err)
		goto out;
	if ((err = check_branch(&nd))) {
		path_release(&nd);
		RECORD_PATH_RELEASE(&nd);
		goto out;
	}

	unionfs_write_lock(inode->i_sb);
	lock_dentry(inode->i_sb->s_root);

	root = inode->i_sb->s_root;
	for (i = dbstart(inode->i_sb->s_root); i <= dbend(inode->i_sb->s_root);
	     i++) {
		hidden_root = dtohd_index(root, i);
		if (is_branch_overlap(hidden_root, nd.dentry)) {
			err = -EINVAL;
			goto out;
		}
	}

	err = -EINVAL;
	if (addargs->ab_branch < 0
	    || (addargs->ab_branch > (sbend(inode->i_sb) + 1)))
		goto out;

	if ((err = newputmap(inode->i_sb)))
		goto out;

	stopd(inode->i_sb)->b_end++;
	dtopd(inode->i_sb->s_root)->udi_bcount++;
	set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) + 1);
	itopd(inode->i_sb->s_root->d_inode)->b_end++;

	atomic_inc(&stopd(inode->i_sb)->usi_generation);
	gen = atomic_read(&stopd(inode->i_sb)->usi_generation);

	pobjects = sbend(inode->i_sb) + 1;

	/* Reallocate the dynamic structures. */
	new_data = alloc_new_data(pobjects);
	new_udi_dentry = alloc_new_dentries(pobjects);
	new_uii_inode = KZALLOC(sizeof(struct inode *) * pobjects, GFP_KERNEL);

	if (!new_udi_dentry || !new_uii_inode || !new_data) {
		err = -ENOMEM;
		goto out;
	}

	/* Copy the in-place values to our new structure. */
	for (i = 0; i < addargs->ab_branch; i++) {
		atomic_set(&(new_data[i].sbcount),
			   branch_count(inode->i_sb, i));

		new_data[i].branchperms = branchperms(inode->i_sb, i);
		new_data[i].hidden_mnt = stohiddenmnt_index(inode->i_sb, i);
		new_data[i].sb = stohs_index(inode->i_sb, i);

		new_udi_dentry[i] = dtohd_index(inode->i_sb->s_root, i);
		new_uii_inode[i] = itohi_index(inode->i_sb->s_root->d_inode, i);
	}

	/* Shift the ends to the right (only handle reallocated bits). */
	for (i = sbend(inode->i_sb) - 1; i >= (int)addargs->ab_branch; i--) {
		int j = i + 1;
		int pmindex;

		atomic_set(&new_data[j].sbcount, branch_count(inode->i_sb, i));

		new_data[j].branchperms = branchperms(inode->i_sb, i);
		new_data[j].hidden_mnt = stohiddenmnt_index(inode->i_sb, i);
		new_data[j].sb = stohs_index(inode->i_sb, i);
		new_udi_dentry[j] = dtohd_index(inode->i_sb->s_root, i);
		new_uii_inode[j] = itohi_index(inode->i_sb->s_root->d_inode, i);

		/* Update the newest putmap, so it is correct for later. */
		pmindex = stopd(inode->i_sb)->usi_lastputmap;
		pmindex -= stopd(inode->i_sb)->usi_firstputmap;
		stopd(inode->i_sb)->usi_putmaps[pmindex]->map[i] = j;

	}

	/* Now we can free the old ones. */
	KFREE(dtopd(inode->i_sb->s_root)->udi_dentry);
	KFREE(itopd(inode->i_sb->s_root->d_inode)->uii_inode);
	KFREE(stopd(inode->i_sb)->usi_data);

	/* Update the real pointers. */
	dtohd_ptr(inode->i_sb->s_root) = new_udi_dentry;
	itohi_ptr(inode->i_sb->s_root->d_inode) = new_uii_inode;
	stopd(inode->i_sb)->usi_data = new_data;

	/* Re-NULL the new ones so we don't try to free them. */
	new_data = NULL;
	new_udi_dentry = NULL;
	new_uii_inode = NULL;

	/* Put the new dentry information into it's slot. */
	set_dtohd_index(inode->i_sb->s_root, addargs->ab_branch, nd.dentry);
	set_itohi_index(inode->i_sb->s_root->d_inode, addargs->ab_branch,
			IGRAB(nd.dentry->d_inode));
	set_branchperms(inode->i_sb, addargs->ab_branch, addargs->ab_perms);
	set_branch_count(inode->i_sb, addargs->ab_branch, 0);
	set_stohiddenmnt_index(inode->i_sb, addargs->ab_branch, nd.mnt);
	set_stohs_index(inode->i_sb, addargs->ab_branch, nd.dentry->d_sb);

	atomic_set(&dtopd(inode->i_sb->s_root)->udi_generation, gen);
	atomic_set(&itopd(inode->i_sb->s_root->d_inode)->uii_generation, gen);

	fixputmaps(inode->i_sb);

      out:
	unlock_dentry(inode->i_sb->s_root);
	unionfs_write_unlock(inode->i_sb);

	KFREE(new_udi_dentry);
	KFREE(new_uii_inode);
	KFREE(new_data);
	KFREE(addargs);
	if (path)
		putname(path);

	print_exit_status(err);

	return err;
}
コード例 #14
0
/*
 * There is no need to lock the unionfs_super_info's rwsem as there is no
 * way anyone can have a reference to the superblock at this point in time.
 */
static int unionfs_read_super(struct super_block *sb, void *raw_data,
			      int silent)
{
	int err = 0;
	struct unionfs_dentry_info *lower_root_info = NULL;
	int bindex, bstart, bend;
	struct inode *inode = NULL;

	if (!raw_data) {
		printk(KERN_ERR
		       "unionfs: read_super: missing data argument\n");
		err = -EINVAL;
		goto out;
	}

	/* Allocate superblock private data */
	sb->s_fs_info = kzalloc(sizeof(struct unionfs_sb_info), GFP_KERNEL);
	if (unlikely(!UNIONFS_SB(sb))) {
		printk(KERN_CRIT "unionfs: read_super: out of memory\n");
		err = -ENOMEM;
		goto out;
	}

	UNIONFS_SB(sb)->bend = -1;
	atomic_set(&UNIONFS_SB(sb)->generation, 1);
	init_rwsem(&UNIONFS_SB(sb)->rwsem);
	UNIONFS_SB(sb)->high_branch_id = -1; /* -1 == invalid branch ID */

	lower_root_info = unionfs_parse_options(sb, raw_data);
	if (IS_ERR(lower_root_info)) {
		printk(KERN_ERR
		       "unionfs: read_super: error while parsing options "
		       "(err = %ld)\n", PTR_ERR(lower_root_info));
		err = PTR_ERR(lower_root_info);
		lower_root_info = NULL;
		goto out_free;
	}
	if (lower_root_info->bstart == -1) {
		err = -ENOENT;
		goto out_free;
	}

	/* set the lower superblock field of upper superblock */
	bstart = lower_root_info->bstart;
	BUG_ON(bstart != 0);
	sbend(sb) = bend = lower_root_info->bend;
	for (bindex = bstart; bindex <= bend; bindex++) {
		struct dentry *d = lower_root_info->lower_paths[bindex].dentry;
		atomic_inc(&d->d_sb->s_active);
		unionfs_set_lower_super_idx(sb, bindex, d->d_sb);
	}

	/* max Bytes is the maximum bytes from highest priority branch */
	sb->s_maxbytes = unionfs_lower_super_idx(sb, 0)->s_maxbytes;

	/*
	 * Our c/m/atime granularity is 1 ns because we may stack on file
	 * systems whose granularity is as good.  This is important for our
	 * time-based cache coherency.
	 */
	sb->s_time_gran = 1;

	sb->s_op = &unionfs_sops;

	/* get a new inode and allocate our root dentry */
	inode = unionfs_iget(sb, iunique(sb, UNIONFS_ROOT_INO));
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
		goto out_dput;
	}
	sb->s_root = d_make_root(inode);
	if (unlikely(!sb->s_root)) {
		err = -ENOMEM;
		goto out_iput;
	}
	d_set_d_op(sb->s_root, &unionfs_dops);

	/* link the upper and lower dentries */
	sb->s_root->d_fsdata = NULL;
	err = new_dentry_private_data(sb->s_root, UNIONFS_DMUTEX_ROOT);
	if (unlikely(err))
		goto out_freedpd;

	/* if get here: cannot have error */

	/* Set the lower dentries for s_root */
	for (bindex = bstart; bindex <= bend; bindex++) {
		struct dentry *d;
		struct vfsmount *m;

		d = lower_root_info->lower_paths[bindex].dentry;
		m = lower_root_info->lower_paths[bindex].mnt;

		unionfs_set_lower_dentry_idx(sb->s_root, bindex, d);
		unionfs_set_lower_mnt_idx(sb->s_root, bindex, m);
	}
	dbstart(sb->s_root) = bstart;
	dbend(sb->s_root) = bend;

	/* Set the generation number to one, since this is for the mount. */
	atomic_set(&UNIONFS_D(sb->s_root)->generation, 1);

	if (atomic_read(&inode->i_count) <= 1)
		unionfs_fill_inode(sb->s_root, inode);

	/*
	 * No need to call interpose because we already have a positive
	 * dentry, which was instantiated by d_alloc_root.  Just need to
	 * d_rehash it.
	 */
	d_rehash(sb->s_root);

	unionfs_unlock_dentry(sb->s_root);
	goto out; /* all is well */

out_freedpd:
	if (UNIONFS_D(sb->s_root)) {
		kfree(UNIONFS_D(sb->s_root)->lower_paths);
		free_dentry_private_data(sb->s_root);
	}
	dput(sb->s_root);

out_iput:
	iput(inode);

out_dput:
	if (lower_root_info && !IS_ERR(lower_root_info)) {
		for (bindex = lower_root_info->bstart;
		     bindex <= lower_root_info->bend; bindex++) {
			struct dentry *d;
			d = lower_root_info->lower_paths[bindex].dentry;
			/* drop refs we took earlier */
			atomic_dec(&d->d_sb->s_active);
			path_put(&lower_root_info->lower_paths[bindex]);
		}
		kfree(lower_root_info->lower_paths);
		kfree(lower_root_info);
		lower_root_info = NULL;
	}

out_free:
	kfree(UNIONFS_SB(sb)->data);
	kfree(UNIONFS_SB(sb));
	sb->s_fs_info = NULL;

out:
	if (lower_root_info && !IS_ERR(lower_root_info)) {
		kfree(lower_root_info->lower_paths);
		kfree(lower_root_info);
	}
	return err;
}
コード例 #15
0
static struct dentry *unionfs_d_alloc_root(struct super_block *sb)
{
	struct dentry *ret = NULL;

	if (sb) {
		static const struct qstr name = {.name = "/",.len = 1 };

		ret = d_alloc(NULL, &name);
		if (ret) {
			ret->d_op = &unionfs_dops;
			ret->d_sb = sb;
			ret->d_parent = ret;
		}
	}
	return ret;
}

static int unionfs_read_super(struct super_block *sb, void *raw_data,
			      int silent)
{
	int err = 0;

	struct unionfs_dentry_info *hidden_root_info = NULL;
	int bindex, bstart, bend;
	unsigned long long maxbytes;

	print_entry_location();

	if (!raw_data) {
		printk(KERN_WARNING
		       "unionfs_read_super: missing data argument\n");
		err = -EINVAL;
		goto out;
	}

	/*
	 * Allocate superblock private data
	 */
	stopd_lhs(sb) = KZALLOC(sizeof(struct unionfs_sb_info), GFP_KERNEL);
	if (!stopd(sb)) {
		printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__);
		err = -ENOMEM;
		goto out;
	}
	stopd(sb)->b_end = -1;
	atomic_set(&stopd(sb)->usi_generation, 1);
	init_rwsem(&stopd(sb)->usi_rwsem);

	hidden_root_info = unionfs_parse_options(sb, raw_data);
	if (IS_ERR(hidden_root_info)) {
		printk(KERN_WARNING
		       "unionfs_read_super: error while parsing options (err = %ld)\n",
		       PTR_ERR(hidden_root_info));
		err = PTR_ERR(hidden_root_info);
		hidden_root_info = NULL;
		goto out_free;
	}
	if (hidden_root_info->udi_bstart == -1) {
		err = -ENOENT;
		goto out_free;
	}

	/* set the hidden superblock field of upper superblock */
	bstart = hidden_root_info->udi_bstart;
	BUG_ON(bstart != 0);
	sbend(sb) = bend = hidden_root_info->udi_bend;
	for (bindex = bstart; bindex <= bend; bindex++) {
		struct dentry *d;

		d = hidden_root_info->udi_dentry[bindex];

		set_stohs_index(sb, bindex, d->d_sb);
	}

	/* Unionfs: Max Bytes is the maximum bytes from among all the branches */
	maxbytes = -1;
	for (bindex = bstart; bindex <= bend; bindex++)
		if (maxbytes < stohs_index(sb, bindex)->s_maxbytes)
			maxbytes = stohs_index(sb, bindex)->s_maxbytes;
	sb->s_maxbytes = maxbytes;

	sb->s_op = &unionfs_sops;
	sb->s_export_op = &unionfs_export_ops;

	/*
	 * we can't use d_alloc_root if we want to use
	 * our own interpose function unchanged,
	 * so we simply call our own "fake" d_alloc_root
	 */
	sb->s_root = unionfs_d_alloc_root(sb);
	if (!sb->s_root) {
		err = -ENOMEM;
		goto out_dput;
	}

	/* link the upper and lower dentries */
	dtopd_lhs(sb->s_root) = NULL;
	if ((err = new_dentry_private_data(sb->s_root)))
		goto out_freedpd;

	/* Set the hidden dentries for s_root */
	for (bindex = bstart; bindex <= bend; bindex++) {
		struct dentry *d;

		d = hidden_root_info->udi_dentry[bindex];

		set_dtohd_index(sb->s_root, bindex, d);
	}
	set_dbstart(sb->s_root, bstart);
	set_dbend(sb->s_root, bend);

	/* Set the generation number to one, since this is for the mount. */
	atomic_set(&dtopd(sb->s_root)->udi_generation, 1);

	/* call interpose to create the upper level inode */
	if ((err = unionfs_interpose(sb->s_root, sb, 0)))
		goto out_freedpd;
	unlock_dentry(sb->s_root);
	goto out;

      out_freedpd:
	if (dtopd(sb->s_root)) {
		KFREE(dtohd_ptr(sb->s_root));
		free_dentry_private_data(dtopd(sb->s_root));
	}
	DPUT(sb->s_root);
      out_dput:
	if (hidden_root_info && !IS_ERR(hidden_root_info)) {
		for (bindex = hidden_root_info->udi_bstart;
		     bindex <= hidden_root_info->udi_bend; bindex++) {
			struct dentry *d;

			d = hidden_root_info->udi_dentry[bindex];

			if (d)
				DPUT(d);

			if (stopd(sb) && stohiddenmnt_index(sb, bindex))
				mntput(stohiddenmnt_index(sb, bindex));
		}
		KFREE(hidden_root_info->udi_dentry);
		KFREE(hidden_root_info);
		hidden_root_info = NULL;
	}
      out_free:
	KFREE(stopd(sb)->usi_data);
	KFREE(stopd(sb));
	stopd_lhs(sb) = NULL;
      out:
	if (hidden_root_info && !IS_ERR(hidden_root_info)) {
		KFREE(hidden_root_info->udi_dentry);
		KFREE(hidden_root_info);
	}
	print_exit_status(err);
	return err;
}