]> Pileus Git - ~andy/linux/commitdiff
Merge git://git.kvack.org/~bcrl/aio-next
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Dec 2013 16:32:59 +0000 (08:32 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Dec 2013 16:32:59 +0000 (08:32 -0800)
Pull aio fix from Benjamin LaHaise:
 "AIO fix from Gu Zheng that fixes a GPF that Dave Jones uncovered with
  trinity"

* git://git.kvack.org/~bcrl/aio-next:
  aio: clean up aio ring in the fail path

1  2 
fs/aio.c

diff --combined fs/aio.c
index 08159ed13649cacbec1825065e24b2b5b61be267,a2f92aa23ee37b49aabf77030854b5a99e916f2d..6efb7f6cb22e9ba5aabb5f111129ef69b7dac370
+++ b/fs/aio.c
  #include <linux/eventfd.h>
  #include <linux/blkdev.h>
  #include <linux/compat.h>
 -#include <linux/anon_inodes.h>
  #include <linux/migrate.h>
  #include <linux/ramfs.h>
  #include <linux/percpu-refcount.h>
 +#include <linux/mount.h>
  
  #include <asm/kmap_types.h>
  #include <asm/uaccess.h>
@@@ -153,67 -153,12 +153,67 @@@ unsigned long aio_max_nr = 0x10000; /* 
  static struct kmem_cache      *kiocb_cachep;
  static struct kmem_cache      *kioctx_cachep;
  
 +static struct vfsmount *aio_mnt;
 +
 +static const struct file_operations aio_ring_fops;
 +static const struct address_space_operations aio_ctx_aops;
 +
 +static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
 +{
 +      struct qstr this = QSTR_INIT("[aio]", 5);
 +      struct file *file;
 +      struct path path;
 +      struct inode *inode = alloc_anon_inode(aio_mnt->mnt_sb);
 +      if (IS_ERR(inode))
 +              return ERR_CAST(inode);
 +
 +      inode->i_mapping->a_ops = &aio_ctx_aops;
 +      inode->i_mapping->private_data = ctx;
 +      inode->i_size = PAGE_SIZE * nr_pages;
 +
 +      path.dentry = d_alloc_pseudo(aio_mnt->mnt_sb, &this);
 +      if (!path.dentry) {
 +              iput(inode);
 +              return ERR_PTR(-ENOMEM);
 +      }
 +      path.mnt = mntget(aio_mnt);
 +
 +      d_instantiate(path.dentry, inode);
 +      file = alloc_file(&path, FMODE_READ | FMODE_WRITE, &aio_ring_fops);
 +      if (IS_ERR(file)) {
 +              path_put(&path);
 +              return file;
 +      }
 +
 +      file->f_flags = O_RDWR;
 +      file->private_data = ctx;
 +      return file;
 +}
 +
 +static struct dentry *aio_mount(struct file_system_type *fs_type,
 +                              int flags, const char *dev_name, void *data)
 +{
 +      static const struct dentry_operations ops = {
 +              .d_dname        = simple_dname,
 +      };
 +      return mount_pseudo(fs_type, "aio:", NULL, &ops, 0xa10a10a1);
 +}
 +
  /* aio_setup
   *    Creates the slab caches used by the aio routines, panic on
   *    failure as this is done early during the boot sequence.
   */
  static int __init aio_setup(void)
  {
 +      static struct file_system_type aio_fs = {
 +              .name           = "aio",
 +              .mount          = aio_mount,
 +              .kill_sb        = kill_anon_super,
 +      };
 +      aio_mnt = kern_mount(&aio_fs);
 +      if (IS_ERR(aio_mnt))
 +              panic("Failed to create aio fs mount.");
 +
        kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
        kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
  
@@@ -341,12 -286,16 +341,12 @@@ static int aio_setup_ring(struct kioct
        if (nr_pages < 0)
                return -EINVAL;
  
 -      file = anon_inode_getfile_private("[aio]", &aio_ring_fops, ctx, O_RDWR);
 +      file = aio_private_file(ctx, nr_pages);
        if (IS_ERR(file)) {
                ctx->aio_ring_file = NULL;
                return -EAGAIN;
        }
  
 -      file->f_inode->i_mapping->a_ops = &aio_ctx_aops;
 -      file->f_inode->i_mapping->private_data = ctx;
 -      file->f_inode->i_size = PAGE_SIZE * (loff_t)nr_pages;
 -
        for (i = 0; i < nr_pages; i++) {
                struct page *page;
                page = find_or_create_page(file->f_inode->i_mapping,
        if (nr_pages > AIO_RING_PAGES) {
                ctx->ring_pages = kcalloc(nr_pages, sizeof(struct page *),
                                          GFP_KERNEL);
-               if (!ctx->ring_pages)
+               if (!ctx->ring_pages) {
+                       put_aio_ring_file(ctx);
                        return -ENOMEM;
+               }
        }
  
        ctx->mmap_size = nr_pages * PAGE_SIZE;
@@@ -645,7 -596,7 +647,7 @@@ static struct kioctx *ioctx_alloc(unsig
            aio_nr + nr_events < aio_nr) {
                spin_unlock(&aio_nr_lock);
                err = -EAGAIN;
-               goto err;
+               goto err_ctx;
        }
        aio_nr += ctx->max_reqs;
        spin_unlock(&aio_nr_lock);
  
  err_cleanup:
        aio_nr_sub(ctx->max_reqs);
+ err_ctx:
+       aio_free_ring(ctx);
  err:
        free_percpu(ctx->cpu);
        free_percpu(ctx->reqs.pcpu_count);