android_kernel_oneplus_msm8998/fs/ext4/crypto.c
Srinivasarao P 9848856fe1 Merge android-4.4.133 (3f51ea2) into msm-4.4
* refs/heads/tmp-3f51ea2
  Linux 4.4.133
  x86/kexec: Avoid double free_page() upon do_kexec_load() failure
  hfsplus: stop workqueue when fill_super() failed
  cfg80211: limit wiphy names to 128 bytes
  gpio: rcar: Add Runtime PM handling for interrupts
  time: Fix CLOCK_MONOTONIC_RAW sub-nanosecond accounting
  dmaengine: ensure dmaengine helpers check valid callback
  scsi: zfcp: fix infinite iteration on ERP ready list
  scsi: sg: allocate with __GFP_ZERO in sg_build_indirect()
  scsi: libsas: defer ata device eh commands to libata
  s390: use expoline thunks in the BPF JIT
  s390: extend expoline to BC instructions
  s390: move spectre sysfs attribute code
  s390/kernel: use expoline for indirect branches
  s390/lib: use expoline for indirect branches
  s390: move expoline assembler macros to a header
  s390: add assembler macros for CPU alternatives
  ext2: fix a block leak
  tcp: purge write queue in tcp_connect_init()
  sock_diag: fix use-after-free read in __sk_free
  packet: in packet_snd start writing at link layer allocation
  net: test tailroom before appending to linear skb
  btrfs: fix reading stale metadata blocks after degraded raid1 mounts
  btrfs: fix crash when trying to resume balance without the resume flag
  Btrfs: fix xattr loss after power failure
  ARM: 8772/1: kprobes: Prohibit kprobes on get_user functions
  ARM: 8770/1: kprobes: Prohibit probing on optimized_callback
  ARM: 8769/1: kprobes: Fix to use get_kprobe_ctlblk after irq-disabed
  tick/broadcast: Use for_each_cpu() specially on UP kernels
  ARM: 8771/1: kprobes: Prohibit kprobes on do_undefinstr
  efi: Avoid potential crashes, fix the 'struct efi_pci_io_protocol_32' definition for mixed mode
  s390: remove indirect branch from do_softirq_own_stack
  s390/qdio: don't release memory in qdio_setup_irq()
  s390/cpum_sf: ensure sample frequency of perf event attributes is non-zero
  s390/qdio: fix access to uninitialized qdio_q fields
  mm: don't allow deferred pages with NEED_PER_CPU_KM
  powerpc/powernv: Fix NVRAM sleep in invalid context when crashing
  procfs: fix pthread cross-thread naming if !PR_DUMPABLE
  proc read mm's {arg,env}_{start,end} with mmap semaphore taken.
  tracing/x86/xen: Remove zero data size trace events trace_xen_mmu_flush_tlb{_all}
  cpufreq: intel_pstate: Enable HWP by default
  signals: avoid unnecessary taking of sighand->siglock
  mm: filemap: avoid unnecessary calls to lock_page when waiting for IO to complete during a read
  mm: filemap: remove redundant code in do_read_cache_page
  proc: meminfo: estimate available memory more conservatively
  vmscan: do not force-scan file lru if its absolute size is small
  powerpc: Don't preempt_disable() in show_cpuinfo()
  cpuidle: coupled: remove unused define cpuidle_coupled_lock
  powerpc/powernv: remove FW_FEATURE_OPALv3 and just use FW_FEATURE_OPAL
  powerpc/powernv: Remove OPALv2 firmware define and references
  powerpc/powernv: panic() on OPAL < V3
  spi: pxa2xx: Allow 64-bit DMA
  ALSA: control: fix a redundant-copy issue
  ALSA: hda: Add Lenovo C50 All in one to the power_save blacklist
  ALSA: usb: mixer: volume quirk for CM102-A+/102S+
  usbip: usbip_host: fix bad unlock balance during stub_probe()
  usbip: usbip_host: fix NULL-ptr deref and use-after-free errors
  usbip: usbip_host: run rebind from exit when module is removed
  usbip: usbip_host: delete device from busid_table after rebind
  usbip: usbip_host: refine probe and disconnect debug msgs to be useful
  kernel/exit.c: avoid undefined behaviour when calling wait4()
  futex: futex_wake_op, fix sign_extend32 sign bits
  pipe: cap initial pipe capacity according to pipe-max-size limit
  l2tp: revert "l2tp: fix missing print session offset info"
  Revert "ARM: dts: imx6qdl-wandboard: Fix audio channel swap"
  lockd: lost rollback of set_grace_period() in lockd_down_net()
  xfrm: fix xfrm_do_migrate() with AEAD e.g(AES-GCM)
  futex: Remove duplicated code and fix undefined behaviour
  futex: Remove unnecessary warning from get_futex_key
  arm64: Add work around for Arm Cortex-A55 Erratum 1024718
  arm64: introduce mov_q macro to move a constant into a 64-bit register
  audit: move calcs after alloc and check when logging set loginuid
  ALSA: timer: Call notifier in the same spinlock
  sctp: delay the authentication for the duplicated cookie-echo chunk
  sctp: fix the issue that the cookie-ack with auth can't get processed
  tcp: ignore Fast Open on repair mode
  bonding: do not allow rlb updates to invalid mac
  tg3: Fix vunmap() BUG_ON() triggered from tg3_free_consistent().
  sctp: use the old asoc when making the cookie-ack chunk in dupcook_d
  sctp: handle two v4 addrs comparison in sctp_inet6_cmp_addr
  r8169: fix powering up RTL8168h
  qmi_wwan: do not steal interfaces from class drivers
  openvswitch: Don't swap table in nlattr_set() after OVS_ATTR_NESTED is found
  net: support compat 64-bit time in {s,g}etsockopt
  net_sched: fq: take care of throttled flows before reuse
  net/mlx4_en: Verify coalescing parameters are in range
  net: ethernet: sun: niu set correct packet size in skb
  llc: better deal with too small mtu
  ipv4: fix memory leaks in udp_sendmsg, ping_v4_sendmsg
  dccp: fix tasklet usage
  bridge: check iface upper dev when setting master via ioctl
  8139too: Use disable_irq_nosync() in rtl8139_poll_controller()
  BACKPORT, FROMLIST: fscrypt: add Speck128/256 support
  cgroup: Disable IRQs while holding css_set_lock
  Revert "cgroup: Disable IRQs while holding css_set_lock"
  cgroup: Disable IRQs while holding css_set_lock
  ANDROID: proc: fix undefined behavior in proc_uid_base_readdir
  x86: vdso: Fix leaky vdso linker with CC=clang.
  ANDROID: build: cuttlefish: Upgrade clang to newer version.
  ANDROID: build: cuttlefish: Upgrade clang to newer version.
  ANDROID: build: cuttlefish: Fix path to clang.
  UPSTREAM: dm bufio: avoid sleeping while holding the dm_bufio lock
  ANDROID: sdcardfs: Don't d_drop in d_revalidate

