Logo Search packages:      
Sourcecode: unionfs version File versions

branchman.c

/*
 * Copyright (c) 2003-2005 Erez Zadok
 * Copyright (c) 2003-2005 Charles P. Wright
 * Copyright (c) 2003-2005 Mohammad Nayyer Zubair
 * Copyright (c) 2003-2005 Puja Gupta
 * Copyright (c) 2003-2005 Harikesavan Krishnan
 * Copyright (c) 2003-2005 Stony Brook University
 * Copyright (c) 2003-2005 The Research Foundation of State University of New York
 *
 * For specific licensing information, see the COPYING file distributed with
 * this package.
 *
 * This Copyright notice must be kept intact and distributed with all sources.
 */
/*
 *  $Id: branchman.c,v 1.23 2005/02/08 15:17:38 cwright Exp $
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include "fist.h"
#include "unionfs.h"
#include <linux/dcache.h>


int unionfs_ioctl_branchcount(inode_t *inode, file_t *file, unsigned int cmd, unsigned long arg)
{
      struct unionfs_sb_info *spd;
      int err = 0;
      int bstart, bend;
      int i;

      print_entry_location();


      spd = stopd(inode->i_sb);

      bstart = spd->b_start;
      bend = spd->b_end;

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


      fist_dprint(1, "b_start = %d, b_end = %d\n", bstart, bend);
      for (i = bstart; i <= bend; i++) {
            if (put_user(atomic_read(&spd->usi_sbcount[i]), ((int *)arg) + i)) {
                  err = -EFAULT;
                  goto out;
            }
      }

out:
      print_exit_status(err);
      return err;
}

int unionfs_ioctl_incgen(inode_t *inode, file_t *file, unsigned int cmd, unsigned long arg)
{
      int err = 0;

      print_entry_location();

      lock_super(inode->i_sb);

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

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

      unlock_super(inode->i_sb);

      print_exit_status(err);

      return err;
}

int unionfs_ioctl_addbranch(inode_t *inode, file_t *unused_file, unsigned int cmd, unsigned long arg)
{
      int err = 0;
      struct unionfs_sb_info *spd;
      struct unionfs_dentry_info *dpd;
      struct unionfs_inode_info *ipd;
      struct unionfs_addbranch_args *addargs = NULL;
      struct nameidata nd;
      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;
      char *path = NULL;
      int gen;
      int i;
      int count;

      print_entry_location();

      /* If we ever use this we have problems! */
      unused_file = EXPLOSIVE;

      lock_super(inode->i_sb);

      spd = stopd(inode->i_sb);
      dpd = dtopd(inode->i_sb->s_root);
      ipd = itopd(inode->i_sb->s_root->d_inode);

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

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

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

      /* Add a branch. */
      if (addargs->ab_branch < 0 || (addargs->ab_branch > (spd->b_end + 1))) {
            err = -EINVAL;
            goto out;
      }

      if ((spd->b_end + 1) > FD_SETSIZE) {
            err = -E2BIG;
            goto out;
      }

      if (addargs->ab_perms & ~(MAY_READ|MAY_WRITE)) {
            err = -EINVAL;
            goto out;
      }
      if (!(addargs->ab_perms & MAY_READ)) {
            err = -EINVAL;
            goto out;
      }
//DQ: 2.6 has a different way of doing this
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
      /* Look it up */
      if (path_init(path, LOOKUP_FOLLOW, &nd)) {
            err = path_walk(path, &nd);
      }
#else
      err = path_lookup(path, LOOKUP_FOLLOW, &nd);
