// SPDX-License-Identifier: GPL-2.0
/*
* fs/f2fs/dir.c
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*/
#include <linux/unaligned.h>
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
#include <linux/sched/signal.h>
#include <linux/unicode.h>
#include "f2fs.h"
#include "node.h"
#include "acl.h"
#include "xattr.h"
#include <trace/events/f2fs.h>
static inline bool f2fs_should_fallback_to_linear(struct inode *dir)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
switch (F2FS_OPTION(sbi).lookup_mode) {
case LOOKUP_PERF:
return false;
case LOOKUP_COMPAT:
return true;
case LOOKUP_AUTO:
return !sb_no_casefold_compat_fallback(sbi->sb);
}
return false;
}
#if IS_ENABLED(CONFIG_UNICODE)
extern struct kmem_cache *f2fs_cf_name_slab;
#endif
static unsigned long dir_blocks(struct inode *inode)
{
return ((unsigned long long) (i_size_read(inode) + PAGE_SIZE - 1))
>> PAGE_SHIFT;
}
static unsigned int dir_buckets(unsigned int level, int dir_level)
{
if (level + dir_level < MAX_DIR_HASH_DEPTH / 2)
return BIT(level + dir_level);
else
return MAX_DIR_BUCKETS;
}
static unsigned int bucket_blocks(unsigned int level)
{
if (level < MAX_DIR_HASH_DEPTH / 2)
return 2;
else
return 4;
}
#if IS_ENABLED(CONFIG_UNICODE)
/* If @dir is casefolded, initialize @fname->cf_name from @fname->usr_fname. */
int f2fs_init_casefolded_name(const struct inode *dir,
struct f2fs_filename *fname)
{
struct super_block *sb = dir->i_sb;
unsigned char *buf;
int len;
if (IS_CASEFOLDED(dir) &&
!is_dot_dotdot(fname->usr_fname->name, fname->usr_fname->len)) {
buf = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
GFP_NOFS, false, F2FS_SB(sb));
if (!buf)
return -ENOMEM;
len = utf8_casefold(sb->s_encoding, fname->usr_fname,
buf, F2FS_NAME_LEN);
if (len <= 0) {
kmem_cache_free(f2fs_cf_name_slab, buf);
if (sb_has_strict_encoding(sb))
return -EINVAL;
/* fall back to treating name as opaque byte sequence */
return 0;
}
fname->cf_name.name = buf;
fname->cf_name.len = len;
}
return 0;
}
void f2fs_free_casefolded_name(struct f2fs_filename *fname)
{
unsigned char *buf = (unsigned char *)fname->cf_name.name;
if (buf) {
kmem_cache_free(f2fs_cf_name_slab, buf);
fname->cf_name.name = NULL;
}
}
#endif /* CONFIG_UNICODE */
static int __f2fs_setup_filename(const struct inode *dir,
const struct fscrypt_name *crypt_name,
struct f2fs_filename *fname)
{
int err;
memset(fname, 0, sizeof(*fname));
fname->usr_fname = crypt_name->usr_fname;
fname->disk_name = crypt_name->disk_name;
#ifdef CONFIG_FS_ENCRYPTION