Merge branch 'akpm' (Andrew's patch-bomb)
[pandora-kernel.git] / fs / nfs / write.c
index e4a2ad2..5829d0c 100644 (file)
@@ -52,7 +52,7 @@ static mempool_t *nfs_commit_mempool;
 
 struct nfs_commit_data *nfs_commitdata_alloc(void)
 {
-       struct nfs_commit_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS);
+       struct nfs_commit_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOIO);
 
        if (p) {
                memset(p, 0, sizeof(*p));
@@ -70,7 +70,7 @@ EXPORT_SYMBOL_GPL(nfs_commit_free);
 
 struct nfs_write_header *nfs_writehdr_alloc(void)
 {
-       struct nfs_write_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
+       struct nfs_write_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO);
 
        if (p) {
                struct nfs_pgio_header *hdr = &p->header;
@@ -142,25 +142,38 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
        set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
 }
 
-static struct nfs_page *nfs_page_find_request_locked(struct page *page)
+static struct nfs_page *
+nfs_page_find_request_locked(struct nfs_inode *nfsi, struct page *page)
 {
        struct nfs_page *req = NULL;
 
-       if (PagePrivate(page)) {
+       if (PagePrivate(page))
                req = (struct nfs_page *)page_private(page);
-               if (req != NULL)
-                       kref_get(&req->wb_kref);
+       else if (unlikely(PageSwapCache(page))) {
+               struct nfs_page *freq, *t;
+
+               /* Linearly search the commit list for the correct req */
+               list_for_each_entry_safe(freq, t, &nfsi->commit_info.list, wb_list) {
+                       if (freq->wb_page == page) {
+                               req = freq;
+                               break;
+                       }
+               }
        }
+
+       if (req)
+               kref_get(&req->wb_kref);
+
        return req;
 }
 
 static struct nfs_page *nfs_page_find_request(struct page *page)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
        struct nfs_page *req = NULL;
 
        spin_lock(&inode->i_lock);
-       req = nfs_page_find_request_locked(page);
+       req = nfs_page_find_request_locked(NFS_I(inode), page);
        spin_unlock(&inode->i_lock);
        return req;
 }
@@ -168,16 +181,16 @@ static struct nfs_page *nfs_page_find_request(struct page *page)
 /* Adjust the file length if we're writing beyond the end */
 static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
        loff_t end, i_size;
        pgoff_t end_index;
 
        spin_lock(&inode->i_lock);
        i_size = i_size_read(inode);
        end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
-       if (i_size > 0 && page->index < end_index)
+       if (i_size > 0 && page_file_index(page) < end_index)
                goto out;
-       end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
+       end = page_file_offset(page) + ((loff_t)offset+count);
        if (i_size >= end)
                goto out;
        i_size_write(inode, end);
@@ -190,7 +203,7 @@ out:
 static void nfs_set_pageerror(struct page *page)
 {
        SetPageError(page);
-       nfs_zap_mapping(page->mapping->host, page->mapping);
+       nfs_zap_mapping(page_file_mapping(page)->host, page_file_mapping(page));
 }
 
 /* We can set the PG_uptodate flag if we see that a write request
@@ -231,7 +244,7 @@ static int nfs_set_page_writeback(struct page *page)
        int ret = test_set_page_writeback(page);
 
        if (!ret) {
-               struct inode *inode = page->mapping->host;
+               struct inode *inode = page_file_mapping(page)->host;
                struct nfs_server *nfss = NFS_SERVER(inode);
 
                if (atomic_long_inc_return(&nfss->writeback) >
@@ -245,7 +258,7 @@ static int nfs_set_page_writeback(struct page *page)
 
 static void nfs_end_page_writeback(struct page *page)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
        struct nfs_server *nfss = NFS_SERVER(inode);
 
        end_page_writeback(page);
@@ -255,13 +268,13 @@ static void nfs_end_page_writeback(struct page *page)
 
 static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
        struct nfs_page *req;
        int ret;
 
        spin_lock(&inode->i_lock);
        for (;;) {
-               req = nfs_page_find_request_locked(page);
+               req = nfs_page_find_request_locked(NFS_I(inode), page);
                if (req == NULL)
                        break;
                if (nfs_lock_request(req))
@@ -316,13 +329,13 @@ out:
 
 static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
        int ret;
 
        nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
        nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
 
-       nfs_pageio_cond_complete(pgio, page->index);
+       nfs_pageio_cond_complete(pgio, page_file_index(page));
        ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);
        if (ret == -EAGAIN) {
                redirty_page_for_writepage(wbc, page);
@@ -339,7 +352,7 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
        struct nfs_pageio_descriptor pgio;
        int err;
 
-       NFS_PROTO(page->mapping->host)->write_pageio_init(&pgio,
+       NFS_PROTO(page_file_mapping(page)->host)->write_pageio_init(&pgio,
                                                          page->mapping->host,
                                                          wb_priority(wbc),
                                                          &nfs_async_write_completion_ops);
@@ -416,9 +429,15 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
        spin_lock(&inode->i_lock);
        if (!nfsi->npages && NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
                inode->i_version++;
-       set_bit(PG_MAPPED, &req->wb_flags);
-       SetPagePrivate(req->wb_page);
-       set_page_private(req->wb_page, (unsigned long)req);
+       /*
+        * Swap-space should not get truncated. Hence no need to plug the race
+        * with invalidate/truncate.
+        */
+       if (likely(!PageSwapCache(req->wb_page))) {
+               set_bit(PG_MAPPED, &req->wb_flags);
+               SetPagePrivate(req->wb_page);
+               set_page_private(req->wb_page, (unsigned long)req);
+       }
        nfsi->npages++;
        kref_get(&req->wb_kref);
        spin_unlock(&inode->i_lock);
@@ -435,9 +454,11 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        BUG_ON (!NFS_WBACK_BUSY(req));
 
        spin_lock(&inode->i_lock);
-       set_page_private(req->wb_page, 0);
-       ClearPagePrivate(req->wb_page);
-       clear_bit(PG_MAPPED, &req->wb_flags);
+       if (likely(!PageSwapCache(req->wb_page))) {
+               set_page_private(req->wb_page, 0);
+               ClearPagePrivate(req->wb_page);
+               clear_bit(PG_MAPPED, &req->wb_flags);
+       }
        nfsi->npages--;
        spin_unlock(&inode->i_lock);
        nfs_release_request(req);
@@ -474,7 +495,7 @@ nfs_request_add_commit_list(struct nfs_page *req, struct list_head *dst,
        spin_unlock(cinfo->lock);
        if (!cinfo->dreq) {
                inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
-               inc_bdi_stat(req->wb_page->mapping->backing_dev_info,
+               inc_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,
                             BDI_RECLAIMABLE);
                __mark_inode_dirty(req->wb_context->dentry->d_inode,
                                   I_DIRTY_DATASYNC);
@@ -541,7 +562,7 @@ static void
 nfs_clear_page_commit(struct page *page)
 {
        dec_zone_page_state(page, NR_UNSTABLE_NFS);
-       dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
+       dec_bdi_stat(page_file_mapping(page)->backing_dev_info, BDI_RECLAIMABLE);
 }
 
 static void
@@ -733,7 +754,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
        spin_lock(&inode->i_lock);
 
        for (;;) {
-               req = nfs_page_find_request_locked(page);
+               req = nfs_page_find_request_locked(NFS_I(inode), page);
                if (req == NULL)
                        goto out_unlock;
 
@@ -792,7 +813,7 @@ out_err:
 static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
                struct page *page, unsigned int offset, unsigned int bytes)
 {
-       struct inode *inode = page->mapping->host;
+       struct inode *inode = page_file_mapping(page)->host;
        struct nfs_page *req;
 
        req = nfs_try_to_update_request(inode, page, offset, bytes);
@@ -845,7 +866,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
                nfs_release_request(req);
                if (!do_flush)
                        return 0;
-               status = nfs_wb_page(page->mapping->host, page);
+               status = nfs_wb_page(page_file_mapping(page)->host, page);
        } while (status == 0);
        return status;
 }
@@ -875,7 +896,7 @@ int nfs_updatepage(struct file *file, struct page *page,
                unsigned int offset, unsigned int count)
 {
        struct nfs_open_context *ctx = nfs_file_open_context(file);
-       struct inode    *inode = page->mapping->host;
+       struct inode    *inode = page_file_mapping(page)->host;
        int             status = 0;
 
        nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
@@ -883,7 +904,7 @@ int nfs_updatepage(struct file *file, struct page *page,
        dprintk("NFS:       nfs_updatepage(%s/%s %d@%lld)\n",
                file->f_path.dentry->d_parent->d_name.name,
                file->f_path.dentry->d_name.name, count,
-               (long long)(page_offset(page) + offset));
+               (long long)(page_file_offset(page) + offset));
 
        /* If we're not using byte range locks, and we know the page
         * is up to date, it may be more efficient to extend the write
@@ -1474,7 +1495,7 @@ void nfs_retry_commit(struct list_head *page_list,
                nfs_mark_request_commit(req, lseg, cinfo);
                if (!cinfo->dreq) {
                        dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
-                       dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
+                       dec_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,
                                     BDI_RECLAIMABLE);
                }
                nfs_unlock_and_release_request(req);
@@ -1731,7 +1752,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
  */
 int nfs_wb_page(struct inode *inode, struct page *page)
 {
-       loff_t range_start = page_offset(page);
+       loff_t range_start = page_file_offset(page);
        loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1);
        struct writeback_control wbc = {
                .sync_mode = WB_SYNC_ALL,