]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - fs/xfs/linux-2.6/xfs_aops.c
xfs: handle negative wbc->nr_to_write during sync writeback
[mirror_ubuntu-artful-kernel.git] / fs / xfs / linux-2.6 / xfs_aops.c
index d24e78f32f3e3f5f41331c80f1f46e86fb700a9a..528be1ba1402f31238429931ac64e3822041d4f2 100644 (file)
@@ -852,8 +852,8 @@ xfs_convert_page(
                SetPageUptodate(page);
 
        if (count) {
-               wbc->nr_to_write--;
-               if (wbc->nr_to_write <= 0)
+               if (--wbc->nr_to_write <= 0 &&
+                   wbc->sync_mode == WB_SYNC_NONE)
                        done = 1;
        }
        xfs_start_page_writeback(page, !page_dirty, count);
@@ -1478,22 +1478,38 @@ xfs_vm_direct_IO(
        if (rw & WRITE) {
                iocb->private = xfs_alloc_ioend(inode, IO_NEW);
 
-               ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
-                                                   offset, nr_segs,
-                                                   xfs_get_blocks_direct,
-                                                   xfs_end_io_direct_write);
+               ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
+                                           offset, nr_segs,
+                                           xfs_get_blocks_direct,
+                                           xfs_end_io_direct_write, NULL, 0);
                if (ret != -EIOCBQUEUED && iocb->private)
                        xfs_destroy_ioend(iocb->private);
        } else {
-               ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
-                                                   offset, nr_segs,
-                                                   xfs_get_blocks_direct,
-                                                   NULL);
+               ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov,
+                                           offset, nr_segs,
+                                           xfs_get_blocks_direct,
+                                           NULL, NULL, 0);
        }
 
        return ret;
 }
 
+STATIC void
+xfs_vm_write_failed(
+       struct address_space    *mapping,
+       loff_t                  to)
+{
+       struct inode            *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               struct iattr    ia = {
+                       .ia_valid       = ATTR_SIZE | ATTR_FORCE,
+                       .ia_size        = inode->i_size,
+               };
+               xfs_setattr(XFS_I(inode), &ia, XFS_ATTR_NOLOCK);
+       }
+}
+
 STATIC int
 xfs_vm_write_begin(
        struct file             *file,
@@ -1504,9 +1520,31 @@ xfs_vm_write_begin(
        struct page             **pagep,
        void                    **fsdata)
 {
-       *pagep = NULL;
-       return block_write_begin(file, mapping, pos, len, flags | AOP_FLAG_NOFS,
-                                pagep, fsdata, xfs_get_blocks);
+       int                     ret;
+
+       ret = block_write_begin(mapping, pos, len, flags | AOP_FLAG_NOFS,
+                               pagep, xfs_get_blocks);
+       if (unlikely(ret))
+               xfs_vm_write_failed(mapping, pos + len);
+       return ret;
+}
+
+STATIC int
+xfs_vm_write_end(
+       struct file             *file,
+       struct address_space    *mapping,
+       loff_t                  pos,
+       unsigned                len,
+       unsigned                copied,
+       struct page             *page,
+       void                    *fsdata)
+{
+       int                     ret;
+
+       ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+       if (unlikely(ret < len))
+               xfs_vm_write_failed(mapping, pos + len);
+       return ret;
 }
 
 STATIC sector_t
@@ -1551,7 +1589,7 @@ const struct address_space_operations xfs_address_space_operations = {
        .releasepage            = xfs_vm_releasepage,
        .invalidatepage         = xfs_vm_invalidatepage,
        .write_begin            = xfs_vm_write_begin,
-       .write_end              = generic_write_end,
+       .write_end              = xfs_vm_write_end,
        .bmap                   = xfs_vm_bmap,
        .direct_IO              = xfs_vm_direct_IO,
        .migratepage            = buffer_migrate_page,