mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 14:19:16 +00:00
ext4 crypto: filename encryption modifications
Modifies htree_dirblock_to_tree, dx_make_map, ext4_match search_dir, and ext4_find_dest_de to support fname crypto. Filename encryption feature is not yet enabled at this patch. Signed-off-by: Uday Savagaonkar <savagaon@google.com> Signed-off-by: Ildar Muslukhov <ildarm@google.com> Signed-off-by: Michael Halcrow <mhalcrow@google.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
b309848644
commit
1f3862b557
1 changed files with 204 additions and 44 deletions
248
fs/ext4/namei.c
248
fs/ext4/namei.c
|
@ -253,8 +253,9 @@ static struct dx_frame *dx_probe(const struct qstr *d_name,
|
||||||
struct dx_hash_info *hinfo,
|
struct dx_hash_info *hinfo,
|
||||||
struct dx_frame *frame);
|
struct dx_frame *frame);
|
||||||
static void dx_release(struct dx_frame *frames);
|
static void dx_release(struct dx_frame *frames);
|
||||||
static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
|
static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
|
||||||
struct dx_hash_info *hinfo, struct dx_map_entry map[]);
|
unsigned blocksize, struct dx_hash_info *hinfo,
|
||||||
|
struct dx_map_entry map[]);
|
||||||
static void dx_sort_map(struct dx_map_entry *map, unsigned count);
|
static void dx_sort_map(struct dx_map_entry *map, unsigned count);
|
||||||
static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
|
static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to,
|
||||||
struct dx_map_entry *offsets, int count, unsigned blocksize);
|
struct dx_map_entry *offsets, int count, unsigned blocksize);
|
||||||
|
@ -968,7 +969,8 @@ static int htree_dirblock_to_tree(struct file *dir_file,
|
||||||
struct buffer_head *bh;
|
struct buffer_head *bh;
|
||||||
struct ext4_dir_entry_2 *de, *top;
|
struct ext4_dir_entry_2 *de, *top;
|
||||||
int err = 0, count = 0;
|
int err = 0, count = 0;
|
||||||
struct ext4_str tmp_str;
|
struct ext4_fname_crypto_ctx *ctx = NULL;
|
||||||
|
struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}, tmp_str;
|
||||||
|
|
||||||
dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
|
dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
|
||||||
(unsigned long)block));
|
(unsigned long)block));
|
||||||
|
@ -980,6 +982,24 @@ static int htree_dirblock_to_tree(struct file *dir_file,
|
||||||
top = (struct ext4_dir_entry_2 *) ((char *) de +
|
top = (struct ext4_dir_entry_2 *) ((char *) de +
|
||||||
dir->i_sb->s_blocksize -
|
dir->i_sb->s_blocksize -
|
||||||
EXT4_DIR_REC_LEN(0));
|
EXT4_DIR_REC_LEN(0));
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
/* Check if the directory is encrypted */
|
||||||
|
ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
|
||||||
|
if (IS_ERR(ctx)) {
|
||||||
|
err = PTR_ERR(ctx);
|
||||||
|
brelse(bh);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (ctx != NULL) {
|
||||||
|
err = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
|
||||||
|
&fname_crypto_str);
|
||||||
|
if (err < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
brelse(bh);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
|
for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) {
|
||||||
if (ext4_check_dir_entry(dir, NULL, de, bh,
|
if (ext4_check_dir_entry(dir, NULL, de, bh,
|
||||||
bh->b_data, bh->b_size,
|
bh->b_data, bh->b_size,
|
||||||
|
@ -988,24 +1008,52 @@ static int htree_dirblock_to_tree(struct file *dir_file,
|
||||||
/* silently ignore the rest of the block */
|
/* silently ignore the rest of the block */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
err = ext4_fname_disk_to_hash(ctx, de, hinfo);
|
||||||
|
if (err < 0) {
|
||||||
|
count = err;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
#else
|
||||||
ext4fs_dirhash(de->name, de->name_len, hinfo);
|
ext4fs_dirhash(de->name, de->name_len, hinfo);
|
||||||
|
#endif
|
||||||
if ((hinfo->hash < start_hash) ||
|
if ((hinfo->hash < start_hash) ||
|
||||||
((hinfo->hash == start_hash) &&
|
((hinfo->hash == start_hash) &&
|
||||||
(hinfo->minor_hash < start_minor_hash)))
|
(hinfo->minor_hash < start_minor_hash)))
|
||||||
continue;
|
continue;
|
||||||
if (de->inode == 0)
|
if (de->inode == 0)
|
||||||
continue;
|
continue;
|
||||||
tmp_str.name = de->name;
|
if (ctx == NULL) {
|
||||||
tmp_str.len = de->name_len;
|
/* Directory is not encrypted */
|
||||||
err = ext4_htree_store_dirent(dir_file,
|
tmp_str.name = de->name;
|
||||||
hinfo->hash, hinfo->minor_hash, de, &tmp_str);
|
tmp_str.len = de->name_len;
|
||||||
|
err = ext4_htree_store_dirent(dir_file,
|
||||||
|
hinfo->hash, hinfo->minor_hash, de,
|
||||||
|
&tmp_str);
|
||||||
|
} else {
|
||||||
|
/* Directory is encrypted */
|
||||||
|
err = ext4_fname_disk_to_usr(ctx, de,
|
||||||
|
&fname_crypto_str);
|
||||||
|
if (err < 0) {
|
||||||
|
count = err;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
err = ext4_htree_store_dirent(dir_file,
|
||||||
|
hinfo->hash, hinfo->minor_hash, de,
|
||||||
|
&fname_crypto_str);
|
||||||
|
}
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
brelse(bh);
|
count = err;
|
||||||
return err;
|
goto errout;
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
errout:
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
ext4_fname_crypto_free_buffer(&fname_crypto_str);
|
||||||
|
#endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1138,17 +1186,33 @@ static inline int search_dirblock(struct buffer_head *bh,
|
||||||
* Create map of hash values, offsets, and sizes, stored at end of block.
|
* Create map of hash values, offsets, and sizes, stored at end of block.
|
||||||
* Returns number of entries mapped.
|
* Returns number of entries mapped.
|
||||||
*/
|
*/
|
||||||
static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
|
static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de,
|
||||||
struct dx_hash_info *hinfo,
|
unsigned blocksize, struct dx_hash_info *hinfo,
|
||||||
struct dx_map_entry *map_tail)
|
struct dx_map_entry *map_tail)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
char *base = (char *) de;
|
char *base = (char *) de;
|
||||||
struct dx_hash_info h = *hinfo;
|
struct dx_hash_info h = *hinfo;
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
struct ext4_fname_crypto_ctx *ctx = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
|
||||||
|
if (IS_ERR(ctx))
|
||||||
|
return PTR_ERR(ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
while ((char *) de < base + blocksize) {
|
while ((char *) de < base + blocksize) {
|
||||||
if (de->name_len && de->inode) {
|
if (de->name_len && de->inode) {
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
err = ext4_fname_disk_to_hash(ctx, de, &h);
|
||||||
|
if (err < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#else
|
||||||
ext4fs_dirhash(de->name, de->name_len, &h);
|
ext4fs_dirhash(de->name, de->name_len, &h);
|
||||||
|
#endif
|
||||||
map_tail--;
|
map_tail--;
|
||||||
map_tail->hash = h.hash;
|
map_tail->hash = h.hash;
|
||||||
map_tail->offs = ((char *) de - base)>>2;
|
map_tail->offs = ((char *) de - base)>>2;
|
||||||
|
@ -1159,6 +1223,9 @@ static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize,
|
||||||
/* XXX: do we need to check rec_len == 0 case? -Chris */
|
/* XXX: do we need to check rec_len == 0 case? -Chris */
|
||||||
de = ext4_next_entry(de, blocksize);
|
de = ext4_next_entry(de, blocksize);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
#endif
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1209,57 +1276,107 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
|
||||||
* `len <= EXT4_NAME_LEN' is guaranteed by caller.
|
* `len <= EXT4_NAME_LEN' is guaranteed by caller.
|
||||||
* `de != NULL' is guaranteed by caller.
|
* `de != NULL' is guaranteed by caller.
|
||||||
*/
|
*/
|
||||||
static inline int ext4_match (int len, const char * const name,
|
static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx,
|
||||||
struct ext4_dir_entry_2 * de)
|
struct ext4_str *fname_crypto_str,
|
||||||
|
int len, const char * const name,
|
||||||
|
struct ext4_dir_entry_2 *de)
|
||||||
{
|
{
|
||||||
if (len != de->name_len)
|
int res;
|
||||||
return 0;
|
|
||||||
if (!de->inode)
|
if (!de->inode)
|
||||||
return 0;
|
return 0;
|
||||||
return !memcmp(name, de->name, len);
|
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
if (ctx) {
|
||||||
|
/* Directory is encrypted */
|
||||||
|
res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
if (len != res)
|
||||||
|
return 0;
|
||||||
|
res = memcmp(name, fname_crypto_str->name, len);
|
||||||
|
return (res == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (len != de->name_len)
|
||||||
|
return 0;
|
||||||
|
res = memcmp(name, de->name, len);
|
||||||
|
return (res == 0) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 0 if not found, -1 on failure, and 1 on success
|
* Returns 0 if not found, -1 on failure, and 1 on success
|
||||||
*/
|
*/
|
||||||
int search_dir(struct buffer_head *bh,
|
int search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
|
||||||
char *search_buf,
|
struct inode *dir, const struct qstr *d_name,
|
||||||
int buf_size,
|
unsigned int offset, struct ext4_dir_entry_2 **res_dir)
|
||||||
struct inode *dir,
|
|
||||||
const struct qstr *d_name,
|
|
||||||
unsigned int offset,
|
|
||||||
struct ext4_dir_entry_2 **res_dir)
|
|
||||||
{
|
{
|
||||||
struct ext4_dir_entry_2 * de;
|
struct ext4_dir_entry_2 * de;
|
||||||
char * dlimit;
|
char * dlimit;
|
||||||
int de_len;
|
int de_len;
|
||||||
const char *name = d_name->name;
|
const char *name = d_name->name;
|
||||||
int namelen = d_name->len;
|
int namelen = d_name->len;
|
||||||
|
struct ext4_fname_crypto_ctx *ctx = NULL;
|
||||||
|
struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
|
||||||
|
int res;
|
||||||
|
|
||||||
|
ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
|
||||||
|
if (IS_ERR(ctx))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ctx != NULL) {
|
||||||
|
/* Allocate buffer to hold maximum name length */
|
||||||
|
res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
|
||||||
|
&fname_crypto_str);
|
||||||
|
if (res < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
de = (struct ext4_dir_entry_2 *)search_buf;
|
de = (struct ext4_dir_entry_2 *)search_buf;
|
||||||
dlimit = search_buf + buf_size;
|
dlimit = search_buf + buf_size;
|
||||||
while ((char *) de < dlimit) {
|
while ((char *) de < dlimit) {
|
||||||
/* this code is executed quadratically often */
|
/* this code is executed quadratically often */
|
||||||
/* do minimal checking `by hand' */
|
/* do minimal checking `by hand' */
|
||||||
|
if ((char *) de + de->name_len <= dlimit) {
|
||||||
|
res = ext4_match(ctx, &fname_crypto_str, namelen,
|
||||||
|
name, de);
|
||||||
|
if (res < 0) {
|
||||||
|
res = -1;
|
||||||
|
goto return_result;
|
||||||
|
}
|
||||||
|
if (res > 0) {
|
||||||
|
/* found a match - just to be sure, do
|
||||||
|
* a full check */
|
||||||
|
if (ext4_check_dir_entry(dir, NULL, de, bh,
|
||||||
|
bh->b_data,
|
||||||
|
bh->b_size, offset)) {
|
||||||
|
res = -1;
|
||||||
|
goto return_result;
|
||||||
|
}
|
||||||
|
*res_dir = de;
|
||||||
|
res = 1;
|
||||||
|
goto return_result;
|
||||||
|
}
|
||||||
|
|
||||||
if ((char *) de + namelen <= dlimit &&
|
|
||||||
ext4_match (namelen, name, de)) {
|
|
||||||
/* found a match - just to be sure, do a full check */
|
|
||||||
if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
|
|
||||||
bh->b_size, offset))
|
|
||||||
return -1;
|
|
||||||
*res_dir = de;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
/* prevent looping on a bad block */
|
/* prevent looping on a bad block */
|
||||||
de_len = ext4_rec_len_from_disk(de->rec_len,
|
de_len = ext4_rec_len_from_disk(de->rec_len,
|
||||||
dir->i_sb->s_blocksize);
|
dir->i_sb->s_blocksize);
|
||||||
if (de_len <= 0)
|
if (de_len <= 0) {
|
||||||
return -1;
|
res = -1;
|
||||||
|
goto return_result;
|
||||||
|
}
|
||||||
offset += de_len;
|
offset += de_len;
|
||||||
de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
|
de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
res = 0;
|
||||||
|
return_result:
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
ext4_fname_crypto_free_buffer(&fname_crypto_str);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
|
static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
|
||||||
|
@ -1448,6 +1565,9 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q
|
||||||
ext4_lblk_t block;
|
ext4_lblk_t block;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||||
|
*res_dir = NULL;
|
||||||
|
#endif
|
||||||
frame = dx_probe(d_name, dir, &hinfo, frames);
|
frame = dx_probe(d_name, dir, &hinfo, frames);
|
||||||
if (IS_ERR(frame))
|
if (IS_ERR(frame))
|
||||||
return (struct buffer_head *) frame;
|
return (struct buffer_head *) frame;
|
||||||
|
@ -1656,7 +1776,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
|
||||||
|
|
||||||
/* create map in the end of data2 block */
|
/* create map in the end of data2 block */
|
||||||
map = (struct dx_map_entry *) (data2 + blocksize);
|
map = (struct dx_map_entry *) (data2 + blocksize);
|
||||||
count = dx_make_map((struct ext4_dir_entry_2 *) data1,
|
count = dx_make_map(dir, (struct ext4_dir_entry_2 *) data1,
|
||||||
blocksize, hinfo, map);
|
blocksize, hinfo, map);
|
||||||
map -= count;
|
map -= count;
|
||||||
dx_sort_map(map, count);
|
dx_sort_map(map, count);
|
||||||
|
@ -1679,7 +1799,8 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
|
||||||
hash2, split, count-split));
|
hash2, split, count-split));
|
||||||
|
|
||||||
/* Fancy dance to stay within two buffers */
|
/* Fancy dance to stay within two buffers */
|
||||||
de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize);
|
de2 = dx_move_dirents(data1, data2, map + split, count - split,
|
||||||
|
blocksize);
|
||||||
de = dx_pack_dirents(data1, blocksize);
|
de = dx_pack_dirents(data1, blocksize);
|
||||||
de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
|
de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
|
||||||
(char *) de,
|
(char *) de,
|
||||||
|
@ -1735,15 +1856,48 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
|
||||||
int nlen, rlen;
|
int nlen, rlen;
|
||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
char *top;
|
char *top;
|
||||||
|
struct ext4_fname_crypto_ctx *ctx = NULL;
|
||||||
|
struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
|
||||||
|
int res;
|
||||||
|
|
||||||
|
ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN);
|
||||||
|
if (IS_ERR(ctx))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ctx != NULL) {
|
||||||
|
/* Calculate record length needed to store the entry */
|
||||||
|
res = ext4_fname_crypto_namelen_on_disk(ctx, namelen);
|
||||||
|
if (res < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
reclen = EXT4_DIR_REC_LEN(res);
|
||||||
|
|
||||||
|
/* Allocate buffer to hold maximum name length */
|
||||||
|
res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN,
|
||||||
|
&fname_crypto_str);
|
||||||
|
if (res < 0) {
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
de = (struct ext4_dir_entry_2 *)buf;
|
de = (struct ext4_dir_entry_2 *)buf;
|
||||||
top = buf + buf_size - reclen;
|
top = buf + buf_size - reclen;
|
||||||
while ((char *) de <= top) {
|
while ((char *) de <= top) {
|
||||||
if (ext4_check_dir_entry(dir, NULL, de, bh,
|
if (ext4_check_dir_entry(dir, NULL, de, bh,
|
||||||
buf, buf_size, offset))
|
buf, buf_size, offset)) {
|
||||||
return -EIO;
|
res = -EIO;
|
||||||
if (ext4_match(namelen, name, de))
|
goto return_result;
|
||||||
return -EEXIST;
|
}
|
||||||
|
/* Provide crypto context and crypto buffer to ext4 match */
|
||||||
|
res = ext4_match(ctx, &fname_crypto_str, namelen, name, de);
|
||||||
|
if (res < 0)
|
||||||
|
goto return_result;
|
||||||
|
if (res > 0) {
|
||||||
|
res = -EEXIST;
|
||||||
|
goto return_result;
|
||||||
|
}
|
||||||
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
nlen = EXT4_DIR_REC_LEN(de->name_len);
|
||||||
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
|
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
|
||||||
if ((de->inode ? rlen - nlen : rlen) >= reclen)
|
if ((de->inode ? rlen - nlen : rlen) >= reclen)
|
||||||
|
@ -1751,11 +1905,17 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
|
||||||
de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
|
de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
|
||||||
offset += rlen;
|
offset += rlen;
|
||||||
}
|
}
|
||||||
if ((char *) de > top)
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
*dest_de = de;
|
if ((char *) de > top)
|
||||||
return 0;
|
res = -ENOSPC;
|
||||||
|
else {
|
||||||
|
*dest_de = de;
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
return_result:
|
||||||
|
ext4_put_fname_crypto_ctx(&ctx);
|
||||||
|
ext4_fname_crypto_free_buffer(&fname_crypto_str);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ext4_insert_dentry(struct inode *dir,
|
int ext4_insert_dentry(struct inode *dir,
|
||||||
|
|
Loading…
Reference in a new issue