]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/nfs/write.c
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[linux-2.6-omap-h63xx.git] / fs / nfs / write.c
index 819a65f5071f8e9482e0cff5114e4574a940fd1b..9449b6835509dae636154341e3257d23e0eaf1db 100644 (file)
@@ -89,24 +89,38 @@ static mempool_t *nfs_commit_mempool;
 
 static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion);
 
-static inline struct nfs_write_data *nfs_commit_alloc(void)
+static inline 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 = kmalloc(size, GFP_NOFS);
+                       if (p->pagevec) {
+                               memset(p->pagevec, 0, size);
+                       } else {
+                               mempool_free(p, nfs_commit_mempool);
+                               p = NULL;
+                       }
+               }
        }
        return p;
 }
 
 static inline void nfs_commit_free(struct nfs_write_data *p)
 {
+       if (p && (p->pagevec != &p->page_array[0]))
+               kfree(p->pagevec);
        mempool_free(p, nfs_commit_mempool);
 }
 
-static void nfs_writedata_release(struct rpc_task *task)
+void nfs_writedata_release(void *wdata)
 {
-       struct nfs_write_data   *wdata = (struct nfs_write_data *)task->tk_calldata;
        nfs_writedata_free(wdata);
 }
 
@@ -168,7 +182,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();
+       wdata = nfs_writedata_alloc(1);
        if (!wdata)
                return -ENOMEM;
 
@@ -189,6 +203,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
                (long long)NFS_FILEID(inode),
                count, (long long)(page_offset(page) + offset));
 
+       set_page_writeback(page);
        nfs_begin_data_update(inode);
        do {
                if (count < wsize)
@@ -221,6 +236,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
 
 io_error:
        nfs_end_data_update(inode);
+       end_page_writeback(page);
        nfs_writedata_free(wdata);
        return written ? written : result;
 }
@@ -230,19 +246,16 @@ static int nfs_writepage_async(struct nfs_open_context *ctx,
                unsigned int offset, unsigned int count)
 {
        struct nfs_page *req;
-       int             status;
 
        req = nfs_update_request(ctx, inode, page, offset, count);
-       status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
-       if (status < 0)
-               goto out;
+       if (IS_ERR(req))
+               return PTR_ERR(req);
        /* Update file length */
        nfs_grow_file(page, offset, count);
        /* Set the PG_uptodate flag? */
        nfs_mark_uptodate(page, offset, count);
        nfs_unlock_request(req);
- out:
-       return status;
+       return 0;
 }
 
 static int wb_priority(struct writeback_control *wbc)
@@ -294,7 +307,7 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
        if (page->index >= end_index+1 || !offset)
                goto out;
 do_it:
-       ctx = nfs_find_open_context(inode, FMODE_WRITE);
+       ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE);
        if (ctx == NULL) {
                err = -EBADF;
                goto out;
@@ -302,11 +315,8 @@ do_it:
        lock_kernel();
        if (!IS_SYNC(inode) && inode_referenced) {
                err = nfs_writepage_async(ctx, inode, page, 0, offset);
-               if (err >= 0) {
-                       err = 0;
-                       if (wbc->for_reclaim)
-                               nfs_flush_inode(inode, 0, 0, FLUSH_STABLE);
-               }
+               if (!wbc->for_writepages)
+                       nfs_flush_inode(inode, 0, 0, wb_priority(wbc));
        } else {
                err = nfs_writepage_sync(ctx, inode, page, 0,
                                                offset, priority);
@@ -734,14 +744,14 @@ int nfs_updatepage(struct file *file, struct page *page,
                unsigned int offset, unsigned int count)
 {
        struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
-       struct dentry   *dentry = file->f_dentry;
        struct inode    *inode = page->mapping->host;
        struct nfs_page *req;
        int             status = 0;
 
        dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
-               dentry->d_parent->d_name.name, dentry->d_name.name,
-               count, (long long)(page_offset(page) +offset));
+               file->f_dentry->d_parent->d_name.name,
+               file->f_dentry->d_name.name, count,
+               (long long)(page_offset(page) +offset));
 
        if (IS_SYNC(inode)) {
                status = nfs_writepage_sync(ctx, inode, page, offset, count, 0);
@@ -850,7 +860,6 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
                unsigned int count, unsigned int offset,
                int how)
 {
-       struct rpc_task         *task = &data->task;
        struct inode            *inode;
 
        /* Set up the RPC argument and reply structs
@@ -876,12 +885,9 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
 
        data->task.tk_priority = flush_task_priority(how);
        data->task.tk_cookie = (unsigned long)inode;
-       data->task.tk_calldata = data;
-       /* Release requests */
-       data->task.tk_release = nfs_writedata_release;
 
        dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
-               task->tk_pid,
+               data->task.tk_pid,
                inode->i_sb->s_id,
                (long long)NFS_FILEID(inode),
                count,
@@ -918,7 +924,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how)
 
        nbytes = req->wb_bytes;
        for (;;) {
-               data = nfs_writedata_alloc();
+               data = nfs_writedata_alloc(1);
                if (!data)
                        goto out_bad;
                list_add(&data->pages, &list);
@@ -930,7 +936,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how)
        atomic_set(&req->wb_complete, requests);
 
        ClearPageError(page);
-       SetPageWriteback(page);
+       set_page_writeback(page);
        offset = 0;
        nbytes = req->wb_bytes;
        do {
@@ -982,7 +988,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how)
        if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)
                return nfs_flush_multi(head, inode, how);
 
