Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[safe/jmp/linux-2.6] / fs / xfs / linux-2.6 / xfs_aops.c
index 0b211cb..c2e30ee 100644 (file)
 #include <linux/pagevec.h>
 #include <linux/writeback.h>
 
+
+/*
+ * Prime number of hash buckets since address is used as the key.
+ */
+#define NVSYNC         37
+#define to_ioend_wq(v) (&xfs_ioend_wq[((unsigned long)v) % NVSYNC])
+static wait_queue_head_t xfs_ioend_wq[NVSYNC];
+
+void __init
+xfs_ioend_init(void)
+{
+       int i;
+
+       for (i = 0; i < NVSYNC; i++)
+               init_waitqueue_head(&xfs_ioend_wq[i]);
+}
+
+void
+xfs_ioend_wait(
+       xfs_inode_t     *ip)
+{
+       wait_queue_head_t *wq = to_ioend_wq(ip);
+
+       wait_event(*wq, (atomic_read(&ip->i_iocount) == 0));
+}
+
+STATIC void
+xfs_ioend_wake(
+       xfs_inode_t     *ip)
+{
+       if (atomic_dec_and_test(&ip->i_iocount))
+               wake_up(to_ioend_wq(ip));
+}
+
 STATIC void
 xfs_count_page_state(
        struct page             *page,
@@ -73,7 +107,6 @@ xfs_page_trace(
        unsigned long   pgoff)
 {
        xfs_inode_t     *ip;
-       bhv_vnode_t     *vp = vn_from_inode(inode);
        loff_t          isize = i_size_read(inode);
        loff_t          offset = page_offset(page);
        int             delalloc = -1, unmapped = -1, unwritten = -1;
@@ -81,7 +114,7 @@ xfs_page_trace(
        if (page_has_buffers(page))
                xfs_count_page_state(page, &delalloc, &unmapped, &unwritten);
 
-       ip = xfs_vtoi(vp);
+       ip = XFS_I(inode);
        if (!ip->i_rwtrace)
                return;
 
@@ -120,23 +153,6 @@ xfs_find_bdev_for_inode(
 }
 
 /*
- * Schedule IO completion handling on a xfsdatad if this was
- * the final hold on this ioend. If we are asked to wait,
- * flush the workqueue.
- */
-STATIC void
-xfs_finish_ioend(
-       xfs_ioend_t     *ioend,
-       int             wait)
-{
-       if (atomic_dec_and_test(&ioend->io_remaining)) {
-               queue_work(xfsdatad_workqueue, &ioend->io_work);
-               if (wait)
-                       flush_workqueue(xfsdatad_workqueue);
-       }
-}
-
-/*
  * We're now finished for good with this ioend structure.
  * Update the page state via the associated buffer_heads,
  * release holds on the inode and bio, and finally free
@@ -147,33 +163,60 @@ xfs_destroy_ioend(
        xfs_ioend_t             *ioend)
 {
        struct buffer_head      *bh, *next;
+       struct xfs_inode        *ip = XFS_I(ioend->io_inode);
 
        for (bh = ioend->io_buffer_head; bh; bh = next) {
                next = bh->b_private;
                bh->b_end_io(bh, !ioend->io_error);
        }
-       if (unlikely(ioend->io_error)) {
-               vn_ioerror(XFS_I(ioend->io_inode), ioend->io_error,
-                               __FILE__,__LINE__);
+
+       /*
+        * Volume managers supporting multiple paths can send back ENODEV
+        * when the final path disappears.  In this case continuing to fill
+        * the page cache with dirty data which cannot be written out is
+        * evil, so prevent that.
+        */
+       if (unlikely(ioend->io_error == -ENODEV)) {
+               xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ,
+                                     __FILE__, __LINE__);
        }
-       vn_iowake(XFS_I(ioend->io_inode));
+
+       xfs_ioend_wake(ip);
        mempool_free(ioend, xfs_ioend_pool);
 }
 
 /*
+ * If the end of the current ioend is beyond the current EOF,
+ * return the new EOF value, otherwise zero.
+ */
+STATIC xfs_fsize_t
+xfs_ioend_new_eof(
+       xfs_ioend_t             *ioend)
+{
+       xfs_inode_t             *ip = XFS_I(ioend->io_inode);
+       xfs_fsize_t             isize;
+       xfs_fsize_t             bsize;
+
+       bsize = ioend->io_offset + ioend->io_size;
+       isize = MAX(ip->i_size, ip->i_new_size);
+       isize = MIN(isize, bsize);
+       return isize > ip->i_d.di_size ? isize : 0;
+}
+
+/*
  * Update on-disk file size now that data has been written to disk.
  * The current in-memory file size is i_size.  If a write is beyond
  * eof i_new_size will be the intended file size until i_size is
  * updated.  If this write does not extend all the way to the valid
  * file size then restrict this update to the end of the write.
  */
+
 STATIC void
 xfs_setfilesize(
        xfs_ioend_t             *ioend)
 {
        xfs_inode_t             *ip = XFS_I(ioend->io_inode);
        xfs_fsize_t             isize;
-       xfs_fsize_t             bsize;
 
        ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
        ASSERT(ioend->io_type != IOMAP_READ);
@@ -181,18 +224,11 @@ xfs_setfilesize(
        if (unlikely(ioend->io_error))
                return;
 
-       bsize = ioend->io_offset + ioend->io_size;
-
        xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-       isize = MAX(ip->i_size, ip->i_new_size);
-       isize = MIN(isize, bsize);
-
-       if (ip->i_d.di_size < isize) {
+       isize = xfs_ioend_new_eof(ioend);
+       if (isize) {
                ip->i_d.di_size = isize;
-               ip->i_update_core = 1;
-               ip->i_update_size = 1;
-               mark_inode_dirty_sync(ioend->io_inode);
+               xfs_mark_inode_dirty_sync(ip);
        }
 
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -268,6 +304,27 @@ xfs_end_bio_read(
 }
 
 /*
+ * Schedule IO completion handling on a xfsdatad if this was
+ * the final hold on this ioend. If we are asked to wait,
+ * flush the workqueue.
+ */
+STATIC void
+xfs_finish_ioend(
+       xfs_ioend_t     *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;
+
+               queue_work(wq, &ioend->io_work);
+               if (wait)
+                       flush_workqueue(wq);
+       }
+}
+
+/*
  * Allocate and initialise an IO completion structure.
  * We need to track unwritten extent write completion here initially.
  * We'll need to extend this for updating the ondisk inode size later
@@ -318,14 +375,9 @@ xfs_map_blocks(
        xfs_iomap_t             *mapp,
        int                     flags)
 {
-       xfs_inode_t             *ip = XFS_I(inode);
-       int                     error, nmaps = 1;
-
-       error = xfs_iomap(ip, offset, count,
-                               flags, mapp, &nmaps);
-       if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE)))
-               xfs_iflags_set(ip, XFS_IMODIFIED);
-       return -error;
+       int                     nmaps = 1;
+
+       return -xfs_iomap(XFS_I(inode), offset, count, flags, mapp, &nmaps);
 }
 
 STATIC_INLINE int
@@ -364,10 +416,16 @@ xfs_submit_ioend_bio(
        struct bio      *bio)
 {
        atomic_inc(&ioend->io_remaining);
-
        bio->bi_private = ioend;
        bio->bi_end_io = xfs_end_bio;
 
+       /*
+        * If the I/O is beyond EOF we mark the inode dirty immediately
+        * but don't update the inode size until I/O completion.
+        */
+       if (xfs_ioend_new_eof(ioend))
+               xfs_mark_inode_dirty_sync(XFS_I(ioend->io_inode));
+
        submit_bio(WRITE, bio);
        ASSERT(!bio_flagged(bio, BIO_EOPNOTSUPP));
        bio_put(bio);
@@ -513,7 +571,7 @@ xfs_cancel_ioend(
                        unlock_buffer(bh);
                } while ((bh = next_bh) != NULL);
 
-               vn_iowake(XFS_I(ioend->io_inode));
+               xfs_ioend_wake(XFS_I(ioend->io_inode));
                mempool_free(ioend, xfs_ioend_pool);
        } while ((ioend = next) != NULL);
 }
@@ -675,7 +733,7 @@ xfs_probe_cluster(
                        } else
                                pg_offset = PAGE_CACHE_SIZE;
 
-                       if (page->index == tindex && !TestSetPageLocked(page)) {
+                       if (page->index == tindex && trylock_page(page)) {
                                pg_len = xfs_probe_page(page, pg_offset, mapped);
                                unlock_page(page);
                        }
@@ -759,7 +817,7 @@ xfs_convert_page(
 
        if (page->index != tindex)
                goto fail;
-       if (TestSetPageLocked(page))
+       if (!trylock_page(page))
                goto fail;
        if (PageWriteback(page))
                goto fail_unlock_page;
@@ -1104,7 +1162,7 @@ xfs_page_state_convert(
                         * that we are writing into for the first time.
                         */
                        type = IOMAP_NEW;
-                       if (!test_and_set_bit(BH_Lock, &bh->b_state)) {
+                       if (trylock_buffer(bh)) {
                                ASSERT(buffer_mapped(bh));
                                if (iomap_valid)
                                        all_bh = 1;
@@ -1227,6 +1285,14 @@ xfs_vm_writepage(
        if (!page_has_buffers(page))
                create_empty_buffers(page, 1 << inode->i_blkbits, 0);
 
+
+       /*
+        *  VM calculation for nr_to_write seems off.  Bump it way
+        *  up, this gets simple streaming writes zippy again.
+        *  To be reviewed again after Jens' writeback changes.
+        */
+       wbc->nr_to_write *= 4;
+
        /*
         * Convert delayed allocate, unwritten or unmapped space
         * to real space and flush out to disk.
@@ -1339,6 +1405,10 @@ __xfs_get_blocks(
        offset = (xfs_off_t)iblock << inode->i_blkbits;
        ASSERT(bh_result->b_size >= (1 << inode->i_blkbits));
        size = bh_result->b_size;
+
+       if (!create && direct && offset >= i_size_read(inode))
+               return 0;
+
        error = xfs_iomap(XFS_I(inode), offset, size,
                             create ? flags : BMAPI_READ, &iomap, &niomap);
        if (error)
@@ -1582,4 +1652,6 @@ const struct address_space_operations xfs_address_space_operations = {
        .bmap                   = xfs_vm_bmap,
        .direct_IO              = xfs_vm_direct_IO,
        .migratepage            = buffer_migrate_page,
+       .is_partially_uptodate  = block_is_partially_uptodate,
+       .error_remove_page      = generic_error_remove_page,
 };