From patchwork Mon Dec 12 20:48:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilya Dryomov X-Patchwork-Id: 9471319 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 05138607D3 for ; Mon, 12 Dec 2016 20:50:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EE9D028518 for ; Mon, 12 Dec 2016 20:50:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E36542851D; Mon, 12 Dec 2016 20:50:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3C53F28518 for ; Mon, 12 Dec 2016 20:50:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753153AbcLLUub (ORCPT ); Mon, 12 Dec 2016 15:50:31 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:34643 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932514AbcLLUuO (ORCPT ); Mon, 12 Dec 2016 15:50:14 -0500 Received: by mail-wm0-f67.google.com with SMTP id g23so13807769wme.1 for ; Mon, 12 Dec 2016 12:50:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:in-reply-to:references; bh=oBGqPLMrOhhzKVX4j+suC7A/aSAlpTbRDw3tbzK12Gs=; b=jmEPLee3qeX1rbSU/d6PJXr4xCvGn4R7Ltjs97GA5LpJF8tU6Ryc8F0+cTaCdwYOUg u8OFrE15eAF2P8NIuT44mIdudxIyUrgPO85DgPWky/xeirLLjotKNwYaV+XTvCcXUcua 2jWcjmV4M1SNVqC//bq5uS3Xbf9h3mmMygQryEf+at9VFz6d6ZKpKM0P8D9/qABOBFiH RQG9FJKbhJiFbKMvWxtLT5ldHMF9pvNRcchYSCETX4s+bw46x9SKz2YfQo4FnERRrKED TlVoYEkax8cM//YRqZv0YyS22IM0jbYxyTh2AivqZBI5s6p0Aov/t8L4+ZhYXyVxGbva tzZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=oBGqPLMrOhhzKVX4j+suC7A/aSAlpTbRDw3tbzK12Gs=; b=FaYxbha5WH2P1SW3cIVtTwzD0HVUWbRz5a9tuiIfQqBTZ3b7skd/nkkQEWgjJ9Mk86 Ez2AzVYOQczo5WPZrK1glCCtkTeJ0DmoFJMnTdNOs8MKnK3GLV+F6qBJsHgvs4va4PBS RuOh2HOq4igS2hbBBGVAH5R556Js4OPQTtMMYPClZySK8IserHw5Yj8N0lMbW0kb0Czf pFRL0etsAnQzwJwDkR9hdUFzuj0TFt6mrl28/1csNWYTgWMpe5QBc5TmfHFJuPo9HXHF msGc/QnAG96DVDurSy7mhiVgmSkMw0yijhTO2LHxdRz0OugjmJXw0/BkdipiaLkNL7l7 KyCQ== X-Gm-Message-State: AKaTC01sjaSxhkB2vUBR5O4nNL9EIIq6XJmmLqKtedxuL821+HgzVasY+U2qsfuyDr1cqg== X-Received: by 10.28.63.16 with SMTP id m16mr20135453wma.113.1481575812586; Mon, 12 Dec 2016 12:50:12 -0800 (PST) Received: from dhcp-1-105.brq.redhat.com ([213.175.37.12]) by smtp.gmail.com with ESMTPSA id 135sm37201887wmh.14.2016.12.12.12.50.11 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 12 Dec 2016 12:50:12 -0800 (PST) From: Ilya Dryomov To: ceph-devel@vger.kernel.org Subject: [PATCH 11/15] libceph: stop allocating a new cipher on every crypto request Date: Mon, 12 Dec 2016 21:48:56 +0100 Message-Id: <1481575740-1834-12-git-send-email-idryomov@gmail.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1481575740-1834-1-git-send-email-idryomov@gmail.com> References: <1481575740-1834-1-git-send-email-idryomov@gmail.com> Sender: ceph-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This is useless and more importantly not allowed on the writeback path, because crypto_alloc_skcipher() allocates memory with GFP_KERNEL, which can recurse back into the filesystem: kworker/9:3 D ffff92303f318180 0 20732 2 0x00000080 Workqueue: ceph-msgr ceph_con_workfn [libceph] ffff923035dd4480 ffff923038f8a0c0 0000000000000001 000000009eb27318 ffff92269eb28000 ffff92269eb27338 ffff923036b145ac ffff923035dd4480 00000000ffffffff ffff923036b145b0 ffffffff951eb4e1 ffff923036b145a8 Call Trace: [] ? schedule+0x31/0x80 [] ? schedule_preempt_disabled+0xa/0x10 [] ? __mutex_lock_slowpath+0xb4/0x130 [] ? mutex_lock+0x1b/0x30 [] ? xfs_reclaim_inodes_ag+0x233/0x2d0 [xfs] [] ? move_active_pages_to_lru+0x125/0x270 [] ? radix_tree_gang_lookup_tag+0xc5/0x1c0 [] ? __list_lru_walk_one.isra.3+0x33/0x120 [] ? xfs_reclaim_inodes_nr+0x31/0x40 [xfs] [] ? super_cache_scan+0x17e/0x190 [] ? shrink_slab.part.38+0x1e3/0x3d0 [] ? shrink_node+0x10a/0x320 [] ? do_try_to_free_pages+0xf4/0x350 [] ? try_to_free_pages+0xea/0x1b0 [] ? __alloc_pages_nodemask+0x61d/0xe60 [] ? cache_grow_begin+0x9d/0x560 [] ? fallback_alloc+0x148/0x1c0 [] ? __crypto_alloc_tfm+0x37/0x130 [] ? __kmalloc+0x1eb/0x580 [] ? crush_choose_firstn+0x3eb/0x470 [libceph] [] ? __crypto_alloc_tfm+0x37/0x130 [] ? crypto_spawn_tfm+0x39/0x60 [] ? crypto_cbc_init_tfm+0x23/0x40 [cbc] [] ? __crypto_alloc_tfm+0xcc/0x130 [] ? crypto_skcipher_init_tfm+0x113/0x180 [] ? crypto_create_tfm+0x43/0xb0 [] ? crypto_larval_lookup+0x150/0x150 [] ? crypto_alloc_tfm+0x72/0x120 [] ? ceph_aes_encrypt2+0x67/0x400 [libceph] [] ? ceph_pg_to_up_acting_osds+0x84/0x5b0 [libceph] [] ? release_sock+0x40/0x90 [] ? tcp_recvmsg+0x4b4/0xae0 [] ? ceph_encrypt2+0x54/0xc0 [libceph] [] ? ceph_x_encrypt+0x5d/0x90 [libceph] [] ? calcu_signature+0x5f/0x90 [libceph] [] ? ceph_x_sign_message+0x35/0x50 [libceph] [] ? prepare_write_message_footer+0x5c/0xa0 [libceph] [] ? ceph_con_workfn+0x2258/0x2dd0 [libceph] [] ? queue_con_delay+0x33/0xd0 [libceph] [] ? __submit_request+0x20d/0x2f0 [libceph] [] ? ceph_osdc_start_request+0x28/0x30 [libceph] [] ? rbd_queue_workfn+0x2f3/0x350 [rbd] [] ? process_one_work+0x160/0x410 [] ? worker_thread+0x4d/0x480 [] ? process_one_work+0x410/0x410 [] ? kthread+0xcd/0xf0 [] ? ret_from_fork+0x1f/0x40 [] ? kthread_create_on_node+0x190/0x190 Allocating the cipher along with the key fixes the issue - as long the key doesn't change, a single cipher context can be used concurrently in multiple requests. We still can't take that GFP_KERNEL allocation though. Both ceph_crypto_key_clone() and ceph_crypto_key_decode() are called from GFP_NOFS context, so resort to memalloc_noio_{save,restore}() here. Reported-by: Lucas Stach Signed-off-by: Ilya Dryomov --- net/ceph/crypto.c | 85 +++++++++++++++++++++++++++++++++++++++---------------- net/ceph/crypto.h | 1 + 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index c4d8f68e0b18..3949ce70be07 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -13,14 +13,60 @@ #include #include "crypto.h" +/* + * Set ->key and ->tfm. The rest of the key should be filled in before + * this function is called. + */ +static int set_secret(struct ceph_crypto_key *key, void *buf) +{ + unsigned int noio_flag; + int ret; + + key->key = NULL; + key->tfm = NULL; + + switch (key->type) { + case CEPH_CRYPTO_NONE: + return 0; /* nothing to do */ + case CEPH_CRYPTO_AES: + break; + default: + return -ENOTSUPP; + } + + WARN_ON(!key->len); + key->key = kmemdup(buf, key->len, GFP_NOIO); + if (!key->key) { + ret = -ENOMEM; + goto fail; + } + + /* crypto_alloc_skcipher() allocates with GFP_KERNEL */ + noio_flag = memalloc_noio_save(); + key->tfm = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); + memalloc_noio_restore(noio_flag); + if (IS_ERR(key->tfm)) { + ret = PTR_ERR(key->tfm); + key->tfm = NULL; + goto fail; + } + + ret = crypto_skcipher_setkey(key->tfm, key->key, key->len); + if (ret) + goto fail; + + return 0; + +fail: + ceph_crypto_key_destroy(key); + return ret; +} + int ceph_crypto_key_clone(struct ceph_crypto_key *dst, const struct ceph_crypto_key *src) { memcpy(dst, src, sizeof(struct ceph_crypto_key)); - dst->key = kmemdup(src->key, src->len, GFP_NOFS); - if (!dst->key) - return -ENOMEM; - return 0; + return set_secret(dst, src->key); } int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end) @@ -37,16 +83,16 @@ int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end) int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end) { + int ret; + ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad); key->type = ceph_decode_16(p); ceph_decode_copy(p, &key->created, sizeof(key->created)); key->len = ceph_decode_16(p); ceph_decode_need(p, end, key->len, bad); - key->key = kmalloc(key->len, GFP_NOFS); - if (!key->key) - return -ENOMEM; - ceph_decode_copy(p, key->key, key->len); - return 0; + ret = set_secret(key, *p); + *p += key->len; + return ret; bad: dout("failed to decode crypto key\n"); @@ -85,14 +131,11 @@ void ceph_crypto_key_destroy(struct ceph_crypto_key *key) if (key) { kfree(key->key); key->key = NULL; + crypto_free_skcipher(key->tfm); + key->tfm = NULL; } } -static struct crypto_skcipher *ceph_crypto_alloc_cipher(void) -{ - return crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); -} - static const u8 *aes_iv = (u8 *)CEPH_AES_IV; /* @@ -168,8 +211,7 @@ static void teardown_sgtable(struct sg_table *sgt) static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt, void *buf, int buf_len, int in_len, int *pout_len) { - struct crypto_skcipher *tfm = ceph_crypto_alloc_cipher(); - SKCIPHER_REQUEST_ON_STACK(req, tfm); + SKCIPHER_REQUEST_ON_STACK(req, key->tfm); struct sg_table sgt; struct scatterlist prealloc_sg; char iv[AES_BLOCK_SIZE]; @@ -177,20 +219,15 @@ static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt, int crypt_len = encrypt ? in_len + pad_byte : in_len; int ret; - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - WARN_ON(crypt_len > buf_len); if (encrypt) memset(buf + in_len, pad_byte, pad_byte); ret = setup_sgtable(&sgt, &prealloc_sg, buf, crypt_len); if (ret) - goto out_tfm; + return ret; - crypto_skcipher_setkey((void *)tfm, key->key, key->len); memcpy(iv, aes_iv, AES_BLOCK_SIZE); - - skcipher_request_set_tfm(req, tfm); + skcipher_request_set_tfm(req, key->tfm); skcipher_request_set_callback(req, 0, NULL, NULL); skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv); @@ -232,8 +269,6 @@ static int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt, out_sgt: teardown_sgtable(&sgt); -out_tfm: - crypto_free_skcipher(tfm); return ret; } diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h index c4211590b721..58d83aa7740f 100644 --- a/net/ceph/crypto.h +++ b/net/ceph/crypto.h @@ -12,6 +12,7 @@ struct ceph_crypto_key { struct ceph_timespec created; int len; void *key; + struct crypto_skcipher *tfm; }; int ceph_crypto_key_clone(struct ceph_crypto_key *dst,