From c23f448ba818cc7996a4056cd2b989f31f60bbd7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 13 Mar 2023 15:12:30 -0700 Subject: [PATCH 1/6] fscrypt: improve fscrypt_destroy_keyring() documentation Document that fscrypt_destroy_keyring() must be called after all potentially-encrypted inodes have been evicted. Link: https://lore.kernel.org/r/20230313221231.272498-3-ebiggers@kernel.org Signed-off-by: Eric Biggers --- fs/crypto/keyring.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 78086f8dbda5..bb15709ac9a4 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -207,10 +207,11 @@ static int allocate_filesystem_keyring(struct super_block *sb) * Release all encryption keys that have been added to the filesystem, along * with the keyring that contains them. * - * This is called at unmount time. The filesystem's underlying block device(s) - * are still available at this time; this is important because after user file - * accesses have been allowed, this function may need to evict keys from the - * keyslots of an inline crypto engine, which requires the block device(s). + * This is called at unmount time, after all potentially-encrypted inodes have + * been evicted. The filesystem's underlying block device(s) are still + * available at this time; this is important because after user file accesses + * have been allowed, this function may need to evict keys from the keyslots of + * an inline crypto engine, which requires the block device(s). */ void fscrypt_destroy_keyring(struct super_block *sb) { @@ -227,12 +228,12 @@ void fscrypt_destroy_keyring(struct super_block *sb) hlist_for_each_entry_safe(mk, tmp, bucket, mk_node) { /* - * Since all inodes were already evicted, every key - * remaining in the keyring should have an empty inode - * list, and should only still be in the keyring due to - * the single active ref associated with ->mk_secret. - * There should be no structural refs beyond the one - * associated with the active ref. + * Since all potentially-encrypted inodes were already + * evicted, every key remaining in the keyring should + * have an empty inode list, and should only still be in + * the keyring due to the single active ref associated + * with ->mk_secret. There should be no structural refs + * beyond the one associated with the active ref. */ WARN_ON(refcount_read(&mk->mk_active_refs) != 1); WARN_ON(refcount_read(&mk->mk_struct_refs) != 1); From 56a6cc4f62961d8324b6d19fa0653e88f547c6e8 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 13 Mar 2023 15:12:31 -0700 Subject: [PATCH 2/6] fscrypt: check for NULL keyring in fscrypt_put_master_key_activeref() It is a bug for fscrypt_put_master_key_activeref() to see a NULL keyring. But it used to be possible due to the bug, now fixed, where fscrypt_destroy_keyring() was called before security_sb_delete(). To be consistent with how fscrypt_destroy_keyring() uses WARN_ON for the same issue, WARN and leak the fscrypt_master_key if the keyring is NULL instead of dereferencing the NULL pointer. This is a robustness improvement, not a fix. Link: https://lore.kernel.org/r/20230313221231.272498-4-ebiggers@kernel.org Signed-off-by: Eric Biggers --- fs/crypto/keyring.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index bb15709ac9a4..13d336a6cc5d 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -92,6 +92,8 @@ void fscrypt_put_master_key_activeref(struct super_block *sb, * destroying any subkeys embedded in it. */ + if (WARN_ON(!sb->s_master_keys)) + return; spin_lock(&sb->s_master_keys->lock); hlist_del_rcu(&mk->mk_node); spin_unlock(&sb->s_master_keys->lock); From 5bbe080fe4b8fe1e8ee844d0185c5029cce46c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Henriques?= Date: Thu, 16 Mar 2023 18:14:11 +0000 Subject: [PATCH 3/6] fscrypt: new helper function - fscrypt_prepare_lookup_partial() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces a new helper function which can be used both in lookups and in atomic_open operations by filesystems that want to handle filename encryption and no-key dentries themselves. The reason for this function to be used in atomic open is that this operation can act as a lookup if handed a dentry that is negative. And in this case we may need to set DCACHE_NOKEY_NAME. Signed-off-by: Luís Henriques Tested-by: Xiubo Li Reviewed-by: Xiubo Li [ebiggers: improved the function comment, and moved the function to just below __fscrypt_prepare_lookup()] Link: https://lore.kernel.org/r/20230320220149.21863-1-ebiggers@kernel.org Signed-off-by: Eric Biggers --- fs/crypto/hooks.c | 30 ++++++++++++++++++++++++++++++ include/linux/fscrypt.h | 7 +++++++ 2 files changed, 37 insertions(+) diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 7b8c5a1104b5..9151934c5086 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -111,6 +111,36 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry, } EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); +/** + * fscrypt_prepare_lookup_partial() - prepare lookup without filename setup + * @dir: the encrypted directory being searched + * @dentry: the dentry being looked up in @dir + * + * This function should be used by the ->lookup and ->atomic_open methods of + * filesystems that handle filename encryption and no-key name encoding + * themselves and thus can't use fscrypt_prepare_lookup(). Like + * fscrypt_prepare_lookup(), this will try to set up the directory's encryption + * key and will set DCACHE_NOKEY_NAME on the dentry if the key is unavailable. + * However, this function doesn't set up a struct fscrypt_name for the filename. + * + * Return: 0 on success; -errno on error. Note that the encryption key being + * unavailable is not considered an error. It is also not an error if + * the encryption policy is unsupported by this kernel; that is treated + * like the key being unavailable, so that files can still be deleted. + */ +int fscrypt_prepare_lookup_partial(struct inode *dir, struct dentry *dentry) +{ + int err = fscrypt_get_encryption_info(dir, true); + + if (!err && !fscrypt_has_encryption_key(dir)) { + spin_lock(&dentry->d_lock); + dentry->d_flags |= DCACHE_NOKEY_NAME; + spin_unlock(&dentry->d_lock); + } + return err; +} +EXPORT_SYMBOL_GPL(fscrypt_prepare_lookup_partial); + int __fscrypt_prepare_readdir(struct inode *dir) { return fscrypt_get_encryption_info(dir, true); diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 82a78c05c1fa..5e2b7f7ae2c0 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -361,6 +361,7 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry, unsigned int flags); int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry, struct fscrypt_name *fname); +int fscrypt_prepare_lookup_partial(struct inode *dir, struct dentry *dentry); int __fscrypt_prepare_readdir(struct inode *dir); int __fscrypt_prepare_setattr(struct dentry *dentry, struct iattr *attr); int fscrypt_prepare_setflags(struct inode *inode, @@ -676,6 +677,12 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir, return -EOPNOTSUPP; } +static inline int fscrypt_prepare_lookup_partial(struct inode *dir, + struct dentry *dentry) +{ + return -EOPNOTSUPP; +} + static inline int __fscrypt_prepare_readdir(struct inode *dir) { return -EOPNOTSUPP; From 10e3e014fdbc5e5ac2f621e666e0a46e3ca11b29 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 20 Mar 2023 16:39:43 -0700 Subject: [PATCH 4/6] fscrypt: use WARN_ON_ONCE instead of WARN_ON As per Linus's suggestion (https://lore.kernel.org/r/CAHk-=whefxRGyNGzCzG6BVeM=5vnvgb-XhSeFJVxJyAxAF8XRA@mail.gmail.com), use WARN_ON_ONCE instead of WARN_ON. This barely adds any extra overhead, and it makes it so that if any of these ever becomes reachable (they shouldn't, but that's the point), the logs can't be flooded. Link: https://lore.kernel.org/r/20230320233943.73600-1-ebiggers@kernel.org Signed-off-by: Eric Biggers --- fs/crypto/bio.c | 6 +++--- fs/crypto/fname.c | 4 ++-- fs/crypto/fscrypt_private.h | 4 ++-- fs/crypto/hkdf.c | 4 ++-- fs/crypto/hooks.c | 2 +- fs/crypto/keyring.c | 14 +++++++------- fs/crypto/keysetup.c | 12 ++++++------ fs/crypto/policy.c | 4 ++-- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index dac786fb6f80..2622913f11ab 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -72,7 +72,7 @@ static int fscrypt_zeroout_range_inline_crypt(const struct inode *inode, bio_set_op_attrs(bio, REQ_OP_WRITE, 0); } ret = bio_add_page(bio, ZERO_PAGE(0), bytes_this_page, 0); - if (WARN_ON(ret != bytes_this_page)) { + if (WARN_ON_ONCE(ret != bytes_this_page)) { err = -EIO; goto out; } @@ -150,7 +150,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, break; } nr_pages = i; - if (WARN_ON(nr_pages <= 0)) + if (WARN_ON_ONCE(nr_pages <= 0)) return -EINVAL; /* This always succeeds since __GFP_DIRECT_RECLAIM is set. */ @@ -175,7 +175,7 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, offset += blocksize; if (offset == PAGE_SIZE || len == 0) { ret = bio_add_page(bio, pages[i++], offset, 0); - if (WARN_ON(ret != offset)) { + if (WARN_ON_ONCE(ret != offset)) { err = -EIO; goto out; } diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 12bd61d20f69..6eae3f12ad50 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -110,7 +110,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, * Copy the filename to the output buffer for encrypting in-place and * pad it with the needed number of NUL bytes. */ - if (WARN_ON(olen < iname->len)) + if (WARN_ON_ONCE(olen < iname->len)) return -ENOBUFS; memcpy(out, iname->name, iname->len); memset(out + iname->len, 0, olen - iname->len); @@ -570,7 +570,7 @@ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name) { const struct fscrypt_info *ci = dir->i_crypt_info; - WARN_ON(!ci->ci_dirhash_key_initialized); + WARN_ON_ONCE(!ci->ci_dirhash_key_initialized); return siphash(name->name, name->len, &ci->ci_dirhash_key); } diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 0fec2dfc36eb..05310aa741fd 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -101,7 +101,7 @@ static inline const u8 *fscrypt_context_nonce(const union fscrypt_context *ctx) case FSCRYPT_CONTEXT_V2: return ctx->v2.nonce; } - WARN_ON(1); + WARN_ON_ONCE(1); return NULL; } @@ -386,7 +386,7 @@ fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key, const u8 *raw_key, const struct fscrypt_info *ci) { - WARN_ON(1); + WARN_ON_ONCE(1); return -EOPNOTSUPP; } diff --git a/fs/crypto/hkdf.c b/fs/crypto/hkdf.c index 7607d18b35fc..5a384dad2c72 100644 --- a/fs/crypto/hkdf.c +++ b/fs/crypto/hkdf.c @@ -79,7 +79,7 @@ int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, return PTR_ERR(hmac_tfm); } - if (WARN_ON(crypto_shash_digestsize(hmac_tfm) != sizeof(prk))) { + if (WARN_ON_ONCE(crypto_shash_digestsize(hmac_tfm) != sizeof(prk))) { err = -EINVAL; goto err_free_tfm; } @@ -125,7 +125,7 @@ int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, u8 counter = 1; u8 tmp[HKDF_HASHLEN]; - if (WARN_ON(okmlen > 255 * HKDF_HASHLEN)) + if (WARN_ON_ONCE(okmlen > 255 * HKDF_HASHLEN)) return -EINVAL; desc->tfm = hkdf->hmac_tfm; diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 9151934c5086..9e786ae66a13 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -345,7 +345,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, int err; /* This is for encrypted symlinks only */ - if (WARN_ON(!IS_ENCRYPTED(inode))) + if (WARN_ON_ONCE(!IS_ENCRYPTED(inode))) return ERR_PTR(-EINVAL); /* If the decrypted target is already cached, just return it. */ diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 13d336a6cc5d..7cbb1fd872ac 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -73,7 +73,7 @@ void fscrypt_put_master_key(struct fscrypt_master_key *mk) * fscrypt_master_key struct itself after an RCU grace period ensures * that concurrent keyring lookups can no longer find it. */ - WARN_ON(refcount_read(&mk->mk_active_refs) != 0); + WARN_ON_ONCE(refcount_read(&mk->mk_active_refs) != 0); key_put(mk->mk_users); mk->mk_users = NULL; call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key); @@ -92,7 +92,7 @@ void fscrypt_put_master_key_activeref(struct super_block *sb, * destroying any subkeys embedded in it. */ - if (WARN_ON(!sb->s_master_keys)) + if (WARN_ON_ONCE(!sb->s_master_keys)) return; spin_lock(&sb->s_master_keys->lock); hlist_del_rcu(&mk->mk_node); @@ -102,8 +102,8 @@ void fscrypt_put_master_key_activeref(struct super_block *sb, * ->mk_active_refs == 0 implies that ->mk_secret is not present and * that ->mk_decrypted_inodes is empty. */ - WARN_ON(is_master_key_secret_present(&mk->mk_secret)); - WARN_ON(!list_empty(&mk->mk_decrypted_inodes)); + WARN_ON_ONCE(is_master_key_secret_present(&mk->mk_secret)); + WARN_ON_ONCE(!list_empty(&mk->mk_decrypted_inodes)); for (i = 0; i <= FSCRYPT_MODE_MAX; i++) { fscrypt_destroy_prepared_key( @@ -237,9 +237,9 @@ void fscrypt_destroy_keyring(struct super_block *sb) * with ->mk_secret. There should be no structural refs * beyond the one associated with the active ref. */ - WARN_ON(refcount_read(&mk->mk_active_refs) != 1); - WARN_ON(refcount_read(&mk->mk_struct_refs) != 1); - WARN_ON(!is_master_key_secret_present(&mk->mk_secret)); + WARN_ON_ONCE(refcount_read(&mk->mk_active_refs) != 1); + WARN_ON_ONCE(refcount_read(&mk->mk_struct_refs) != 1); + WARN_ON_ONCE(!is_master_key_secret_present(&mk->mk_secret)); wipe_master_key_secret(&mk->mk_secret); fscrypt_put_master_key_activeref(sb, mk); } diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index aa94fba9d17e..84cdae306328 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -125,7 +125,7 @@ fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, pr_info("fscrypt: %s using implementation \"%s\"\n", mode->friendly_name, crypto_skcipher_driver_name(tfm)); } - if (WARN_ON(crypto_skcipher_ivsize(tfm) != mode->ivsize)) { + if (WARN_ON_ONCE(crypto_skcipher_ivsize(tfm) != mode->ivsize)) { err = -EINVAL; goto err_free_tfm; } @@ -199,7 +199,7 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci, unsigned int hkdf_infolen = 0; int err; - if (WARN_ON(mode_num > FSCRYPT_MODE_MAX)) + if (WARN_ON_ONCE(mode_num > FSCRYPT_MODE_MAX)) return -EINVAL; prep_key = &keys[mode_num]; @@ -282,8 +282,8 @@ int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, void fscrypt_hash_inode_number(struct fscrypt_info *ci, const struct fscrypt_master_key *mk) { - WARN_ON(ci->ci_inode->i_ino == 0); - WARN_ON(!mk->mk_ino_hash_key_initialized); + WARN_ON_ONCE(ci->ci_inode->i_ino == 0); + WARN_ON_ONCE(!mk->mk_ino_hash_key_initialized); ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino, &mk->mk_ino_hash_key); @@ -503,7 +503,7 @@ static int setup_file_encryption_key(struct fscrypt_info *ci, err = fscrypt_setup_v2_file_key(ci, mk, need_dirhash_key); break; default: - WARN_ON(1); + WARN_ON_ONCE(1); err = -EINVAL; break; } @@ -577,7 +577,7 @@ fscrypt_setup_encryption_info(struct inode *inode, res = PTR_ERR(mode); goto out; } - WARN_ON(mode->ivsize > FSCRYPT_MAX_IV_SIZE); + WARN_ON_ONCE(mode->ivsize > FSCRYPT_MAX_IV_SIZE); crypt_info->ci_mode = mode; res = setup_file_encryption_key(crypt_info, need_dirhash_key, &mk); diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index cb941114d92a..aeb9e5e8bceb 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -48,7 +48,7 @@ int fscrypt_policy_to_key_spec(const union fscrypt_policy *policy, FSCRYPT_KEY_IDENTIFIER_SIZE); return 0; default: - WARN_ON(1); + WARN_ON_ONCE(1); return -EINVAL; } } @@ -463,7 +463,7 @@ static int set_encryption_policy(struct inode *inode, current->comm, current->pid); break; default: - WARN_ON(1); + WARN_ON_ONCE(1); return -EINVAL; } From ed78a2e6ff60b2756ca828e462a7a16cdf10c1e1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 6 Apr 2023 11:12:45 -0700 Subject: [PATCH 5/6] fscrypt: optimize fscrypt_initialize() fscrypt_initialize() is a "one-time init" function that is called whenever the key is set up for any inode on any filesystem. Make it implement "one-time init" more efficiently by not taking a global mutex in the "already initialized case" and doing fewer pointer dereferences. Link: https://lore.kernel.org/r/20230406181245.36091-1-ebiggers@kernel.org Signed-off-by: Eric Biggers --- fs/crypto/crypto.c | 19 ++++++++++++------- fs/crypto/fscrypt_private.h | 2 +- fs/crypto/keysetup.c | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 059344a8900e..d1e8541f7c2b 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -306,19 +306,24 @@ EXPORT_SYMBOL(fscrypt_decrypt_block_inplace); /** * fscrypt_initialize() - allocate major buffers for fs encryption. - * @cop_flags: fscrypt operations flags + * @sb: the filesystem superblock * * We only call this when we start accessing encrypted files, since it * results in memory getting allocated that wouldn't otherwise be used. * * Return: 0 on success; -errno on failure */ -int fscrypt_initialize(unsigned int cop_flags) +int fscrypt_initialize(struct super_block *sb) { int err = 0; + mempool_t *pool; + + /* pairs with smp_store_release() below */ + if (likely(smp_load_acquire(&fscrypt_bounce_page_pool))) + return 0; /* No need to allocate a bounce page pool if this FS won't use it. */ - if (cop_flags & FS_CFLG_OWN_PAGES) + if (sb->s_cop->flags & FS_CFLG_OWN_PAGES) return 0; mutex_lock(&fscrypt_init_mutex); @@ -326,11 +331,11 @@ int fscrypt_initialize(unsigned int cop_flags) goto out_unlock; err = -ENOMEM; - fscrypt_bounce_page_pool = - mempool_create_page_pool(num_prealloc_crypto_pages, 0); - if (!fscrypt_bounce_page_pool) + pool = mempool_create_page_pool(num_prealloc_crypto_pages, 0); + if (!pool) goto out_unlock; - + /* pairs with smp_load_acquire() above */ + smp_store_release(&fscrypt_bounce_page_pool, pool); err = 0; out_unlock: mutex_unlock(&fscrypt_init_mutex); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 05310aa741fd..7ab5a7b7eef8 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -264,7 +264,7 @@ typedef enum { /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; -int fscrypt_initialize(unsigned int cop_flags); +int fscrypt_initialize(struct super_block *sb); int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, u64 lblk_num, struct page *src_page, struct page *dest_page, unsigned int len, diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 84cdae306328..361f41ef46c7 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -560,7 +560,7 @@ fscrypt_setup_encryption_info(struct inode *inode, struct fscrypt_master_key *mk = NULL; int res; - res = fscrypt_initialize(inode->i_sb->s_cop->flags); + res = fscrypt_initialize(inode->i_sb); if (res) return res; From 3b772494fda938edf9f694c6971bd371670573ed Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 13 Mar 2023 15:12:29 -0700 Subject: [PATCH 6/6] fscrypt: destroy keyring after security_sb_delete() fscrypt_destroy_keyring() must be called after all potentially-encrypted inodes were evicted; otherwise it cannot safely destroy the keyring. Since inodes that are in-use by the Landlock LSM don't get evicted until security_sb_delete(), this means that fscrypt_destroy_keyring() must be called *after* security_sb_delete(). This fixes a WARN_ON followed by a NULL dereference, only possible if Landlock was being used on encrypted files. Fixes: d7e7b9af104c ("fscrypt: stop using keyrings subsystem for fscrypt_master_key") Cc: stable@vger.kernel.org Reported-by: syzbot+93e495f6a4f748827c88@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/00000000000044651705f6ca1e30@google.com Reviewed-by: Christian Brauner Link: https://lore.kernel.org/r/20230313221231.272498-2-ebiggers@kernel.org Signed-off-by: Eric Biggers --- fs/super.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs/super.c b/fs/super.c index d636ae6b69d0..23def92a4127 100644 --- a/fs/super.c +++ b/fs/super.c @@ -449,13 +449,22 @@ void generic_shutdown_super(struct super_block *sb) cgroup_writeback_umount(); - /* evict all inodes with zero refcount */ + /* Evict all inodes with zero refcount. */ evict_inodes(sb); - /* only nonzero refcount inodes can have marks */ + + /* + * Clean up and evict any inodes that still have references due + * to fsnotify or the security policy. + */ fsnotify_sb_delete(sb); - fscrypt_destroy_keyring(sb); security_sb_delete(sb); + /* + * Now that all potentially-encrypted inodes have been evicted, + * the fscrypt keyring can be destroyed. + */ + fscrypt_destroy_keyring(sb); + if (sb->s_dio_done_wq) { destroy_workqueue(sb->s_dio_done_wq); sb->s_dio_done_wq = NULL;