NFS: Create a common rw_header_alloc and rw_header_free function
[linux-2.6-block.git] / fs / nfs / read.c
index 411aedda14bb70c413fc771eb2a44e60817ed8ff..4cf3577bd54eb36ff3d190ebc4a67c0203e1c6cd 100644 (file)
 #include "internal.h"
 #include "iostat.h"
 #include "fscache.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
 static const struct nfs_pageio_ops nfs_pageio_read_ops;
 static const struct rpc_call_ops nfs_read_common_ops;
 static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops;
+static const struct nfs_rw_ops nfs_rw_read_ops;
 
 static struct kmem_cache *nfs_rdata_cachep;
 
-struct nfs_read_header *nfs_readhdr_alloc(void)
+static struct nfs_rw_header *nfs_readhdr_alloc(void)
 {
-       struct nfs_read_header *rhdr;
-
-       rhdr = kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
-       if (rhdr) {
-               struct nfs_pgio_header *hdr = &rhdr->header;
-
-               INIT_LIST_HEAD(&hdr->pages);
-               INIT_LIST_HEAD(&hdr->rpc_list);
-               spin_lock_init(&hdr->lock);
-               atomic_set(&hdr->refcnt, 0);
-       }
-       return rhdr;
-}
-EXPORT_SYMBOL_GPL(nfs_readhdr_alloc);
-
-static struct nfs_read_data *nfs_readdata_alloc(struct nfs_pgio_header *hdr,
-                                               unsigned int pagecount)
-{
-       struct nfs_read_data *data, *prealloc;
-
-       prealloc = &container_of(hdr, struct nfs_read_header, header)->rpc_data;
-       if (prealloc->header == NULL)
-               data = prealloc;
-       else
-               data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data)
-               goto out;
-
-       if (nfs_pgarray_set(&data->pages, pagecount)) {
-               data->header = hdr;
-               atomic_inc(&hdr->refcnt);
-       } else {
-               if (data != prealloc)
-                       kfree(data);
-               data = NULL;
-       }
-out:
-       return data;
+       return kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
 }
 
-void nfs_readhdr_free(struct nfs_pgio_header *hdr)
+static void nfs_readhdr_free(struct nfs_rw_header *rhdr)
 {
-       struct nfs_read_header *rhdr = container_of(hdr, struct nfs_read_header, header);
-
        kmem_cache_free(nfs_rdata_cachep, rhdr);
 }
-EXPORT_SYMBOL_GPL(nfs_readhdr_free);
-
-void nfs_readdata_release(struct nfs_read_data *rdata)
-{
-       struct nfs_pgio_header *hdr = rdata->header;
-       struct nfs_read_header *read_header = container_of(hdr, struct nfs_read_header, header);
-
-       put_nfs_open_context(rdata->args.context);
-       if (rdata->pages.pagevec != rdata->pages.page_array)
-               kfree(rdata->pages.pagevec);
-       if (rdata == &read_header->rpc_data) {
-               rdata->header = NULL;
-               rdata = NULL;
-       }
-       if (atomic_dec_and_test(&hdr->refcnt))
-               hdr->completion_ops->completion(hdr);
-       /* Note: we only free the rpc_task after callbacks are done.
-        * See the comment in rpc_free_task() for why
-        */
-       kfree(rdata);
-}
-EXPORT_SYMBOL_GPL(nfs_readdata_release);
 
 static
 int nfs_return_empty_page(struct page *page)
@@ -114,11 +55,18 @@ int nfs_return_empty_page(struct page *page)
 }
 
 void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
-                             struct inode *inode,
+                             struct inode *inode, bool force_mds,
                              const struct nfs_pgio_completion_ops *compl_ops)
 {
-       nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops, compl_ops,
-                       NFS_SERVER(inode)->rsize, 0);
+       struct nfs_server *server = NFS_SERVER(inode);
+       const struct nfs_pageio_ops *pg_ops = &nfs_pageio_read_ops;
+
+#ifdef CONFIG_NFS_V4_1
+       if (server->pnfs_curr_ld && !force_mds)
+               pg_ops = server->pnfs_curr_ld->pg_read_ops;
+#endif
+       nfs_pageio_init(pgio, inode, pg_ops, compl_ops, &nfs_rw_read_ops,
+                       server->rsize, 0);
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_init_read);
 