#endif
      if (err) {
            goto out;
      }
      if (!nd.dentry->d_inode) {
            path_release(&nd);
            err = -ENOENT;
            goto out;
      }
      if (!S_ISDIR(nd.dentry->d_inode->i_mode)) {
            path_release(&nd);
            err = -ENOTDIR;
            goto out;
      }

      spd->b_end++;
      dtopd(inode->i_sb->s_root)->udi_bcount++;
      set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) + 1);
      ipd->b_end++;

      atomic_inc(&spd->usi_generation);
      gen = atomic_read(&spd->usi_generation);

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

      /* Copy the values to our new structure, but shift some to the right. */
      for (i = 0; i < addargs->ab_branch; i++) {
            count = atomic_read(&(spd->usi_sbcount[i]));
            atomic_set(&(new_counts[i]), count);
            new_branchperms[i] = spd->usi_branchperms[i];

            new_hidden_mnt[i] = spd->usi_hidden_mnt[i];

            new_usi_sb[i] = spd->usi_sb[i];
            new_udi_dentry[i] = dpd->udi_dentry[i];
            new_uii_inode[i] = ipd->uii_inode[i];
      }

      for (i = addargs->ab_branch; i < spd->b_end; i++) {
            count = atomic_read(&(spd->usi_sbcount[i]));
            atomic_set(&(new_counts[i + 1]), count);

            new_branchperms[i + 1] = spd->usi_branchperms[i];

            new_hidden_mnt[i + 1] = spd->usi_hidden_mnt[i];
            new_usi_sb[i + 1] = spd->usi_sb[i];
            new_udi_dentry[i + 1] = dpd->udi_dentry[i];
            new_uii_inode[i + 1] = ipd->uii_inode[i];
      }

      /* Put the new dentry information into it's slot. */
      new_udi_dentry[addargs->ab_branch] = nd.dentry;
      new_uii_inode[addargs->ab_branch] = igrab(nd.dentry->d_inode);
      new_hidden_mnt[addargs->ab_branch] = nd.mnt;
      new_usi_sb[addargs->ab_branch] = nd.dentry->d_sb;
      new_branchperms[addargs->ab_branch] = addargs->ab_perms;
      atomic_set(&new_counts[addargs->ab_branch], 0);

      /* Free the pointers. */
      KFREE(dpd->udi_dentry);
      KFREE(ipd->uii_inode);
      KFREE(spd->usi_hidden_mnt);
      KFREE(spd->usi_sb);
      KFREE(spd->usi_branchperms);

      /* Update the real pointers. */
      dpd->udi_dentry = new_udi_dentry;
      ipd->uii_inode = new_uii_inode;
      spd->usi_hidden_mnt = new_hidden_mnt;
      spd->usi_sb = new_usi_sb;
      spd->usi_sbcount = new_counts;
      spd->usi_branchperms = 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;

      atomic_set(&dpd->udi_generation, gen);
      atomic_set(&ipd->uii_generation, gen);

out:
      unlock_super(inode->i_sb);

      if (new_hidden_mnt) {
            KFREE(new_hidden_mnt);
      }
      if (new_udi_dentry) {
            KFREE(new_udi_dentry);
      }
      if (new_uii_inode) {
            KFREE(new_uii_inode);
      }
      if (new_usi_sb) {
            KFREE(new_usi_sb);
      }
      if (new_counts) {
            KFREE(new_counts);
      }
      if (new_branchperms) {
            KFREE(new_branchperms);
      }
      if (addargs) {
          KFREE(addargs);
      }

      if (path) {
          putname(path);
      }

      print_exit_status(err);

      return err;
}

