Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / fs / nfs / write.c
index 24de4f3..4cfada2 100644 (file)
@@ -46,6 +46,7 @@
  * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -63,7 +64,6 @@
 
 #include "delegation.h"
 #include "iostat.h"
-#include "internal.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
@@ -91,13 +91,23 @@ static mempool_t *nfs_commit_mempool;
 
 static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
 
-struct nfs_write_data *nfs_commit_alloc(void)
+struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount)
 {
        struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
 
        if (p) {
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
+               if (pagecount < NFS_PAGEVEC_SIZE)
+                       p->pagevec = &p->page_array[0];
+               else {
+                       size_t size = ++pagecount * sizeof(struct page *);
+                       p->pagevec = kzalloc(size, GFP_NOFS);
+                       if (!p->pagevec) {
+                               mempool_free(p, nfs_commit_mempool);
+                               p = NULL;
+                       }
+               }
        }
        return p;
 }
@@ -109,20 +119,21 @@ void nfs_commit_free(struct nfs_write_data *p)
        mempool_free(p, nfs_commit_mempool);
 }
 
-struct nfs_write_data *nfs_writedata_alloc(size_t len)
+struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
 {
-       unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, SLAB_NOFS);
 
        if (p) {
                memset(p, 0, sizeof(*p));
                INIT_LIST_HEAD(&p->pages);
-               p->npages = pagecount;
-               if (pagecount <= ARRAY_SIZE(p->page_array))
-                       p->pagevec = p->page_array;
+               if (pagecount < NFS_PAGEVEC_SIZE)
+                       p->pagevec = &p->page_array[0];
                else {
-                       p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
-                       if (!p->pagevec) {
+                       size_t size = ++pagecount * sizeof(struct page *);
+                       p->pagevec = kmalloc(size, GFP_NOFS);
+                       if (p->pagevec) {
+                               memset(p->pagevec, 0, size);
+                       } else {
                                mempool_free(p, nfs_wdata_mempool);
                                p = NULL;
                        }
@@ -131,7 +142,7 @@ struct nfs_write_data *nfs_writedata_alloc(size_t len)
        return p;
 }
 
-static void nfs_writedata_free(struct nfs_write_data *p)
+void nfs_writedata_free(struct nfs_write_data *p)
 {
        if (p && (p->pagevec != &p->page_array[0]))
                kfree(p->pagevec);
@@ -157,9 +168,6 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c
                return;
        nfs_inc_stats(inode, NFSIOS_EXTENDWRITE);
        i_size_write(inode, end);
-#ifdef FSCACHE_WRITE_SUPPORT
-       nfs_set_fscsize(NFS_SERVER(inode), NFS_I(inode), end);
-#endif
 }
 
 /* We can set the PG_uptodate flag if we see that a write request
@@ -205,7 +213,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
        int             result, written = 0;
        struct nfs_write_data *wdata;
 
-       wdata = nfs_writedata_alloc(wsize);
+       wdata = nfs_writedata_alloc(1);
        if (!wdata)
                return -ENOMEM;
 
@@ -339,9 +347,6 @@ do_it:
                err = -EBADF;
                goto out;
        }
-
-       nfs_writepage_to_fscache(inode, page);
-
        lock_kernel();
        if (!IS_SYNC(inode) && inode_referenced) {
                err = nfs_writepage_async(ctx, inode, page, 0, offset);
@@ -424,7 +429,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
                if (nfs_have_delegation(inode, FMODE_WRITE))
                        nfsi->change_attr++;
        }
-       SetPageNfsWriting(req->wb_page);
+       SetPagePrivate(req->wb_page);
        nfsi->npages++;
        atomic_inc(&req->wb_count);
        return 0;
@@ -441,7 +446,7 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        BUG_ON (!NFS_WBACK_BUSY(req));
 
        spin_lock(&nfsi->req_lock);
-       ClearPageNfsWriting(req->wb_page);
+       ClearPagePrivate(req->wb_page);
        radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
        nfsi->npages--;
        if (!nfsi->npages) {
@@ -496,7 +501,7 @@ nfs_mark_request_dirty(struct nfs_page *req)
        nfs_list_add_request(req, &nfsi->dirty);
        nfsi->ndirty++;
        spin_unlock(&nfsi->req_lock);
-       inc_zone_page_state(req->wb_page, NR_FILE_DIRTY);
+       inc_page_state(nr_dirty);
        mark_inode_dirty(inode);
 }
 
@@ -524,7 +529,7 @@ nfs_mark_request_commit(struct nfs_page *req)
        nfs_list_add_request(req, &nfsi->commit);
        nfsi->ncommit++;
        spin_unlock(&nfsi->req_lock);
-       inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+       inc_page_state(nr_unstable);
        mark_inode_dirty(inode);
 }
 #endif
@@ -578,30 +583,6 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
        return ret;
 }
 
-static void nfs_cancel_dirty_list(struct list_head *head)
-{
-       struct nfs_page *req;
-       while(!list_empty(head)) {
-               req = nfs_list_entry(head->next);
-               nfs_list_remove_request(req);
-               nfs_inode_remove_request(req);
-               nfs_clear_page_writeback(req);
-       }
-}
-
-static void nfs_cancel_commit_list(struct list_head *head)
-{
-       struct nfs_page *req;
-
-       while(!list_empty(head)) {
-               req = nfs_list_entry(head->next);
-               nfs_list_remove_request(req);
-               nfs_inode_remove_request(req);
-               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
-               nfs_clear_page_writeback(req);
-       }
-}
-
 /*
  * nfs_scan_dirty - Scan an inode for dirty requests
  * @inode: NFS inode to scan
@@ -621,6 +602,7 @@ nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_sta
        if (nfsi->ndirty != 0) {
                res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages);
                nfsi->ndirty -= res;
+               sub_page_state(nr_dirty,res);
                if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty))
                        printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
        }
@@ -645,7 +627,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st
        int res = 0;
 
        if (nfsi->ncommit != 0) {
-               res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages);
+               res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);
                nfsi->ncommit -= res;
                if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
                        printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
@@ -999,24 +981,24 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
        struct nfs_write_data *data;
-       size_t wsize = NFS_SERVER(inode)->wsize, nbytes;
-       unsigned int offset;
+       unsigned int wsize = NFS_SERVER(inode)->wsize;
+       unsigned int nbytes, offset;
        int requests = 0;
        LIST_HEAD(list);
 
        nfs_list_remove_request(req);
 
        nbytes = req->wb_bytes;
-       do {
-               size_t len = min(nbytes, wsize);
-
-               data = nfs_writedata_alloc(len);
+       for (;;) {
+               data = nfs_writedata_alloc(1);
                if (!data)
                        goto out_bad;
                list_add(&data->pages, &list);
                requests++;
-               nbytes -= len;
-       } while (nbytes != 0);
+               if (nbytes <= wsize)
+                       break;
+               nbytes -= wsize;
+       }
        atomic_set(&req->wb_complete, requests);
 
        ClearPageError(page);
@@ -1070,7 +1052,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how)
        struct nfs_write_data   *data;
        unsigned int            count;
 
-       data = nfs_writedata_alloc(NFS_SERVER(inode)->wsize);
+       data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages);
        if (!data)
                goto out_bad;
 
@@ -1280,7 +1262,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
                if (time_before(complain, jiffies)) {
                        dprintk("NFS: faulty NFS server %s:"
                                " (committed = %d) != (stable = %d)\n",
-                               NFS_SERVER(data->inode)->nfs_client->cl_hostname,
+                               NFS_SERVER(data->inode)->hostname,
                                resp->verf->committed, argp->stable);
                        complain = jiffies + 300 * HZ;
                }
@@ -1378,7 +1360,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
        struct nfs_write_data   *data;
        struct nfs_page         *req;
 
-       data = nfs_commit_alloc();
+       data = nfs_commit_alloc(NFS_SERVER(inode)->wpages);
 
        if (!data)
                goto out_bad;
@@ -1393,7 +1375,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
                req = nfs_list_entry(head->next);
                nfs_list_remove_request(req);
                nfs_mark_request_commit(req);
-               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
                nfs_clear_page_writeback(req);
        }
        return -ENOMEM;
@@ -1406,6 +1387,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
 {
        struct nfs_write_data   *data = calldata;
        struct nfs_page         *req;
+       int res = 0;
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
                                 task->tk_pid, task->tk_status);
@@ -1417,7 +1399,6 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
        while (!list_empty(&data->pages)) {
                req = nfs_list_entry(data->pages.next);
                nfs_list_remove_request(req);
-               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
 
                dprintk("NFS: commit (%s/%Ld %d@%Ld)",
                        req->wb_context->dentry->d_inode->i_sb->s_id,
@@ -1444,7 +1425,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
                nfs_mark_request_dirty(req);
        next:
                nfs_clear_page_writeback(req);
+               res++;
        }
+       sub_page_state(nr_unstable,res);
 }
 
 static const struct rpc_call_ops nfs_commit_ops = {
@@ -1512,25 +1495,15 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
                pages = nfs_scan_dirty(inode, &head, idx_start, npages);
                if (pages != 0) {
                        spin_unlock(&nfsi->req_lock);
-                       if (how & FLUSH_INVALIDATE)
-                               nfs_cancel_dirty_list(&head);
-                       else
-                               ret = nfs_flush_list(inode, &head, pages, how);
+                       ret = nfs_flush_list(inode, &head, pages, how);
                        spin_lock(&nfsi->req_lock);
                        continue;
                }
                if (nocommit)
                        break;
-               pages = nfs_scan_commit(inode, &head, idx_start, npages);
+               pages = nfs_scan_commit(inode, &head, 0, 0);
                if (pages == 0)
                        break;
-               if (how & FLUSH_INVALIDATE) {
-                       spin_unlock(&nfsi->req_lock);
-                       nfs_cancel_commit_list(&head);
-                       spin_lock(&nfsi->req_lock);
-                       continue;
-               }
-               pages += nfs_scan_commit(inode, &head, 0, 0);
                spin_unlock(&nfsi->req_lock);
                ret = nfs_commit_list(inode, &head, how);
                spin_lock(&nfsi->req_lock);
@@ -1539,7 +1512,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
        return ret;
 }
 
-int __init nfs_init_writepagecache(void)
+int nfs_init_writepagecache(void)
 {
        nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
                                             sizeof(struct nfs_write_data),