From patchwork Thu Sep 5 20:22:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 11133911 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E66C517E0 for ; Thu, 5 Sep 2019 20:22:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6936B20825 for ; Thu, 5 Sep 2019 20:22:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lIEa2DK1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389823AbfIEUWb (ORCPT ); Thu, 5 Sep 2019 16:22:31 -0400 Received: from mail-io1-f50.google.com ([209.85.166.50]:43688 "EHLO mail-io1-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389678AbfIEUWb (ORCPT ); Thu, 5 Sep 2019 16:22:31 -0400 Received: by mail-io1-f50.google.com with SMTP id u185so7685951iod.10 for ; Thu, 05 Sep 2019 13:22:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=8D6FuQXYV0uaDcUmZnFqujn9eeJ8hk7TXTK7/PtYQgw=; b=lIEa2DK1bLq10R+KueM3iaylDtUPP1D4hYE7R8lEKhd3ho1JIH5sazThYRz1ohtXko rX5/ydFxtq3udiseWkz7IZLdgi5fMhqG7IFHzsuwuCUdF7GV4rvlnZK14o24oC4U0B4o r0w4Tkxulf9GEAmCis09B8DwJyOitwbvcVSMdhRNnM5euSInjcFl4khNTuMTKJXxSc2H bjk0Z8d4YTvoEZiLgCkJ1aubMseu7SyPvL8cWY3J3ORsW0c0xBwvsZfp5/dMZU0YKNiv IxajrVdIKw3cOtr3lqvDOKQB5lDz4itC9ekNQNJdOwbaTkDtFP1WVZMt1Q015G1G1Q4P i78Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=8D6FuQXYV0uaDcUmZnFqujn9eeJ8hk7TXTK7/PtYQgw=; b=pYhvbGTI63N5X+yE3pik9WJfeXIxNXfyldjIFGnwCs360Aa5hBD7C4MGKsQJsyrISE tEJNehXbeMGBsib7iiHDz5bpuf18Hx6ISpz58B0QAs8yeUOQ2TVDe/eSkFvyd448dtJP WASAdXSz10ryY7PurnyJ1lYsW6dUYiYzsM+GUOcn35Y6JYMO02hUdgpIv09T0bEq/tid MMbo/sPzjfI3S97ZcHz4oQW4qkLEnatadXMI9Ge50rcmxk1+s0/A0TGVW9qgHL8grtIn jrGXJEO3oTfdBmj2HCXZ6Vpo0k7fUA83gRXfsVbHKWWPvn0XZyspemg/6S1hljB9Oyge tbMw== X-Gm-Message-State: APjAAAX7AvZ59d8Q4ga2W4ZPc/Mlzuc17aBCA0v0fJx1WWErT3KKK5hI 76/ArjEMDVaRdA/OZgJNNO3+SLtDtqbit/WTB77xoJbb X-Google-Smtp-Source: APXvYqzdwqfAlJUCSrToS5X7rVY5JhrEPHhADlhNLkl1sUEIhaBZWKe6Z91v5fWcRIICKLFen/bunxFcGQJOYHc/t6Y= X-Received: by 2002:a5d:9c4c:: with SMTP id 12mr5872008iof.5.1567714949778; Thu, 05 Sep 2019 13:22:29 -0700 (PDT) MIME-Version: 1.0 From: Steve French Date: Thu, 5 Sep 2019 15:22:19 -0500 Message-ID: Subject: decrypt large read offload patch To: CIFS Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org I am getting EBADMSG from the call (in crypt_message in smb2ops.c) to crypto_wait_req when trying to decrypt a 512K array of pages from an SMB3 read in a worker thread (rather than in the usual cifsd thread which works) - see attached patch (doesn't fail with non-offload case). Any obvious bug anyone spots here? Looking at the crypto library for CCM wasn't exactly clear to me what could be going on diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index de90e665ef11..0bd68b0c9e36 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -109,6 +109,7 @@ extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_mid_poolp; struct workqueue_struct *cifsiod_wq; +struct workqueue_struct *decrypt_wq; struct workqueue_struct *cifsoplockd_wq; __u32 cifs_lock_secret; @@ -1499,11 +1500,19 @@ init_cifs(void) goto out_clean_proc; } + /* BB Consider set limit!=0 so don't launch too many worker threads */ + decrypt_wq = alloc_workqueue("smb3decryptd", + WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); + if (!decrypt_wq) { + rc = -ENOMEM; + goto out_destroy_cifsiod_wq; + } + cifsoplockd_wq = alloc_workqueue("cifsoplockd", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); if (!cifsoplockd_wq) { rc = -ENOMEM; - goto out_destroy_cifsiod_wq; + goto out_destroy_decrypt_wq; } rc = cifs_fscache_register(); @@ -1569,6 +1578,8 @@ init_cifs(void) cifs_fscache_unregister(); out_destroy_cifsoplockd_wq: destroy_workqueue(cifsoplockd_wq); +out_destroy_decrypt_wq: + destroy_workqueue(decrypt_wq); out_destroy_cifsiod_wq: destroy_workqueue(cifsiod_wq); out_clean_proc: @@ -1595,6 +1606,7 @@ exit_cifs(void) cifs_destroy_inodecache(); cifs_fscache_unregister(); destroy_workqueue(cifsoplockd_wq); + destroy_workqueue(decrypt_wq); destroy_workqueue(cifsiod_wq); cifs_proc_clean(); } 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); extern const struct slow_work_ops cifs_oplock_break_ops; extern struct workqueue_struct *cifsiod_wq; +extern struct workqueue_struct *decrypt_wq; extern struct workqueue_struct *cifsoplockd_wq; extern __u32 cifs_lock_secret; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 070d0b7b21dc..4f985f517bbb 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3683,6 +3683,8 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst, if (!rc && enc) memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); + else + cifs_dbg(VFS, "crypto_wait_req returned %d with enc %d\n", rc, enc); /* BB REMOVEME */ kfree(iv); free_sg: @@ -3814,7 +3816,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char *buf, rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE; rc = crypt_message(server, 1, &rqst, 0); - cifs_dbg(FYI, "Decrypt message returned %d\n", rc); + cifs_dbg(VFS, "Decrypt message returned %d with pages %p npages %d tailsz %d\n", rc, pages, npages, rqst.rq_tailsz); /* BB REMOVEME */ if (rc) return rc; @@ -4017,8 +4019,65 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, return length; } +struct smb2_decrypt_work { + struct work_struct decrypt; + struct TCP_Server_Info *server; + struct page **ppages; + char *buf; + unsigned int npages; + unsigned int len; +}; + + +static void smb2_decrypt_offload(struct work_struct *work) +{ + struct smb2_decrypt_work *dw = container_of(work, + struct smb2_decrypt_work, decrypt); + int i, rc; + struct mid_q_entry *mid; + + rc = decrypt_raw_data(dw->server, dw->buf, dw->server->vals->read_rsp_size, + dw->ppages, dw->npages, dw->len); + if (rc) { + cifs_dbg(VFS, "error decrypting rc=%d\n", rc); + goto free_pages; + } + + mid = smb2_find_mid(dw->server, dw->buf); + if (mid == NULL) + cifs_dbg(VFS, "mid not found\n"); + else { + cifs_dbg(VFS, "mid found %lld\n", mid->mid); /* BB removeme */ + mid->decrypted = true; + rc = handle_read_data(dw->server, mid, dw->buf, + dw->server->vals->read_rsp_size, + dw->ppages, dw->npages, dw->len); + } + + dw->server->lstrp = jiffies; + + mid->callback(mid); + + cifs_mid_q_entry_release(mid); + +free_pages: + /* BB TODO double check that we are freeing the right number of pages */ + for (i = dw->npages; i >= 0; i--) { + cifs_dbg(VFS, "free page %d %p\n", i, dw->ppages[i-1]); + put_page(dw->ppages[i-1]); + msleep(10); + } + kfree(dw->buf); +/* FIXME */ +/* discard_data: + cifs_discard_remaining_data(server); + goto free_pages; */ +} + + static int -receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) +receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, + int *num_mids) { char *buf = server->smallbuf; struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf; @@ -4028,7 +4087,9 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) unsigned int buflen = server->pdu_size; int rc; int i = 0; + struct smb2_decrypt_work *dw; + *num_mids = 1; len = min_t(unsigned int, buflen, server->vals->read_rsp_size + sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1; @@ -4064,6 +4125,33 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) if (rc) goto free_pages; + /* + * For large reads, offload to different thread for better performance, + * use more cores decrypting which can be expensive + */ + + if (server->pdu_size > (512 * 1024)) { + dw = kmalloc(sizeof(struct smb2_decrypt_work), GFP_KERNEL); + if (dw == NULL) + goto non_offloaded_decrypt; + dw->buf = kmalloc(sizeof(struct smb2_transform_hdr), GFP_KERNEL); + if (dw->buf == NULL) { + kfree(dw); + goto non_offloaded_decrypt; + } + memcpy(dw->buf, buf, sizeof(struct smb2_transform_hdr)); + INIT_WORK(&dw->decrypt, smb2_decrypt_offload); + + dw->npages = npages; + dw->server = server; + dw->ppages = pages; + dw->len = len; + queue_work(cifsiod_wq, &dw->decrypt); + *num_mids = 0; /* worker thread takes care of finding mid */ + return -1; + } + +non_offloaded_decrypt: rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size, pages, npages, len); if (rc) @@ -4210,8 +4298,7 @@ smb3_receive_transform(struct TCP_Server_Info *server, /* TODO: add support for compounds containing READ. */ if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) { - *num_mids = 1; - return receive_encrypted_read(server, &mids[0]); + return receive_encrypted_read(server, &mids[0], num_mids); } return receive_encrypted_standard(server, mids, bufs, num_mids);