* 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>
#include "delegation.h"
#include "iostat.h"
-#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
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;
}
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;
}
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);
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
int result, written = 0;
struct nfs_write_data *wdata;
- wdata = nfs_writedata_alloc(wsize);
+ wdata = nfs_writedata_alloc(1);
if (!wdata)
return -ENOMEM;
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);
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;
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) {
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);
}
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
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
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");
}
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");
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);
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;
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;
}
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;
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;
{
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);
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,
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 = {
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);
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),