Read pages from a FS-Cache data storage object into a CIFS inode.

Signed-off-by: Suresh Jayaraman <[email protected]>
---
 fs/cifs/file.c    |   19 ++++++++++++++
 fs/cifs/fscache.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/fscache.h |   40 ++++++++++++++++++++++++++++-
 3 files changed, 131 insertions(+), 1 deletions(-)

diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 39c1ce0..42d2f25 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1978,6 +1978,16 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        pTcon = cifs_sb->tcon;
 
+       /*
+        * Reads as many pages as possible from fscache. Returns -ENOBUFS
+        * immediately if the cookie is negative
+        */
+       rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list,
+                                        &num_pages);
+       cFYI(1, "CIFS: readpages_from_fscache returned %d\n", rc);
+       if (rc == 0)
+               goto read_complete;
+
        cFYI(DBG2, "rpages: num pages %d", num_pages);
        for (i = 0; i < num_pages; ) {
                unsigned contig_pages;
@@ -2090,6 +2100,7 @@ static int cifs_readpages(struct file *file, struct 
address_space *mapping,
                smb_read_data = NULL;
        }
 
+read_complete:
        FreeXid(xid);
        return rc;
 }
@@ -2100,6 +2111,12 @@ static int cifs_readpage_worker(struct file *file, 
struct page *page,
        char *read_data;
        int rc;
 
+       /* Is the page cached? */
+       rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page);
+       cFYI(1, "CIFS: cifs_readpage_from_fscache returned %d\n", rc);
+       if (rc == 0)
+               goto read_complete;
+
        page_cache_get(page);
        read_data = kmap(page);
        /* for reads over a certain size could initiate async read ahead */
@@ -2128,6 +2145,8 @@ static int cifs_readpage_worker(struct file *file, struct 
page *page,
 io_error:
        kunmap(page);
        page_cache_release(page);
+
+read_complete:
        return rc;
 }
 
diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c
index 13e47d5..6813737 100644
--- a/fs/cifs/fscache.c
+++ b/fs/cifs/fscache.c
@@ -145,6 +145,79 @@ int cifs_fscache_release_page(struct page *page, gfp_t gfp)
        return 1;
 }
 
+static void cifs_readpage_from_fscache_complete(struct page *page, void *ctx,
+                                               int error)
+{
+       cFYI(1, "CFS: readpage_from_fscache_complete (0x%p/%d)\n",
+                       page, error);
+       if (!error)
+               SetPageUptodate(page);
+       unlock_page(page);
+}
+
+/*
+ * Retrieve a page from FS-Cache
+ */
+int __cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+       int ret;
+
+       cFYI(1, "CIFS: readpage_from_fscache(fsc:%p, p:%p, i:0x%p\n",
+                       CIFS_I(inode)->fscache, page, inode);
+       ret = fscache_read_or_alloc_page(CIFS_I(inode)->fscache, page,
+                                        cifs_readpage_from_fscache_complete,
+                                        NULL,
+                                        GFP_KERNEL);
+       switch (ret) {
+
+       case 0: /* page found in fscache, read submitted */
+               cFYI(1, "CIFS: readpage_from_fscache: submitted\n");
+               return ret;
+       case -ENOBUFS:  /* page won't be cached */
+       case -ENODATA:  /* page not in cache */
+               cFYI(1, "CIFS: readpage_from_fscache %d\n", ret);
+               return 1;
+
+       default:
+               cFYI(1, "unknown error ret = %d", ret);
+       }
+       return ret;
+}
+
+/*
+ * Retrieve a set of pages from FS-Cache
+ */
+int __cifs_readpages_from_fscache(struct inode *inode,
+                               struct address_space *mapping,
+                               struct list_head *pages,
+                               unsigned *nr_pages)
+{
+       int ret;
+
+       cFYI(1, "CIFS: __cifs_readpages_from_fscache (0x%p/%u/0x%p)\n",
+                       CIFS_I(inode)->fscache, *nr_pages, inode);
+       ret = fscache_read_or_alloc_pages(CIFS_I(inode)->fscache, mapping,
+                                         pages, nr_pages,
+                                         cifs_readpage_from_fscache_complete,
+                                         NULL,
+                                         mapping_gfp_mask(mapping));
+       switch (ret) {
+       case 0: /* read submitted to the cache for all pages */
+               cFYI(1, "CIFS: readpages_from_fscache\n");
+               return ret;
+
+       case -ENOBUFS:  /* some pages are not cached and can't be */
+       case -ENODATA:  /* some pages are not cached */
+               cFYI(1, "CIFS: readpages_from_fscache: no page\n");
+               return 1;
+
+       default:
+               cFYI(1, "unknown error ret = %d", ret);
+       }
+
+       return ret;
+}
+
 void __cifs_readpage_to_fscache(struct inode *inode, struct page *page)
 {
        int ret;
diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h
index e34d8ab..03bd3fe 100644
--- a/fs/cifs/fscache.h
+++ b/fs/cifs/fscache.h
@@ -31,7 +31,6 @@ extern const struct fscache_cookie_def 
cifs_fscache_server_index_def;
 extern const struct fscache_cookie_def cifs_fscache_super_index_def;
 extern const struct fscache_cookie_def cifs_fscache_inode_object_def;
 
-
 extern int cifs_fscache_register(void);
 extern void cifs_fscache_unregister(void);
 
@@ -49,6 +48,11 @@ extern void cifs_fscache_reset_inode_cookie(struct inode *);
 
 extern void __cifs_fscache_invalidate_page(struct page *, struct inode *);
 extern int cifs_fscache_release_page(struct page *page, gfp_t gfp);
+extern int __cifs_readpage_from_fscache(struct inode *, struct page *);
+extern int __cifs_readpages_from_fscache(struct inode *,
+                                        struct address_space *,
+                                        struct list_head *,
+                                        unsigned *);
 
 extern void __cifs_readpage_to_fscache(struct inode *, struct page *);
 
@@ -59,6 +63,26 @@ static inline void cifs_fscache_invalidate_page(struct page 
*page,
                __cifs_fscache_invalidate_page(page, inode);
 }
 
+static inline int cifs_readpage_from_fscache(struct inode *inode,
+                                            struct page *page)
+{
+       if (CIFS_I(inode)->fscache)
+               return __cifs_readpage_from_fscache(inode, page);
+
+       return -ENOBUFS;
+}
+
+static inline int cifs_readpages_from_fscache(struct inode *inode,
+                                             struct address_space *mapping,
+                                             struct list_head *pages,
+                                             unsigned *nr_pages)
+{
+       if (CIFS_I(inode)->fscache)
+               return __cifs_readpages_from_fscache(inode, mapping, pages,
+                                                    nr_pages);
+       return -ENOBUFS;
+}
+
 static inline void cifs_readpage_to_fscache(struct inode *inode,
                                            struct page *page)
 {
@@ -89,6 +113,20 @@ static inline void cifs_fscache_release_page(struct page 
*page, gfp_t gfp)
 
 static inline int cifs_fscache_invalidate_page(struct page *page,
                        struct inode *) {}
+static inline int
+cifs_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+       return -ENOBUFS;
+}
+
+static inline int cifs_readpages_from_fscache(struct inode *inode,
+                                             struct address_space *mapping,
+                                             struct list_head *pages,
+                                             unsigned *nr_pages)
+{
+       return -ENOBUFS;
+}
+
 static inline void cifs_readpage_to_fscache(struct inode *inode,
                        struct page *page) {}
 
-- 
1.6.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to