Unionfs: imported fixes from korg branch
authorErez_Zadok <ezk@cs.sunysb.edu>
Sun, 18 Nov 2007 19:08:27 +0000 (14:08 -0500)
committerRachita Kothiyal <rachita@dewey.fsl.cs.sunysb.edu>
Thu, 1 May 2008 23:03:03 +0000 (19:03 -0400)
Export release_open_intent.
SElinux: xattr fixes (CAP_FOWNER).
unionfs_xattr_kfree inline function.
alloc_lower_nd -> init_lower_nd.
free_lower_nd -> release_lower_nd.
unionfs_purge_extras -> unionfs_postcopyup_release.
unionfs_inherit_mnt -> unionfs_postcopyup_setmnt.
minor code/copyright cleanups.
MS_SILENT remount fix.
simplify unionfs_mntget/put.

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
fs/namei.c
fs/unionfs/copyup.c
fs/unionfs/inode.c
fs/unionfs/lookup.c
fs/unionfs/main.c
fs/unionfs/rename.c
fs/unionfs/sioq.c
fs/unionfs/sioq.h
fs/unionfs/union.h
fs/unionfs/unlink.c

index 73e2e665817a100c9f05c33a12756f639d9c5ae7..784ef51e83e132294e567d1b5d3a1898be09e21c 100644 (file)
@@ -389,6 +389,7 @@ void release_open_intent(struct nameidata *nd)
        else
                fput(nd->intent.open.file);
 }
+EXPORT_SYMBOL(release_open_intent);
 
 static inline struct dentry *
 do_revalidate(struct dentry *dentry, struct nameidata *nd)
index 2d67e1d52355ec5b05f32a719ff7742fdd18ce61..1b296a72ea1461323af917b2696f360b455cb92a 100644 (file)
@@ -84,21 +84,27 @@ static int copyup_xattrs(struct dentry *old_lower_dentry,
                /* Don't lock here since vfs_setxattr does it for us. */
                err = vfs_setxattr(new_lower_dentry, name_list, attr_value,
                                   size, 0);
+               /*
+                * Selinux depends on "security.*" xattrs, so to maintain
+                * the security of copied-up files, if Selinux is active,
+                * then we must copy these xattrs as well.  So we need to
+                * temporarily get FOWNER privileges.
+                */
+               if (err == -EPERM && !capable(CAP_FOWNER)) {
+                       cap_raise(current->cap_effective, CAP_FOWNER);
+                       err = vfs_setxattr(new_lower_dentry, name_list,
+                                          attr_value, size, 0);
+                       cap_lower(current->cap_effective, CAP_FOWNER);
+               }
                if (err < 0)
                        goto out;
                name_list += strlen(name_list) + 1;
        }
 out:
-       if (name_list_orig)
-               kfree(name_list_orig);
-       if (attr_value)
-               kfree(attr_value);
-       /*
-        * Ignore if xattr isn't supported.  Also ignore EPERM because that
-        * requires CAP_SYS_ADMIN for security.* xattrs, but copyup happens
-        * as normal users.
-        */
-       if (err == -ENOTSUPP || err == -EOPNOTSUPP || err == -EPERM)
+       unionfs_xattr_kfree(name_list_orig);
+       unionfs_xattr_kfree(attr_value);
+       /* Ignore if xattr isn't supported */
+       if (err == -ENOTSUPP || err == -EOPNOTSUPP)
                err = 0;
        return err;
 }