Conflicts:
	arch/arm64/include/asm/cputype.h
	fs/ext4/crypto.c
	fs/ext4/ext4.h
	kernel/cgroup.c
	mm/vmscan.c

Change-Id: Ic10c5722b6439af1cf423fd949c493f786764d7e
Signed-off-by: Srinivasarao P <spathi@codeaurora.org>
2018-05-31 12:28:38 +05:30

542 lines
14 KiB
C

/*
* linux/fs/ext4/crypto.c
*
* Copyright (C) 2015, Google, Inc.
*
* This contains encryption functions for ext4
*
* Written by Michael Halcrow, 2014.
*
* Filename encryption additions
* Uday Savagaonkar, 2014
* Encryption policy handling additions
* Ildar Muslukhov, 2014
*
* This has not yet undergone a rigorous security audit.
*
* The usage of AES-XTS should conform to recommendations in NIST
* Special Publication 800-38E and IEEE P1619/D16.
*/
#include <crypto/hash.h>
#include <crypto/sha.h>
#include <keys/user-type.h>
#include <keys/encrypted-type.h>
#include <linux/crypto.h>
#include <linux/ecryptfs.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/key.h>
#include <linux/list.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/scatterlist.h>
#include <linux/spinlock_types.h>
#include <linux/namei.h>
#include "ext4_extents.h"
#include "xattr.h"
/* Encryption added and removed here! (L: */
static unsigned int num_prealloc_crypto_pages = 32;
static unsigned int num_prealloc_crypto_ctxs = 128;
module_param(num_prealloc_crypto_pages, uint, 0444);
MODULE_PARM_DESC(num_prealloc_crypto_pages,
"Number of crypto pages to preallocate");
module_param(num_prealloc_crypto_ctxs, uint, 0444);
MODULE_PARM_DESC(num_prealloc_crypto_ctxs,
"Number of crypto contexts to preallocate");
static mempool_t *ext4_bounce_page_pool;
static LIST_HEAD(ext4_free_crypto_ctxs);
static DEFINE_SPINLOCK(ext4_crypto_ctx_lock);
static struct kmem_cache *ext4_crypto_ctx_cachep;
struct kmem_cache *ext4_crypt_info_cachep;
/**
* ext4_release_crypto_ctx() - Releases an encryption context
* @ctx: The encryption context to release.
*
* If the encryption context was allocated from the pre-allocated pool, returns
* it to that pool. Else, frees it.
*
* If there's a bounce page in the context, this frees that.
*/
void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx)
{
unsigned long flags;
if (ctx->flags & EXT4_WRITE_PATH_FL && ctx->w.bounce_page)
mempool_free(ctx->w.bounce_page, ext4_bounce_page_pool);
ctx->w.bounce_page = NULL;
ctx->w.control_page = NULL;
if (ctx->flags & EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL) {
kmem_cache_free(ext4_crypto_ctx_cachep, ctx);
} else {
spin_lock_irqsave(&ext4_crypto_ctx_lock, flags);
list_add(&ctx->free_list, &ext4_free_crypto_ctxs);
spin_unlock_irqrestore(&ext4_crypto_ctx_lock, flags);
}
}
/**
* ext4_get_crypto_ctx() - Gets an encryption context
* @inode: The inode for which we are doing the crypto
*
* Allocates and initializes an encryption context.
*
* Return: An allocated and initialized encryption context on success; error
* value or NULL otherwise.
*/
struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
gfp_t gfp_flags)
{
struct ext4_crypto_ctx *ctx = NULL;
int res = 0;
unsigned long flags;
struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
if (ci == NULL)
return ERR_PTR(-ENOKEY);
/*
* We first try getting the ctx from a free list because in
* the common case the ctx will have an allocated and
* initialized crypto tfm, so it's probably a worthwhile
* optimization. For the bounce page, we first try getting it
* from the kernel allocator because that's just about as fast
* as getting it from a list and because a cache of free pages
* should generally be a "last resort" option for a filesystem
* to be able to do its job.
*/
spin_lock_irqsave(&ext4_crypto_ctx_lock, flags);
ctx = list_first_entry_or_null(&ext4_free_crypto_ctxs,
struct ext4_crypto_ctx, free_list);
if (ctx)
list_del(&ctx->free_list);
spin_unlock_irqrestore(&ext4_crypto_ctx_lock, flags);
if (!ctx) {
ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, gfp_flags);
if (!ctx) {
res = -ENOMEM;
goto out;
}
ctx->flags |= EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL;
} else {
ctx->flags &= ~EXT4_CTX_REQUIRES_FREE_ENCRYPT_FL;
}
ctx->flags &= ~EXT4_WRITE_PATH_FL;
out:
if (res) {
if (!IS_ERR_OR_NULL(ctx))
ext4_release_crypto_ctx(ctx);
ctx = ERR_PTR(res);
}
return ctx;
}
struct workqueue_struct *ext4_read_workqueue;
static DEFINE_MUTEX(crypto_init);
/**
* ext4_exit_crypto() - Shutdown the ext4 encryption system
*/
void ext4_exit_crypto(void)
{
struct ext4_crypto_ctx *pos, *n;
list_for_each_entry_safe(pos, n, &ext4_free_crypto_ctxs, free_list)
kmem_cache_free(ext4_crypto_ctx_cachep, pos);
INIT_LIST_HEAD(&ext4_free_crypto_ctxs);
if (ext4_bounce_page_pool)
mempool_destroy(ext4_bounce_page_pool);
ext4_bounce_page_pool = NULL;
if (ext4_read_workqueue)
destroy_workqueue(ext4_read_workqueue);
ext4_read_workqueue = NULL;
if (ext4_crypto_ctx_cachep)
kmem_cache_destroy(ext4_crypto_ctx_cachep);
ext4_crypto_ctx_cachep = NULL;
if (ext4_crypt_info_cachep)
kmem_cache_destroy(ext4_crypt_info_cachep);
ext4_crypt_info_cachep = NULL;
}
/**
* ext4_init_crypto() - Set up for ext4 encryption.
*
* We only call this when we start accessing encrypted files, since it
* results in memory getting allocated that wouldn't otherwise be used.
*
* Return: Zero on success, non-zero otherwise.
*/
int ext4_init_crypto(void)
{
int i, res = -ENOMEM;
mutex_lock(&crypto_init);
if (ext4_read_workqueue)
goto already_initialized;
ext4_read_workqueue = alloc_workqueue("ext4_crypto", WQ_HIGHPRI, 0);
if (!ext4_read_workqueue)
goto fail;
ext4_crypto_ctx_cachep = KMEM_CACHE(ext4_crypto_ctx,
SLAB_RECLAIM_ACCOUNT);
if (!ext4_crypto_ctx_cachep)
goto fail;
ext4_crypt_info_cachep = KMEM_CACHE(ext4_crypt_info,
SLAB_RECLAIM_ACCOUNT);
if (!ext4_crypt_info_cachep)
goto fail;
for (i = 0; i < num_prealloc_crypto_ctxs; i++) {
struct ext4_crypto_ctx *ctx;
ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, GFP_NOFS);
if (!ctx) {
res = -ENOMEM;
goto fail;
}
list_add(&ctx->free_list, &ext4_free_crypto_ctxs);
}
ext4_bounce_page_pool =
mempool_create_page_pool(num_prealloc_crypto_pages, 0);
if (!ext4_bounce_page_pool) {
res = -ENOMEM;
goto fail;
}
already_initialized:
mutex_unlock(&crypto_init);
return 0;
fail:
ext4_exit_crypto();
mutex_unlock(&crypto_init);
return res;
}
void ext4_restore_control_page(struct page *data_page)
{
struct ext4_crypto_ctx *ctx =
(struct ext4_crypto_ctx *)page_private(data_page);
set_page_private(data_page, (unsigned long)NULL);
ClearPagePrivate(data_page);
unlock_page(data_page);
ext4_release_crypto_ctx(ctx);
}
/**
* ext4_crypt_complete() - The completion callback for page encryption
* @req: The asynchronous encryption request context
* @res: The result of the encryption operation
*/
static void ext4_crypt_complete(struct crypto_async_request *req, int res)
{
struct ext4_completion_result *ecr = req->data;
if (res == -EINPROGRESS)
return;
ecr->res = res;
complete(&ecr->completion);
}
typedef enum {
EXT4_DECRYPT = 0,
EXT4_ENCRYPT,
} ext4_direction_t;
static int ext4_page_crypto(struct inode *inode,
ext4_direction_t rw,
pgoff_t index,
struct page *src_page,
struct page *dest_page,
gfp_t gfp_flags)
{
u8 xts_tweak[EXT4_XTS_TWEAK_SIZE];
struct ablkcipher_request *req = NULL;
DECLARE_EXT4_COMPLETION_RESULT(ecr);
struct scatterlist dst, src;
struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info;
struct crypto_ablkcipher *tfm = ci->ci_ctfm;
int res = 0;
req = ablkcipher_request_alloc(tfm, gfp_flags);
if (!req) {
printk_ratelimited(KERN_ERR
"%s: crypto_request_alloc() failed\n",
__func__);
return -ENOMEM;
}
ablkcipher_request_set_callback(
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
ext4_crypt_complete, &ecr);
BUILD_BUG_ON(EXT4_XTS_TWEAK_SIZE < sizeof(index));
memcpy(xts_tweak, &index, sizeof(index));
memset(&xts_tweak[sizeof(index)], 0,
EXT4_XTS_TWEAK_SIZE - sizeof(index));
sg_init_table(&dst, 1);
sg_set_page(&dst, dest_page, PAGE_CACHE_SIZE, 0);
sg_init_table(&src, 1);
sg_set_page(&src, src_page, PAGE_CACHE_SIZE, 0);
ablkcipher_request_set_crypt(req, &src, &dst, PAGE_CACHE_SIZE,
xts_tweak);
if (rw == EXT4_DECRYPT)
res = crypto_ablkcipher_decrypt(req);
else
res = crypto_ablkcipher_encrypt(req);
if (res == -EINPROGRESS || res == -EBUSY) {
wait_for_completion(&ecr.completion);
res = ecr.res;
}
ablkcipher_request_free(req);
if (res) {
printk_ratelimited(
KERN_ERR
"%s: crypto_ablkcipher_encrypt() returned %d\n",
__func__, res);
return res;
}
return 0;
}
static struct page *alloc_bounce_page(struct ext4_crypto_ctx *ctx,
gfp_t gfp_flags)
{
ctx->w.bounce_page = mempool_alloc(ext4_bounce_page_pool, gfp_flags);
if (ctx->w.bounce_page == NULL)
return ERR_PTR(-ENOMEM);
ctx->flags |= EXT4_WRITE_PATH_FL;
return ctx->w.bounce_page;
}
/**
* ext4_encrypt() - Encrypts a page
* @inode: The inode for which the encryption should take place
* @plaintext_page: The page to encrypt. Must be locked.
*
* Allocates a ciphertext page and encrypts plaintext_page into it using the ctx
* encryption context.
*
* Called on the page write path. The caller must call
* ext4_restore_control_page() on the returned ciphertext page to
* release the bounce buffer and the encryption context.
*
* Return: An allocated page with the encrypted content on success. Else, an
* error value or NULL.
*/
struct page *ext4_encrypt(struct inode *inode,
struct page *plaintext_page,
gfp_t gfp_flags)
{
struct ext4_crypto_ctx *ctx;
struct page *ciphertext_page = NULL;
int err;
BUG_ON(!PageLocked(plaintext_page));
ctx = ext4_get_crypto_ctx(inode, gfp_flags);
if (IS_ERR(ctx))
return (struct page *) ctx;
/* The encryption operation will require a bounce page. */
ciphertext_page = alloc_bounce_page(ctx, gfp_flags);
if (IS_ERR(ciphertext_page))
goto errout;
ctx->w.control_page = plaintext_page;
err = ext4_page_crypto(inode, EXT4_ENCRYPT, plaintext_page->index,
plaintext_page, ciphertext_page, gfp_flags);
if (err) {
ciphertext_page = ERR_PTR(err);
errout:
ext4_release_crypto_ctx(ctx);
return ciphertext_page;
}
SetPagePrivate(ciphertext_page);
set_page_private(ciphertext_page, (unsigned long)ctx);
lock_page(ciphertext_page);
return ciphertext_page;
}
/**
* ext4_decrypt() - Decrypts a page in-place
* @ctx: The encryption context.
* @page: The page to decrypt. Must be locked.
*
* Decrypts page in-place using the ctx encryption context.
*
* Called from the read completion callback.
*
* Return: Zero on success, non-zero otherwise.
*/
int ext4_decrypt(struct page *page)
{
BUG_ON(!PageLocked(page));
return ext4_page_crypto(page->mapping->host, EXT4_DECRYPT,
page->index, page, page, GFP_NOFS);
}
int ext4_encrypted_zeroout(struct inode *inode, ext4_lblk_t lblk,
ext4_fsblk_t pblk, ext4_lblk_t len)
{
struct ext4_crypto_ctx *ctx;
struct page *ciphertext_page = NULL;
struct bio *bio;
int ret, err = 0;
#if 0
ext4_msg(inode->i_sb, KERN_CRIT,
"ext4_encrypted_zeroout ino %lu lblk %u len %u",
(unsigned long) inode->i_ino, lblk, len);
#endif
BUG_ON(inode->i_sb->s_blocksize != PAGE_CACHE_SIZE);
ctx = ext4_get_crypto_ctx(inode, GFP_NOFS);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT);
if (IS_ERR(ciphertext_page)) {
err = PTR_ERR(ciphertext_page);
goto errout;
}
while (len--) {
err = ext4_page_crypto(inode, EXT4_ENCRYPT, lblk,
ZERO_PAGE(0), ciphertext_page,
GFP_NOFS);
if (err)
goto errout;
bio = bio_alloc(GFP_NOWAIT, 1);
if (!bio) {
err = -ENOMEM;
goto errout;
}
bio->bi_bdev = inode->i_sb->s_bdev;
bio->bi_iter.bi_sector =
pblk << (inode->i_sb->s_blocksize_bits - 9);
ret = bio_add_page(bio, ciphertext_page,
inode->i_sb->s_blocksize, 0);
if (ret != inode->i_sb->s_blocksize) {
/* should never happen! */
ext4_msg(inode->i_sb, KERN_ERR,
"bio_add_page failed: %d", ret);
WARN_ON(1);
bio_put(bio);
err = -EIO;
goto errout;
}
err = submit_bio_wait(WRITE, bio);
if ((err == 0) && bio->bi_error)
err = -EIO;
bio_put(bio);
if (err)
goto errout;
lblk++; pblk++;
}
err = 0;
errout:
ext4_release_crypto_ctx(ctx);
return err;
}
bool ext4_valid_enc_modes(uint32_t contents_mode, uint32_t filenames_mode)
{
if (contents_mode == EXT4_ENCRYPTION_MODE_AES_256_XTS ||
contents_mode == EXT4_ENCRYPTION_MODE_PRIVATE) {
return (filenames_mode == EXT4_ENCRYPTION_MODE_AES_256_CTS ||
filenames_mode == EXT4_ENCRYPTION_MODE_AES_256_HEH);
}
if (contents_mode == EXT4_ENCRYPTION_MODE_SPECK128_256_XTS)
return filenames_mode == EXT4_ENCRYPTION_MODE_SPECK128_256_CTS;
return false;
}
/**
* ext4_validate_encryption_key_size() - Validate the encryption key size
* @mode: The key mode.
* @size: The key size to validate.
*
* Return: The validated key size for @mode. Zero if invalid.
*/
uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size)
{
if (size == ext4_encryption_key_size(mode))
return size;
return 0;
}
/*
* Validate dentries for encrypted directories to make sure we aren't
* potentially caching stale data after a key has been added or
* removed.
*/
static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags)
{
struct dentry *dir;
struct ext4_crypt_info *ci;
int dir_has_key, cached_with_key;
if (flags & LOOKUP_RCU)
return -ECHILD;
dir = dget_parent(dentry);
if (!ext4_encrypted_inode(d_inode(dir))) {
dput(dir);
return 0;
}
ci = EXT4_I(d_inode(dir))->i_crypt_info;
/* this should eventually be an flag in d_flags */
cached_with_key = dentry->d_fsdata != NULL;
dir_has_key = (ci != NULL);
dput(dir);
/*
* If the dentry was cached without the key, and it is a
* negative dentry, it might be a valid name. We can't check
* if the key has since been made available due to locking
* reasons, so we fail the validation so ext4_lookup() can do
* this check.
*
* We also fail the validation if the dentry was created with
* the key present, but we no longer have the key, or vice versa.
*/
if ((!cached_with_key && d_is_negative(dentry)) ||
(!cached_with_key && dir_has_key) ||
(cached_with_key && !dir_has_key)) {
#if 0 /* Revalidation debug */
char buf[80];
char *cp = simple_dname(dentry, buf, sizeof(buf));
if (IS_ERR(cp))
cp = (char *) "???";
pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata,
cached_with_key, d_is_negative(dentry),
dir_has_key);
#endif
return 0;
}
return 1;
}
const struct dentry_operations ext4_encrypted_d_ops = {
.d_revalidate = ext4_d_revalidate,
};