@@ -147,7 +95,8 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
        if (len < PAGE_CACHE_SIZE)
                zero_user_segment(page, len, PAGE_CACHE_SIZE);
 
-       NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops);
+       nfs_pageio_init_read(&pgio, inode, false,
+                            &nfs_async_read_completion_ops);
        nfs_pageio_add_request(&pgio, new);
        nfs_pageio_complete(&pgio);
        NFS_I(inode)->read_io += pgio.pg_bytes_written;
@@ -204,7 +153,7 @@ out:
 }
 
 int nfs_initiate_read(struct rpc_clnt *clnt,
-                     struct nfs_read_data *data,
+                     struct nfs_pgio_data *data,
                      const struct rpc_call_ops *call_ops, int flags)
 {
        struct inode *inode = data->header->inode;
@@ -247,7 +196,7 @@ EXPORT_SYMBOL_GPL(nfs_initiate_read);
 /*
  * Set up the NFS read request struct
  */
-static void nfs_read_rpcsetup(struct nfs_read_data *data,
+static void nfs_read_rpcsetup(struct nfs_pgio_data *data,
                unsigned int count, unsigned int offset)
 {
        struct nfs_page *req = data->header->req;
@@ -266,7 +215,7 @@ static void nfs_read_rpcsetup(struct nfs_read_data *data,
        nfs_fattr_init(&data->fattr);
 }
 
-static int nfs_do_read(struct nfs_read_data *data,
+static int nfs_do_read(struct nfs_pgio_data *data,
                const struct rpc_call_ops *call_ops)
 {
        struct inode *inode = data->header->inode;
@@ -278,13 +227,13 @@ static int
 nfs_do_multiple_reads(struct list_head *head,
                const struct rpc_call_ops *call_ops)
 {
-       struct nfs_read_data *data;
+       struct nfs_pgio_data *data;
        int ret = 0;
 
        while (!list_empty(head)) {
                int ret2;
 
-               data = list_first_entry(head, struct nfs_read_data, list);
+               data = list_first_entry(head, struct nfs_pgio_data, list);
                list_del_init(&data->list);
 
                ret2 = nfs_do_read(data, call_ops);
@@ -316,10 +265,10 @@ static void nfs_pagein_error(struct nfs_pageio_descriptor *desc,
 {
        set_bit(NFS_IOHDR_REDO, &hdr->flags);
        while (!list_empty(&hdr->rpc_list)) {
-               struct nfs_read_data *data = list_first_entry(&hdr->rpc_list,
-                               struct nfs_read_data, list);
+               struct nfs_pgio_data *data = list_first_entry(&hdr->rpc_list,
+                               struct nfs_pgio_data, list);
                list_del(&data->list);
-               nfs_readdata_release(data);
+               nfs_pgio_data_release(data);
        }
        desc->pg_completion_ops->error_cleanup(&desc->pg_list);
 }
@@ -342,7 +291,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc,
 {
        struct nfs_page *req = hdr->req;
        struct page *page = req->wb_page;
-       struct nfs_read_data *data;
+       struct nfs_pgio_data *data;
        size_t rsize = desc->pg_bsize, nbytes;
        unsigned int offset;
 
@@ -351,7 +300,7 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc,
        do {
                size_t len = min(nbytes,rsize);
 
-               data = nfs_readdata_alloc(hdr, 1);
+               data = nfs_pgio_data_alloc(hdr, 1);
                if (!data) {
                        nfs_pagein_error(desc, hdr);
                        return -ENOMEM;
@@ -374,10 +323,10 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc,
 {
        struct nfs_page         *req;
        struct page             **pages;
-       struct nfs_read_data    *data;
+       struct nfs_pgio_data    *data;
        struct list_head *head = &desc->pg_list;
 
-       data = nfs_readdata_alloc(hdr, nfs_page_array_len(desc->pg_base,
+       data = nfs_pgio_data_alloc(hdr, nfs_page_array_len(desc->pg_base,
                                                          desc->pg_count));
        if (!data) {
                nfs_pagein_error(desc, hdr);
@@ -409,17 +358,17 @@ EXPORT_SYMBOL_GPL(nfs_generic_pagein);
 
 static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
 {
-       struct nfs_read_header *rhdr;
+       struct nfs_rw_header *rhdr;
        struct nfs_pgio_header *hdr;
        int ret;
 
-       rhdr = nfs_readhdr_alloc();
+       rhdr = nfs_rw_header_alloc(desc->pg_rw_ops);
        if (!rhdr) {
                desc->pg_completion_ops->error_cleanup(&desc->pg_list);
                return -ENOMEM;
        }
        hdr = &rhdr->header;
-       nfs_pgheader_init(desc, hdr, nfs_readhdr_free);
+       nfs_pgheader_init(desc, hdr, nfs_rw_header_free);
        atomic_inc(&hdr->refcnt);
        ret = nfs_generic_pagein(desc, hdr);
        if (ret == 0)
@@ -439,7 +388,7 @@ static const struct nfs_pageio_ops nfs_pageio_read_ops = {
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
  */
-int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
+int nfs_readpage_result(struct rpc_task *task, struct nfs_pgio_data *data)
 {
        struct inode *inode = data->header->inode;
        int status;
@@ -460,10 +409,10 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data)
        return 0;
 }
 
-static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data)
+static void nfs_readpage_retry(struct rpc_task *task, struct nfs_pgio_data *data)
 {
-       struct nfs_readargs *argp = &data->args;
-       struct nfs_readres *resp = &data->res;
+       struct nfs_pgio_args *argp = &data->args;
+       struct nfs_pgio_res  *resp = &data->res;
 
        /* This is a short read! */
        nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD);
@@ -482,7 +431,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
 
 static void nfs_readpage_result_common(struct rpc_task *task, void *calldata)
 {
-       struct nfs_read_data *data = calldata;
+       struct nfs_pgio_data *data = calldata;
        struct nfs_pgio_header *hdr = data->header;
 
        /* Note the only returns of nfs_readpage_result are 0 and -EAGAIN */
@@ -507,12 +456,12 @@ static void nfs_readpage_result_common(struct rpc_task *task, void *calldata)
 
 static void nfs_readpage_release_common(void *calldata)
 {
-       nfs_readdata_release(calldata);
+       nfs_pgio_data_release(calldata);
 }
 
 void nfs_read_prepare(struct rpc_task *task, void *calldata)
 {
-       struct nfs_read_data *data = calldata;
+       struct nfs_pgio_data *data = calldata;
        int err;
        err = NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
        if (err)
@@ -654,7 +603,8 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        if (ret == 0)
                goto read_complete; /* all pages were read */
 
-       NFS_PROTO(inode)->read_pageio_init(&pgio, inode, &nfs_async_read_completion_ops);
+       nfs_pageio_init_read(&pgio, inode, false,
+                            &nfs_async_read_completion_ops);
 
        ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
 
@@ -671,7 +621,7 @@ out:
 int __init nfs_init_readpagecache(void)
 {
        nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
-                                            sizeof(struct nfs_read_header),
+                                            sizeof(struct nfs_rw_header),
                                             0, SLAB_HWCACHE_ALIGN,
                                             NULL);
        if (nfs_rdata_cachep == NULL)
@@ -684,3 +634,8 @@ void nfs_destroy_readpagecache(void)
 {
        kmem_cache_destroy(nfs_rdata_cachep);
 }
+
+static const struct nfs_rw_ops nfs_rw_read_ops = {
+       .rw_alloc_header        = nfs_readhdr_alloc,
+       .rw_free_header         = nfs_readhdr_free,
+};