]> git.karo-electronics.de Git - linux-beck.git/blobdiff - fs/xfs/linux-2.6/xfs_aops.c
direct-io: cleanup blockdev_direct_IO locking
[linux-beck.git] / fs / xfs / linux-2.6 / xfs_aops.c
index 70f989895d15bfe4ab9d9df2241196eed764d54a..66abe36c1213e60ae49e483c82193c72a0d57758 100644 (file)
@@ -38,6 +38,7 @@
 #include "xfs_rw.h"
 #include "xfs_iomap.h"
 #include "xfs_vnodeops.h"
+#include "xfs_trace.h"
 #include <linux/mpage.h>
 #include <linux/pagevec.h>
 #include <linux/writeback.h>
@@ -76,7 +77,7 @@ xfs_ioend_wake(
                wake_up(to_ioend_wq(ip));
 }
 
-STATIC void
+void
 xfs_count_page_state(
        struct page             *page,
        int                     *delalloc,
@@ -98,48 +99,6 @@ xfs_count_page_state(
        } while ((bh = bh->b_this_page) != head);
 }
 
-#if defined(XFS_RW_TRACE)
-void
-xfs_page_trace(
-       int             tag,
-       struct inode    *inode,
-       struct page     *page,
-       unsigned long   pgoff)
-{
-       xfs_inode_t     *ip;
-       loff_t          isize = i_size_read(inode);
-       loff_t          offset = page_offset(page);
-       int             delalloc = -1, unmapped = -1, unwritten = -1;
-
-       if (page_has_buffers(page))
-               xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
-
-       ip = XFS_I(inode);
-       if (!ip->i_rwtrace)
-               return;
-
-       ktrace_enter(ip->i_rwtrace,
-               (void *)((unsigned long)tag),
-               (void *)ip,
-               (void *)inode,
-               (void *)page,
-               (void *)pgoff,
-               (void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
-               (void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
-               (void *)((unsigned long)((isize >> 32) & 0xffffffff)),
-               (void *)((unsigned long)(isize & 0xffffffff)),
-               (void *)((unsigned long)((offset >> 32) & 0xffffffff)),
-               (void *)((unsigned long)(offset & 0xffffffff)),
-               (void *)((unsigned long)delalloc),
-               (void *)((unsigned long)unmapped),
-               (void *)((unsigned long)unwritten),
-               (void *)((unsigned long)current_pid()),
-               (void *)NULL);
-}
-#else
-#define xfs_page_trace(tag, inode, page, pgoff)
-#endif
-
 STATIC struct block_device *
 xfs_find_bdev_for_inode(
        struct xfs_inode        *ip)
@@ -235,71 +194,36 @@ xfs_setfilesize(
 }
 
 /*
- * Buffered IO write completion for delayed allocate extents.
- */
-STATIC void
-xfs_end_bio_delalloc(
-       struct work_struct      *work)
-{
-       xfs_ioend_t             *ioend =
-               container_of(work, xfs_ioend_t, io_work);
-
-       xfs_setfilesize(ioend);
-       xfs_destroy_ioend(ioend);
-}
-
-/*
- * Buffered IO write completion for regular, written extents.
+ * IO write completion.
  */
 STATIC void
-xfs_end_bio_written(
-       struct work_struct      *work)
-{
-       xfs_ioend_t             *ioend =
-               container_of(work, xfs_ioend_t, io_work);
-
-       xfs_setfilesize(ioend);
-       xfs_destroy_ioend(ioend);
-}
-
-/*
- * IO write completion for unwritten extents.
- *
- * Issue transactions to convert a buffer range from unwritten
- * to written extents.
- */
-STATIC void
-xfs_end_bio_unwritten(
+xfs_end_io(
        struct work_struct      *work)
 {
        xfs_ioend_t             *ioend =
                container_of(work, xfs_ioend_t, io_work);
        struct xfs_inode        *ip = XFS_I(ioend->io_inode);
-       xfs_off_t               offset = ioend->io_offset;
-       size_t                  size = ioend->io_size;
-
-       if (likely(!ioend->io_error)) {
-               if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-                       int error;
-                       error = xfs_iomap_write_unwritten(ip, offset, size);
-                       if (error)
-                               ioend->io_error = error;
-               }
-               xfs_setfilesize(ioend);
-       }
-       xfs_destroy_ioend(ioend);
-}
 
-/*
- * IO read completion for regular, written extents.
- */
-STATIC void
-xfs_end_bio_read(
-       struct work_struct      *work)
-{
-       xfs_ioend_t             *ioend =
-               container_of(work, xfs_ioend_t, io_work);
+       /*
+        * For unwritten extents we need to issue transactions to convert a
+        * range to normal written extens after the data I/O has finished.
+        */
+       if (ioend->io_type == IOMAP_UNWRITTEN &&
+           likely(!ioend->io_error && !XFS_FORCED_SHUTDOWN(ip->i_mount))) {
+               int error;
+
+               error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
+                                                ioend->io_size);
+               if (error)
+                       ioend->io_error = error;
+       }
 
+       /*
+        * We might have to update the on-disk file size after extending
+        * writes.
+        */
+       if (ioend->io_type != IOMAP_READ)
+               xfs_setfilesize(ioend);
        xfs_destroy_ioend(ioend);
 }
 
@@ -314,10 +238,10 @@ xfs_finish_ioend(
        int             wait)
 {
        if (atomic_dec_and_test(&ioend->io_remaining)) {
-               struct workqueue_struct *wq = xfsdatad_workqueue;
-               if (ioend->io_work.func == xfs_end_bio_unwritten)
-                       wq = xfsconvertd_workqueue;
+               struct workqueue_struct *wq;
 
+               wq = (ioend->io_type == IOMAP_UNWRITTEN) ?
+                       xfsconvertd_workqueue : xfsdatad_workqueue;
                queue_work(wq, &ioend->io_work);
                if (wait)
                        flush_workqueue(wq);
@@ -355,15 +279,7 @@ xfs_alloc_ioend(
        ioend->io_offset = 0;
        ioend->io_size = 0;
 
-       if (type == IOMAP_UNWRITTEN)
-               INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten);
-       else if (type == IOMAP_DELAY)
-               INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc);
-       else if (type == IOMAP_READ)
-               INIT_WORK(&ioend->io_work, xfs_end_bio_read);
-       else
-               INIT_WORK(&ioend->io_work, xfs_end_bio_written);
-
+       INIT_WORK(&ioend->io_work, xfs_end_io);
        return ioend;
 }
 
@@ -380,7 +296,7 @@ xfs_map_blocks(
        return -xfs_iomap(XFS_I(inode), offset, count, flags, mapp, &nmaps);
 }
 
-STATIC_INLINE int
+STATIC int
 xfs_iomap_valid(
        xfs_iomap_t             *iomapp,
        loff_t                  offset)
@@ -412,8 +328,9 @@ xfs_end_bio(
 
 STATIC void
 xfs_submit_ioend_bio(
-       xfs_ioend_t     *ioend,
-       struct bio      *bio)
+       struct writeback_control *wbc,
+       xfs_ioend_t             *ioend,
+       struct bio              *bio)
 {
        atomic_inc(&ioend->io_remaining);
        bio->bi_private = ioend;
@@ -426,7 +343,8 @@ xfs_submit_ioend_bio(
        if (xfs_ioend_new_eof(ioend))
                xfs_mark_inode_dirty_sync(XFS_I(ioend->io_inode));
 
-       submit_bio(WRITE, bio);
+       submit_bio(wbc->sync_mode == WB_SYNC_ALL ?
+                  WRITE_SYNC_PLUG : WRITE, bio);
        ASSERT(!bio_flagged(bio, BIO_EOPNOTSUPP));
        bio_put(bio);
 }
@@ -505,6 +423,7 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
  */
 STATIC void
 xfs_submit_ioend(
+       struct writeback_control *wbc,
        xfs_ioend_t             *ioend)
 {
        xfs_ioend_t             *head = ioend;
@@ -533,19 +452,19 @@ xfs_submit_ioend(
  retry:
                                bio = xfs_alloc_ioend_bio(bh);
                        } else if (bh->b_blocknr != lastblock + 1) {
-                               xfs_submit_ioend_bio(ioend, bio);
+                               xfs_submit_ioend_bio(wbc, ioend, bio);
                                goto retry;
                        }
 
                        if (bio_add_buffer(bio, bh) != bh->b_size) {
-                               xfs_submit_ioend_bio(ioend, bio);
+                               xfs_submit_ioend_bio(wbc, ioend, bio);
                                goto retry;
                        }
 
                        lastblock = bh->b_blocknr;
                }
                if (bio)
-                       xfs_submit_ioend_bio(ioend, bio);
+                       xfs_submit_ioend_bio(wbc, ioend, bio);
                xfs_finish_ioend(ioend, 0);
        } while ((ioend = next) != NULL);
 }
