From nobody Thu Oct 2 20:46:25 2025 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8AD826E16C for ; Thu, 11 Sep 2025 07:32:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757575934; cv=none; b=QAFgD1LeDaWEGLN1EFzUaRNEbpI/UNOh7VTwQ8serQdV5yhRu/WZJrew3vA2QGRc4ibdLZDP5NvqBMfpy/TmUdbZvCA2dqlifqRR+fWNQ1xkDAjftNH61fg7sAiVItX2C1EqcN038Fl5hEnIJ/FZ4a7m8lzV8qYz4DtZDcuAcaQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757575934; c=relaxed/simple; bh=LvP6xvP6ZpqgZqS6HIHSDKtto3Kcjz+TrfwBMvXJT9k=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=u77BighUGFzd8ZREMzUwP0tKAFj/0jLF2IRLYIvCgph9pk1GN+wSSLk59e+wqYC3llInSyjR1O5xN0SVYkFm1LOnWrU73GlmG7zg6Xln/YAAFKRbCeR1hqVR1p6COigLRkWRa66J7vwgufum+3JegyaNgbtTTohw93/eGQkXN3s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw; spf=pass smtp.mailfrom=gms.tku.edu.tw; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b=k50nhQrr; arc=none smtp.client-ip=209.85.214.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b="k50nhQrr" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-2445806e03cso4676925ad.1 for ; Thu, 11 Sep 2025 00:32:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gms-tku-edu-tw.20230601.gappssmtp.com; s=20230601; t=1757575932; x=1758180732; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GZBzkNSMlmIkXR7v+DqjmX4bPRcIBLEhcOlgv/ZqaSw=; b=k50nhQrrVm3DVAFhHz1sT0VyRdwLo7eagqLRFFGU4M4mvA6a9p+1kvYuozO0W8Z/+t zTOVKSZwz9o9oLNiG0oVez/Bx2Kl2h/bzZzDmdcKjuTZ48ioBbv8PDfTmfgn5tdc6Y/F 4ntLthC4L28Ret5KeFpGiXSckQc0buHrK/9ipCppmkxxaG0xpVKpAfWXUPYOg4SjMY3I ZoofkrXmaQbFMtGHquAVFJ2t2VrKf4YoqC8lk95+99dtcHYUQcvdToctMDvl/YsON/Iq +93Lu0MvHa0a+ozQ8l4HW0/TROz3KLV+kQAcSgiYBX+dY31vsppu/HE+gOIMl7zjzm5J tHyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757575932; x=1758180732; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GZBzkNSMlmIkXR7v+DqjmX4bPRcIBLEhcOlgv/ZqaSw=; b=VlPRkV9YydKLyDdJe5sGnt5DxbUVSSkEk5isfN4yx9ncAIXiUVXqDeIpxlRiIGQady ozCD4avcjGHRMPbbvFB2D8mdXzK2vQYNWPu2DuFjSKVgPoSsskopMOenwjKCv6x883Mh iSkrJ8bH2QYIs9H7COTSucxpQr8OyqvnjgZiQu+PGk3eCY7drhaApoE/+icejF5Y12SP 66SmmRyUiEVMA09fo4COw7JYcWVTgLK1hKIx83/CQodHc/MTaJ4mJkOGZrip93WihRc5 FDdwcNzoAGPLcdgztm/sG7gnrcOBI55v1gtLdPkbNIrJLw4eFBmLe9Vyu7JvAK+UVnq/ LRzg== X-Forwarded-Encrypted: i=1; AJvYcCXL5RTGnf9hZ6VzeI51lBaYJaSZSMKMwGsf0z6AkW6ERbOU03kzc70mahfjQHJvcSaDNdgo/dE062V/WFE=@vger.kernel.org X-Gm-Message-State: AOJu0YwRPigrHVG+YOtkBoFj/doyv78/jeBUb+yoEatA2dNf8mpImB2H 0qT/xnGx9zizVmeZfnPY6o5yi6bjejK5fhCgD9LhPSMq/rkLD3r0nZv6gU398m7sLH5m4RrCju2 eJ4y4tfw= X-Gm-Gg: ASbGncs3KvPAVRzWzc/IEXFXKkcwsWWctJGH4x3WqEm4XSwoZNb3AaJecjOALWkyV56 7XXrzXEnC3l0/vwEH4wLDqbV8UcN2rBxgBjmnfoLSp/Eu4nlQGDCFdjygRLLk+64nDfcJRK0ALy mW9hd3citQn5YHHE5i+I+eWYMPOvOlbPt0rhpHL7wvBNgy0Pjf+DPs6vILHRiyzySdQD2mXaMyn OcggEMFKnwfXVCaD86ZxrOK5q+PBnm5SLvWVRX8wud+QBN0P1hHcnN+dgkljBWvuyP/69vtJWmE O60C3S8qpg4Eousk5G3qrBh8v5ugE89kRA84XjVeG+mub7dTeaNh/IHlj9kmeu17Sm2M1hUCvVC /+H5oSWOrPvzj4mr5vD6eWQYYkt4pKAVFMLClXNOBdXgzBSw= X-Google-Smtp-Source: AGHT+IHb3fEzi2I0Xw68tnhgTa5p89puCkcqtSm1frcG1ldvJKNL158VkcHDDriI2alZgWwrHA5Yrw== X-Received: by 2002:a17:903:990:b0:242:9be2:f67a with SMTP id d9443c01a7336-2516d52cef2mr261971415ad.11.1757575931815; Thu, 11 Sep 2025 00:32:11 -0700 (PDT) Received: from wu-Pro-E500-G6-WS720T.. ([2001:288:7001:2703:7811:c085:c184:85be]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c3ab4345csm9667835ad.96.2025.09.11.00.32.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Sep 2025 00:32:10 -0700 (PDT) From: Guan-Chun Wu <409411716@gms.tku.edu.tw> To: 409411716@gms.tku.edu.tw Cc: akpm@linux-foundation.org, axboe@kernel.dk, ceph-devel@vger.kernel.org, ebiggers@kernel.org, hch@lst.de, home7438072@gmail.com, idryomov@gmail.com, jaegeuk@kernel.org, kbusch@kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, linux-nvme@lists.infradead.org, sagi@grimberg.me, tytso@mit.edu, visitorckw@gmail.com, xiubli@redhat.com Subject: [PATCH v2 1/5] lib/base64: Replace strchr() for better performance Date: Thu, 11 Sep 2025 15:32:04 +0800 Message-Id: <20250911073204.574742-1-409411716@gms.tku.edu.tw> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250911072925.547163-1-409411716@gms.tku.edu.tw> References: <20250911072925.547163-1-409411716@gms.tku.edu.tw> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Kuan-Wei Chiu The base64 decoder previously relied on strchr() to locate each character in the base64 table. In the worst case, this requires scanning all 64 entries, and even with bitwise tricks or word-sized comparisons, still needs up to 8 checks. Introduce a small helper function that maps input characters directly to their position in the base64 table. This reduces the maximum number of comparisons to 5, improving decoding efficiency while keeping the logic straightforward. Benchmarks on x86_64 (Intel Core i7-10700 @ 2.90GHz, averaged over 1000 runs, tested with KUnit): Decode: - 64B input: avg ~1530ns -> ~126ns (~12x faster) - 1KB input: avg ~27726ns -> ~2003ns (~14x faster) Signed-off-by: Kuan-Wei Chiu Co-developed-by: Guan-Chun Wu <409411716@gms.tku.edu.tw> Signed-off-by: Guan-Chun Wu <409411716@gms.tku.edu.tw> --- lib/base64.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/base64.c b/lib/base64.c index b736a7a43..9416bded2 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -18,6 +18,21 @@ static const char base64_table[65] =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; =20 +static inline const char *find_chr(const char *base64_table, char ch) +{ + if ('A' <=3D ch && ch <=3D 'Z') + return base64_table + ch - 'A'; + if ('a' <=3D ch && ch <=3D 'z') + return base64_table + 26 + ch - 'a'; + if ('0' <=3D ch && ch <=3D '9') + return base64_table + 26 * 2 + ch - '0'; + if (ch =3D=3D base64_table[26 * 2 + 10]) + return base64_table + 26 * 2 + 10; + if (ch =3D=3D base64_table[26 * 2 + 10 + 1]) + return base64_table + 26 * 2 + 10 + 1; + return NULL; +} + /** * base64_encode() - base64-encode some binary data * @src: the binary data to encode @@ -78,7 +93,7 @@ int base64_decode(const char *src, int srclen, u8 *dst) u8 *bp =3D dst; =20 for (i =3D 0; i < srclen; i++) { - const char *p =3D strchr(base64_table, src[i]); + const char *p =3D find_chr(base64_table, src[i]); =20 if (src[i] =3D=3D '=3D') { ac =3D (ac << 6); --=20 2.34.1 From nobody Thu Oct 2 20:46:25 2025 Received: from mail-pl1-f170.google.com (mail-pl1-f170.google.com [209.85.214.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2E61F277CAB for ; Thu, 11 Sep 2025 07:42:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576546; cv=none; b=N+s/hoc1Mbzh+XYJX2z6kD9gLgKYZtuq3zSOs5MluXUowVK4zAV6uaNtLjcPUO911Ie5/qm5zfi6wWpIJh3CwTb64yGkvLN5skw/mypoYSw094xATOhewEs5DNC/og/C/8eeFYS3IaZpbvXhmUVfvCc6IZ0K2OPKsgBZyKZeXqY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576546; c=relaxed/simple; bh=DbBRKdVH+9Q89Q8i0n6xkt59hwQ6Vht8OFO/4eKnAYE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=miBXveKS2uvctI0UncUmhyHYXqYEteUu4CzXVVBmJttQ1tzVJowGZjR9Va6ATCOIihMh3BXT/9FwIxqKFzEPBpv5XSgX5HW5s7aQS3MttfCnclUjlvgzxhq2BYAb7VbIMTwv+2ZEn1rYWzJdVpwxpLvOddsZ/+iJd3/iq5oLfgI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw; spf=pass smtp.mailfrom=gms.tku.edu.tw; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b=iEF0cQLV; arc=none smtp.client-ip=209.85.214.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b="iEF0cQLV" Received: by mail-pl1-f170.google.com with SMTP id d9443c01a7336-24c89867a17so3800345ad.1 for ; Thu, 11 Sep 2025 00:42:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gms-tku-edu-tw.20230601.gappssmtp.com; s=20230601; t=1757576543; x=1758181343; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=F67NXKwM5gojyeH+csfDMKkA7qAECq4psBmSZp1Issg=; b=iEF0cQLVPqyOtzBTxocRmOAEsBj9Xc3+l68oXNkBINDuaR7lCFLjbODIrGUCJX9W1w eJcAVy4UNp73b8Qc2FHUQVplWKF/VeRlIqBafyalptNMYsFJKeo0t7G2F/eMKUxzfIfl Nut4kSi8DCcQopdcF3ITHHzYGtybv4V7jsqul+IIbRzuKJUI408hma2+DHJmCmbWCrRU EMWGZrFwUr4E3Y68vODcL5rfrV21zRUck6wUOHrhy89olwSiPGYQUKJZ4o57mOur9dgg Rxrxz9yn77oVI7RNv9rJstBjDfFI/17CM3zd64xBbxd39ZbhwCVaNlMFzUNBouUsHGzk hdLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757576543; x=1758181343; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=F67NXKwM5gojyeH+csfDMKkA7qAECq4psBmSZp1Issg=; b=WVNlCYxGtIWZfpPotFPxG2r0kLioR1NWrhAyVuyswoZ0NcjY8HUpAgudri4t6mVJCs NwdSNogR/4W9layog2DkWEg73ssY1wur5J4asfT8P4qZnVUDi2AgjTAOfz4IU0yHgk76 R702YMv5nLc7uBQfYNDyvShwQgrDaHvHWHX5NrYAzCVfMnnUFKlqOs66XHRuWwO0aoV4 iCHsOhO92riku2wcTZnXB3ZeTlFX3d0+kYWdcCkYYuJLuwmz0icSR8A8Q6MtG1WXUQxQ NXPwTV1Pyr4fTatiQ8MB2eoahj/fjcuP+G9jQGvS9j17SvwOIQlXH6vFW9IBwXqWt00C YrIQ== X-Forwarded-Encrypted: i=1; AJvYcCVq8Gkqprcbijhgj93ElinDBGHo2ATfPaknFaWTvL9EFxM/dPpzg7JOxPBGA8RNrFt//3c/L7cqP4zAMls=@vger.kernel.org X-Gm-Message-State: AOJu0YzraaewiGPyuuGfSAC9hoFuc5Zv3GpI8FwMdkgmKxqYjnn46LEg r95OFQwNvJal3yk20pCASzVQa7tuQXqINcO3ZEr1LSTgTI37pLdKRYqSZZxlLyNawSI= X-Gm-Gg: ASbGnctHQGhHtRoycTFPv7xFx5S7mN09RgsE8NXeSkiYlUeKthjnaz3++X2uOTE/9ve pMmk3L3UkRORp/y34FKcXLGbQtibApryJ+czL3xn+1TqsJ7Gxv1xKSboHd1MAQLp3T/foXdfZns XEmdFxF8zo6cBXCGyTPRSzxThihz7vx2rSk30Lfw1Wjn3X6uwpgO8534lyEQKpQ7yxagl5W6Qhh GM9JWwiywgdrL5gXNSPatyMFybTpuK0keqdztBarHY8/wSdW816sMrDzd6cNf5nWiXKPXD0m3Zp ARK0fHDsRUVx4VLR39UiW8nm/2/cUS3M35SKLKkXyF3tkmhBBytBTHEVZaDqSakjN1r7ndFCQYb y3IdtE1ZbrFQ7xbj6r0KEGwTvs5L9IGCYac4BvtiDJJu24bk= X-Google-Smtp-Source: AGHT+IHpwQZR4pOG/m4IsGz46fLea1EeKJTzCL8WS3vqubstcq/YoLDI8C/oWhXYWGU773jLDfy7zQ== X-Received: by 2002:a17:902:db0a:b0:250:1c22:e78 with SMTP id d9443c01a7336-2516d33bb3bmr251815775ad.1.1757576543202; Thu, 11 Sep 2025 00:42:23 -0700 (PDT) Received: from wu-Pro-E500-G6-WS720T.. ([2001:288:7001:2703:7811:c085:c184:85be]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-32dd6306eecsm1657905a91.15.2025.09.11.00.42.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Sep 2025 00:42:22 -0700 (PDT) From: Guan-Chun Wu <409411716@gms.tku.edu.tw> To: 409411716@gms.tku.edu.tw Cc: akpm@linux-foundation.org, axboe@kernel.dk, ceph-devel@vger.kernel.org, ebiggers@kernel.org, hch@lst.de, home7438072@gmail.com, idryomov@gmail.com, jaegeuk@kernel.org, kbusch@kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, linux-nvme@lists.infradead.org, sagi@grimberg.me, tytso@mit.edu, visitorckw@gmail.com, xiubli@redhat.com Subject: [PATCH v2 2/5] lib/base64: rework encoder/decoder with customizable support and update nvme-auth Date: Thu, 11 Sep 2025 15:41:59 +0800 Message-Id: <20250911074159.656943-1-409411716@gms.tku.edu.tw> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250911072925.547163-1-409411716@gms.tku.edu.tw> References: <20250911072925.547163-1-409411716@gms.tku.edu.tw> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Rework base64_encode() and base64_decode() with extended interfaces that support custom 64-character tables and optional '=3D' padding. This makes them flexible enough to cover both standard RFC4648 Base64 and non-standard variants such as base64url. The encoder is redesigned to process input in 3-byte blocks, each mapped directly into 4 output symbols. Base64 naturally encodes 24 bits of input as four 6-bit values, so operating on aligned 3-byte chunks matches the algorithm's structure. This block-based approach eliminates the need for bit-by-bit streaming, reduces shifts, masks, and loop iterations, and removes data-dependent branches from the main loop. Only the final 1 or 2 leftover bytes are handled separately according to the standard rules. As a result, the encoder achieves ~2.8x speedup for small inputs (64B) and up to ~2.6x speedup for larger inputs (1KB), while remaining fully RFC4648-compliant. The decoder replaces strchr()-based lookups with direct table-indexed mapping. It processes input in 4-character groups and supports both padded and non-padded forms. Validation has been strengthened: illegal characters and misplaced '=3D' padding now cause errors, preventing silent data corruption. These changes improve decoding performance by ~12-15x. Benchmarks on x86_64 (Intel Core i7-10700 @ 2.90GHz, averaged over 1000 runs, tested with KUnit): Encode: - 64B input: avg ~90ns -> ~32ns (~2.8x faster) - 1KB input: avg ~1332ns -> ~510ns (~2.6x faster) Decode: - 64B input: avg ~1530ns -> ~122ns (~12.5x faster) - 1KB input: avg ~27726ns -> ~1859ns (~15x faster) Update nvme-auth to use the reworked base64_encode() and base64_decode() interfaces, which now require explicit padding and table parameters. A static base64_table is defined to preserve RFC4648 standard encoding with padding enabled, ensuring functional behavior remains unchanged. While this is a mechanical update following the lib/base64 rework, nvme-auth also benefits from the performance improvements in the new encoder/decoder, achieving faster encode/decode without altering the output format. The reworked encoder and decoder unify Base64 handling across the kernel with higher performance, stricter correctness, and flexibility to support subsystem-specific variants. Co-developed-by: Kuan-Wei Chiu Signed-off-by: Kuan-Wei Chiu Co-developed-by: Yu-Sheng Huang Signed-off-by: Yu-Sheng Huang Signed-off-by: Guan-Chun Wu <409411716@gms.tku.edu.tw> --- drivers/nvme/common/auth.c | 7 +- include/linux/base64.h | 4 +- lib/base64.c | 238 ++++++++++++++++++++++++++++--------- 3 files changed, 192 insertions(+), 57 deletions(-) diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c index 91e273b89..4d57694f8 100644 --- a/drivers/nvme/common/auth.c +++ b/drivers/nvme/common/auth.c @@ -161,6 +161,9 @@ u32 nvme_auth_key_struct_size(u32 key_len) } EXPORT_SYMBOL_GPL(nvme_auth_key_struct_size); =20 +static const char base64_table[65] =3D + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + struct nvme_dhchap_key *nvme_auth_extract_key(unsigned char *secret, u8 key_hash) { @@ -178,7 +181,7 @@ struct nvme_dhchap_key *nvme_auth_extract_key(unsigned = char *secret, if (!key) return ERR_PTR(-ENOMEM); =20 - key_len =3D base64_decode(secret, allocated_len, key->key); + key_len =3D base64_decode(secret, allocated_len, key->key, true, base64_t= able); if (key_len < 0) { pr_debug("base64 key decoding error %d\n", key_len); @@ -663,7 +666,7 @@ int nvme_auth_generate_digest(u8 hmac_id, u8 *psk, size= _t psk_len, if (ret) goto out_free_digest; =20 - ret =3D base64_encode(digest, digest_len, enc); + ret =3D base64_encode(digest, digest_len, enc, true, base64_table); if (ret < hmac_len) { ret =3D -ENOKEY; goto out_free_digest; diff --git a/include/linux/base64.h b/include/linux/base64.h index 660d4cb1e..22351323d 100644 --- a/include/linux/base64.h +++ b/include/linux/base64.h @@ -10,7 +10,7 @@ =20 #define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3) =20 -int base64_encode(const u8 *src, int len, char *dst); -int base64_decode(const char *src, int len, u8 *dst); +int base64_encode(const u8 *src, int len, char *dst, bool padding, const c= har *table); +int base64_decode(const char *src, int len, u8 *dst, bool padding, const c= har *table); =20 #endif /* _LINUX_BASE64_H */ diff --git a/lib/base64.c b/lib/base64.c index 9416bded2..b2bd5dab5 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -15,104 +15,236 @@ #include #include =20 -static const char base64_table[65] =3D - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#define BASE64_6BIT_MASK 0x3f /* Mask to extract lowest 6 bits */ +#define BASE64_BITS_PER_BYTE 8 +#define BASE64_CHUNK_BITS 6 + +/* Output-char-indexed shifts: for output chars 0,1,2,3 respectively */ +#define BASE64_SHIFT_OUT0 (BASE64_CHUNK_BITS * 3) /* 18 */ +#define BASE64_SHIFT_OUT1 (BASE64_CHUNK_BITS * 2) /* 12 */ +#define BASE64_SHIFT_OUT2 (BASE64_CHUNK_BITS * 1) /* 6 */ +/* OUT3 uses 0 shift and just masks with BASE64_6BIT_MASK */ + +/* For extracting bytes from the 24-bit value (decode main loop) */ +#define BASE64_SHIFT_BYTE0 (BASE64_BITS_PER_BYTE * 2) /* 16 */ +#define BASE64_SHIFT_BYTE1 (BASE64_BITS_PER_BYTE * 1) /* 8 */ + +/* Tail (no padding) shifts to extract bytes */ +#define BASE64_TAIL2_BYTE0_SHIFT ((BASE64_CHUNK_BITS * 2) - BASE64_BITS_P= ER_BYTE) /* 4 */ +#define BASE64_TAIL3_BYTE0_SHIFT ((BASE64_CHUNK_BITS * 3) - BASE64_BITS_P= ER_BYTE) /* 10 */ +#define BASE64_TAIL3_BYTE1_SHIFT ((BASE64_CHUNK_BITS * 3) - (BASE64_BITS_= PER_BYTE * 2)) /* 2 */ + +/* Extra: masks for leftover validation (no padding) */ +#define BASE64_MASK(n) ({ \ + unsigned int __n =3D (n); \ + __n ? ((1U << __n) - 1U) : 0U; \ +}) +#define BASE64_TAIL2_UNUSED_BITS (BASE64_CHUNK_BITS * 2 - BASE64_BITS_PER= _BYTE) /* 4 */ +#define BASE64_TAIL3_UNUSED_BITS (BASE64_CHUNK_BITS * 3 - BASE64_BITS_PER= _BYTE * 2) /* 2 */ =20 static inline const char *find_chr(const char *base64_table, char ch) { if ('A' <=3D ch && ch <=3D 'Z') - return base64_table + ch - 'A'; + return base64_table + (ch - 'A'); if ('a' <=3D ch && ch <=3D 'z') - return base64_table + 26 + ch - 'a'; + return base64_table + 26 + (ch - 'a'); if ('0' <=3D ch && ch <=3D '9') - return base64_table + 26 * 2 + ch - '0'; - if (ch =3D=3D base64_table[26 * 2 + 10]) - return base64_table + 26 * 2 + 10; - if (ch =3D=3D base64_table[26 * 2 + 10 + 1]) - return base64_table + 26 * 2 + 10 + 1; + return base64_table + 52 + (ch - '0'); + if (ch =3D=3D base64_table[62]) + return &base64_table[62]; + if (ch =3D=3D base64_table[63]) + return &base64_table[63]; return NULL; } =20 /** - * base64_encode() - base64-encode some binary data + * base64_encode() - base64-encode with custom table and optional padding * @src: the binary data to encode * @srclen: the length of @src in bytes - * @dst: (output) the base64-encoded string. Not NUL-terminated. + * @dst: (output) the base64-encoded string. Not NUL-terminated. + * @padding: whether to append '=3D' characters so output length is a mult= iple of 4 + * @table: 64-character encoding table to use (e.g. standard or URL-safe v= ariant) * - * Encodes data using base64 encoding, i.e. the "Base 64 Encoding" specifi= ed - * by RFC 4648, including the '=3D'-padding. + * Encodes data using the given 64-character @table. If @padding is true, + * the output is padded with '=3D' as described in RFC 4648; otherwise pad= ding + * is omitted. This allows generation of both standard and non-standard + * Base64 variants (e.g. URL-safe encoding). * * Return: the length of the resulting base64-encoded string in bytes. */ -int base64_encode(const u8 *src, int srclen, char *dst) +int base64_encode(const u8 *src, int srclen, char *dst, bool padding, cons= t char *table) { u32 ac =3D 0; - int bits =3D 0; - int i; char *cp =3D dst; =20 - for (i =3D 0; i < srclen; i++) { - ac =3D (ac << 8) | src[i]; - bits +=3D 8; - do { - bits -=3D 6; - *cp++ =3D base64_table[(ac >> bits) & 0x3f]; - } while (bits >=3D 6); - } - if (bits) { - *cp++ =3D base64_table[(ac << (6 - bits)) & 0x3f]; - bits -=3D 6; + while (srclen >=3D 3) { + ac =3D ((u32)src[0] << (BASE64_BITS_PER_BYTE * 2)) | + ((u32)src[1] << (BASE64_BITS_PER_BYTE)) | + (u32)src[2]; + + *cp++ =3D table[ac >> BASE64_SHIFT_OUT0]; + *cp++ =3D table[(ac >> BASE64_SHIFT_OUT1) & BASE64_6BIT_MASK]; + *cp++ =3D table[(ac >> BASE64_SHIFT_OUT2) & BASE64_6BIT_MASK]; + *cp++ =3D table[ac & BASE64_6BIT_MASK]; + + src +=3D 3; + srclen -=3D 3; } - while (bits < 0) { - *cp++ =3D '=3D'; - bits +=3D 2; + + switch (srclen) { + case 2: + ac =3D ((u32)src[0] << (BASE64_BITS_PER_BYTE * 2)) | + ((u32)src[1] << (BASE64_BITS_PER_BYTE)); + + *cp++ =3D table[ac >> BASE64_SHIFT_OUT0]; + *cp++ =3D table[(ac >> BASE64_SHIFT_OUT1) & BASE64_6BIT_MASK]; + *cp++ =3D table[(ac >> BASE64_SHIFT_OUT2) & BASE64_6BIT_MASK]; + if (padding) + *cp++ =3D '=3D'; + break; + case 1: + ac =3D ((u32)src[0] << (BASE64_BITS_PER_BYTE * 2)); + *cp++ =3D table[ac >> BASE64_SHIFT_OUT0]; + *cp++ =3D table[(ac >> BASE64_SHIFT_OUT1) & BASE64_6BIT_MASK]; + if (padding) { + *cp++ =3D '=3D'; + *cp++ =3D '=3D'; + } + break; } return cp - dst; } EXPORT_SYMBOL_GPL(base64_encode); =20 /** - * base64_decode() - base64-decode a string + * base64_decode() - base64-decode with custom table and optional padding * @src: the string to decode. Doesn't need to be NUL-terminated. * @srclen: the length of @src in bytes * @dst: (output) the decoded binary data + * @padding: when true, accept and handle '=3D' padding as per RFC 4648; + * when false, '=3D' is treated as invalid + * @table: 64-character encoding table to use (e.g. standard or URL-safe v= ariant) * - * Decodes a string using base64 encoding, i.e. the "Base 64 Encoding" - * specified by RFC 4648, including the '=3D'-padding. + * Decodes a string using the given 64-character @table. If @padding is tr= ue, + * '=3D' padding is accepted as described in RFC 4648; otherwise '=3D' is + * treated as an error. This allows decoding of both standard and + * non-standard Base64 variants (e.g. URL-safe decoding). * * This implementation hasn't been optimized for performance. * * Return: the length of the resulting decoded binary data in bytes, * or -1 if the string isn't a valid base64 string. */ -int base64_decode(const char *src, int srclen, u8 *dst) +static inline int base64_decode_table(char ch, const char *table) +{ + if (ch =3D=3D '\0') + return -1; + const char *p =3D find_chr(table, ch); + + return p ? (p - table) : -1; +} + +static inline int decode_base64_block(const char *src, const char *table, + int *input1, int *input2, + int *input3, int *input4, + bool padding) +{ + *input1 =3D base64_decode_table(src[0], table); + *input2 =3D base64_decode_table(src[1], table); + *input3 =3D base64_decode_table(src[2], table); + *input4 =3D base64_decode_table(src[3], table); + + /* Return error if any base64 character is invalid */ + if (*input1 < 0 || *input2 < 0 || (!padding && (*input3 < 0 || *input4 < = 0))) + return -1; + + /* Handle padding */ + if (padding) { + if (*input3 < 0 && *input4 >=3D 0) + return -1; + if (*input3 < 0 && src[2] !=3D '=3D') + return -1; + if (*input4 < 0 && src[3] !=3D '=3D') + return -1; + } + return 0; +} + +int base64_decode(const char *src, int srclen, u8 *dst, bool padding, cons= t char *table) { - u32 ac =3D 0; - int bits =3D 0; - int i; u8 *bp =3D dst; + int input1, input2, input3, input4; + u32 val; =20 - for (i =3D 0; i < srclen; i++) { - const char *p =3D find_chr(base64_table, src[i]); + if (srclen =3D=3D 0) + return 0; =20 - if (src[i] =3D=3D '=3D') { - ac =3D (ac << 6); - bits +=3D 6; - if (bits >=3D 8) - bits -=3D 8; - continue; + /* Validate the input length for padding */ + if (padding && (srclen & 0x03) !=3D 0) + return -1; + + while (srclen >=3D 4) { + /* Decode the next 4 characters */ + if (decode_base64_block(src, table, &input1, &input2, &input3, + &input4, padding) < 0) + return -1; + if (padding && srclen > 4) { + if (input3 < 0 || input4 < 0) + return -1; } - if (p =3D=3D NULL || src[i] =3D=3D 0) + val =3D ((u32)input1 << BASE64_SHIFT_OUT0) | + ((u32)input2 << BASE64_SHIFT_OUT1) | + ((u32)((input3 < 0) ? 0 : input3) << BASE64_SHIFT_OUT2) | + (u32)((input4 < 0) ? 0 : input4); + + *bp++ =3D (u8)(val >> BASE64_SHIFT_BYTE0); + + if (input3 >=3D 0) + *bp++ =3D (u8)(val >> BASE64_SHIFT_BYTE1); + if (input4 >=3D 0) + *bp++ =3D (u8)val; + + src +=3D 4; + srclen -=3D 4; + } + + /* Handle leftover characters when padding is not used */ + if (!padding && srclen > 0) { + switch (srclen) { + case 2: + input1 =3D base64_decode_table(src[0], table); + input2 =3D base64_decode_table(src[1], table); + if (input1 < 0 || input2 < 0) + return -1; + + val =3D ((u32)input1 << BASE64_CHUNK_BITS) | (u32)input2; /* 12 bits */ + if (val & BASE64_MASK(BASE64_TAIL2_UNUSED_BITS)) + return -1; /* low 4 bits must be zero */ + + *bp++ =3D (u8)(val >> BASE64_TAIL2_BYTE0_SHIFT); + break; + case 3: + input1 =3D base64_decode_table(src[0], table); + input2 =3D base64_decode_table(src[1], table); + input3 =3D base64_decode_table(src[2], table); + if (input1 < 0 || input2 < 0 || input3 < 0) + return -1; + + val =3D ((u32)input1 << (BASE64_CHUNK_BITS * 2)) | + ((u32)input2 << BASE64_CHUNK_BITS) | + (u32)input3; /* 18 bits */ + + if (val & BASE64_MASK(BASE64_TAIL3_UNUSED_BITS)) + return -1; /* low 2 bits must be zero */ + + *bp++ =3D (u8)(val >> BASE64_TAIL3_BYTE0_SHIFT); + *bp++ =3D (u8)((val >> BASE64_TAIL3_BYTE1_SHIFT) & 0xFF); + break; + default: return -1; - ac =3D (ac << 6) | (p - base64_table); - bits +=3D 6; - if (bits >=3D 8) { - bits -=3D 8; - *bp++ =3D (u8)(ac >> bits); } } - if (ac & ((1 << bits) - 1)) - return -1; + return bp - dst; } EXPORT_SYMBOL_GPL(base64_decode); --=20 2.34.1 From nobody Thu Oct 2 20:46:25 2025 Received: from mail-pg1-f181.google.com (mail-pg1-f181.google.com [209.85.215.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 66B5A28150F for ; Thu, 11 Sep 2025 07:45:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576726; cv=none; b=fRIMnyCc5E+OXHbYvemUrnk2UBZr8hIQkk6XKUQpV4Fkw7NZ5eLsUj1DkRDmyoC1NtLeyIMYDbT6NfcaKU+q4teNP8DR+dIu4NrV1VSju61DGXtb6k4qoNsHqg9r/ypaOnEF6O2LMn4ZKsqH0sL0gSNMqGwa/2jaeaxMIL8nJ3U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576726; c=relaxed/simple; bh=AAz7YSSQv6u7ioBYlTXmetOdmobu2QVMJYFy3LfyNpU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=SyQrQmiVTBsFDimN8jK7TX7XRSRRcwBR00l55CE20nFoT+0GcJ4t8sJnjYRa99PtDcjocE2WG1RiIkveO8q91V0TPPq6kvFn/ZjV6ZJpRfyIqrST4TrcVgiKTBXa4iQaDL4Lw4MXSOh0pMy5QorNQN9CMiL5Ct+eHrN/76ls648= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw; spf=pass smtp.mailfrom=gms.tku.edu.tw; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b=hMJJi4gP; arc=none smtp.client-ip=209.85.215.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b="hMJJi4gP" Received: by mail-pg1-f181.google.com with SMTP id 41be03b00d2f7-b47173749dbso314812a12.1 for ; Thu, 11 Sep 2025 00:45:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gms-tku-edu-tw.20230601.gappssmtp.com; s=20230601; t=1757576723; x=1758181523; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=7s0darRmpAoSF4AYzaEAKr+Som3Rl5+XVaBmiwsyicM=; b=hMJJi4gPSXcBkN/JJqody53gUiKdmJv2dZbHb0MDHSo2KksGh8eXH7Qp2fwfhuyJjF tNY8EYWmR8SmOA2vufr4wxYzKVhvpFat/ANKvKviUw7uKDiB12lwNTVuhgWw7REfUlEd FUZOtGE9Ro1q8I0HOYMnoBE2UDDj8PsuauOfJ9KvjgBbDnZE2FAFZ/3WR7KiQeABNWXC SEvr5hBoiTu6At7yFNsXMDK5pUc1Iw5zbu8R6ZVEzf8ky/sOpwhBBpq5Ida7CzBLbfGJ BxM3ZlFTxBoYG+3SpyKT8le1ujbhWLPFUd0U4aRLXnfHQA9eM14AHAACpD34dp1fPTrV YoxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757576723; x=1758181523; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=7s0darRmpAoSF4AYzaEAKr+Som3Rl5+XVaBmiwsyicM=; b=GUKWJP8ds4jyPKFSZtRUlUfEtH4ZntmfAEttmOqX5CPB3YpFbuoAKQ/ZEnNghlMSGr uHyldN6WgLULfdziJS95Fkc+hwljjP0OSC5TLKClSmxdTJmEp8KpolzVsZChZ2EfPLSt xJyEMDi7X9w0fkC2rHpd2CFKjxklrL+48fDKZ4FLZbIPNBrb+1pGPqvBdV75KfZaB5oe +ONk8gKKPcKnuejHbNkejApp4fAE8rmh1BLrMeoDT3qvUaZOiiODqPBkIKaHvmewTZf2 EyJAFJumiOm5Phj7G6wouBCYXf3zmZEOOwIKHHyogvVXztkWRcmCIy9IIlAm4ahdCPqM +epg== X-Forwarded-Encrypted: i=1; AJvYcCXjV4LzvUECaEvH/nl3BTI4bPxRWN/jVlGRQL9htmvnwEADFU5PQfzJ1fAc//HcSDbHUHBOvAYo/CE1qr4=@vger.kernel.org X-Gm-Message-State: AOJu0YzQLdstwEz4gU9y5NKTSl51M+jy6OqSxJFfwE7F8u02arieRo3o Yil23kpJ9bWdXYuCqD5sRYcst/B9Rtx8ZOYkYvRemWw0GgNjGRMKPuDxunZTZ3NhlvI= X-Gm-Gg: ASbGncvWWGbJ28DfKq5fwS8TkPC5YlQVALP4cxes0GzJhknXYOXo1Zeui/2hrPQipYV jjuOLWFRvTC42Ud5gY361YFVAJSqrQ5gwkMAy54dMLo/3tWkUMx8V38Or+YOQ+xD5igpCWeYeJj WPtBqGazlqe30Akw670MH8ddv0J5Gsn8KqwjNis2SjVQ6oDYjPeTAbNT2jc+staSLIrei9jqJpF t/8FxQuTmukhmMZuFQ+HoBaX6GwW6bt/meXqe/11p0ybuf0qBjMc5UcyBpVcnYR9J5FbsGjGVo+ b1W4zJXtcywCpAIWQBk2nSNNq+sovYDQ24Go5xSj24ZkxZPYhNkhn6/ZBECfQsTmzBnEeeGb+Vu KWwHdh6NlEJ/c5A69lXUsja0z8gJ6AlFjqmkI2+atbYAoQJQ= X-Google-Smtp-Source: AGHT+IEqJNXLNJAINV677IYIL5EReMelpFkf7dFD6n7F4RIuL6WJn8Kv9Y6X1eDhV8xZE+Ct5kotng== X-Received: by 2002:a17:902:ea06:b0:24c:e6fa:2a3b with SMTP id d9443c01a7336-25170e41037mr262573745ad.38.1757576722587; Thu, 11 Sep 2025 00:45:22 -0700 (PDT) Received: from wu-Pro-E500-G6-WS720T.. ([2001:288:7001:2703:7811:c085:c184:85be]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-25c37294b44sm10499645ad.45.2025.09.11.00.45.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Sep 2025 00:45:21 -0700 (PDT) From: Guan-Chun Wu <409411716@gms.tku.edu.tw> To: 409411716@gms.tku.edu.tw Cc: akpm@linux-foundation.org, axboe@kernel.dk, ceph-devel@vger.kernel.org, ebiggers@kernel.org, hch@lst.de, home7438072@gmail.com, idryomov@gmail.com, jaegeuk@kernel.org, kbusch@kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, linux-nvme@lists.infradead.org, sagi@grimberg.me, tytso@mit.edu, visitorckw@gmail.com, xiubli@redhat.com Subject: [PATCH v2 3/5] lib: add KUnit tests for base64 encoding/decoding Date: Thu, 11 Sep 2025 15:45:10 +0800 Message-Id: <20250911074510.685568-1-409411716@gms.tku.edu.tw> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250911072925.547163-1-409411716@gms.tku.edu.tw> References: <20250911072925.547163-1-409411716@gms.tku.edu.tw> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a KUnit test suite for the base64 helpers. The tests exercise both encoding and decoding, cover padded and unpadded forms per RFC 4648, and include negative cases for malformed inputs and padding errors. The suite also validates behavior with a caller-supplied encoding table. In addition to functional checks, the suite includes simple microbenchmarks which report average encode/decode latency for small (64B) and larger (1KB) inputs. These numbers are informational only and do not gate the tests. Kconfig (BASE64_KUNIT) and lib/tests/Makefile are updated accordingly. Sample KUnit output: KTAP version 1 # Subtest: base64 # module: base64_kunit 1..3 # base64_performance_tests: [64B] encode run : 32ns # base64_performance_tests: [64B] decode run : 122ns # base64_performance_tests: [1KB] encode run : 507ns # base64_performance_tests: [1KB] decode run : 1870ns ok 1 base64_performance_tests ok 2 base64_encode_tests ok 3 base64_decode_tests # base64: pass:3 fail:0 skip:0 total:3 # Totals: pass:3 fail:0 skip:0 total:3 Signed-off-by: Guan-Chun Wu <409411716@gms.tku.edu.tw> Reviewed-by: Kuan-Wei Chiu --- lib/Kconfig.debug | 19 +++- lib/tests/Makefile | 1 + lib/tests/base64_kunit.c | 230 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 lib/tests/base64_kunit.c diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index dc0e0c6ed..1cfb12d02 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2794,8 +2794,25 @@ config CMDLINE_KUNIT_TEST =20 If unsure, say N. =20 +config BASE64_KUNIT + tristate "KUnit test for base64 decoding and encoding" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + This builds the base64 unit tests. + + The tests cover the encoding and decoding logic of Base64 functions + in the kernel. + In addition to correctness checks, simple performance benchmarks + for both encoding and decoding are also included. + + For more information on KUnit and unit tests in general please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + config BITS_TEST - tristate "KUnit test for bits.h" if !KUNIT_ALL_TESTS + tristate "KUnit test for bit functions and macros" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS help diff --git a/lib/tests/Makefile b/lib/tests/Makefile index fa6d728a8..6593a2873 100644 --- a/lib/tests/Makefile +++ b/lib/tests/Makefile @@ -4,6 +4,7 @@ =20 # KUnit tests CFLAGS_bitfield_kunit.o :=3D $(DISABLE_STRUCTLEAK_PLUGIN) +obj-$(CONFIG_BASE64_KUNIT) +=3D base64_kunit.o obj-$(CONFIG_BITFIELD_KUNIT) +=3D bitfield_kunit.o obj-$(CONFIG_BITS_TEST) +=3D test_bits.o obj-$(CONFIG_BLACKHOLE_DEV_KUNIT_TEST) +=3D blackhole_dev_kunit.o diff --git a/lib/tests/base64_kunit.c b/lib/tests/base64_kunit.c new file mode 100644 index 000000000..1941ac504 --- /dev/null +++ b/lib/tests/base64_kunit.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * base64_kunit_test.c - KUnit tests for base64 encoding and decoding func= tions + * + * Copyright (c) 2025, Guan-Chun Wu <409411716@gms.tku.edu.tw> + */ + +#include +#include + +static const char base64_table[65] =3D + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* ---------- Benchmark helpers ---------- */ +static u64 bench_encode_ns(const u8 *data, int len, char *dst, int reps) +{ + u64 t0, t1; + + t0 =3D ktime_get_ns(); + for (int i =3D 0; i < reps; i++) + base64_encode(data, len, dst, true, base64_table); + t1 =3D ktime_get_ns(); + + return div64_u64(t1 - t0, (u64)reps); +} + +static u64 bench_decode_ns(const char *data, int len, u8 *dst, int reps) +{ + u64 t0, t1; + + t0 =3D ktime_get_ns(); + for (int i =3D 0; i < reps; i++) + base64_decode(data, len, dst, true, base64_table); + t1 =3D ktime_get_ns(); + + return div64_u64(t1 - t0, (u64)reps); +} + +static void run_perf_and_check(struct kunit *test, const char *label, int = size) +{ + const int reps =3D 1000; + size_t outlen =3D DIV_ROUND_UP(size, 3) * 4; + u8 *in =3D kmalloc(size, GFP_KERNEL); + char *enc =3D kmalloc(outlen, GFP_KERNEL); + u8 *decoded =3D kmalloc(size, GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, in); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, enc); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, decoded); + + get_random_bytes(in, size); + int enc_len =3D base64_encode(in, size, enc, true, base64_table); + int dec_len =3D base64_decode(enc, enc_len, decoded, true, base64_table); + + /* correctness sanity check */ + KUNIT_EXPECT_EQ(test, dec_len, size); + KUNIT_EXPECT_MEMEQ(test, decoded, in, size); + + /* benchmark encode */ + + u64 t1 =3D bench_encode_ns(in, size, enc, reps); + + kunit_info(test, "[%s] encode run : %lluns", label, t1); + + u64 t2 =3D bench_decode_ns(enc, enc_len, decoded, reps); + + kunit_info(test, "[%s] decode run : %lluns", label, t2); + + kfree(in); + kfree(enc); + kfree(decoded); +} + +static void base64_performance_tests(struct kunit *test) +{ + run_perf_and_check(test, "64B", 64); + run_perf_and_check(test, "1KB", 1024); +} + +/* ---------- Helpers for encode ---------- */ +static void expect_encode_ok(struct kunit *test, const u8 *src, int srclen, + const char *expected, bool padding) +{ + char buf[128]; + int encoded_len =3D base64_encode(src, srclen, buf, padding, base64_table= ); + + buf[encoded_len] =3D '\0'; + + KUNIT_EXPECT_EQ(test, encoded_len, strlen(expected)); + KUNIT_EXPECT_STREQ(test, buf, expected); +} + +/* ---------- Helpers for decode ---------- */ +static void expect_decode_ok(struct kunit *test, const char *src, + const u8 *expected, int expected_len, bool padding) +{ + u8 buf[128]; + int decoded_len =3D base64_decode(src, strlen(src), buf, padding, base64_= table); + + KUNIT_EXPECT_EQ(test, decoded_len, expected_len); + KUNIT_EXPECT_MEMEQ(test, buf, expected, expected_len); +} + +static void expect_decode_err(struct kunit *test, const char *src, + int srclen, bool padding) +{ + u8 buf[64]; + int decoded_len =3D base64_decode(src, srclen, buf, padding, base64_table= ); + + KUNIT_EXPECT_EQ(test, decoded_len, -1); +} + +/* ---------- Encode Tests ---------- */ +static void base64_encode_tests(struct kunit *test) +{ + /* With padding */ + expect_encode_ok(test, (const u8 *)"", 0, "", true); + expect_encode_ok(test, (const u8 *)"f", 1, "Zg=3D=3D", true); + expect_encode_ok(test, (const u8 *)"fo", 2, "Zm8=3D", true); + expect_encode_ok(test, (const u8 *)"foo", 3, "Zm9v", true); + expect_encode_ok(test, (const u8 *)"foob", 4, "Zm9vYg=3D=3D", true); + expect_encode_ok(test, (const u8 *)"fooba", 5, "Zm9vYmE=3D", true); + expect_encode_ok(test, (const u8 *)"foobar", 6, "Zm9vYmFy", true); + + /* Extra cases with padding */ + expect_encode_ok(test, (const u8 *)"Hello, world!", 13, "SGVsbG8sIHdvcmxk= IQ=3D=3D", true); + expect_encode_ok(test, (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, + "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=3D", true); + expect_encode_ok(test, (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=3D", true); + expect_encode_ok(test, (const u8 *)"0123456789+/", 12, "MDEyMzQ1Njc4OSsv"= , true); + + /* Without padding */ + expect_encode_ok(test, (const u8 *)"", 0, "", false); + expect_encode_ok(test, (const u8 *)"f", 1, "Zg", false); + expect_encode_ok(test, (const u8 *)"fo", 2, "Zm8", false); + expect_encode_ok(test, (const u8 *)"foo", 3, "Zm9v", false); + expect_encode_ok(test, (const u8 *)"foob", 4, "Zm9vYg", false); + expect_encode_ok(test, (const u8 *)"fooba", 5, "Zm9vYmE", false); + expect_encode_ok(test, (const u8 *)"foobar", 6, "Zm9vYmFy", false); + + /* Extra cases without padding */ + expect_encode_ok(test, (const u8 *)"Hello, world!", 13, "SGVsbG8sIHdvcmxk= IQ", false); + expect_encode_ok(test, (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, + "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", false); + expect_encode_ok(test, (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", false); + expect_encode_ok(test, (const u8 *)"0123456789+/", 12, "MDEyMzQ1Njc4OSsv"= , false); +} + +/* ---------- Decode Tests ---------- */ +static void base64_decode_tests(struct kunit *test) +{ + /* -------- With padding --------*/ + expect_decode_ok(test, "", (const u8 *)"", 0, true); + expect_decode_ok(test, "Zg=3D=3D", (const u8 *)"f", 1, true); + expect_decode_ok(test, "Zm8=3D", (const u8 *)"fo", 2, true); + expect_decode_ok(test, "Zm9v", (const u8 *)"foo", 3, true); + expect_decode_ok(test, "Zm9vYg=3D=3D", (const u8 *)"foob", 4, true); + expect_decode_ok(test, "Zm9vYmE=3D", (const u8 *)"fooba", 5, true); + expect_decode_ok(test, "Zm9vYmFy", (const u8 *)"foobar", 6, true); + expect_decode_ok(test, "SGVsbG8sIHdvcmxkIQ=3D=3D", (const u8 *)"Hello, wo= rld!", 13, true); + expect_decode_ok(test, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=3D", + (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, true); + expect_decode_ok(test, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=3D", + (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, true); + + /* Error cases */ + expect_decode_err(test, "Zg=3D!", 4, true); + expect_decode_err(test, "Zm$=3D", 4, true); + expect_decode_err(test, "Z=3D=3D=3D", 4, true); + expect_decode_err(test, "Zg", 2, true); + expect_decode_err(test, "Zm9v=3D=3D=3D=3D", 8, true); + expect_decode_err(test, "Zm=3D=3DA", 5, true); + + { + char with_nul[4] =3D { 'Z', 'g', '\0', '=3D' }; + + expect_decode_err(test, with_nul, 4, true); + } + + /* -------- Without padding --------*/ + expect_decode_ok(test, "", (const u8 *)"", 0, false); + expect_decode_ok(test, "Zg", (const u8 *)"f", 1, false); + expect_decode_ok(test, "Zm8", (const u8 *)"fo", 2, false); + expect_decode_ok(test, "Zm9v", (const u8 *)"foo", 3, false); + expect_decode_ok(test, "Zm9vYg", (const u8 *)"foob", 4, false); + expect_decode_ok(test, "Zm9vYmE", (const u8 *)"fooba", 5, false); + expect_decode_ok(test, "Zm9vYmFy", (const u8 *)"foobar", 6, false); + expect_decode_ok(test, "TWFu", (const u8 *)"Man", 3, false); + expect_decode_ok(test, "SGVsbG8sIHdvcmxkIQ", (const u8 *)"Hello, world!",= 13, false); + expect_decode_ok(test, "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo", + (const u8 *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26, false); + expect_decode_ok(test, "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo", + (const u8 *)"abcdefghijklmnopqrstuvwxyz", 26, false); + expect_decode_ok(test, "MDEyMzQ1Njc4OSsv", (const u8 *)"0123456789+/", 12= , false); + + /* Error cases */ + expect_decode_err(test, "Zg=3D!", 4, false); + expect_decode_err(test, "Zm$=3D", 4, false); + expect_decode_err(test, "Z=3D=3D=3D", 4, false); + expect_decode_err(test, "Zg=3D", 3, false); + expect_decode_err(test, "Zm9v=3D=3D=3D=3D", 8, false); + expect_decode_err(test, "Zm=3D=3Dv", 4, false); + + { + char with_nul[4] =3D { 'Z', 'g', '\0', '=3D' }; + + expect_decode_err(test, with_nul, 4, false); + } +} + +/* ---------- Test registration ---------- */ +static struct kunit_case base64_test_cases[] =3D { + KUNIT_CASE(base64_performance_tests), + KUNIT_CASE(base64_encode_tests), + KUNIT_CASE(base64_decode_tests), + {} +}; + +static struct kunit_suite base64_test_suite =3D { + .name =3D "base64", + .test_cases =3D base64_test_cases, +}; + +kunit_test_suite(base64_test_suite); + +MODULE_AUTHOR("Guan-Chun Wu <409411716@gms.tku.edu.tw>"); +MODULE_DESCRIPTION("KUnit tests for Base64 encoding/decoding, including pe= rformance checks"); +MODULE_LICENSE("GPL"); --=20 2.34.1 From nobody Thu Oct 2 20:46:25 2025 Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1794B29A9C9 for ; Thu, 11 Sep 2025 07:46:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576764; cv=none; b=VQOA3hKXlEMV7GN2YY+GQIEwxvL1wgZ4QZu7V7wiHy7I7ejBOPmBehEHat7kTvWtoDd5R199BWub8Le+hFzl44tzsNdE5N0iKi5uA4pPcCrGYXok/4ekVPQKY+DKNn7nXUc5QHAA3zZQn5sAEK5l/uFltCU6TS2gGLsJEkNCEMw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576764; c=relaxed/simple; bh=O71eOxXN8qtxCpJO9bMs63EIF1c0j2xDoLcNf4kljL0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=J+nizy9e1KyhQc+ZCzgxJlMm5qL7YGTZ0RTXDCkuMgCyJOjPpoCYoY1hucInVMRdTAhlSDp3vwB18cWspQc0+3GUzaIEulHA4bpcqs9jA6P0YuPXy+zwbnOKqn0RGjLEtgKKBazCS+xBjqe2QuzXHUmb4HV2Xpu9melsWrZ+zjI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw; spf=pass smtp.mailfrom=gms.tku.edu.tw; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b=g10tbuW9; arc=none smtp.client-ip=209.85.210.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b="g10tbuW9" Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-7725fb32e1bso449962b3a.1 for ; Thu, 11 Sep 2025 00:46:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gms-tku-edu-tw.20230601.gappssmtp.com; s=20230601; t=1757576762; x=1758181562; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=9sqCK5RjxgMvTS/KMSGZswVuHs/rB1hx6QH50USYYeg=; b=g10tbuW9C+sdkHbwh7urrPDyrm5TOiaVt9kYOHfwfutBNr6w2JLnzInh++vN6KghRk FEdfY3vqOOEPP30LZ3/g587DNZn2zUSYZEOJZnCwIThETSvDuE86uJp/cO2I+L3yuoxt EEBlJRDONMCnbcIFEC8CGztF4y8eCYKCOYKfRadPxNcUDffbQmSv8jms6l5MAS792DnJ 9ww1QfZlWdbxOkipCyfSEErOoiMjPWHSRcRUyou3nmlTykSJ096iyXHynBNVKX7vquW+ 8gE47TMqsVrGR1eWBTSHtrrR02bIX8KWrsQ2i3zBRrho0/ibU+m3rfjQq+QH8KZLKE2K rhBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757576762; x=1758181562; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9sqCK5RjxgMvTS/KMSGZswVuHs/rB1hx6QH50USYYeg=; b=V0tbC9AZp/F0luAAhqAC/1Pn60jTC8w7B+Dnl3cgd6ysA/jLrLt1fs9bzG8mwhjHgW JoCXHxY0Caz/dMWAOPDpMU0QBuUixGHvRYY76KjJ3RNS7dNSjk2SFcKP9fkqzb+VVHfb 2jY8DV8EuKI4r14SHPtZadeRvdBe3p+/slWokHEHWqaVzPngNfZVbSjj3KQVyv61F28s jtZ5Vyj8kNa2ZyZVTo5DzuJyY2LtjGJ6UfEOEj9aMIzLGitPFlBWN40KLOwQi+vQVtzG gXFDgWKWxKlH7+y7DDNMDzuygmAmouuxA+VY0QeU50VYsaeRCZK78UO5g7EUi6ieHQwF suqw== X-Forwarded-Encrypted: i=1; AJvYcCXhSpI4j1f+K3TSlOz4oLQXYkb9T4RSMEpYXH3AtilaRmznLbFDTHMEb9F9cJSmDf3sITndat+nl62Zn+A=@vger.kernel.org X-Gm-Message-State: AOJu0YxFmWsvZXANo01mlV2fouE7+rz++DxymnidvZXwYiLlKir/8iM3 NuNCZRTiWWZX00yZPLZ7ESFexEbfV8XiXzXsBRZozDGT3R9LD/pbInvZKJBusxWWIyU= X-Gm-Gg: ASbGncsVCxlgFYfGeclQTKDEKIYMuw1qH7wow9kAaJkF0VaR8DmIhw3xNw2mMir7rJI hRUG3kDDD3cfGIEuu+5Rw2qSEZFxqJFoN60+4PmpoZqda28l2KV1RIw+aNlbQdpVlxD6+uz7V7Y OGTwxlsqjzvbc4JSWC4jYqJR2qniCMHG6qmCJ1f1U7566Q5JGnAAly6sF4wZXX+nvzSY/4IZj+S Izvb3tRXWAxIkS9kIpytU/LxHc2p/Bamw1gFCAtYfJ5t1KBSR5m/XG4bw2fpp5Oyv3YcZ7naCCQ IA2HVQZ1aQm/Nd9okS4xsJD/+NeSA2B/doMGMDbdTRNONxcLiy8l0TzWxKkj5yA5YsZHAIZWMK7 UTFqBl1Uj9wt6xqQ5r1XzBPcPXohM093JebwMsghkRAPFckLUtO3+li5DrG8S6yQTtYUK X-Google-Smtp-Source: AGHT+IFTtCHwqNfIBOXwlFvy/P0nkEKjAL4uI3LrM5NYhtuUi4RxaoEj1xk7ImpRtf5RyJZJwkkNeg== X-Received: by 2002:a05:6a00:1a8f:b0:772:2850:783d with SMTP id d2e1a72fcca58-7742dedf06emr24743666b3a.22.1757576762510; Thu, 11 Sep 2025 00:46:02 -0700 (PDT) Received: from wu-Pro-E500-G6-WS720T.. ([2001:288:7001:2703:7811:c085:c184:85be]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-77607b18424sm1134273b3a.63.2025.09.11.00.45.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Sep 2025 00:46:01 -0700 (PDT) From: Guan-Chun Wu <409411716@gms.tku.edu.tw> To: 409411716@gms.tku.edu.tw Cc: akpm@linux-foundation.org, axboe@kernel.dk, ceph-devel@vger.kernel.org, ebiggers@kernel.org, hch@lst.de, home7438072@gmail.com, idryomov@gmail.com, jaegeuk@kernel.org, kbusch@kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, linux-nvme@lists.infradead.org, sagi@grimberg.me, tytso@mit.edu, visitorckw@gmail.com, xiubli@redhat.com Subject: [PATCH v2 4/5] fscrypt: replace local base64url helpers with generic lib/base64 helpers Date: Thu, 11 Sep 2025 15:45:56 +0800 Message-Id: <20250911074556.691401-1-409411716@gms.tku.edu.tw> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250911072925.547163-1-409411716@gms.tku.edu.tw> References: <20250911072925.547163-1-409411716@gms.tku.edu.tw> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace the existing local base64url encoding and decoding functions in fscrypt with the generic base64_encode_custom and base64_decode_custom helpers from the kernel's lib/base64 library. This removes custom implementations in fscrypt, reduces code duplication, and leverages the well-maintained, standard base64 code within the kernel. The new helpers preserve RFC 4648-compliant URL-safe Base64 encoding without padding behavior, ensuring no functional changes. At the same time, they also deliver significant performance gains: with the optimized encoder and decoder, encoding runs about 2.7x faster and decoding achieves 12-15x improvements over the previous implementation. This improves maintainability and aligns fscrypt with other kernel components using the generic base64 helpers. Signed-off-by: Guan-Chun Wu <409411716@gms.tku.edu.tw> Reviewed-by: Kuan-Wei Chiu --- fs/crypto/fname.c | 86 ++++------------------------------------------- 1 file changed, 6 insertions(+), 80 deletions(-) diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index f9f6713e1..38be85cd5 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -17,6 +17,7 @@ #include #include #include +#include =20 #include "fscrypt_private.h" =20 @@ -72,7 +73,7 @@ struct fscrypt_nokey_name { =20 /* Encoded size of max-size no-key name */ #define FSCRYPT_NOKEY_NAME_MAX_ENCODED \ - FSCRYPT_BASE64URL_CHARS(FSCRYPT_NOKEY_NAME_MAX) + BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) =20 static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) { @@ -166,81 +167,6 @@ static int fname_decrypt(const struct inode *inode, static const char base64url_table[65] =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; =20 -#define FSCRYPT_BASE64URL_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3) - -/** - * fscrypt_base64url_encode() - base64url-encode some binary data - * @src: the binary data to encode - * @srclen: the length of @src in bytes - * @dst: (output) the base64url-encoded string. Not NUL-terminated. - * - * Encodes data using base64url encoding, i.e. the "Base 64 Encoding with = URL - * and Filename Safe Alphabet" specified by RFC 4648. '=3D'-padding isn't= used, - * as it's unneeded and not required by the RFC. base64url is used instea= d of - * base64 to avoid the '/' character, which isn't allowed in filenames. - * - * Return: the length of the resulting base64url-encoded string in bytes. - * This will be equal to FSCRYPT_BASE64URL_CHARS(srclen). - */ -static int fscrypt_base64url_encode(const u8 *src, int srclen, char *dst) -{ - u32 ac =3D 0; - int bits =3D 0; - int i; - char *cp =3D dst; - - for (i =3D 0; i < srclen; i++) { - ac =3D (ac << 8) | src[i]; - bits +=3D 8; - do { - bits -=3D 6; - *cp++ =3D base64url_table[(ac >> bits) & 0x3f]; - } while (bits >=3D 6); - } - if (bits) - *cp++ =3D base64url_table[(ac << (6 - bits)) & 0x3f]; - return cp - dst; -} - -/** - * fscrypt_base64url_decode() - base64url-decode a string - * @src: the string to decode. Doesn't need to be NUL-terminated. - * @srclen: the length of @src in bytes - * @dst: (output) the decoded binary data - * - * Decodes a string using base64url encoding, i.e. the "Base 64 Encoding w= ith - * URL and Filename Safe Alphabet" specified by RFC 4648. '=3D'-padding i= sn't - * accepted, nor are non-encoding characters such as whitespace. - * - * This implementation hasn't been optimized for performance. - * - * Return: the length of the resulting decoded binary data in bytes, - * or -1 if the string isn't a valid base64url string. - */ -static int fscrypt_base64url_decode(const char *src, int srclen, u8 *dst) -{ - u32 ac =3D 0; - int bits =3D 0; - int i; - u8 *bp =3D dst; - - for (i =3D 0; i < srclen; i++) { - const char *p =3D strchr(base64url_table, src[i]); - - if (p =3D=3D NULL || src[i] =3D=3D 0) - return -1; - ac =3D (ac << 6) | (p - base64url_table); - bits +=3D 6; - if (bits >=3D 8) { - bits -=3D 8; - *bp++ =3D (u8)(ac >> bits); - } - } - if (ac & ((1 << bits) - 1)) - return -1; - return bp - dst; -} - bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, u32 orig_len, u32 max_len, u32 *encrypted_len_ret) @@ -387,8 +313,8 @@ int fscrypt_fname_disk_to_usr(const struct inode *inode, nokey_name.sha256); size =3D FSCRYPT_NOKEY_NAME_MAX; } - oname->len =3D fscrypt_base64url_encode((const u8 *)&nokey_name, size, - oname->name); + oname->len =3D base64_encode((const u8 *)&nokey_name, size, + oname->name, false, base64url_table); return 0; } EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); @@ -467,8 +393,8 @@ int fscrypt_setup_filename(struct inode *dir, const str= uct qstr *iname, if (fname->crypto_buf.name =3D=3D NULL) return -ENOMEM; =20 - ret =3D fscrypt_base64url_decode(iname->name, iname->len, - fname->crypto_buf.name); + ret =3D base64_decode(iname->name, iname->len, + fname->crypto_buf.name, false, base64url_table); if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) || (ret > offsetof(struct fscrypt_nokey_name, sha256) && ret !=3D FSCRYPT_NOKEY_NAME_MAX)) { --=20 2.34.1 From nobody Thu Oct 2 20:46:25 2025 Received: from mail-pg1-f182.google.com (mail-pg1-f182.google.com [209.85.215.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E3AB296BA9 for ; Thu, 11 Sep 2025 07:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576790; cv=none; b=jtNG7SnmBGKb02aHadxdpWX+yYPsxeDACjdAIFhVAakl9e0p4fJi+2PnsZYGPEYnBbzRiQmrGvHWyRKcpC+sXaOtjrxdt3kbCFbC/ixs6jCJRCxQ8Mq8Yow732CTYYmUHclllXbmgZX9fFfmkZ6lpl0Yt8t1Hx69GEMcWZoDcks= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757576790; c=relaxed/simple; bh=hyrovsqb25GvOk5ch0SE10QIDXuqIsRkz/P2XEfDCm4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Oow/PojyGQrg6pIB+ZlEYssP+fHT6YEoS+Um9qHsLKzGDJ49D1riNX5NChKpQu51GVLUe/jjrXK1bKNMweeNc4UjMysfNbVKvm9bkyXqVlpgX7jA8lie70dvtpKD8L6/nfFaT1HVdVq9FOH+Jvua3F3sswgHKfe6Z5xp1GclA/c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw; spf=pass smtp.mailfrom=gms.tku.edu.tw; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b=TDK4leq3; arc=none smtp.client-ip=209.85.215.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gms.tku.edu.tw Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gms-tku-edu-tw.20230601.gappssmtp.com header.i=@gms-tku-edu-tw.20230601.gappssmtp.com header.b="TDK4leq3" Received: by mail-pg1-f182.google.com with SMTP id 41be03b00d2f7-b523af71683so402931a12.3 for ; Thu, 11 Sep 2025 00:46:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gms-tku-edu-tw.20230601.gappssmtp.com; s=20230601; t=1757576788; x=1758181588; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/o5UYWtgC17zidQRxgu3di44p2yuLDtqoBTP3KdD9qk=; b=TDK4leq3UlGV/qzuVwuOMXfh6wGfrcmPYnDlI+gt1yO9LJYLd5J86OM1yHMIosStXN QJVQRjBMCKcfr310lUmDDWlbCl0veaX7RPs1s630aPCwWRWnRebXEE5TLzCjnvWt9rto GnKHuEDVUJy8kOYs8oxSjJqS+WWkNBYALPglTcsryNg1jn/rFCi9Y4pV2WbeWX6dmey8 Rlsfj3Ljc831tLj2taQWnrVtOQUtUQTo5YcwaeLFiPoNlrHvJw7ArM5y6PpWwCu7j/ZR ZrQH/V323u38WrV/1a2K6xwtN+TCuB2B0s9p+Jg26g3AMRwW4YHThbPPTfhTEvKMAl12 rYww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757576788; x=1758181588; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/o5UYWtgC17zidQRxgu3di44p2yuLDtqoBTP3KdD9qk=; b=Jocn/3Hu7J611QOGQKTKDZw34l0ExOk3Q+YRp51PhnkuP3UzSDlAaADQe5mx1OQDoB Rr+qh59Ioq385ydYnIhzxj4aizNAR0Rgmlt+eYQ0LMGpPWgfSCjaWxoBkt8AT+JKk227 rmHPs/Q6BHXsEk+7eEZtiRgc3aMaCzzmfdrPvfdJp+IxqDWVXMY8cjEBBRPVzbdtADn0 y/x8LkF4kuC9zG670Zaq3kQlkOdcr1S37D2vNtKm2KTST6p+FSC44ns5qZ1HlTh7mZHh jeYDYAmkJHktuPLdTy0Xin46muP8DDkF+E9j9a+UU0ToIGKCGWTUe/Q+WZTR89h077Eq 6dYA== X-Forwarded-Encrypted: i=1; AJvYcCXyXSrYDwcDrkE6B1Z2Pd0RP2SpVAIg12zkrE18qERc7BWX4SKwMD2A4s68JnZsJPt4Y7020qlEKBstJ0g=@vger.kernel.org X-Gm-Message-State: AOJu0YyTfC8d1aWQTKl3LxdNNbJN0i4GWlgpgru3RG6S79oTmEhvPjTa 6XH8O2AbwwsJvy/0ZawP76hpCdupi7T/oqrM7/zisELS3W2sE3r1b3zmzUih7J3X4PG90mnzxLc CSJ88qII= X-Gm-Gg: ASbGncvxc3ScAmUxXF7GDbuEWQsYRTEZ8hDu6GjgSAkgSSkzYW58+ZlEczu7surgOn5 lq4xz7g0xX5vX2jxiUTKXIHyrXGbCu+hk9DOrD1yehDO/McfFg2utOPy1cZngN1/f6rTLOjiIUN uKYi4wi4Jj9ArnnDFwuo0MWL61yqgunxsOdOFkK6u2aZImcniSkJmLMZjyNDWJSFti8e+LGUakL SLmaSPXUCjvqN98/rHy3wGDeDyntKgANFGwQJBmFOFQoMMdMKUI3CuXSZlsAUc/U1bHGdBjWV+M aMbYU3hUHPwZ/11Z2GZyBdWUf+4fdiyvKKLe+bvUYiCm9a0NgJLNe9yjVFa6O1zC7WsJhb+Ork1 uO0+rBhM73YNu3KH8gfeQQAAh81HOhtOla61sKEEBuHeaacD7/+EhU4VGFejcn5qSFA5u X-Google-Smtp-Source: AGHT+IHUrbIDUjSvWXWDJnw2/rvjU/6tI+i+eOkABLbPn89zVIkTMb70/fAZWJUo/N9Zo8PVFcB0yA== X-Received: by 2002:a05:6a20:939d:b0:24a:8315:7e2 with SMTP id adf61e73a8af0-2533fab6295mr27158794637.20.1757576787693; Thu, 11 Sep 2025 00:46:27 -0700 (PDT) Received: from wu-Pro-E500-G6-WS720T.. ([2001:288:7001:2703:7811:c085:c184:85be]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-77607a47c47sm1152799b3a.35.2025.09.11.00.46.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Sep 2025 00:46:26 -0700 (PDT) From: Guan-Chun Wu <409411716@gms.tku.edu.tw> To: 409411716@gms.tku.edu.tw Cc: akpm@linux-foundation.org, axboe@kernel.dk, ceph-devel@vger.kernel.org, ebiggers@kernel.org, hch@lst.de, home7438072@gmail.com, idryomov@gmail.com, jaegeuk@kernel.org, kbusch@kernel.org, linux-fscrypt@vger.kernel.org, linux-kernel@vger.kernel.org, linux-nvme@lists.infradead.org, sagi@grimberg.me, tytso@mit.edu, visitorckw@gmail.com, xiubli@redhat.com Subject: [PATCH v2 5/5] ceph: replace local base64 encode/decode with generic lib/base64 helpers Date: Thu, 11 Sep 2025 15:46:17 +0800 Message-Id: <20250911074617.694704-1-409411716@gms.tku.edu.tw> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20250911072925.547163-1-409411716@gms.tku.edu.tw> References: <20250911072925.547163-1-409411716@gms.tku.edu.tw> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Remove the local ceph_base64_encode and ceph_base64_decode functions and replace their usage with the generic base64_encode and base64_decode helpers from the kernel's lib/base64 library. This eliminates redundant implementations in Ceph, reduces code duplication, and leverages the optimized and well-maintained standard base64 code within the kernel. The change keeps the existing encoding table and disables padding, ensuring no functional or format changes. At the same time, Ceph also benefits from the optimized encoder/decoder: encoding performance improves by ~2.7x and decoding by ~12-15x compared to the previous local implementation. Overall, this improves maintainability, consistency with other kernel components, and runtime performance. Signed-off-by: Guan-Chun Wu <409411716@gms.tku.edu.tw> Reviewed-by: Kuan-Wei Chiu --- fs/ceph/crypto.c | 53 +++++------------------------------------------- fs/ceph/crypto.h | 6 ++---- fs/ceph/dir.c | 5 +++-- fs/ceph/inode.c | 2 +- 4 files changed, 11 insertions(+), 55 deletions(-) diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index cab722619..a3cb4ad99 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -21,53 +21,9 @@ * used the base64 encoding defined for IMAP mailbox names (RFC 3501) inst= ead, * which replaces '-' and '_' by '+' and ','. */ -static const char base64_table[65] =3D +const char ceph_base64_table[65] =3D "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; =20 -int ceph_base64_encode(const u8 *src, int srclen, char *dst) -{ - u32 ac =3D 0; - int bits =3D 0; - int i; - char *cp =3D dst; - - for (i =3D 0; i < srclen; i++) { - ac =3D (ac << 8) | src[i]; - bits +=3D 8; - do { - bits -=3D 6; - *cp++ =3D base64_table[(ac >> bits) & 0x3f]; - } while (bits >=3D 6); - } - if (bits) - *cp++ =3D base64_table[(ac << (6 - bits)) & 0x3f]; - return cp - dst; -} - -int ceph_base64_decode(const char *src, int srclen, u8 *dst) -{ - u32 ac =3D 0; - int bits =3D 0; - int i; - u8 *bp =3D dst; - - for (i =3D 0; i < srclen; i++) { - const char *p =3D strchr(base64_table, src[i]); - - if (p =3D=3D NULL || src[i] =3D=3D 0) - return -1; - ac =3D (ac << 6) | (p - base64_table); - bits +=3D 6; - if (bits >=3D 8) { - bits -=3D 8; - *bp++ =3D (u8)(ac >> bits); - } - } - if (ac & ((1 << bits) - 1)) - return -1; - return bp - dst; -} - static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t l= en) { struct ceph_inode_info *ci =3D ceph_inode(inode); @@ -316,7 +272,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, c= har *buf, int elen) } =20 /* base64 encode the encrypted name */ - elen =3D ceph_base64_encode(cryptbuf, len, p); + elen =3D base64_encode(cryptbuf, len, p, false, ceph_base64_table); doutc(cl, "base64-encoded ciphertext name =3D %.*s\n", elen, p); =20 /* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */ @@ -410,7 +366,8 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, s= truct fscrypt_str *tname, tname =3D &_tname; } =20 - declen =3D ceph_base64_decode(name, name_len, tname->name); + declen =3D base64_decode(name, name_len, + tname->name, false, ceph_base64_table); if (declen <=3D 0) { ret =3D -EIO; goto out; @@ -424,7 +381,7 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, s= truct fscrypt_str *tname, =20 ret =3D fscrypt_fname_disk_to_usr(dir, 0, 0, &iname, oname); if (!ret && (dir !=3D fname->dir)) { - char tmp_buf[CEPH_BASE64_CHARS(NAME_MAX)]; + char tmp_buf[BASE64_CHARS(NAME_MAX)]; =20 name_len =3D snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld", oname->len, oname->name, dir->i_ino); diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h index 23612b2e9..c94da3818 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h @@ -8,6 +8,7 @@ =20 #include #include +#include =20 #define CEPH_FSCRYPT_BLOCK_SHIFT 12 #define CEPH_FSCRYPT_BLOCK_SIZE (_AC(1, UL) << CEPH_FSCRYPT_BLOCK_SHIFT) @@ -89,10 +90,7 @@ static inline u32 ceph_fscrypt_auth_len(struct ceph_fscr= ypt_auth *fa) */ #define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE) =20 -#define CEPH_BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3) - -int ceph_base64_encode(const u8 *src, int srclen, char *dst); -int ceph_base64_decode(const char *src, int srclen, u8 *dst); +extern const char ceph_base64_table[65]; =20 void ceph_fscrypt_set_ops(struct super_block *sb); =20 diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 8478e7e75..830715988 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -998,13 +998,14 @@ static int prep_encrypted_symlink_target(struct ceph_= mds_request *req, if (err) goto out; =20 - req->r_path2 =3D kmalloc(CEPH_BASE64_CHARS(osd_link.len) + 1, GFP_KERNEL); + req->r_path2 =3D kmalloc(BASE64_CHARS(osd_link.len) + 1, GFP_KERNEL); if (!req->r_path2) { err =3D -ENOMEM; goto out; } =20 - len =3D ceph_base64_encode(osd_link.name, osd_link.len, req->r_path2); + len =3D base64_encode(osd_link.name, osd_link.len, + req->r_path2, false, ceph_base64_table); req->r_path2[len] =3D '\0'; out: fscrypt_fname_free_buffer(&osd_link); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index fc543075b..94b729ccc 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -911,7 +911,7 @@ static int decode_encrypted_symlink(struct ceph_mds_cli= ent *mdsc, if (!sym) return -ENOMEM; =20 - declen =3D ceph_base64_decode(encsym, enclen, sym); + declen =3D base64_decode(encsym, enclen, sym, false, ceph_base64_table); if (declen < 0) { pr_err_client(cl, "can't decode symlink (%d). Content: %.*s\n", --=20 2.34.1