summaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <stfrench@microsoft.com>2019-09-07 02:09:49 -0400
committerSteve French <stfrench@microsoft.com>2019-09-16 12:43:38 -0400
commit35cf94a397280b9e27576ac1480f631bdd3e7b70 (patch)
treeeed59267fe903c092e9ec7e7e6e710f861c295de /fs/cifs
parent3175eb9b577e82b44a25ad2d515ec9418ae06c04 (diff)
smb3: allow parallelizing decryption of reads
decrypting large reads on encrypted shares can be slow (e.g. adding multiple milliseconds per-read on non-GCM capable servers or when mounting with dialects prior to SMB3.1.1) - allow parallelizing of read decryption by launching worker threads. Testing to Samba on localhost showed 25% improvement. Testing to remote server showed very large improvement when doing more than one 'cp' command was called at one time. Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsfs.c17
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/smb2ops.c83
3 files changed, 97 insertions, 4 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index de90e665ef11..b0ea332af35c 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -109,6 +109,7 @@ extern mempool_t *cifs_req_poolp;
109extern mempool_t *cifs_mid_poolp; 109extern mempool_t *cifs_mid_poolp;
110 110
111struct workqueue_struct *cifsiod_wq; 111struct workqueue_struct *cifsiod_wq;
112struct workqueue_struct *decrypt_wq;
112struct workqueue_struct *cifsoplockd_wq; 113struct workqueue_struct *cifsoplockd_wq;
113__u32 cifs_lock_secret; 114__u32 cifs_lock_secret;
114 115
@@ -1499,11 +1500,22 @@ init_cifs(void)
1499 goto out_clean_proc; 1500 goto out_clean_proc;
1500 } 1501 }
1501 1502
1503 /*
1504 * BB Consider setting limit!=0 maybe to min(num_of_cores - 1, 3) so we
1505 * don't launch too many worker threads
1506 */
1507 decrypt_wq = alloc_workqueue("smb3decryptd",
1508 WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
1509 if (!decrypt_wq) {
1510 rc = -ENOMEM;
1511 goto out_destroy_cifsiod_wq;
1512 }
1513
1502 cifsoplockd_wq = alloc_workqueue("cifsoplockd", 1514 cifsoplockd_wq = alloc_workqueue("cifsoplockd",
1503 WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); 1515 WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
1504 if (!cifsoplockd_wq) { 1516 if (!cifsoplockd_wq) {
1505 rc = -ENOMEM; 1517 rc = -ENOMEM;
1506 goto out_destroy_cifsiod_wq; 1518 goto out_destroy_decrypt_wq;
1507 } 1519 }
1508 1520
1509 rc = cifs_fscache_register(); 1521 rc = cifs_fscache_register();
@@ -1569,6 +1581,8 @@ out_unreg_fscache:
1569 cifs_fscache_unregister(); 1581 cifs_fscache_unregister();
1570out_destroy_cifsoplockd_wq: 1582out_destroy_cifsoplockd_wq:
1571 destroy_workqueue(cifsoplockd_wq); 1583 destroy_workqueue(cifsoplockd_wq);
1584out_destroy_decrypt_wq:
1585 destroy_workqueue(decrypt_wq);
1572out_destroy_cifsiod_wq: 1586out_destroy_cifsiod_wq:
1573 destroy_workqueue(cifsiod_wq); 1587 destroy_workqueue(cifsiod_wq);
1574out_clean_proc: 1588out_clean_proc:
@@ -1595,6 +1609,7 @@ exit_cifs(void)
1595 cifs_destroy_inodecache(); 1609 cifs_destroy_inodecache();
1596 cifs_fscache_unregister(); 1610 cifs_fscache_unregister();
1597 destroy_workqueue(cifsoplockd_wq); 1611 destroy_workqueue(cifsoplockd_wq);
1612 destroy_workqueue(decrypt_wq);
1598 destroy_workqueue(cifsiod_wq); 1613 destroy_workqueue(cifsiod_wq);
1599 cifs_proc_clean(); 1614 cifs_proc_clean();
1600} 1615}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1f53dee211d8..d66106ac031a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1892,6 +1892,7 @@ void cifs_queue_oplock_break(struct cifsFileInfo *cfile);
1892 1892
1893extern const struct slow_work_ops cifs_oplock_break_ops; 1893extern const struct slow_work_ops cifs_oplock_break_ops;
1894extern struct workqueue_struct *cifsiod_wq; 1894extern struct workqueue_struct *cifsiod_wq;
1895extern struct workqueue_struct *decrypt_wq;
1895extern struct workqueue_struct *cifsoplockd_wq; 1896extern struct workqueue_struct *cifsoplockd_wq;
1896extern __u32 cifs_lock_secret; 1897extern __u32 cifs_lock_secret;
1897 1898
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 83b02d74d48e..c74284484947 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -4017,8 +4017,58 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
4017 return length; 4017 return length;
4018} 4018}
4019 4019
4020struct smb2_decrypt_work {
4021 struct work_struct decrypt;
4022 struct TCP_Server_Info *server;
4023 struct page **ppages;
4024 char *buf;
4025 unsigned int npages;
4026 unsigned int len;
4027};
4028
4029
4030static void smb2_decrypt_offload(struct work_struct *work)
4031{
4032 struct smb2_decrypt_work *dw = container_of(work,
4033 struct smb2_decrypt_work, decrypt);
4034 int i, rc;
4035 struct mid_q_entry *mid;
4036
4037 rc = decrypt_raw_data(dw->server, dw->buf, dw->server->vals->read_rsp_size,
4038 dw->ppages, dw->npages, dw->len);
4039 if (rc) {
4040 cifs_dbg(VFS, "error decrypting rc=%d\n", rc);
4041 goto free_pages;
4042 }
4043
4044 mid = smb2_find_mid(dw->server, dw->buf);
4045 if (mid == NULL)
4046 cifs_dbg(FYI, "mid not found\n");
4047 else {
4048 mid->decrypted = true;
4049 rc = handle_read_data(dw->server, mid, dw->buf,
4050 dw->server->vals->read_rsp_size,
4051 dw->ppages, dw->npages, dw->len);
4052 }
4053
4054 dw->server->lstrp = jiffies;
4055
4056 mid->callback(mid);
4057
4058 cifs_mid_q_entry_release(mid);
4059
4060free_pages:
4061 for (i = dw->npages-1; i >= 0; i--)
4062 put_page(dw->ppages[i]);
4063
4064 kfree(dw->ppages);
4065 cifs_small_buf_release(dw->buf);
4066}
4067
4068
4020static int 4069static int
4021receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) 4070receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
4071 int *num_mids)
4022{ 4072{
4023 char *buf = server->smallbuf; 4073 char *buf = server->smallbuf;
4024 struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf; 4074 struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
@@ -4028,7 +4078,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
4028 unsigned int buflen = server->pdu_size; 4078 unsigned int buflen = server->pdu_size;
4029 int rc; 4079 int rc;
4030 int i = 0; 4080 int i = 0;
4081 struct smb2_decrypt_work *dw;
4031 4082
4083 *num_mids = 1;
4032 len = min_t(unsigned int, buflen, server->vals->read_rsp_size + 4084 len = min_t(unsigned int, buflen, server->vals->read_rsp_size +
4033 sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1; 4085 sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
4034 4086
@@ -4064,6 +4116,32 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid)
4064 if (rc) 4116 if (rc)
4065 goto free_pages; 4117 goto free_pages;
4066 4118
4119 /*
4120 * For large reads, offload to different thread for better performance,
4121 * use more cores decrypting which can be expensive
4122 */
4123
4124 /* TODO: make the size limit to enable decrypt offload configurable */
4125 if (server->pdu_size > (512 * 1024)) {
4126 dw = kmalloc(sizeof(struct smb2_decrypt_work), GFP_KERNEL);
4127 if (dw == NULL)
4128 goto non_offloaded_decrypt;
4129
4130 dw->buf = server->smallbuf;
4131 server->smallbuf = (char *)cifs_small_buf_get();
4132
4133 INIT_WORK(&dw->decrypt, smb2_decrypt_offload);
4134
4135 dw->npages = npages;
4136 dw->server = server;
4137 dw->ppages = pages;
4138 dw->len = len;
4139 queue_work(cifsiod_wq, &dw->decrypt);
4140 *num_mids = 0; /* worker thread takes care of finding mid */
4141 return -1;
4142 }
4143
4144non_offloaded_decrypt:
4067 rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size, 4145 rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size,
4068 pages, npages, len); 4146 pages, npages, len);
4069 if (rc) 4147 if (rc)
@@ -4210,8 +4288,7 @@ smb3_receive_transform(struct TCP_Server_Info *server,
4210 4288
4211 /* TODO: add support for compounds containing READ. */ 4289 /* TODO: add support for compounds containing READ. */
4212 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) { 4290 if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) {
4213 *num_mids = 1; 4291 return receive_encrypted_read(server, &mids[0], num_mids);
4214 return receive_encrypted_read(server, &mids[0]);
4215 } 4292 }
4216 4293
4217 return receive_encrypted_standard(server, mids, bufs, num_mids); 4294 return receive_encrypted_standard(server, mids, bufs, num_mids);