Skip to content

Commit d08089f

Browse files
dhowellsSteve French
authored andcommitted
cifs: Change the I/O paths to use an iterator rather than a page list
Currently, the cifs I/O paths hand lists of pages from the VM interface routines at the top all the way through the intervening layers to the socket interface at the bottom. This is a problem, however, for interfacing with netfslib which passes an iterator through to the ->issue_read() method (and will pass an iterator through to the ->issue_write() method in future). Netfslib takes over bounce buffering for direct I/O, async I/O and encrypted content, so cifs doesn't need to do that. Netfslib also converts IOVEC-type iterators into BVEC-type iterators if necessary. Further, cifs needs foliating - and folios may come in a variety of sizes, so a page list pointing to an array of heterogeneous pages may cause problems in places such as where crypto is done. Change the cifs I/O paths to hand iov_iter iterators all the way through instead. Notes: (1) Some old routines are #if'd out to be removed in a follow up patch so as to avoid confusing diff, thereby making the diff output easier to follow. I've removed functions that don't overlap with anything added. (2) struct smb_rqst loses rq_pages, rq_offset, rq_npages, rq_pagesz and rq_tailsz which describe the pages forming the buffer; instead there's an rq_iter describing the source buffer and an rq_buffer which is used to hold the buffer for encryption. (3) struct cifs_readdata and cifs_writedata are similarly modified to smb_rqst. The ->read_into_pages() and ->copy_into_pages() are then replaced with passing the iterator directly to the socket. The iterators are stored in these structs so that they are persistent and don't get deallocated when the function returns (unlike if they were stack variables). (4) Buffered writeback is overhauled, borrowing the code from the afs filesystem to gather up contiguous runs of folios. The XARRAY-type iterator is then used to refer directly to the pagecache and can be passed to the socket to transmit data directly from there. This includes: cifs_extend_writeback() cifs_write_back_from_locked_folio() cifs_writepages_region() cifs_writepages() (5) Pages are converted to folios. (6) Direct I/O uses netfs_extract_user_iter() to create a BVEC-type iterator from an IOBUF/UBUF-type source iterator. (7) smb2_get_aead_req() uses netfs_extract_iter_to_sg() to extract page fragments from the iterator into the scatterlists that the crypto layer prefers. (8) smb2_init_transform_rq() attached pages to smb_rqst::rq_buffer, an xarray, to use as a bounce buffer for encryption. An XARRAY-type iterator can then be used to pass the bounce buffer to lower layers. Signed-off-by: David Howells <[email protected]> cc: Steve French <[email protected]> cc: Shyam Prasad N <[email protected]> cc: Rohith Surabattula <[email protected]> cc: Paulo Alcantara <[email protected]> cc: Jeff Layton <[email protected]> cc: [email protected] Link: https://lore.kernel.org/r/164311907995.2806745.400147335497304099.stgit@warthog.procyon.org.uk/ # rfc Link: https://lore.kernel.org/r/164928620163.457102.11602306234438271112.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/165211420279.3154751.15923591172438186144.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/165348880385.2106726.3220789453472800240.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/165364827111.3334034.934805882842932881.stgit@warthog.procyon.org.uk/ # v3 Link: https://lore.kernel.org/r/166126396180.708021.271013668175370826.stgit@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/166697259595.61150.5982032408321852414.stgit@warthog.procyon.org.uk/ # rfc Link: https://lore.kernel.org/r/166732031756.3186319.12528413619888902872.stgit@warthog.procyon.org.uk/ # rfc Signed-off-by: Steve French <[email protected]>
1 parent 1654119 commit d08089f

File tree

14 files changed

+1133
-1091
lines changed

14 files changed

+1133
-1091
lines changed

fs/cifs/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ config CIFS
1818
select DNS_RESOLVER
1919
select ASN1
2020
select OID_REGISTRY
21+
select NETFS_SUPPORT
2122
help
2223
This is the client VFS module for the SMB3 family of network file
2324
protocols (including the most recent, most secure dialect SMB3.1.1).

fs/cifs/cifsencrypt.c

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,11 @@ static int cifs_shash_iter(const struct iov_iter *iter, size_t maxsize,
169169
}
170170

171171
int __cifs_calc_signature(struct smb_rqst *rqst,
172-
struct TCP_Server_Info *server, char *signature,
173-
struct shash_desc *shash)
172+
struct TCP_Server_Info *server, char *signature,
173+
struct shash_desc *shash)
174174
{
175175
int i;
176-
int rc;
176+
ssize_t rc;
177177
struct kvec *iov = rqst->rq_iov;
178178
int n_vec = rqst->rq_nvec;
179179

@@ -205,25 +205,9 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
205205
}
206206
}
207207

