]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Jan 2012 05:46:36 +0000 (21:46 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Jan 2012 05:46:36 +0000 (21:46 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  autofs4: deal with autofs4_write/autofs4_write races
  autofs4: catatonic_mode vs. notify_daemon race
  autofs4: autofs4_wait() vs. autofs4_catatonic_mode() race
  hfsplus: creation of hidden dir on mount can fail
  block_dev: Suppress bdev_cache_init() kmemleak warninig
  fix shrink_dcache_parent() livelock
  coda: switch coda_cnode_make() to sane API as well, clean coda_lookup()
  coda: deal correctly with allocation failure from coda_cnode_makectl()
  securityfs: fix object creation races

12 files changed:
fs/autofs4/autofs_i.h
fs/autofs4/inode.c
fs/autofs4/waitq.c
fs/block_dev.c
fs/coda/cnode.c
fs/coda/coda_fs_i.h
fs/coda/dir.c
fs/coda/inode.c
fs/dcache.c
fs/hfsplus/super.c
include/linux/dcache.h
security/inode.c

index 5869d4e974a94569b5457e0e7d7cf5b68f03ca5a..d8d8e7ba6a1e1bf52c367a73514aeaa202b8fcea 100644 (file)
@@ -116,6 +116,7 @@ struct autofs_sb_info {
        int needs_reghost;
        struct super_block *sb;
        struct mutex wq_mutex;
+       struct mutex pipe_mutex;
        spinlock_t fs_lock;
        struct autofs_wait_queue *queues; /* Wait queue pointer */
        spinlock_t lookup_lock;
index 2ba44c79d5486f7d39b999d0666eda0ddc3425b3..e16980b00b8d7315dda8d7b92d93fdaf7062e843 100644 (file)
@@ -225,6 +225,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        sbi->min_proto = 0;
        sbi->max_proto = 0;
        mutex_init(&sbi->wq_mutex);
+       mutex_init(&sbi->pipe_mutex);
        spin_lock_init(&sbi->fs_lock);
        sbi->queues = NULL;
        spin_lock_init(&sbi->lookup_lock);
index e1fbdeef85db2e4b73e78eaf6266d2784e2385b0..9ef5b2914407c40327db81a5688850a808210991 100644 (file)
@@ -56,26 +56,27 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
        mutex_unlock(&sbi->wq_mutex);
 }
 
-static int autofs4_write(struct file *file, const void *addr, int bytes)
+static int autofs4_write(struct autofs_sb_info *sbi,
+                        struct file *file, const void *addr, int bytes)
 {
        unsigned long sigpipe, flags;
        mm_segment_t fs;
        const char *data = (const char *)addr;
        ssize_t wr = 0;
 
-       /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
-
        sigpipe = sigismember(&current->pending.signal, SIGPIPE);
 
        /* Save pointer to user space and point back to kernel space */
        fs = get_fs();
        set_fs(KERNEL_DS);
 
+       mutex_lock(&sbi->pipe_mutex);
        while (bytes &&
               (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) {
                data += wr;
                bytes -= wr;
        }
+       mutex_lock(&sbi->pipe_mutex);
 
        set_fs(fs);
 
@@ -110,6 +111,13 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
 
        pkt.hdr.proto_version = sbi->version;
        pkt.hdr.type = type;
+       mutex_lock(&sbi->wq_mutex);
+
+       /* Check if we have become catatonic */
+       if (sbi->catatonic) {
+               mutex_unlock(&sbi->wq_mutex);
+               return;
+       }
        switch (type) {
        /* Kernel protocol v4 missing and expire packets */
        case autofs_ptype_missing:
@@ -163,22 +171,18 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
        }
        default:
                printk("autofs4_notify_daemon: bad type %d!\n", type);
+               mutex_unlock(&sbi->wq_mutex);
                return;
        }
 
-       /* Check if we have become catatonic */
-       mutex_lock(&sbi->wq_mutex);
-       if (!sbi->catatonic) {
-               pipe = sbi->pipe;
-               get_file(pipe);
-       }
+       pipe = sbi->pipe;
+       get_file(pipe);
+
        mutex_unlock(&sbi->wq_mutex);
 
-       if (pipe) {
-               if (autofs4_write(pipe, &pkt, pktsz))
-                       autofs4_catatonic_mode(sbi);
-               fput(pipe);
-       }
+       if (autofs4_write(sbi, pipe, &pkt, pktsz))
+               autofs4_catatonic_mode(sbi);
+       fput(pipe);
 }
 
 static int autofs4_getpath(struct autofs_sb_info *sbi,
@@ -257,6 +261,9 @@ static int validate_request(struct autofs_wait_queue **wait,
        struct autofs_wait_queue *wq;
        struct autofs_info *ino;
 
+       if (sbi->catatonic)
+               return -ENOENT;
+
        /* Wait in progress, continue; */
        wq = autofs4_find_wait(sbi, qstr);
        if (wq) {
@@ -289,6 +296,9 @@ static int validate_request(struct autofs_wait_queue **wait,
                        if (mutex_lock_interruptible(&sbi->wq_mutex))
                                return -EINTR;
 
+                       if (sbi->catatonic)
+                               return -ENOENT;
+
                        wq = autofs4_find_wait(sbi, qstr);
                        if (wq) {
                                *wait = wq;
@@ -389,7 +399,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
 
        ret = validate_request(&wq, sbi, &qstr, dentry, notify);
        if (ret <= 0) {
-               if (ret == 0)
+               if (ret != -EINTR)
                        mutex_unlock(&sbi->wq_mutex);
                kfree(qstr.name);
                return ret;
index 69a5b6fbee2bd9a000a92b34afe4e8338ae989ab..afe74dda632b92ae529aff9a92d319e5ff7052c5 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/uio.h>
 #include <linux/namei.h>
 #include <linux/log2.h>
-#include <linux/kmemleak.h>
 #include <linux/cleancache.h>
 #include <asm/uaccess.h>
 #include "internal.h"
@@ -521,7 +520,7 @@ static struct super_block *blockdev_superblock __read_mostly;
 void __init bdev_cache_init(void)
 {
        int err;
-       struct vfsmount *bd_mnt;
+       static struct vfsmount *bd_mnt;
 
        bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
                        0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
@@ -533,12 +532,7 @@ void __init bdev_cache_init(void)
        bd_mnt = kern_mount(&bd_type);
        if (IS_ERR(bd_mnt))
                panic("Cannot create bdev pseudo-fs");
-       /*
-        * This vfsmount structure is only used to obtain the
-        * blockdev_superblock, so tell kmemleak not to report it.
-        */
-       kmemleak_not_leak(bd_mnt);
-       blockdev_superblock = bd_mnt->mnt_sb;   /* For writeback */
+       blockdev_superblock = bd_mnt->mnt_sb;   /* For writeback */
 }
 
 /*
index 6475877b07632cda1af59664e629aa5ab92d958b..911cf30d057d21b3e7608a0b3f5f1855dacaf584 100644 (file)
@@ -88,24 +88,21 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
    - link the two up if this is needed
    - fill in the attributes
 */
-int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_block *sb)
+struct inode *coda_cnode_make(struct CodaFid *fid, struct super_block *sb)
 {
         struct coda_vattr attr;
+       struct inode *inode;
         int error;
         
        /* We get inode numbers from Venus -- see venus source */
        error = venus_getattr(sb, fid, &attr);
-       if ( error ) {
-           *inode = NULL;
-           return error;
-       } 
+       if (error)
+               return ERR_PTR(error);
 
-       *inode = coda_iget(sb, fid, &attr);
-       if ( IS_ERR(*inode) ) {
+       inode = coda_iget(sb, fid, &attr);
+       if (IS_ERR(inode))
                printk("coda_cnode_make: coda_iget failed\n");
-                return PTR_ERR(*inode);
-        }
-       return 0;
+       return inode;
 }
 
 
@@ -156,19 +153,16 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
 }
 
 /* the CONTROL inode is made without asking attributes from Venus */
-int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
+struct inode *coda_cnode_makectl(struct super_block *sb)
 {
-       int error = -ENOMEM;
-
-       *inode = new_inode(sb);
-       if (*inode) {
-               (*inode)->i_ino = CTL_INO;
-               (*inode)->i_op = &coda_ioctl_inode_operations;
-               (*inode)->i_fop = &coda_ioctl_operations;
-               (*inode)->i_mode = 0444;
-               error = 0;
+       struct inode *inode = new_inode(sb);
+       if (inode) {
+               inode->i_ino = CTL_INO;
+               inode->i_op = &coda_ioctl_inode_operations;
+               inode->i_fop = &coda_ioctl_operations;
+               inode->i_mode = 0444;
+               return inode;
        }
-
-       return error;
+       return ERR_PTR(-ENOMEM);
 }
 
index e35071b1de0e26a3d8f5e1ee27c1da3d3667a4ad..b24fdfd8a3f097a091fe5b04362cd437b96ba0f7 100644 (file)
@@ -49,9 +49,9 @@ struct coda_file_info {
 #define C_DYING       0x4   /* from venus (which died) */
 #define C_PURGE       0x8
 
-int coda_cnode_make(struct inode **, struct CodaFid *, struct super_block *);
+struct inode *coda_cnode_make(struct CodaFid *, struct super_block *);
 struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr);
-int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
+struct inode *coda_cnode_makectl(struct super_block *sb);
 struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb);
 void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *);
 
index 83d2fd8ec24b2cac427be38610f36ea076a71eac..177515829062d82aed7dcdce9bda390535804614 100644 (file)
@@ -96,12 +96,11 @@ const struct file_operations coda_dir_operations = {
 /* access routines: lookup, readlink, permission */
 static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
 {
-       struct inode *inode = NULL;
-       struct CodaFid resfid = { { 0, } };
-       int type = 0;
-       int error = 0;
+       struct super_block *sb = dir->i_sb;
        const char *name = entry->d_name.name;
        size_t length = entry->d_name.len;
+       struct inode *inode;
+       int type = 0;
 
        if (length > CODA_MAXNAMLEN) {
                printk(KERN_ERR "name too long: lookup, %s (%*s)\n",
@@ -111,23 +110,21 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc
 
        /* control object, create inode on the fly */
        if (coda_isroot(dir) && coda_iscontrol(name, length)) {
-               error = coda_cnode_makectl(&inode, dir->i_sb);
+               inode = coda_cnode_makectl(sb);
                type = CODA_NOCACHE;
-               goto exit;
+       } else {
+               struct CodaFid fid = { { 0, } };
+               int error = venus_lookup(sb, coda_i2f(dir), name, length,
+                                    &type, &fid);
+               inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error);
        }
 
-       error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
-                            &type, &resfid);
-       if (!error)
-               error = coda_cnode_make(&inode, &resfid, dir->i_sb);
-
-       if (error && error != -ENOENT)
-               return ERR_PTR(error);
-
-exit:
-       if (inode && (type & CODA_NOCACHE))
+       if (!IS_ERR(inode) && (type & CODA_NOCACHE))
                coda_flag_inode(inode, C_VATTR | C_PURGE);
 
+       if (inode == ERR_PTR(-ENOENT))
+               inode = NULL;
+
        return d_splice_alias(inode, entry);
 }
 
index 1c08a8cd673a917d1e73f68a31ef3bd675c3acd1..5e2e1b3f068d432ab082c43f97b0cb00d3d86000 100644 (file)
@@ -204,10 +204,12 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
        printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
        
        /* make root inode */
-        error = coda_cnode_make(&root, &fid, sb);
-        if ( error || !root ) {
-           printk("Failure of coda_cnode_make for root: error %d\n", error);
-           goto error;
+        root = coda_cnode_make(&fid, sb);
+        if (IS_ERR(root)) {
+               error = PTR_ERR(root);
+               printk("Failure of coda_cnode_make for root: error %d\n", error);
+               root = NULL;
+               goto error;
        } 
 
        printk("coda_read_super: rootinode is %ld dev %s\n", 
index 3c6d3113a255c7af1519fdb6aa1c211ec092e992..616fedff011a7080c36b6446a33b3479c9c7e7d9 100644 (file)
@@ -243,6 +243,7 @@ static void dentry_lru_add(struct dentry *dentry)
 static void __dentry_lru_del(struct dentry *dentry)
 {
        list_del_init(&dentry->d_lru);
+       dentry->d_flags &= ~DCACHE_SHRINK_LIST;
        dentry->d_sb->s_nr_dentry_unused--;
        dentry_stat.nr_unused--;
 }
@@ -806,6 +807,7 @@ relock:
                        spin_unlock(&dentry->d_lock);
                } else {
                        list_move_tail(&dentry->d_lru, &tmp);
+                       dentry->d_flags |= DCACHE_SHRINK_LIST;
                        spin_unlock(&dentry->d_lock);
                        if (!--count)
                                break;
@@ -1097,14 +1099,19 @@ resume:
 
                /*
                 * move only zero ref count dentries to the dispose list.
+                *
+                * Those which are presently on the shrink list, being processed
+                * by shrink_dentry_list(), shouldn't be moved.  Otherwise the
+                * loop in shrink_dcache_parent() might not make any progress
+                * and loop forever.
                 */
-               if (!dentry->d_count) {
+               if (dentry->d_count) {
+                       dentry_lru_del(dentry);
+               } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
                        dentry_lru_move_list(dentry, dispose);
+                       dentry->d_flags |= DCACHE_SHRINK_LIST;
                        found++;
-               } else {
-                       dentry_lru_del(dentry);
                }
-
                /*
                 * We can return to the caller if we have found some (this
                 * ensures forward progress). We'll be coming back to find
index edf0a801446b3d83c4c1e0e04cf88e546317760e..427682ca9e48d3e6aeac2087100c40725a811e2c 100644 (file)
@@ -499,9 +499,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                if (!sbi->hidden_dir) {
                        mutex_lock(&sbi->vh_mutex);
                        sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
-                       hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str,
-                                          sbi->hidden_dir);
+                       if (!sbi->hidden_dir) {
+                               mutex_unlock(&sbi->vh_mutex);
+                               err = -ENOMEM;
+                               goto out_put_root;
+                       }
+                       err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root,
+                                                &str, sbi->hidden_dir);
                        mutex_unlock(&sbi->vh_mutex);
+                       if (err)
+                               goto out_put_hidden_dir;
 
                        hfsplus_mark_inode_dirty(sbi->hidden_dir,
                                                 HFSPLUS_I_CAT_DIRTY);
index a47bda5f76db125288898fb1aea2f098bc2dfa42..31f73220e7d71a888e0fcb895f2de54b25ecea29 100644 (file)
@@ -203,6 +203,7 @@ struct dentry_operations {
 
 #define DCACHE_CANT_MOUNT      0x0100
 #define DCACHE_GENOCIDE                0x0200
+#define DCACHE_SHRINK_LIST     0x0400
 
 #define DCACHE_NFSFS_RENAMED   0x1000
      /* this dentry has been "silly renamed" and has to be deleted on the last
index 90a70a67d8352aff1bc91e7f817a82bdcee3f5ce..43ce6e19015fc81e80786c26a07e2ac47e71109b 100644 (file)
 static struct vfsmount *mount;
 static int mount_count;
 
-/*
- * TODO:
- *   I think I can get rid of these default_file_ops, but not quite sure...
- */
-static ssize_t default_read_file(struct file *file, char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-       return 0;
-}
-
-static ssize_t default_write_file(struct file *file, const char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       return count;
-}
-
-static int default_open(struct inode *inode, struct file *file)
-{
-       if (inode->i_private)
-               file->private_data = inode->i_private;
-
-       return 0;
-}
-
-static const struct file_operations default_file_ops = {
-       .read =         default_read_file,
-       .write =        default_write_file,
-       .open =         default_open,
-       .llseek =       noop_llseek,
-};
-
-static struct inode *get_inode(struct super_block *sb, umode_t mode, dev_t dev)
-{
-       struct inode *inode = new_inode(sb);
-
-       if (inode) {
-               inode->i_ino = get_next_ino();
-               inode->i_mode = mode;
-               inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-               switch (mode & S_IFMT) {
-               default:
-                       init_special_inode(inode, mode, dev);
-                       break;
-               case S_IFREG:
-                       inode->i_fop = &default_file_ops;
-                       break;
-               case S_IFDIR:
-                       inode->i_op = &simple_dir_inode_operations;
-                       inode->i_fop = &simple_dir_operations;
-
-                       /* directory inodes start off with i_nlink == 2 (for "." entry) */
-                       inc_nlink(inode);
-                       break;
-               }
-       }
-       return inode;
-}
-
-/* SMP-safe */
-static int mknod(struct inode *dir, struct dentry *dentry,
-                        umode_t mode, dev_t dev)
-{
-       struct inode *inode;
-       int error = -ENOMEM;
-
-       if (dentry->d_inode)
-               return -EEXIST;
-
-       inode = get_inode(dir->i_sb, mode, dev);
-       if (inode) {
-               d_instantiate(dentry, inode);
-               dget(dentry);
-               error = 0;
-       }
-       return error;
-}
-
-static int mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
-{
-       int res;
-
-       mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
-       res = mknod(dir, dentry, mode, 0);
-       if (!res)
-               inc_nlink(dir);
-       return res;
-}
-
-static int create(struct inode *dir, struct dentry *dentry, umode_t mode)
-{
-       mode = (mode & S_IALLUGO) | S_IFREG;
-       return mknod(dir, dentry, mode, 0);
-}
-
 static inline int positive(struct dentry *dentry)
 {
        return dentry->d_inode && !d_unhashed(dentry);
@@ -145,38 +51,6 @@ static struct file_system_type fs_type = {
        .kill_sb =      kill_litter_super,
 };
 
-static int create_by_name(const char *name, umode_t mode,
-                         struct dentry *parent,
-                         struct dentry **dentry)
-{
-       int error = 0;
-
-       *dentry = NULL;
-
-       /* If the parent is not specified, we create it in the root.
-        * We need the root dentry to do this, which is in the super
-        * block. A pointer to that is in the struct vfsmount that we
-        * have around.
-        */
-       if (!parent)
-               parent = mount->mnt_root;
-
-       mutex_lock(&parent->d_inode->i_mutex);
-       *dentry = lookup_one_len(name, parent, strlen(name));
-       if (!IS_ERR(*dentry)) {
-               if (S_ISDIR(mode))
-                       error = mkdir(parent->d_inode, *dentry, mode);
-               else
-                       error = create(parent->d_inode, *dentry, mode);
-               if (error)
-                       dput(*dentry);
-       } else
-               error = PTR_ERR(*dentry);
-       mutex_unlock(&parent->d_inode->i_mutex);
-
-       return error;
-}
-
 /**
  * securityfs_create_file - create a file in the securityfs filesystem
  *
@@ -209,31 +83,66 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops)
 {
-       struct dentry *dentry = NULL;
+       struct dentry *dentry;
+       int is_dir = S_ISDIR(mode);
+       struct inode *dir, *inode;
        int error;
 
+       if (!is_dir) {
+               BUG_ON(!fops);
+               mode = (mode & S_IALLUGO) | S_IFREG;
+       }
+
        pr_debug("securityfs: creating file '%s'\n",name);
 
        error = simple_pin_fs(&fs_type, &mount, &mount_count);
-       if (error) {
-               dentry = ERR_PTR(error);
-               goto exit;
+       if (error)
+               return ERR_PTR(error);
+
+       if (!parent)
+               parent = mount->mnt_root;
+
+       dir = parent->d_inode;
+
+       mutex_lock(&dir->i_mutex);
+       dentry = lookup_one_len(name, parent, strlen(name));
+       if (IS_ERR(dentry))
+               goto out;
+
+       if (dentry->d_inode) {
+               error = -EEXIST;
+               goto out1;
        }
 
-       error = create_by_name(name, mode, parent, &dentry);
-       if (error) {
-               dentry = ERR_PTR(error);
-               simple_release_fs(&mount, &mount_count);
-               goto exit;
+       inode = new_inode(dir->i_sb);
+       if (!inode) {
+               error = -ENOMEM;
+               goto out1;
        }
 
-       if (dentry->d_inode) {
-               if (fops)
-                       dentry->d_inode->i_fop = fops;
-               if (data)
-                       dentry->d_inode->i_private = data;
+       inode->i_ino = get_next_ino();
+       inode->i_mode = mode;
+       inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+       inode->i_private = data;
+       if (is_dir) {
+               inode->i_op = &simple_dir_inode_operations;
+               inode->i_fop = &simple_dir_operations;
+               inc_nlink(inode);
+               inc_nlink(dir);
+       } else {
+               inode->i_fop = fops;
        }
-exit:
+       d_instantiate(dentry, inode);
+       dget(dentry);
+       mutex_unlock(&dir->i_mutex);
+       return dentry;
+
+out1:
+       dput(dentry);
+       dentry = ERR_PTR(error);
+out:
+       mutex_unlock(&dir->i_mutex);
+       simple_release_fs(&mount, &mount_count);
        return dentry;
 }
 EXPORT_SYMBOL_GPL(securityfs_create_file);