nfs: move nfs_pgio_data and remove nfs_rw_header
[cascardo/linux.git] / fs / nfs / read.c
index ebd1666..d9df4ab 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
-static const struct nfs_pageio_ops nfs_pageio_read_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;
 
-static struct nfs_rw_header *nfs_readhdr_alloc(void)
+static struct nfs_pgio_header *nfs_readhdr_alloc(void)
 {
        return kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL);
 }
 
-static void nfs_readhdr_free(struct nfs_rw_header *rhdr)
+static void nfs_readhdr_free(struct nfs_pgio_header *rhdr)
 {
        kmem_cache_free(nfs_rdata_cachep, rhdr);
 }
@@ -58,7 +57,7 @@ void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
                              const struct nfs_pgio_completion_ops *compl_ops)
 {
        struct nfs_server *server = NFS_SERVER(inode);
-       const struct nfs_pageio_ops *pg_ops = &nfs_pageio_read_ops;
+       const struct nfs_pageio_ops *pg_ops = &nfs_pgio_rw_ops;
 
 #ifdef CONFIG_NFS_V4_1
        if (server->pnfs_curr_ld && !force_mds)
@@ -71,7 +70,7 @@ EXPORT_SYMBOL_GPL(nfs_pageio_init_read);
 
 void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio)
 {
-       pgio->pg_ops = &nfs_pageio_read_ops;
+       pgio->pg_ops = &nfs_pgio_rw_ops;
        pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize;
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds);
@@ -86,7 +85,7 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
        len = nfs_page_length(page);
        if (len == 0)
                return nfs_return_empty_page(page);
-       new = nfs_create_request(ctx, inode, page, 0, len);
+       new = nfs_create_request(ctx, page, NULL, 0, len);
        if (IS_ERR(new)) {
                unlock_page(page);
                return PTR_ERR(new);
@@ -106,10 +105,16 @@ static void nfs_readpage_release(struct nfs_page *req)
 {
        struct inode *d_inode = req->wb_context->dentry->d_inode;
 
-       if (PageUptodate(req->wb_page))
-               nfs_readpage_to_fscache(d_inode, req->wb_page, 0);
+       dprintk("NFS: read done (%s/%llu %d@%lld)\n", d_inode->i_sb->s_id,
+               (unsigned long long)NFS_FILEID(d_inode), req->wb_bytes,
+               (long long)req_offset(req));
 
-       unlock_page(req->wb_page);
+       if (nfs_page_group_sync_on_bit(req, PG_UNLOCKPAGE)) {
+               if (PageUptodate(req->wb_page))
+                       nfs_readpage_to_fscache(d_inode, req->wb_page, 0);
+
+               unlock_page(req->wb_page);
+       }
 
        dprintk("NFS: read done (%s/%Lu %d@%Ld)\n",
                        req->wb_context->dentry->d_inode->i_sb->s_id,
@@ -119,7 +124,12 @@ static void nfs_readpage_release(struct nfs_page *req)
        nfs_release_request(req);
 }
 
-/* Note io was page aligned */
+static void nfs_page_group_set_uptodate(struct nfs_page *req)
+{
+       if (nfs_page_group_sync_on_bit(req, PG_UPTODATE))
+               SetPageUptodate(req->wb_page);
+}
+
 static void nfs_read_completion(struct nfs_pgio_header *hdr)
 {
        unsigned long bytes = 0;
@@ -129,21 +139,32 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr)
        while (!list_empty(&hdr->pages)) {
                struct nfs_page *req = nfs_list_entry(hdr->pages.next);
                struct page *page = req->wb_page;
+               unsigned long start = req->wb_pgbase;
+               unsigned long end = req->wb_pgbase + req->wb_bytes;
 
                if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) {
-                       if (bytes > hdr->good_bytes)
-                               zero_user(page, 0, PAGE_SIZE);
-                       else if (hdr->good_bytes - bytes < PAGE_SIZE)
-                               zero_user_segment(page,
-                                       hdr->good_bytes & ~PAGE_MASK,
-                                       PAGE_SIZE);
+                       /* note: regions of the page not covered by a
+                        * request are zeroed in nfs_readpage_async /
+                        * readpage_async_filler */
+                       if (bytes > hdr->good_bytes) {
+                               /* nothing in this request was good, so zero
+                                * the full extent of the request */
+                               zero_user_segment(page, start, end);
+
+                       } else if (hdr->good_bytes - bytes < req->wb_bytes) {
+                               /* part of this request has good bytes, but
+                                * not all. zero the bad bytes */
+                               start += hdr->good_bytes - bytes;
+                               WARN_ON(start < req->wb_pgbase);
+                               zero_user_segment(page, start, end);
+                       }
                }
                bytes += req->wb_bytes;
                if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
                        if (bytes <= hdr->good_bytes)
-                               SetPageUptodate(page);
+                               nfs_page_group_set_uptodate(req);
                } else
-                       SetPageUptodate(page);
+                       nfs_page_group_set_uptodate(req);
                nfs_list_remove_request(req);
                nfs_readpage_release(req);
        }
@@ -178,11 +199,6 @@ static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops = {
        .completion = nfs_read_completion,
 };
 
-static const struct nfs_pageio_ops nfs_pageio_read_ops = {
-       .pg_test = nfs_generic_pg_test,
-       .pg_doio = nfs_generic_pg_pgios,
-};
-
 /*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
@@ -309,7 +325,6 @@ static int
 readpage_async_filler(void *data, struct page *page)
 {
        struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
-       struct inode *inode = page_file_mapping(page)->host;
        struct nfs_page *new;
        unsigned int len;
        int error;
@@ -318,7 +333,7 @@ readpage_async_filler(void *data, struct page *page)
        if (len == 0)
                return nfs_return_empty_page(page);
 
-       new = nfs_create_request(desc->ctx, inode, page, 0, len);
+       new = nfs_create_request(desc->ctx, page, NULL, 0, len);
        if (IS_ERR(new))
                goto out_error;
 
@@ -389,7 +404,7 @@ out:
 int __init nfs_init_readpagecache(void)
 {
        nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
-                                            sizeof(struct nfs_rw_header),
+                                            sizeof(struct nfs_pgio_header),
                                             0, SLAB_HWCACHE_ALIGN,
                                             NULL);
        if (nfs_rdata_cachep == NULL)