-       data = nfs_writedata_alloc();
+       data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages);
        if (!data)
                goto out_bad;
 
@@ -993,7 +999,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how)
                nfs_list_remove_request(req);
                nfs_list_add_request(req, &data->pages);
                ClearPageError(req->wb_page);
-               SetPageWriteback(req->wb_page);
+               set_page_writeback(req->wb_page);
                *pages++ = req->wb_page;
                count += req->wb_bytes;
        }
@@ -1136,9 +1142,9 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status)
 /*
  * This function is called when the WRITE call is complete.
  */
-void nfs_writeback_done(struct rpc_task *task)
+void nfs_writeback_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs_write_data   *data = (struct nfs_write_data *) task->tk_calldata;
+       struct nfs_write_data   *data = calldata;
        struct nfs_writeargs    *argp = &data->args;
        struct nfs_writeres     *resp = &data->res;
 
@@ -1205,9 +1211,8 @@ void nfs_writeback_done(struct rpc_task *task)
 
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-static void nfs_commit_release(struct rpc_task *task)
+void nfs_commit_release(void *wdata)
 {
-       struct nfs_write_data   *wdata = (struct nfs_write_data *)task->tk_calldata;
        nfs_commit_free(wdata);
 }
 
@@ -1217,7 +1222,6 @@ static void nfs_commit_release(struct rpc_task *task)
 static void nfs_commit_rpcsetup(struct list_head *head,
                struct nfs_write_data *data, int how)
 {
-       struct rpc_task         *task = &data->task;
        struct nfs_page         *first;
        struct inode            *inode;
 
@@ -1244,23 +1248,20 @@ static void nfs_commit_rpcsetup(struct list_head *head,
 
        data->task.tk_priority = flush_task_priority(how);
        data->task.tk_cookie = (unsigned long)inode;
-       data->task.tk_calldata = data;
-       /* Release requests */
-       data->task.tk_release = nfs_commit_release;
        
-       dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
+       dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid);
 }
 
 /*
  * Commit dirty pages
  */
 static int
-nfs_commit_list(struct list_head *head, int how)
+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;
@@ -1283,10 +1284,9 @@ nfs_commit_list(struct list_head *head, int how)
 /*
  * COMMIT call returned
  */
-void
-nfs_commit_done(struct rpc_task *task)
+void nfs_commit_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs_write_data   *data = (struct nfs_write_data *)task->tk_calldata;
+       struct nfs_write_data   *data = calldata;
        struct nfs_page         *req;
        int res = 0;
 
@@ -1366,7 +1366,7 @@ int nfs_commit_inode(struct inode *inode, int how)
        res = nfs_scan_commit(inode, &head, 0, 0);
        spin_unlock(&nfsi->req_lock);
        if (res) {
-               error = nfs_commit_list(&head, how);
+               error = nfs_commit_list(inode, &head, how);
                if (error < 0)
                        return error;
        }
@@ -1377,22 +1377,23 @@ int nfs_commit_inode(struct inode *inode, int how)
 int nfs_sync_inode(struct inode *inode, unsigned long idx_start,
                  unsigned int npages, int how)
 {
-       int     error,
-               wait;
+       int nocommit = how & FLUSH_NOCOMMIT;
+       int wait = how & FLUSH_WAIT;
+       int error;
 
-       wait = how & FLUSH_WAIT;
-       how &= ~FLUSH_WAIT;
+       how &= ~(FLUSH_WAIT|FLUSH_NOCOMMIT);
 
        do {
-               error = 0;
-               if (wait)
+               if (wait) {
                        error = nfs_wait_on_requests(inode, idx_start, npages);
-               if (error == 0)
-                       error = nfs_flush_inode(inode, idx_start, npages, how);
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-               if (error == 0)
+                       if (error != 0)
+                               continue;
+               }
+               error = nfs_flush_inode(inode, idx_start, npages, how);
+               if (error != 0)
+                       continue;
+               if (!nocommit)
                        error = nfs_commit_inode(inode, how);
-#endif
        } while (error > 0);
        return error;
 }