cifs: Change the I/O paths to use an iterator rather than a page list
[sfrench/cifs-2.6.git] / fs / cifs / cifsglob.h
index 1d893bea4723a41a63ce414aa88e7187e2eee57c..893c2e21eb8eb9dff84736f54810ebbceea2834b 100644 (file)
@@ -216,11 +216,9 @@ static inline void cifs_free_open_info(struct cifs_open_info_data *data)
 struct smb_rqst {
        struct kvec     *rq_iov;        /* array of kvecs */
        unsigned int    rq_nvec;        /* number of kvecs in array */
-       struct page     **rq_pages;     /* pointer to array of page ptrs */
-       unsigned int    rq_offset;      /* the offset to the 1st page */
-       unsigned int    rq_npages;      /* number pages in array */
-       unsigned int    rq_pagesz;      /* page size to use */
-       unsigned int    rq_tailsz;      /* length of last page */
+       size_t          rq_iter_size;   /* Amount of data in ->rq_iter */
+       struct iov_iter rq_iter;        /* Data iterator */
+       struct xarray   rq_buffer;      /* Page buffer for encryption */
 };
 
 struct mid_q_entry;
@@ -1428,10 +1426,11 @@ struct cifs_aio_ctx {
        struct cifsFileInfo     *cfile;
        struct bio_vec          *bv;
        loff_t                  pos;
-       unsigned int            npages;
+       unsigned int            nr_pinned_pages;
        ssize_t                 rc;
        unsigned int            len;
        unsigned int            total_len;
+       unsigned int            bv_need_unpin;  /* If ->bv[] needs unpinning */
        bool                    should_dirty;
        /*
         * Indicates if this aio_ctx is for direct_io,
@@ -1449,28 +1448,18 @@ struct cifs_readdata {
        struct address_space            *mapping;
        struct cifs_aio_ctx             *ctx;
        __u64                           offset;
+       ssize_t                         got_bytes;
        unsigned int                    bytes;
-       unsigned int                    got_bytes;
        pid_t                           pid;
        int                             result;
        struct work_struct              work;
-       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 iov_iter                 iter;
        struct kvec                     iov[2];
        struct TCP_Server_Info          *server;
 #ifdef CONFIG_CIFS_SMB_DIRECT
        struct smbd_mr                  *mr;
 #endif
-       unsigned int                    pagesz;
-       unsigned int                    page_offset;
-       unsigned int                    tailsz;
        struct cifs_credits             credits;
-       unsigned int                    nr_pages;
-       struct page                     **pages;
 };
 
 /* asynchronous write support */
@@ -1482,6 +1471,8 @@ struct cifs_writedata {
        struct work_struct              work;
        struct cifsFileInfo             *cfile;
        struct cifs_aio_ctx             *ctx;
+       struct iov_iter                 iter;
+       struct bio_vec                  *bv;
        __u64                           offset;
        pid_t                           pid;
        unsigned int                    bytes;
@@ -1490,12 +1481,7 @@ struct cifs_writedata {
 #ifdef CONFIG_CIFS_SMB_DIRECT
        struct smbd_mr                  *mr;
 #endif
-       unsigned int                    pagesz;
-       unsigned int                    page_offset;
-       unsigned int                    tailsz;
        struct cifs_credits             credits;
-       unsigned int                    nr_pages;
-       struct page                     **pages;
 };
 
 /*
@@ -2155,9 +2141,9 @@ static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const
        dst->FileNameLength = src->FileNameLength;
 }
 
-static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
-                                           int num_rqst,
-                                           const u8 *sig)
+static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
+                                  int num_rqst,
+                                  const u8 *sig)
 {
        unsigned int len, skip;
        unsigned int nents = 0;
@@ -2177,6 +2163,19 @@ static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
         * rqst[1+].rq_iov[0+] data to be encrypted/decrypted
         */
        for (i = 0; i < num_rqst; i++) {
+               /* We really don't want a mixture of pinned and unpinned pages
+                * in the sglist.  It's hard to keep track of which is what.
+                * Instead, we convert to a BVEC-type iterator higher up.
+                */
+               if (WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
+                       return -EIO;
+
+               /* We also don't want to have any extra refs or pins to clean
+                * up in the sglist.
+                */
+               if (WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
+                       return -EIO;
+
                for (j = 0; j < rqst[i].rq_nvec; j++) {
                        struct kvec *iov = &rqst[i].rq_iov[j];
 
@@ -2190,7 +2189,7 @@ static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
                        }
                        skip = 0;
                }
-               nents += rqst[i].rq_npages;
+               nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
        }
        nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
        return nents;
@@ -2199,9 +2198,9 @@ static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
 /* We can not use the normal sg_set_buf() as we will sometimes pass a
  * stack object as buf.
  */
-static inline struct scatterlist *cifs_sg_set_buf(struct scatterlist *sg,
-                                                 const void *buf,
-                                                 unsigned int buflen)
+static inline void cifs_sg_set_buf(struct sg_table *sgtable,
+                                  const void *buf,
+                                  unsigned int buflen)
 {
        unsigned long addr = (unsigned long)buf;
        unsigned int off = offset_in_page(addr);
@@ -2211,16 +2210,17 @@ static inline struct scatterlist *cifs_sg_set_buf(struct scatterlist *sg,
                do {
                        unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
 
-                       sg_set_page(sg++, vmalloc_to_page((void *)addr), len, off);
+                       sg_set_page(&sgtable->sgl[sgtable->nents++],
+                                   vmalloc_to_page((void *)addr), len, off);
 
                        off = 0;
                        addr += PAGE_SIZE;
                        buflen -= len;
                } while (buflen);
        } else {
-               sg_set_page(sg++, virt_to_page(addr), buflen, off);
+               sg_set_page(&sgtable->sgl[sgtable->nents++],
+                           virt_to_page(addr), buflen, off);
        }
-       return sg;
 }
 
 #endif /* _CIFS_GLOB_H */