@@ -1191,7 +1110,7 @@ xfs_page_state_convert(
        }
 
        if (iohead)
-               xfs_submit_ioend(iohead);
+               xfs_submit_ioend(wbc, iohead);
 
        return page_dirty;
 
@@ -1242,7 +1161,7 @@ xfs_vm_writepage(
        int                     delalloc, unmapped, unwritten;
        struct inode            *inode = page->mapping->host;
 
-       xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0);
+       trace_xfs_writepage(inode, page, 0);
 
        /*
         * We need a transaction if:
@@ -1347,7 +1266,7 @@ xfs_vm_releasepage(
                .nr_to_write = 1,
        };
 
-       xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, 0);
+       trace_xfs_releasepage(inode, page, 0);
 
        if (!page_has_buffers(page))
                return 0;
@@ -1528,7 +1447,7 @@ xfs_end_io_direct(
                 * didn't map an unwritten extent so switch it's completion
                 * handler.
                 */
-               INIT_WORK(&ioend->io_work, xfs_end_bio_written);
+               ioend->io_type = IOMAP_NEW;
                xfs_finish_ioend(ioend, 0);
        }
 
@@ -1555,19 +1474,13 @@ xfs_vm_direct_IO(
 
        bdev = xfs_find_bdev_for_inode(XFS_I(inode));
 
-       if (rw == WRITE) {
-               iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN);
-               ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
-                       bdev, iov, offset, nr_segs,
-                       xfs_get_blocks_direct,
-                       xfs_end_io_direct);
-       } else {
-               iocb->private = xfs_alloc_ioend(inode, IOMAP_READ);
-               ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
-                       bdev, iov, offset, nr_segs,
-                       xfs_get_blocks_direct,
-                       xfs_end_io_direct);
-       }
+       iocb->private = xfs_alloc_ioend(inode, rw == WRITE ?
+                                       IOMAP_UNWRITTEN : IOMAP_READ);
+
+       ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
+                                           offset, nr_segs,
+                                           xfs_get_blocks_direct,
+                                           xfs_end_io_direct);
 
        if (unlikely(ret != -EIOCBQUEUED && iocb->private))
                xfs_destroy_ioend(iocb->private);
@@ -1627,8 +1540,7 @@ xfs_vm_invalidatepage(
        struct page             *page,
        unsigned long           offset)
 {
-       xfs_page_trace(XFS_INVALIDPAGE_ENTER,
-                       page->mapping->host, page, offset);
+       trace_xfs_invalidatepage(page->mapping->host, page, offset);
        block_invalidatepage(page, offset);
 }