208-
/* now hash over the rq_pages array */
209-
for (i = 0; i < rqst->rq_npages; i++) {
210-
void *kaddr;
211-
unsigned int len, offset;
212-
213-
rqst_page_get_length(rqst, i, &len, &offset);
214-
215-
kaddr = (char *) kmap(rqst->rq_pages[i]) + offset;
216-
217-
rc = crypto_shash_update(shash, kaddr, len);
218-
if (rc) {
219-
cifs_dbg(VFS, "%s: Could not update with payload\n",
220-
__func__);
221-
kunmap(rqst->rq_pages[i]);
222-
return rc;
223-
}
224-
225-
kunmap(rqst->rq_pages[i]);
226-
}
208+
rc = cifs_shash_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), shash);
209+
if (rc < 0)
210+
return rc;
227211

228212
rc = crypto_shash_final(shash, signature);
229213
if (rc)

fs/cifs/cifsglob.h

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,9 @@ static inline void cifs_free_open_info(struct cifs_open_info_data *data)
212212
struct smb_rqst {
213213
struct kvec *rq_iov; /* array of kvecs */
214214
unsigned int rq_nvec; /* number of kvecs in array */
215-
struct page **rq_pages; /* pointer to array of page ptrs */
216-
unsigned int rq_offset; /* the offset to the 1st page */
217-
unsigned int rq_npages; /* number pages in array */
218-
unsigned int rq_pagesz; /* page size to use */
219-
unsigned int rq_tailsz; /* length of last page */
215+
size_t rq_iter_size; /* Amount of data in ->rq_iter */
216+
struct iov_iter rq_iter; /* Data iterator */
217+
struct xarray rq_buffer; /* Page buffer for encryption */
220218
};
221219

222220
struct mid_q_entry;
@@ -1421,10 +1419,11 @@ struct cifs_aio_ctx {
14211419
struct cifsFileInfo *cfile;
14221420
struct bio_vec *bv;
14231421
loff_t pos;
1424-
unsigned int npages;
1422+
unsigned int nr_pinned_pages;
14251423
ssize_t rc;
14261424
unsigned int len;
14271425
unsigned int total_len;
1426+
unsigned int bv_need_unpin; /* If ->bv[] needs unpinning */
14281427
bool should_dirty;
14291428
/*
14301429
* Indicates if this aio_ctx is for direct_io,
@@ -1442,28 +1441,18 @@ struct cifs_readdata {
14421441
struct address_space *mapping;
14431442
struct cifs_aio_ctx *ctx;
14441443
__u64 offset;
1444+
ssize_t got_bytes;
14451445
unsigned int bytes;
1446-
unsigned int got_bytes;
14471446
pid_t pid;
14481447
int result;
14491448
struct work_struct work;
1450-
int (*read_into_pages)(struct TCP_Server_Info *server,
1451-
struct cifs_readdata *rdata,
1452-
unsigned int len);
1453-
int (*copy_into_pages)(struct TCP_Server_Info *server,
1454-
struct cifs_readdata *rdata,
1455-
struct iov_iter *iter);
1449+
struct iov_iter iter;
14561450
struct kvec iov[2];
14571451
struct TCP_Server_Info *server;
14581452
#ifdef CONFIG_CIFS_SMB_DIRECT
14591453
struct smbd_mr *mr;
14601454
#endif
1461-
unsigned int pagesz;
1462-
unsigned int page_offset;
1463-
unsigned int tailsz;
14641455
struct cifs_credits credits;
1465-
unsigned int nr_pages;
1466-
struct page **pages;
14671456
};
14681457

14691458
/* asynchronous write support */
@@ -1475,6 +1464,8 @@ struct cifs_writedata {
14751464
struct work_struct work;
14761465
struct cifsFileInfo *cfile;
14771466
struct cifs_aio_ctx *ctx;
1467+
struct iov_iter iter;
1468+
struct bio_vec *bv;
14781469
__u64 offset;
14791470
pid_t pid;
14801471
unsigned int bytes;
@@ -1483,12 +1474,7 @@ struct cifs_writedata {
14831474
#ifdef CONFIG_CIFS_SMB_DIRECT
14841475
struct smbd_mr *mr;
14851476
#endif
1486-
unsigned int pagesz;
1487-
unsigned int page_offset;
1488-
unsigned int tailsz;
14891477
struct cifs_credits credits;
1490-
unsigned int nr_pages;
1491-
struct page **pages;
14921478
};
14931479

14941480
/*
@@ -2148,9 +2134,9 @@ static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const
21482134
dst->FileNameLength = src->FileNameLength;
21492135
}
21502136

2151-
static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
2152-
int num_rqst,
2153-
const u8 *sig)
2137+
static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
2138+
int num_rqst,
2139+
const u8 *sig)
21542140
{
21552141
unsigned int len, skip;
21562142
unsigned int nents = 0;
@@ -2170,6 +2156,19 @@ static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
21702156
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
21712157
*/
21722158
for (i = 0; i < num_rqst; i++) {
2159+
/* We really don't want a mixture of pinned and unpinned pages
2160+
* in the sglist. It's hard to keep track of which is what.
2161+
* Instead, we convert to a BVEC-type iterator higher up.
2162+
*/
2163+
if (WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter)))
2164+
return -EIO;
2165+
2166+
/* We also don't want to have any extra refs or pins to clean
2167+
* up in the sglist.
2168+
*/
2169+
if (WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter)))
2170+
return -EIO;
2171+
21732172
for (j = 0; j < rqst[i].rq_nvec; j++) {
21742173
struct kvec *iov = &rqst[i].rq_iov[j];
21752174

@@ -2183,7 +2182,7 @@ static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
21832182
}
21842183
skip = 0;
21852184
}
2186-
nents += rqst[i].rq_npages;
2185+
nents += iov_iter_npages(&rqst[i].rq_iter, INT_MAX);
21872186
}
21882187
nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
21892188
return nents;
@@ -2192,9 +2191,9 @@ static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
21922191
/* We can not use the normal sg_set_buf() as we will sometimes pass a
21932192
* stack object as buf.
21942193
*/
2195-
static inline struct scatterlist *cifs_sg_set_buf(struct scatterlist *sg,
2196-
const void *buf,
2197-
unsigned int buflen)
2194+
static inline void cifs_sg_set_buf(struct sg_table *sgtable,
2195+
const void *buf,
2196+
unsigned int buflen)
21982197
{
21992198
unsigned long addr = (unsigned long)buf;
22002199
unsigned int off = offset_in_page(addr);
@@ -2204,16 +2203,17 @@ static inline struct scatterlist *cifs_sg_set_buf(struct scatterlist *sg,
22042203
do {
22052204
unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
22062205

2207-
sg_set_page(sg++, vmalloc_to_page((void *)addr), len, off);
2206+
sg_set_page(&sgtable->sgl[sgtable->nents++],
2207+
vmalloc_to_page((void *)addr), len, off);
22082208

22092209
off = 0;
22102210
addr += PAGE_SIZE;
22112211
buflen -= len;
22122212
} while (buflen);
22132213
} else {
2214-
sg_set_page(sg++, virt_to_page(addr), buflen, off);
2214+
sg_set_page(&sgtable->sgl[sgtable->nents++],
2215+
virt_to_page(addr), buflen, off);
22152216
}
2216-
return sg;
22172217
}
22182218