@@ -189,19 +195,18 @@ static int __copyup_ndentry(struct dentry *old_lower_dentry,
                run_sioq(__unionfs_mknod, &args);
                err = args.err;
        } else if (S_ISREG(old_mode)) {
-               struct nameidata *nd = alloc_lower_nd(LOOKUP_CREATE);
-               if (!nd) {
-                       err = -ENOMEM;
+               struct nameidata nd;
+               err = init_lower_nd(&nd, LOOKUP_CREATE);
+               if (err < 0)
                        goto out;
-               }
-               args.create.nd = nd;
+               args.create.nd = &nd;
                args.create.parent = new_lower_parent_dentry->d_inode;
                args.create.dentry = new_lower_dentry;
                args.create.mode = old_mode;
 
                run_sioq(__unionfs_create, &args);
                err = args.err;
-               free_lower_nd(nd, err);
+               release_lower_nd(&nd, err);
        } else {
                printk(KERN_ERR "unionfs: unknown inode type %d\n",
                       old_mode);
@@ -516,7 +521,7 @@ out_free:
        if (err)
                goto out;
        if (!S_ISDIR(dentry->d_inode->i_mode)) {
-               unionfs_purge_extras(dentry);
+               unionfs_postcopyup_release(dentry);
                if (!unionfs_lower_inode(dentry->d_inode)) {
                        /*
                         * If we got here, then we copied up to an
@@ -529,7 +534,7 @@ out_free:
                                                    inode);
                }
        }
-       unionfs_inherit_mnt(dentry);
+       unionfs_postcopyup_setmnt(dentry);
        /* sync inode times from copied-up inode to our inode */
        unionfs_copy_attr_times(dentry->d_inode);
        unionfs_check_inode(dir);
@@ -851,8 +856,11 @@ out:
        return lower_dentry;
 }
 
-/* set lower mnt of dentry+parents to the first parent node that has an mnt */
-void unionfs_inherit_mnt(struct dentry *dentry)
+/*
+ * Post-copyup helper to ensure we have valid mnts: set lower mnt of
+ * dentry+parents to the first parent node that has an mnt.
+ */
+void unionfs_postcopyup_setmnt(struct dentry *dentry)
 {
        struct dentry *parent, *hasone;
        int bindex = dbstart(dentry);
@@ -861,9 +869,8 @@ void unionfs_inherit_mnt(struct dentry *dentry)
                return;
        hasone = dentry->d_parent;
        /* this loop should stop at root dentry */
-       while (!unionfs_lower_mnt_idx(hasone, bindex)) {
+       while (!unionfs_lower_mnt_idx(hasone, bindex))
                hasone = hasone->d_parent;
-       }
        parent = dentry;
        while (!unionfs_lower_mnt_idx(parent, bindex)) {
                unionfs_set_lower_mnt_idx(parent, bindex,
@@ -873,11 +880,10 @@ void unionfs_inherit_mnt(struct dentry *dentry)
 }
 
 /*
- * Regular files should have only one lower object(s).  On copyup, we may
- * have leftover objects from previous branches.  So purge all such extra
- * objects and keep only the most recent, leftmost, copied-up one.
+ * Post-copyup helper to release all non-directory source objects of a
+ * copied-up file.  Regular files should have only one lower object.
  */
-void unionfs_purge_extras(struct dentry *dentry)
+void unionfs_postcopyup_release(struct dentry *dentry)
 {
        int bindex;
 
index fdbd06cc9f5e996c118b6609f4d02e2a5d4b34b9..262e955672ac16bfb5c09f2e33a20e3a1e0bcaa7 100644 (file)
@@ -64,7 +64,7 @@ static int unionfs_create(struct inode *parent, struct dentry *dentry,
                                err = PTR_ERR(lower_dentry);
                        goto out;
                }
-               unionfs_inherit_mnt(dentry->d_parent);
+               unionfs_postcopyup_setmnt(dentry->d_parent);
        }
 
        if (lower_dentry->d_inode && UNIONFS_D(dentry)->odf.whiteout) {
@@ -109,7 +109,7 @@ static int unionfs_create(struct inode *parent, struct dentry *dentry,
 
 out:
        if (!err)
-               unionfs_inherit_mnt(dentry);
+               unionfs_postcopyup_setmnt(dentry);
        unionfs_unlock_dentry(dentry);
        unionfs_read_unlock(dentry->d_sb);
 
@@ -297,7 +297,7 @@ out:
                d_drop(new_dentry);
 
        if (!err)
-               unionfs_inherit_mnt(new_dentry);
+               unionfs_postcopyup_setmnt(new_dentry);
 
        unionfs_unlock_dentry(new_dentry);
        unionfs_unlock_dentry(old_dentry);
@@ -351,7 +351,7 @@ static int unionfs_symlink(struct inode *dir, struct dentry *dentry,
                               "for bindex = %d\n", bstart);
                        goto out;
                }
-               unionfs_inherit_mnt(dentry->d_parent);
+               unionfs_postcopyup_setmnt(dentry->d_parent);
        }
 
        if (lower_dentry->d_inode && UNIONFS_D(dentry)->odf.whiteout) {
@@ -397,7 +397,7 @@ static int unionfs_symlink(struct inode *dir, struct dentry *dentry,
 
 out:
        if (!err)
-               unionfs_inherit_mnt(dentry);
+               unionfs_postcopyup_setmnt(dentry);
        unionfs_unlock_dentry(dentry);
 
        unionfs_check_inode(dir);
@@ -442,7 +442,7 @@ static int unionfs_mkdir(struct inode *parent, struct dentry *dentry, int mode)
                        err = PTR_ERR(lower_dentry);
                        goto out;
                }
-               unionfs_inherit_mnt(dentry->d_parent);
+               unionfs_postcopyup_setmnt(dentry->d_parent);
        }
 
        if (lower_dentry->d_inode && UNIONFS_D(dentry)->odf.whiteout) {
@@ -547,7 +547,7 @@ static int unionfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
                               bstart, PTR_ERR(lower_dentry));
                        goto out;
                }
-               unionfs_inherit_mnt(dentry->d_parent);
+               unionfs_postcopyup_setmnt(dentry->d_parent);
        }
 
        if (lower_dentry->d_inode && UNIONFS_D(dentry)->odf.whiteout) {
@@ -596,7 +596,7 @@ out:
                d_drop(dentry);
 
        if (!err)
-               unionfs_inherit_mnt(dentry);
+               unionfs_postcopyup_setmnt(dentry);
        unionfs_unlock_dentry(dentry);
 
        unionfs_check_inode(dir);
index 1f1598d550430116d52edf5ccfd703057296a44c..c171a94a6f23c388bcfad9b6e3043a641dd2c002 100644 (file)
@@ -513,16 +513,15 @@ void update_bstart(struct dentry *dentry)
 
 
 /*
- * Allocate and fill in a nameidata structure (the intent part) we can pass
- * to a lower file system.  Returns NULL on error (only -ENOMEM possible),
- * or a valid allocated nameidata structure.  Inside that structure, this
- * function may also return an allocated struct file (for open intents).
- * The caller, when done with this nd, must kfree both the intent file and
- * the entire nd.
+ * Initialize a nameidata structure (the intent part) we can pass to a lower
+ * file system.  Returns 0 on success or -error (only -ENOMEM possible).
+ * Inside that nd structure, this function may also return an allocated
+ * struct file (for open intents).  The caller, when done with this nd, must
+ * kfree the intent file (using release_lower_nd).
  */
-struct nameidata *alloc_lower_nd(unsigned int flags)
+int init_lower_nd(struct nameidata *nd, unsigned int flags)
 {
-       struct nameidata *nd;
+       int err = 0;
 #ifdef ALLOC_LOWER_ND_FILE
        /*
         * XXX: one day we may need to have the lower return an open file
@@ -532,10 +531,6 @@ struct nameidata *alloc_lower_nd(unsigned int flags)
        struct file *file;
 #endif /* ALLOC_LOWER_ND_FILE */
 
-       nd = kzalloc(sizeof(struct nameidata), GFP_KERNEL);
-       if (!nd)
-               goto out;
-
        switch (flags) {
        case LOOKUP_CREATE:
                nd->flags = LOOKUP_CREATE;
@@ -543,9 +538,8 @@ struct nameidata *alloc_lower_nd(unsigned int flags)
 #ifdef ALLOC_LOWER_ND_FILE
                file = kzalloc(sizeof(struct file), GFP_KERNEL);
                if (!file) {
-                       kfree(nd);
-                       nd = NULL;
-                       goto out;
+                       err = -ENOMEM;
+                       break; /* exit switch statement and thus return */
                }
                nd->intent.open.file = file;
 #endif /* ALLOC_LOWER_ND_FILE */
@@ -558,17 +552,15 @@ struct nameidata *alloc_lower_nd(unsigned int flags)
                BUG();
                break;
        }
-out:
-       return nd;
+
+       return err;
 }
 
-void free_lower_nd(struct nameidata *nd, int err)
+void release_lower_nd(struct nameidata *nd, int err)
 {
-       if (nd->intent.open.file) {
-               if (!err)
-                       fput(nd->intent.open.file); /* XXX: open file not needed? */
-               kfree(nd->intent.open.file);
-       }
-       kfree(nd);
+       if (nd->intent.open.file)
+               return;
+       if (!err)
+               release_open_intent(nd);
+       kfree(nd->intent.open.file);
 }
-
index a26525b0e74a2182f5af5b0780415f970324bfa8..d2735833837a01bd0d11ae94707073a56513eeb0 100644 (file)
@@ -165,14 +165,15 @@ skip:
                spliced = d_splice_alias(inode, dentry);
                if (IS_ERR(spliced))
                        err = PTR_ERR(spliced);
-
-               /*
-                * d_splice can return a dentry if it was disconnected and
-                * had to be moved.  We must make sure that the private data
-                * of the new dentry is correct and that the inode info was
-                * filled properly.  Finally we must return this new dentry.
-                */
                else if (spliced && spliced != dentry) {
+                       /*
+                        * d_splice can return a dentry if it was
+                        * disconnected and had to be moved.  We must ensure
+                        * that the private data of the new dentry is
+                        * correct and that the inode info was filled
+                        * properly.  Finally we must return this new
+                        * dentry.
+                        */
                        spliced->d_op = &unionfs_dops;
                        spliced->d_fsdata = dentry->d_fsdata;
                        dentry->d_fsdata = NULL;
index e75b5d98fc016127d30f8d562c3f697862485854..3af9a7a82d9639aeeac35b02b7d5205ed661f4e3 100644 (file)
@@ -228,7 +228,7 @@ static int do_unionfs_rename(struct inode *old_dir,
                        if (err)
                                goto revert;
                }
-               free_lower_nd(nd, local_err);
+               release_lower_nd(&nd, local_err);
        }
        else if (err && old_bstart == 0) {
                if (bindex == 0)
@@ -429,7 +429,7 @@ out:
                if (S_ISDIR(old_dentry->d_inode->i_mode))
                        atomic_dec(&UNIONFS_D(old_dentry)->generation);
                else
-                       unionfs_purge_extras(old_dentry);
+                       unionfs_postcopyup_release(old_dentry);
 
                /*
                 * If the dentry already existed before the rename and is
index 529a71f9d3c6b6abf3fec0cf92c44f22cb55eb7b..1574461b65f33199e19da1342bfc00b4cdc13164 100644 (file)
@@ -3,11 +3,7 @@
  * 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-2007 Stony Brook University
  * Copyright (c) 2003-2007 The Research Foundation of SUNY
  *
index a3167a7c1f4a3fe2e133fb819f0ddc16e10f0dd3..50e1a3d2ea5d69f37b213ab6d3ac0edffcc5b533 100644 (file)
@@ -3,11 +3,7 @@
  * 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-2007 Stony Brook University
  * Copyright (c) 2003-2007 The Research Foundation of SUNY
  *
index cf34f679b0d214e0a4dd57fc14ef94c2c23b3e15..a5c96b99881732674f45d2bc9bacd7db4d1fc550 100644 (file)
@@ -266,8 +266,8 @@ static inline void unionfs_double_lock_dentry(struct dentry *d1,
 extern int new_dentry_private_data(struct dentry *dentry);
 extern void free_dentry_private_data(struct dentry *dentry);
 extern void update_bstart(struct dentry *dentry);
-extern struct nameidata *alloc_lower_nd(unsigned int flags);
-extern void free_lower_nd(struct nameidata *nd, int err);
+extern int init_lower_nd(struct nameidata *nd, unsigned int flags);
+extern void release_lower_nd(struct nameidata *nd, int err);
 
 /*
  * EXTERNALS:
@@ -289,9 +289,9 @@ extern int copyup_named_file(struct inode *dir, struct file *file,
 extern int copyup_dentry(struct inode *dir, struct dentry *dentry,
                         int bstart, int new_bindex, const char *name,
                         int namelen, struct file **copyup_file, loff_t len);
-/* helper functions for post-copyup cleanup */
-extern void unionfs_inherit_mnt(struct dentry *dentry);
-extern void unionfs_purge_extras(struct dentry *dentry);
+/* helper functions for post-copyup actions */
+extern void unionfs_postcopyup_setmnt(struct dentry *dentry);
+extern void unionfs_postcopyup_release(struct dentry *dentry);
 
 /* Is this directory empty: 0 if it is empty, -ENOTEMPTY if not. */
 extern int check_empty(struct dentry *dentry,
@@ -346,7 +346,7 @@ extern struct dentry *unionfs_interpose(struct dentry *this_dentry,
 #ifdef CONFIG_UNION_FS_XATTR
 /* Extended attribute functions. */
 extern void *unionfs_xattr_alloc(size_t size, size_t limit);
-
+static inline void unionfs_xattr_kfree(const void *p) {kfree((p));}
 extern ssize_t unionfs_getxattr(struct dentry *dentry, const char *name,
                                void *value, size_t size);
 extern int unionfs_removexattr(struct dentry *dentry, const char *name);
@@ -452,32 +452,18 @@ static inline struct vfsmount *unionfs_mntget(struct dentry *dentry,
 {
        struct vfsmount *mnt;
 
-       if (!dentry) {
-               if (bindex < 0)
-                       return NULL;
-               if (!dentry && bindex >= 0) {
-#ifdef UNIONFS_DEBUG
-                       printk(KERN_DEBUG
-                              "unionfs_mntget: dentry=%p bindex=%d\n",
-                              dentry, bindex);
-#endif /* UNIONFS_DEBUG */
-                       return NULL;
-               }
-       }
+       BUG_ON(!dentry);
+       BUG_ON(bindex < 0);
+
        mnt = unionfs_lower_mnt_idx(dentry, bindex);
-       if (!mnt) {
-               if (bindex < 0)
-                       return NULL;
-               if (!mnt && bindex >= 0) {
+       if (mnt)
+               mnt = mntget(mnt);
 #ifdef UNIONFS_DEBUG
-                       printk(KERN_DEBUG
-                              "unionfs_mntget: mnt=%p bindex=%d\n",
-                              mnt, bindex);
+       else
+               printk(KERN_DEBUG "unionfs_mntget: mnt=%p bindex=%d\n",
+                      mnt, bindex);
 #endif /* UNIONFS_DEBUG */
-                       return NULL;
-               }
-       }
-       mnt = mntget(mnt);
+
        return mnt;
 }
 
@@ -485,42 +471,22 @@ static inline void unionfs_mntput(struct dentry *dentry, int bindex)
 {
        struct vfsmount *mnt;
 
-       if (!dentry) {
-               if (bindex < 0)
-                       return;
-               if (!dentry && bindex >= 0) {
-#ifdef UNIONFS_DEBUG
-                       printk(KERN_DEBUG
-                              "unionfs_mntput: dentry=%p bindex=%d\n",
-                              dentry, bindex);
-#endif /* UNIONFS_DEBUG */
-                       return;
-               }
-       }
+       if (!dentry && bindex < 0)
+               return;
+       BUG_ON(!dentry || bindex < 0);
+
        mnt = unionfs_lower_mnt_idx(dentry, bindex);
-       if (!mnt) {
-               if (bindex < 0)
-                       return;
-               if (!mnt && bindex >= 0) {
-#ifdef UNIONFS_DEBUG
-                       /*
-                        * Directories can have NULL lower objects in
-                        * between start/end, but NOT if at the start/end
-                        * range.  We cannot verify that this dentry is a
-                        * type=DIR, because it may already be a negative
-                        * dentry.  But if dbstart is greater than dbend, we
-                        * know that this couldn't have been a regular file:
-                        * it had to have been a directory.
-                        */
-                       if (!(bindex > dbstart(dentry) &&
-                             bindex < dbend(dentry)))
-                               printk(KERN_WARNING
-                                      "unionfs_mntput: mnt=%p bindex=%d\n",
-                                      mnt, bindex);
-#endif /* UNIONFS_DEBUG */
-                       return;
-               }
-       }
+#ifdef CONFIG_UNION_FS_DEBUG
+       /*
+        * Directories can have NULL lower objects in between start/end, but
+        * NOT if at the start/end range.  We cannot verify that this dentry
+        * is a type=DIR, because it may already be a negative dentry.  But
+        * if dbstart is greater than dbend, we know that this couldn't have
+        * been a regular file: it had to have been a directory.
+        */
+       if (!mnt && !(bindex > dbstart(dentry) && bindex < dbend(dentry)))
+               pr_debug("unionfs: mntput: mnt=%p bindex=%d\n", mnt, bindex);
+#endif /* CONFIG_UNION_FS_DEBUG */
        mntput(mnt);
 }
 
index 9b67066c7b948b5962d9290d722da1e0c360cc08..303880d32a08a6447984473b22e8915a330be3bb 100644 (file)
@@ -126,7 +126,7 @@ int unionfs_unlink(struct inode *dir, struct dentry *dentry)
        }
        if (!err) {
                if (!S_ISDIR(dentry->d_inode->i_mode))
-                       unionfs_purge_extras(dentry);
+                       unionfs_postcopyup_release(dentry);
                d_drop(dentry);
                /*
                 * if unlink/whiteout succeeded, parent dir mtime has