staging: comedi: ni_6527: tidy up ni6527_intr_cancel()
[cascardo/linux.git] / fs / aio.c
index 3bc068c..6b868f0 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -183,11 +183,6 @@ static void aio_free_ring(struct kioctx *ctx)
 
        if (aio_ring_file) {
                truncate_setsize(aio_ring_file->f_inode, 0);
-               pr_debug("pid(%d) i_nlink=%u d_count=%d d_unhashed=%d i_count=%d\n",
-                       current->pid, aio_ring_file->f_inode->i_nlink,
-                       aio_ring_file->f_path.dentry->d_count,
-                       d_unhashed(aio_ring_file->f_path.dentry),
-                       atomic_read(&aio_ring_file->f_inode->i_count));
                fput(aio_ring_file);
                ctx->aio_ring_file = NULL;
        }
@@ -312,16 +307,25 @@ static int aio_setup_ring(struct kioctx *ctx)
                aio_free_ring(ctx);
                return -EAGAIN;
        }
-       up_write(&mm->mmap_sem);
-
-       mm_populate(ctx->mmap_base, populate);
 
        pr_debug("mmap address: 0x%08lx\n", ctx->mmap_base);
+
+       /* We must do this while still holding mmap_sem for write, as we
+        * need to be protected against userspace attempting to mremap()
+        * or munmap() the ring buffer.
+        */
        ctx->nr_pages = get_user_pages(current, mm, ctx->mmap_base, nr_pages,
                                       1, 0, ctx->ring_pages, NULL);
+
+       /* Dropping the reference here is safe as the page cache will hold
+        * onto the pages for us.  It is also required so that page migration
+        * can unmap the pages and get the right reference count.
+        */
        for (i = 0; i < ctx->nr_pages; i++)
                put_page(ctx->ring_pages[i]);
 
+       up_write(&mm->mmap_sem);
+
        if (unlikely(ctx->nr_pages != nr_pages)) {
                aio_free_ring(ctx);
                return -EAGAIN;
@@ -475,7 +479,8 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
        struct aio_ring *ring;
 
        spin_lock(&mm->ioctx_lock);
-       table = mm->ioctx_table;
+       rcu_read_lock();
+       table = rcu_dereference(mm->ioctx_table);
 
        while (1) {
                if (table)
@@ -483,6 +488,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                                if (!table->table[i]) {
                                        ctx->id = i;
                                        table->table[i] = ctx;
+                                       rcu_read_unlock();
                                        spin_unlock(&mm->ioctx_lock);
 
                                        ring = kmap_atomic(ctx->ring_pages[0]);
@@ -493,6 +499,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
 
                new_nr = (table ? table->nr : 1) * 4;
 
+               rcu_read_unlock();
                spin_unlock(&mm->ioctx_lock);
 
                table = kzalloc(sizeof(*table) + sizeof(struct kioctx *) *
@@ -503,7 +510,8 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                table->nr = new_nr;
 
                spin_lock(&mm->ioctx_lock);
-               old = mm->ioctx_table;
+               rcu_read_lock();
+               old = rcu_dereference(mm->ioctx_table);
 
                if (!old) {
                        rcu_assign_pointer(mm->ioctx_table, table);
@@ -627,10 +635,12 @@ static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx)
                struct kioctx_table *table;
 
                spin_lock(&mm->ioctx_lock);
-               table = mm->ioctx_table;
+               rcu_read_lock();
+               table = rcu_dereference(mm->ioctx_table);
 
                WARN_ON(ctx != table->table[ctx->id]);
                table->table[ctx->id] = NULL;
+               rcu_read_unlock();
                spin_unlock(&mm->ioctx_lock);
 
                /* percpu_ref_kill() will do the necessary call_rcu() */
@@ -812,7 +822,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
                goto out;
 
        ctx = table->table[id];
-       if (ctx->user_id == ctx_id) {
+       if (ctx && ctx->user_id == ctx_id) {
                percpu_ref_get(&ctx->users);
                ret = ctx;
        }