[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <tencent_583C288FFF6BA70BAF0880FB7A5CCAB5EA05@qq.com>
Date: Fri, 4 Jul 2025 12:13:22 +0800
From: Yuwen Chen <ywen.chen@...mail.com>
To: ywen.chen@...mail.com
Cc: davem@...emloft.net,
ebiggers@...nel.org,
herbert@...dor.apana.org.au,
jaegeuk@...nel.org,
linux-crypto@...r.kernel.org,
linux-fscrypt@...r.kernel.org,
linux-kernel@...r.kernel.org,
tytso@....edu
Subject: [PATCH v2] fscrypt: improve filename encryption and decryption performance
With the CONFIG_UNICODE configuration enabled, the fname_decrypt
and fscrypt_fname_encrypt functions may be called very frequently.
Since filenames are generally short, the frequent invocation of
memory allocation and release operations by these two functions
will lead to very poor performance.
Use the following program to conduct a file-creation test in
the private program directory(/data/media/0/Android/data/*)
of Android.
int main(int argc, char **argv)
{
size_t fcnt = 0;
char path[PATH_MAX];
char buf[4096] = {0};
int i, fd;
if (argc < 2)
return - EINVAL;
fcnt = atoi(argv[1]);
for (i = 0; i < fcnt; i++) {
snprintf(path, sizeof(path), "./%d", i);
fd = open(path, O_RDWR | O_CREAT, 0600);
if (fd < 0)
return - 1;
write(fd, buf, sizeof(buf));
close(fd);
}
return 0;
}
The test platform is Snapdragon 8s Gen4, with a kernel version
of v6.6 and a userdebug version.
Before this submission was merged, when creating 2000 files,
the performance test results are as follows:
$ time /data/file_creater 2000
0m14.83s real 0m00.00s user 0m14.30s system
0m15.61s real 0m00.00s user 0m15.04s system
0m14.72s real 0m00.01s user 0m14.18s system
After this submission was merged, the performance is as follows:
$ time /data/file_creater 2000
0m07.64s real 0m00.00s user 0m07.37s system
0m07.66s real 0m00.00s user 0m07.40s system
0m08.67s real 0m00.01s user 0m08.35s system
Signed-off-by: Yuwen Chen <ywen.chen@...mail.com>
---
fs/crypto/fname.c | 22 ++++++++++++++--------
include/crypto/skcipher.h | 9 +++++++++
2 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 010f9c0a4c2f1..168b2a88fa23b 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -92,14 +92,20 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
u8 *out, unsigned int olen)
{
- struct skcipher_request *req = NULL;
DECLARE_CRYPTO_WAIT(wait);
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
+ SKCIPHER_REQUEST_ON_STACK(req, tfm, MAX_SKCIPHER_REQSIZE);
union fscrypt_iv iv;
struct scatterlist sg;
int res;
+ /*
+ * When the size of the statically - allocated skcipher_request
+ * structure is insufficient, remind us to make modifications.
+ */
+ BUG_ON(MAX_SKCIPHER_REQSIZE < crypto_skcipher_reqsize(tfm));
+
/*
* Copy the filename to the output buffer for encrypting in-place and
* pad it with the needed number of NUL bytes.
@@ -124,7 +130,6 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
/* Do the encryption */
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
- skcipher_request_free(req);
if (res < 0) {
fscrypt_err(inode, "Filename encryption failed: %d", res);
return res;
@@ -148,18 +153,20 @@ static int fname_decrypt(const struct inode *inode,
const struct fscrypt_str *iname,
struct fscrypt_str *oname)
{
- struct skcipher_request *req = NULL;
DECLARE_CRYPTO_WAIT(wait);
struct scatterlist src_sg, dst_sg;
const struct fscrypt_inode_info *ci = inode->i_crypt_info;
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm;
+ SKCIPHER_REQUEST_ON_STACK(req, tfm, MAX_SKCIPHER_REQSIZE);
union fscrypt_iv iv;
int res;
- /* Allocate request */
- req = skcipher_request_alloc(tfm, GFP_NOFS);
- if (!req)
- return -ENOMEM;
+ /*
+ * When the size of the statically - allocated skcipher_request
+ * structure is insufficient, remind us to make modifications.
+ */
+ BUG_ON(MAX_SKCIPHER_REQSIZE < crypto_skcipher_reqsize(tfm));
+
skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &wait);
@@ -172,7 +179,6 @@ static int fname_decrypt(const struct inode *inode,
sg_init_one(&dst_sg, oname->name, oname->len);
skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv);
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
- skcipher_request_free(req);
if (res < 0) {
fscrypt_err(inode, "Filename decryption failed: %d", res);
return res;
diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h
index 9e5853464345b..77e74a038c36e 100644
--- a/include/crypto/skcipher.h
+++ b/include/crypto/skcipher.h
@@ -213,6 +213,7 @@ struct lskcipher_alg {
};
#define MAX_SYNC_SKCIPHER_REQSIZE 384
+#define MAX_SKCIPHER_REQSIZE 384
/*
* This performs a type-check against the "_tfm" argument to make sure
* all users have the correct skcipher tfm for doing on-stack requests.
@@ -226,6 +227,14 @@ struct lskcipher_alg {
crypto_sync_skcipher_tfm((_tfm)), \
(void *)__##name##_desc)
+#define SKCIPHER_REQUEST_ON_STACK(name, _tfm, reqsize) \
+ char __##name##_desc[sizeof(struct skcipher_request) + reqsize \
+ ] CRYPTO_MINALIGN_ATTR; \
+ struct skcipher_request *name = \
+ (((struct skcipher_request *)__##name##_desc)->base.tfm = \
+ crypto_skcipher_tfm((_tfm)), \
+ (void *)__##name##_desc)
+
/**
* DOC: Symmetric Key Cipher API
*
--
2.34.1
Powered by blists - more mailing lists