Skip to content

Commit 2c58d54

Browse files
ebiggerstytso
authored andcommitted
fscrypt: cache decrypted symlink target in ->i_link
Path lookups that traverse encrypted symlink(s) are very slow because each encrypted symlink needs to be decrypted each time it's followed. This also involves dropping out of rcu-walk mode. Make encrypted symlinks faster by caching the decrypted symlink target in ->i_link. The first call to fscrypt_get_symlink() sets it. Then, the existing VFS path lookup code uses the non-NULL ->i_link to take the fast path where ->get_link() isn't called, and lookups in rcu-walk mode remain in rcu-walk mode. Also set ->i_link immediately when a new encrypted symlink is created. To safely free the symlink target after an RCU grace period has elapsed, introduce a new function fscrypt_free_inode(), and make the relevant filesystems call it just before actually freeing the inode. Cc: Al Viro <[email protected]> Signed-off-by: Eric Biggers <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 4c4f7c1 commit 2c58d54

File tree

6 files changed

+68
-7
lines changed

6 files changed

+68
-7
lines changed

fs/crypto/hooks.c

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -189,21 +189,30 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
189189
sd->len = cpu_to_le16(ciphertext_len);
190190

191191
err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len);
192-
if (err) {
193-
if (!disk_link->name)
194-
kfree(sd);
195-
return err;
196-
}
192+
if (err)
193+
goto err_free_sd;
194+
197195
/*
198196
* Null-terminating the ciphertext doesn't make sense, but we still
199197
* count the null terminator in the length, so we might as well
200198
* initialize it just in case the filesystem writes it out.
201199
*/
202200
sd->encrypted_path[ciphertext_len] = '\0';
203201

202+
/* Cache the plaintext symlink target for later use by get_link() */
203+
err = -ENOMEM;
204+
inode->i_link = kmemdup(target, len + 1, GFP_NOFS);
205+
if (!inode->i_link)
206+
goto err_free_sd;
207+
204208
if (!disk_link->name)
205209
disk_link->name = (unsigned char *)sd;
206210
return 0;
211+
212+
err_free_sd:
213+
if (!disk_link->name)
214+
kfree(sd);
215+
return err;
207216
}
208217
EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
209218

@@ -212,7 +221,7 @@ EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
212221
* @inode: the symlink inode
213222
* @caddr: the on-disk contents of the symlink
214223
* @max_size: size of @caddr buffer
215-
* @done: if successful, will be set up to free the returned target
224+
* @done: if successful, will be set up to free the returned target if needed
216225
*
217226
* If the symlink's encryption key is available, we decrypt its target.
218227
* Otherwise, we encode its target for presentation.
@@ -227,19 +236,26 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
227236
{
228237
const struct fscrypt_symlink_data *sd;
229238
struct fscrypt_str cstr, pstr;
239+
bool has_key;
230240
int err;
231241

232242
/* This is for encrypted symlinks only */
233243
if (WARN_ON(!IS_ENCRYPTED(inode)))
234244
return ERR_PTR(-EINVAL);
235245

246+
/* If the decrypted target is already cached, just return it. */
247+
pstr.name = READ_ONCE(inode->i_link);
248+
if (pstr.name)
249+
return pstr.name;
250+
236251
/*
237252
* Try to set up the symlink's encryption key, but we can continue
238253
* regardless of whether the key is available or not.
239254
*/
240255
err = fscrypt_get_encryption_info(inode);
241256
if (err)
242257
return ERR_PTR(err);
258+
has_key = fscrypt_has_encryption_key(inode);
243259

244260
/*
245261
* For historical reasons, encrypted symlink targets are prefixed with
@@ -271,7 +287,17 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
271287
goto err_kfree;
272288

273289
pstr.name[pstr.len] = '\0';
274-
set_delayed_call(done, kfree_link, pstr.name);
290+
291+
/*
292+
* Cache decrypted symlink targets in i_link for later use. Don't cache
293+
* symlink targets encoded without the key, since those become outdated
294+
* once the key is added. This pairs with the READ_ONCE() above and in
295+
* the VFS path lookup code.
296+
*/
297+
if (!has_key ||
298+
cmpxchg_release(&inode->i_link, NULL, pstr.name) != NULL)
299+
set_delayed_call(done, kfree_link, pstr.name);
300+
275301
return pstr.name;
276302

277303
err_kfree:

fs/crypto/keyinfo.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,9 +584,30 @@ int fscrypt_get_encryption_info(struct inode *inode)
584584
}
585585
EXPORT_SYMBOL(fscrypt_get_encryption_info);
586586

587+
/**
588+
* fscrypt_put_encryption_info - free most of an inode's fscrypt data
589+
*
590+
* Free the inode's fscrypt_info. Filesystems must call this when the inode is
591+
* being evicted. An RCU grace period need not have elapsed yet.
592+
*/
587593
void fscrypt_put_encryption_info(struct inode *inode)
588594
{
589595
put_crypt_info(inode->i_crypt_info);
590596
inode->i_crypt_info = NULL;
591597
}
592598
EXPORT_SYMBOL(fscrypt_put_encryption_info);
599+
600+
/**
601+
* fscrypt_free_inode - free an inode's fscrypt data requiring RCU delay
602+
*
603+
* Free the inode's cached decrypted symlink target, if any. Filesystems must
604+
* call this after an RCU grace period, just before they free the inode.
605+
*/
606+
void fscrypt_free_inode(struct inode *inode)
607+
{
608+
if (IS_ENCRYPTED(inode) && S_ISLNK(inode->i_mode)) {
609+
kfree(inode->i_link);
610+
inode->i_link = NULL;
611+
}
612+
}
613+
EXPORT_SYMBOL(fscrypt_free_inode);

fs/ext4/super.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,9 @@ static int ext4_drop_inode(struct inode *inode)
11101110
static void ext4_i_callback(struct rcu_head *head)
11111111
{
11121112
struct inode *inode = container_of(head, struct inode, i_rcu);
1113+
1114+
fscrypt_free_inode(inode);
1115+
11131116
kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
11141117
}
11151118

fs/f2fs/super.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,9 @@ static void f2fs_dirty_inode(struct inode *inode, int flags)
10031003
static void f2fs_i_callback(struct rcu_head *head)
10041004
{
10051005
struct inode *inode = container_of(head, struct inode, i_rcu);
1006+
1007+
fscrypt_free_inode(inode);
1008+
10061009
kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode));
10071010
}
10081011

fs/ubifs/super.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,10 @@ static void ubifs_i_callback(struct rcu_head *head)
276276
{
277277
struct inode *inode = container_of(head, struct inode, i_rcu);
278278
struct ubifs_inode *ui = ubifs_inode(inode);
279+
279280
kfree(ui->data);
281+
fscrypt_free_inode(inode);
282+
280283
kmem_cache_free(ubifs_inode_slab, ui);
281284
}
282285

include/linux/fscrypt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *,
128128
/* keyinfo.c */
129129
extern int fscrypt_get_encryption_info(struct inode *);
130130
extern void fscrypt_put_encryption_info(struct inode *);
131+
extern void fscrypt_free_inode(struct inode *);
131132

132133
/* fname.c */
133134
extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
@@ -341,6 +342,10 @@ static inline void fscrypt_put_encryption_info(struct inode *inode)
341342
return;
342343
}
343344

345+
static inline void fscrypt_free_inode(struct inode *inode)
346+
{
347+
}
348+
344349
/* fname.c */
345350
static inline int fscrypt_setup_filename(struct inode *dir,
346351
const struct qstr *iname,

0 commit comments

Comments
 (0)