int unionfs_ioctl_delbranch(inode_t *inode, file_t *unused_file, unsigned int cmd, unsigned long arg)
{
      struct dentry *hidden_dentry;
      struct inode *hidden_inode;
      struct super_block *hidden_sb;
      vfs_mount_t *hidden_mnt;
      struct unionfs_sb_info *spd;
      struct unionfs_dentry_info *dpd;
      struct unionfs_inode_info *ipd;
      int err = 0;
      int i;
      int gen;
      int count;

      print_entry("branch = %lu ", arg); /* Delete a branch. */

      /* If we ever use this we have problems! */
      unused_file = EXPLOSIVE;

      lock_super(inode->i_sb);

      spd = stopd(inode->i_sb);
      dpd = dtopd(inode->i_sb->s_root);
      ipd = itopd(inode->i_sb->s_root->d_inode);

      if (sbmax(inode->i_sb) == 1) {
            err = -EBUSY;
            goto out;
      }

      /* Delete a branch. */
      if (arg < 0 || arg > spd->b_end) {
            err = -EINVAL;
            goto out;
      }

      if (atomic_read(&(spd->usi_sbcount[arg]))) {
            err = -EBUSY;
            goto out;
      }

      atomic_inc(&spd->usi_generation);
      gen = atomic_read(&spd->usi_generation);

      hidden_dentry = dpd->udi_dentry[arg];
      hidden_mnt = spd->usi_hidden_mnt[arg];
      hidden_inode = ipd->uii_inode[arg];
      hidden_sb = spd->usi_sb[arg];

      dput(hidden_dentry);
      iput(hidden_inode);
      mntput(hidden_mnt);
      //XXX: Leak! put_super(hidden_sb);

      for (i = arg; i <= (spd->b_end - 1); i++) {
            count = atomic_read(&(spd->usi_sbcount[i]));
            atomic_set(&(spd->usi_sbcount[i]), count);

            spd->usi_hidden_mnt[i] = spd->usi_hidden_mnt[i + 1];
            spd->usi_sb[i] = spd->usi_sb[i + 1];
            spd->usi_branchperms[i] = spd->usi_branchperms[i + 1];
            dpd->udi_dentry[i] = dpd->udi_dentry[i + 1];
            ipd->uii_inode[i] = ipd->uii_inode[i + 1];
      }

      dpd->udi_dentry[spd->b_end] = EXPLOSIVE;
      ipd->uii_inode[spd->b_end] = EXPLOSIVE;
        spd->usi_hidden_mnt[spd->b_end] = EXPLOSIVE;

      spd->b_end--;
      set_dbend(inode->i_sb->s_root, dbend(inode->i_sb->s_root) - 1);
      dtopd(inode->i_sb->s_root)->udi_bcount--;
      ipd->b_end--;

      atomic_set(&dpd->udi_generation, gen);
      atomic_set(&ipd->uii_generation, gen);

out:
      unlock_super(inode->i_sb);

      print_exit_status(err);

      return err;
}

int unionfs_ioctl_rdwrbranch(inode_t *inode, file_t *unused_file, unsigned int cmd, unsigned long arg)
{
      int err = 0;
      struct unionfs_sb_info *spd;
      struct unionfs_dentry_info *dpd;
      struct unionfs_inode_info *ipd;
      struct unionfs_rdwrbranch_args *rdwrargs = NULL;
      int gen;

      print_entry_location();

      /* If we ever use this we have problems! */
      unused_file = EXPLOSIVE;

      lock_super(inode->i_sb);

      spd = stopd(inode->i_sb);
      dpd = dtopd(inode->i_sb->s_root);
      ipd = itopd(inode->i_sb->s_root->d_inode);

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

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

      if (rdwrargs->rwb_branch < 0 || (rdwrargs->rwb_branch > (spd->b_end + 1))) {
            err = -EINVAL;
            goto out;
      }

      if (rdwrargs->rwb_perms & ~(MAY_READ|MAY_WRITE)) {
            err = -EINVAL;
            goto out;
      }
      if (!(rdwrargs->rwb_perms & MAY_READ)) {
            err = -EINVAL;
            goto out;
      }

      spd->usi_branchperms[rdwrargs->rwb_branch] = rdwrargs->rwb_perms;

      atomic_inc(&spd->usi_generation);
      gen = atomic_read(&spd->usi_generation);

      atomic_set(&dpd->udi_generation, gen);
      atomic_set(&ipd->uii_generation, gen);

out:
      unlock_super(inode->i_sb);
      if (rdwrargs) {
          KFREE(rdwrargs);
      }

      print_exit_status(err);

      return err;
}

int unionfs_ioctl_superduper(inode_t *inode, file_t *file, unsigned int cmd, unsigned long arg) {
      int err = 0;
#ifdef SPLIT_VIEW_CACHES
      struct super_block *ret_sb;
#endif

      print_entry_location();

#ifdef SPLIT_VIEW_CACHES
      lock_super(inode->i_sb);

      ret_sb = unionfs_duplicate_super(inode->i_sb);
      if (IS_ERR(ret_sb)) {
          err = PTR_ERR(ret_sb);
      }

      unlock_super(inode->i_sb);
#else
      err = -ENOSYS;
#endif

      print_exit_status(err);
      return err;
}

Generated by  Doxygen 1.6.0   Back to index