]> err.no Git - linux-2.6/blobdiff - fs/gfs2/ops_address.c
Merge branch 'server-cluster-locking-api' of git://linux-nfs.org/~bfields/linux
[linux-2.6] / fs / gfs2 / ops_address.c
index 37bfeb961eb367507511cbd9eac4760db2a71d52..30c15622174fdbc59f3b94ab8cec331001b2a943 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pagevec.h>
 #include <linux/mpage.h>
 #include <linux/fs.h>
+#include <linux/writeback.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/lm_interface.h>
 
@@ -156,6 +157,32 @@ out_ignore:
        return 0;
 }
 
+/**
+ * gfs2_writepages - Write a bunch of dirty pages back to disk
+ * @mapping: The mapping to write
+ * @wbc: Write-back control
+ *
+ * For journaled files and/or ordered writes this just falls back to the
+ * kernel's default writepages path for now. We will probably want to change
+ * that eventually (i.e. when we look at allocate on flush).
+ *
+ * For the data=writeback case though we can already ignore buffer heads
+ * and write whole extents at once. This is a big reduction in the
+ * number of I/O requests we send and the bmap calls we make in this case.
+ */
+static int gfs2_writepages(struct address_space *mapping,
+                          struct writeback_control *wbc)
+{
+       struct inode *inode = mapping->host;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+
+       if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip))
+               return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+
+       return generic_writepages(mapping, wbc);
+}
+
 /**
  * stuffed_readpage - Fill in a Linux page with stuffed file data
  * @ip: the inode
@@ -170,7 +197,19 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
        void *kaddr;
        int error;
 
-       BUG_ON(page->index);
+       /*
+        * Due to the order of unstuffing files and ->nopage(), we can be
+        * asked for a zero page in the case of a stuffed file being extended,
+        * so we need to supply one here. It doesn't happen often.
+        */
+       if (unlikely(page->index)) {
+               kaddr = kmap_atomic(page, KM_USER0);
+               memset(kaddr, 0, PAGE_CACHE_SIZE);
+               kunmap_atomic(kaddr, KM_USER0);
+               flush_dcache_page(page);
+               SetPageUptodate(page);
+               return 0;
+       }
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (error)
@@ -181,9 +220,8 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
               ip->i_di.di_size);
        memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
        kunmap_atomic(kaddr, KM_USER0);
-
+       flush_dcache_page(page);
        brelse(dibh);
-
        SetPageUptodate(page);
 
        return 0;
@@ -239,9 +277,11 @@ skip_lock:
 out:
        return error;
 out_unlock:
-       if (error == GLR_TRYFAILED)
-               error = AOP_TRUNCATED_PAGE;
        unlock_page(page);
+       if (error == GLR_TRYFAILED) {
+               error = AOP_TRUNCATED_PAGE;
+               yield();
+       }
        if (do_unlock)
                gfs2_holder_uninit(&gh);
        goto out;
@@ -334,8 +374,11 @@ static int gfs2_prepare_write(struct file *file, struct page *page,
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh);
        error = gfs2_glock_nq_atime(&ip->i_gh);
        if (unlikely(error)) {
-               if (error == GLR_TRYFAILED)
+               if (error == GLR_TRYFAILED) {
+                       unlock_page(page);
                        error = AOP_TRUNCATED_PAGE;
+                       yield();
+               }
                goto out_uninit;
        }
 
@@ -475,7 +518,9 @@ static int gfs2_commit_write(struct file *file, struct page *page,
                gfs2_quota_unlock(ip);
                gfs2_alloc_put(ip);
        }
+       unlock_page(page);
        gfs2_glock_dq_m(1, &ip->i_gh);
+       lock_page(page);
        gfs2_holder_uninit(&ip->i_gh);
        return 0;
 
@@ -488,7 +533,9 @@ fail_endtrans:
                gfs2_quota_unlock(ip);
                gfs2_alloc_put(ip);
        }
+       unlock_page(page);
        gfs2_glock_dq_m(1, &ip->i_gh);
+       lock_page(page);
        gfs2_holder_uninit(&ip->i_gh);
 fail_nounlock:
        ClearPageUptodate(page);
@@ -757,6 +804,7 @@ out:
 
 const struct address_space_operations gfs2_file_aops = {
        .writepage = gfs2_writepage,
+       .writepages = gfs2_writepages,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
        .sync_page = block_sync_page,