22192219
#endif /* _CIFS_GLOB_H */

fs/cifs/cifsproto.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -584,10 +584,7 @@ int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
584584
int cifs_async_writev(struct cifs_writedata *wdata,
585585
void (*release)(struct kref *kref));
586586
void cifs_writev_complete(struct work_struct *work);
587-
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
588-
work_func_t complete);
589-
struct cifs_writedata *cifs_writedata_direct_alloc(struct page **pages,
590-
work_func_t complete);
587+
struct cifs_writedata *cifs_writedata_alloc(work_func_t complete);
591588
void cifs_writedata_release(struct kref *refcount);
592589
int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
593590
struct cifs_sb_info *cifs_sb,
@@ -604,13 +601,10 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
604601
enum securityEnum);
605602
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
606603
void cifs_aio_ctx_release(struct kref *refcount);
607-
int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
608604

609605
int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
610606
void cifs_free_hash(struct shash_desc **sdesc);
611607

612-
void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page,
613-
unsigned int *len, unsigned int *offset);
614608
struct cifs_chan *
615609
cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server);
616610
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses);

fs/cifs/cifssmb.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/task_io_accounting_ops.h>
2525
#include <linux/uaccess.h>
2626
#include "cifspdu.h"
27+
#include "cifsfs.h"
2728
#include "cifsglob.h"
2829
#include "cifsacl.h"
2930
#include "cifsproto.h"
@@ -1294,11 +1295,8 @@ cifs_readv_callback(struct mid_q_entry *mid)
12941295
struct TCP_Server_Info *server = tcon->ses->server;
12951296
struct smb_rqst rqst = { .rq_iov = rdata->iov,
12961297
.rq_nvec = 2,
1297-
.rq_pages = rdata->pages,
1298-
.rq_offset = rdata->page_offset,
1299-
.rq_npages = rdata->nr_pages,
1300-
.rq_pagesz = rdata->pagesz,
1301-
.rq_tailsz = rdata->tailsz };
1298+
.rq_iter_size = iov_iter_count(&rdata->iter),
1299+
.rq_iter = rdata->iter };
13021300
struct cifs_credits credits = { .value = 1, .instance = 0 };
13031301

13041302
cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
@@ -1737,11 +1735,8 @@ cifs_async_writev(struct cifs_writedata *wdata,
17371735

17381736
rqst.rq_iov = iov;
17391737
rqst.rq_nvec = 2;
1740-
rqst.rq_pages = wdata->pages;
1741-
rqst.rq_offset = wdata->page_offset;
1742-
rqst.rq_npages = wdata->nr_pages;
1743-
rqst.rq_pagesz = wdata->pagesz;
1744-
rqst.rq_tailsz = wdata->tailsz;
1738+
rqst.rq_iter = wdata->iter;
1739+
rqst.rq_iter_size = iov_iter_count(&wdata->iter);
17451740

17461741
cifs_dbg(FYI, "async write at %llu %u bytes\n",
17471742
wdata->offset, wdata->bytes);

0 commit comments

Comments
 (0)