]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/write.c
NFS: Remove use of the Big Kernel Lock around calls to rpc_execute.
[mv-sheeva.git] / fs / nfs / write.c
index b674462793d3375cf2adab2d642a8526e956fa0d..4948dc1fbd7420bdcc080ad286fe3e2824eae994 100644 (file)
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/file.h>
-#include <linux/mpage.h>
 #include <linux/writeback.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs_page.h>
+#include <linux/backing-dev.h>
+
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
 
@@ -101,13 +102,19 @@ struct nfs_write_data *nfs_commit_alloc(void)
        return p;
 }
 
-void nfs_commit_free(struct nfs_write_data *p)
+void nfs_commit_rcu_free(struct rcu_head *head)
 {
+       struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu);
        if (p && (p->pagevec != &p->page_array[0]))
                kfree(p->pagevec);
        mempool_free(p, nfs_commit_mempool);
 }
 
+void nfs_commit_free(struct nfs_write_data *wdata)
+{
+       call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free);
+}
+
 struct nfs_write_data *nfs_writedata_alloc(size_t len)
 {
        unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -130,13 +137,19 @@ struct nfs_write_data *nfs_writedata_alloc(size_t len)
        return p;
 }
 
-static void nfs_writedata_free(struct nfs_write_data *p)
+static void nfs_writedata_rcu_free(struct rcu_head *head)
 {
+       struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu);
        if (p && (p->pagevec != &p->page_array[0]))
                kfree(p->pagevec);
        mempool_free(p, nfs_wdata_mempool);
 }
 
+static void nfs_writedata_free(struct nfs_write_data *wdata)
+{
+       call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free);
+}
+
 void nfs_writedata_release(void *wdata)
 {
        nfs_writedata_free(wdata);
@@ -257,7 +270,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);
+       nfs_writedata_release(wdata);
        return written ? written : result;
 }
 
@@ -396,7 +409,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 out:
        clear_bit(BDI_write_congested, &bdi->state);
        wake_up_all(&nfs_write_congestion);
-       writeback_congestion_end();
+       congestion_end(WRITE);
        return err;
 }
 
@@ -589,10 +602,10 @@ static void nfs_cancel_commit_list(struct list_head *head)
 
        while(!list_empty(head)) {
                req = nfs_list_entry(head->next);
+               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
                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_unlock_request(req);
        }
 }
 
@@ -978,9 +991,7 @@ static void nfs_execute_write(struct nfs_write_data *data)
        sigset_t oldset;
 
        rpc_clnt_sigmask(clnt, &oldset);
-       lock_kernel();
        rpc_execute(&data->task);
-       unlock_kernel();
        rpc_clnt_sigunmask(clnt, &oldset);
 }
 
@@ -1042,7 +1053,7 @@ out_bad:
        while (!list_empty(&list)) {
                data = list_entry(list.next, struct nfs_write_data, pages);
                list_del(&data->pages);
-               nfs_writedata_free(data);
+               nfs_writedata_release(data);
        }
        nfs_mark_request_dirty(req);
        nfs_clear_page_writeback(req);
@@ -1512,9 +1523,10 @@ 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)
+                       if (how & FLUSH_INVALIDATE) {
                                nfs_cancel_dirty_list(&head);
-                       else
+                               ret = pages;
+                       } else
                                ret = nfs_flush_list(inode, &head, pages, how);
                        spin_lock(&nfsi->req_lock);
                        continue;
@@ -1527,6 +1539,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
                if (how & FLUSH_INVALIDATE) {
                        spin_unlock(&nfsi->req_lock);
                        nfs_cancel_commit_list(&head);
+                       ret = pages;
                        spin_lock(&nfsi->req_lock);
                        continue;
                }