CIFS: Add copy into pages callback for a read operation
authorPavel Shilovsky <pshilov@microsoft.com>
Fri, 18 Nov 2016 00:20:18 +0000 (16:20 -0800)
committerSteve French <smfrench@gmail.com>
Wed, 1 Feb 2017 22:46:36 +0000 (16:46 -0600)
Since we have two different types of reads (pagecache and direct)
we need to process such responses differently after decryption of
a packet. The change allows to specify a callback that copies a read
payload data into preallocated pages.

Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
fs/cifs/cifsglob.h
fs/cifs/file.c

index 8a04a013a4ac9954f491f34e8200fa81e1ebeb9a..d6172c8b61bf7bac0e2196986d5e4bae9ada1286 100644 (file)
@@ -1129,6 +1129,9 @@ struct cifs_readdata {
        int (*read_into_pages)(struct TCP_Server_Info *server,
                                struct cifs_readdata *rdata,
                                unsigned int len);
+       int (*copy_into_pages)(struct TCP_Server_Info *server,
+                               struct cifs_readdata *rdata,
+                               struct iov_iter *iter);
        struct kvec                     iov[2];
        unsigned int                    pagesz;
        unsigned int                    tailsz;
index 1cd0e2eefc667aa8dbf22aa84516c1d527d774ac..98dc842e724512cb5eb71d5f1d94ccb0afe1222e 100644 (file)
@@ -2911,8 +2911,9 @@ cifs_uncached_readv_complete(struct work_struct *work)
 }
 
 static int
-cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
-                       struct cifs_readdata *rdata, unsigned int len)
+uncached_fill_pages(struct TCP_Server_Info *server,
+                   struct cifs_readdata *rdata, struct iov_iter *iter,
+                   unsigned int len)
 {
        int result = 0;
        unsigned int i;
@@ -2941,7 +2942,10 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
                        rdata->tailsz = len;
                        len = 0;
                }
-               result = cifs_read_page_from_socket(server, page, n);
+               if (iter)
+                       result = copy_page_from_iter(page, 0, n, iter);
+               else
+                       result = cifs_read_page_from_socket(server, page, n);
                if (result < 0)
                        break;
 
@@ -2952,6 +2956,21 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
                                                rdata->got_bytes : result;
 }
 
+static int
+cifs_uncached_read_into_pages(struct TCP_Server_Info *server,
+                             struct cifs_readdata *rdata, unsigned int len)
+{
+       return uncached_fill_pages(server, rdata, NULL, len);
+}
+
+static int
+cifs_uncached_copy_into_pages(struct TCP_Server_Info *server,
+                             struct cifs_readdata *rdata,
+                             struct iov_iter *iter)
+{
+       return uncached_fill_pages(server, rdata, iter, iter->count);
+}
+
 static int
 cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                     struct cifs_sb_info *cifs_sb, struct list_head *rdata_list)
@@ -2999,6 +3018,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
                rdata->pid = pid;
                rdata->pagesz = PAGE_SIZE;
                rdata->read_into_pages = cifs_uncached_read_into_pages;
+               rdata->copy_into_pages = cifs_uncached_copy_into_pages;
                rdata->credits = credits;
 
                if (!rdata->cfile->invalidHandle ||
@@ -3349,8 +3369,9 @@ cifs_readv_complete(struct work_struct *work)
 }
 
 static int
-cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
-                       struct cifs_readdata *rdata, unsigned int len)
+readpages_fill_pages(struct TCP_Server_Info *server,
+                    struct cifs_readdata *rdata, struct iov_iter *iter,
+                    unsigned int len)
 {
        int result = 0;
        unsigned int i;
@@ -3404,7 +3425,10 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
                        continue;
                }
 
-               result = cifs_read_page_from_socket(server, page, n);
+               if (iter)
+                       result = copy_page_from_iter(page, 0, n, iter);
+               else
+                       result = cifs_read_page_from_socket(server, page, n);
                if (result < 0)
                        break;
 
@@ -3415,6 +3439,21 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
                                                rdata->got_bytes : result;
 }
 
+static int
+cifs_readpages_read_into_pages(struct TCP_Server_Info *server,
+                              struct cifs_readdata *rdata, unsigned int len)
+{
+       return readpages_fill_pages(server, rdata, NULL, len);
+}
+
+static int
+cifs_readpages_copy_into_pages(struct TCP_Server_Info *server,
+                              struct cifs_readdata *rdata,
+                              struct iov_iter *iter)
+{
+       return readpages_fill_pages(server, rdata, iter, iter->count);
+}
+
 static int
 readpages_get_pages(struct address_space *mapping, struct list_head *page_list,
                    unsigned int rsize, struct list_head *tmplist,
@@ -3569,6 +3608,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
                rdata->pid = pid;
                rdata->pagesz = PAGE_SIZE;
                rdata->read_into_pages = cifs_readpages_read_into_pages;
+               rdata->copy_into_pages = cifs_readpages_copy_into_pages;
                rdata->credits = credits;
 
                list_for_each_entry_safe(page, tpage, &tmplist, lru) {