Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-4.19.y' into android-4.19-stable

This series addressed merge conflicts based on pa/c/1664425/15, mainly
integrated with a patch "f2fs: Handle casefolding with Encryption" for
casefolding support in ACK only.

* aosp/upstream-f2fs-stable-linux-4.19.y:
  f2fs: flush dirty meta pages when flushing them
  f2fs: fix checkpoint=disable:%u%%
  f2fs: rework filename handling
  f2fs: split f2fs_d_compare() from f2fs_match_name()
  f2fs: don't leak filename in f2fs_try_convert_inline_dir()
  f2fs: fix missing check for f2fs_unlock_op

Conflicts:
	fs/f2fs/dir.c
	fs/f2fs/f2fs.h
	fs/f2fs/hash.c
	fs/f2fs/inline.c
	fs/f2fs/namei.c

Change-Id: Ib5ceb0f2f076d6c215d4c0c6262f3c1d41cde7c8
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
This commit is contained in:
Jaegeuk Kim 2020-05-27 13:40:56 -07:00
commit 15a4eab01e
8 changed files with 415 additions and 275 deletions

View file

@ -1266,6 +1266,9 @@ void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type)
if (unlikely(f2fs_cp_error(sbi)))
break;
if (type == F2FS_DIRTY_META)
f2fs_sync_meta_pages(sbi, META, LONG_MAX,
FS_CP_META_IO);
io_schedule_timeout(DEFAULT_IO_TIMEOUT);
}
finish_wait(&sbi->cp_wait, &wait);

View file

@ -5,6 +5,7 @@
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*/
#include <asm/unaligned.h>
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
#include <linux/sched/signal.h>
@ -70,6 +71,111 @@ unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de)
return DT_UNKNOWN;
}
/* 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)
{
#ifdef CONFIG_UNICODE
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
if (IS_CASEFOLDED(dir)) {
fname->cf_name.name = f2fs_kmalloc(sbi, F2FS_NAME_LEN,
GFP_NOFS);
if (!fname->cf_name.name)
return -ENOMEM;
fname->cf_name.len = utf8_casefold(sbi->sb->s_encoding,
fname->usr_fname,
fname->cf_name.name,
F2FS_NAME_LEN);
if ((int)fname->cf_name.len <= 0) {
kfree(fname->cf_name.name);
fname->cf_name.name = NULL;
if (sb_has_enc_strict_mode(dir->i_sb))
return -EINVAL;
/* fall back to treating name as opaque byte sequence */
}
}
#endif
return 0;
}
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
fname->crypto_buf = crypt_name->crypto_buf;
#endif
if (crypt_name->is_ciphertext_name) {
/* hash was decoded from the no-key name */
fname->hash = cpu_to_le32(crypt_name->hash);
} else {
err = f2fs_init_casefolded_name(dir, fname);
if (err) {
f2fs_free_filename(fname);
return err;
}
f2fs_hash_filename(dir, fname);
}
return 0;
}
/*
* Prepare to search for @iname in @dir. This is similar to
* fscrypt_setup_filename(), but this also handles computing the casefolded name
* and the f2fs dirhash if needed, then packing all the information about this
* filename up into a 'struct f2fs_filename'.
*/
int f2fs_setup_filename(struct inode *dir, const struct qstr *iname,
int lookup, struct f2fs_filename *fname)
{
struct fscrypt_name crypt_name;
int err;
err = fscrypt_setup_filename(dir, iname, lookup, &crypt_name);
if (err)
return err;
return __f2fs_setup_filename(dir, &crypt_name, fname);
}
/*
* Prepare to look up @dentry in @dir. This is similar to
* fscrypt_prepare_lookup(), but this also handles computing the casefolded name
* and the f2fs dirhash if needed, then packing all the information about this
* filename up into a 'struct f2fs_filename'.
*/
int f2fs_prepare_lookup(struct inode *dir, struct dentry *dentry,
struct f2fs_filename *fname)
{
struct fscrypt_name crypt_name;
int err;
err = fscrypt_prepare_lookup(dir, dentry, &crypt_name);
if (err)
return err;
return __f2fs_setup_filename(dir, &crypt_name, fname);
}
void f2fs_free_filename(struct f2fs_filename *fname)
{
#ifdef CONFIG_FS_ENCRYPTION
kfree(fname->crypto_buf.name);
fname->crypto_buf.name = NULL;
#endif
#ifdef CONFIG_UNICODE
kfree(fname->cf_name.name);
fname->cf_name.name = NULL;
#endif
}
static unsigned long dir_block_index(unsigned int level,
int dir_level, unsigned int idx)
{
@ -84,8 +190,7 @@ static unsigned long dir_block_index(unsigned int level,
static struct f2fs_dir_entry *find_in_block(struct inode *dir,
struct page *dentry_page,
struct fscrypt_name *fname,
f2fs_hash_t namehash,
const struct f2fs_filename *fname,
int *max_slots,
struct page **res_page)
{
@ -96,7 +201,7 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
make_dentry_ptr_block(dir, &d, dentry_blk);
de = f2fs_find_target_dentry(fname, namehash, max_slots, &d);
de = f2fs_find_target_dentry(&d, fname, max_slots);
if (de)
*res_page = dentry_page;
@ -107,130 +212,79 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir,
/*
* Test whether a case-insensitive directory entry matches the filename
* being searched for.
*
* Only called for encrypted names if the key is available.
*
* Returns: 0 if the directory entry matches, more than 0 if it
* doesn't match or less than zero on error.
*/
static int f2fs_ci_compare(const struct inode *parent, const struct qstr *name,
u8 *de_name, size_t de_name_len, bool quick)
static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
const u8 *de_name, u32 de_name_len)
{
const struct super_block *sb = parent->i_sb;
const struct super_block *sb = dir->i_sb;
const struct unicode_map *um = sb->s_encoding;
struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len);
struct qstr entry = QSTR_INIT(de_name, de_name_len);
int ret;
int res;
if (IS_ENCRYPTED(parent)) {
if (IS_ENCRYPTED(dir)) {
const struct fscrypt_str encrypted_name =
FSTR_INIT(de_name, de_name_len);
FSTR_INIT((u8 *)de_name, de_name_len);
if (WARN_ON_ONCE(!fscrypt_has_encryption_key(dir)))
return false;
decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL);
if (!decrypted_name.name)
return -ENOMEM;
ret = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name,
return false;
res = fscrypt_fname_disk_to_usr(dir, 0, 0, &encrypted_name,
&decrypted_name);
if (ret < 0)
if (res < 0)
goto out;
entry.name = decrypted_name.name;
entry.len = decrypted_name.len;
}
if (quick)
ret = utf8_strncasecmp_folded(um, name, &entry);
else
ret = utf8_strncasecmp(um, name, &entry);
if (ret < 0) {
/* Handle invalid character sequence as either an error
* or as an opaque byte sequence.
res = utf8_strncasecmp_folded(um, name, &entry);
if (res < 0) {
/*
* In strict mode, ignore invalid names. In non-strict mode,
* fall back to treating them as opaque byte sequences.
*/
if (sb_has_enc_strict_mode(sb))
ret = -EINVAL;
else if (name->len != entry.len)
ret = 1;
if (sb_has_enc_strict_mode(sb) || name->len != entry.len)
res = 1;
else
ret = !!memcmp(name->name, entry.name, entry.len);
res = memcmp(name->name, entry.name, name->len);
}
out:
kfree(decrypted_name.name);
return ret;
return res == 0;
}
#endif /* CONFIG_UNICODE */
static void f2fs_fname_setup_ci_filename(struct inode *dir,
const struct qstr *iname,
struct fscrypt_str *cf_name)
static inline bool f2fs_match_name(const struct inode *dir,
const struct f2fs_filename *fname,
const u8 *de_name, u32 de_name_len)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
if (!IS_CASEFOLDED(dir)) {
cf_name->name = NULL;
return;
}
cf_name->name = f2fs_kmalloc(sbi, F2FS_NAME_LEN, GFP_NOFS);
if (!cf_name->name)
return;
cf_name->len = utf8_casefold(dir->i_sb->s_encoding,
iname, cf_name->name,
F2FS_NAME_LEN);
if ((int)cf_name->len <= 0) {
kvfree(cf_name->name);
cf_name->name = NULL;
}
}
#endif
static inline bool f2fs_match_name(struct f2fs_dentry_ptr *d,
struct f2fs_dir_entry *de,
struct fscrypt_name *fname,
struct fscrypt_str *cf_str,
unsigned long bit_pos,
f2fs_hash_t namehash)
{
#ifdef CONFIG_UNICODE
struct inode *parent = d->inode;
u8 *name;
int len;
#endif
if (de->hash_code != namehash)
return false;
struct fscrypt_name f;
#ifdef CONFIG_UNICODE
name = d->filename[bit_pos];
len = le16_to_cpu(de->name_len);
if (fname->cf_name.name) {
struct qstr cf = FSTR_TO_QSTR(&fname->cf_name);
if (needs_casefold(parent)) {
if (cf_str->name) {
struct qstr cf = {.name = cf_str->name,
.len = cf_str->len};
return !f2fs_ci_compare(parent, &cf, name, len, true);
}
return !f2fs_ci_compare(parent, fname->usr_fname, name, len,
false);
return f2fs_match_ci_name(dir, &cf, de_name, de_name_len);
}
#endif
if (fscrypt_match_name(fname, d->filename[bit_pos],
le16_to_cpu(de->name_len)))
return true;
return false;
f.usr_fname = fname->usr_fname;
f.disk_name = fname->disk_name;
#ifdef CONFIG_FS_ENCRYPTION
f.crypto_buf = fname->crypto_buf;
#endif
return fscrypt_match_name(&f, de_name, de_name_len);
}
struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname,
f2fs_hash_t namehash, int *max_slots,
struct f2fs_dentry_ptr *d)
struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
const struct f2fs_filename *fname, int *max_slots)
{
struct f2fs_dir_entry *de;
struct fscrypt_str cf_str = { .name = NULL, .len = 0 };
unsigned long bit_pos = 0;
int max_len = 0;
#ifdef CONFIG_UNICODE
f2fs_fname_setup_ci_filename(d->inode, fname->usr_fname, &cf_str);
#endif
if (max_slots)
*max_slots = 0;
while (bit_pos < d->max) {
@ -247,7 +301,9 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname,
continue;
}
if (f2fs_match_name(d, de, fname, &cf_str, bit_pos, namehash))
if (de->hash_code == fname->hash &&
f2fs_match_name(d->inode, fname, d->filename[bit_pos],
le16_to_cpu(de->name_len)))
goto found;
if (max_slots && max_len > *max_slots)
@ -261,33 +317,27 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname,
found:
if (max_slots && max_len > *max_slots)
*max_slots = max_len;
#ifdef CONFIG_UNICODE
kvfree(cf_str.name);
#endif
return de;
}
static struct f2fs_dir_entry *find_in_level(struct inode *dir,
unsigned int level,
struct fscrypt_name *fname,
const struct f2fs_filename *fname,
struct page **res_page)
{
struct qstr name = FSTR_TO_QSTR(&fname->disk_name);
int s = GET_DENTRY_SLOTS(name.len);
int s = GET_DENTRY_SLOTS(fname->disk_name.len);
unsigned int nbucket, nblock;
unsigned int bidx, end_block;
struct page *dentry_page;
struct f2fs_dir_entry *de = NULL;
bool room = false;
int max_slots;
f2fs_hash_t namehash = f2fs_dentry_hash(dir, &name, fname);
nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);
nblock = bucket_blocks(level);
bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level,
le32_to_cpu(namehash) % nbucket);
le32_to_cpu(fname->hash) % nbucket);
end_block = bidx + nblock;
for (; bidx < end_block; bidx++) {
@ -303,8 +353,8 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
}
}
de = find_in_block(dir, dentry_page, fname, namehash,
&max_slots, res_page);
de = find_in_block(dir, dentry_page, fname, &max_slots,
res_page);
if (de)
break;
@ -313,8 +363,8 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
f2fs_put_page(dentry_page, 0);
}
if (!de && room && F2FS_I(dir)->chash != namehash) {
F2FS_I(dir)->chash = namehash;
if (!de && room && F2FS_I(dir)->chash != fname->hash) {
F2FS_I(dir)->chash = fname->hash;
F2FS_I(dir)->clevel = level;
}
@ -322,7 +372,8 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
}
struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
struct fscrypt_name *fname, struct page **res_page)
const struct f2fs_filename *fname,
struct page **res_page)
{
unsigned long npages = dir_blocks(dir);
struct f2fs_dir_entry *de = NULL;
@ -371,18 +422,10 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
const struct qstr *child, struct page **res_page)
{
struct f2fs_dir_entry *de = NULL;
struct fscrypt_name fname;
struct f2fs_filename fname;
int err;
#ifdef CONFIG_UNICODE
if (sb_has_enc_strict_mode(dir->i_sb) && IS_CASEFOLDED(dir) &&
utf8_validate(dir->i_sb->s_encoding, child)) {
*res_page = ERR_PTR(-EINVAL);
return NULL;
}
#endif
err = fscrypt_setup_filename(dir, child, 1, &fname);
err = f2fs_setup_filename(dir, child, 1, &fname);
if (err) {
if (err == -ENOENT)
*res_page = NULL;
@ -393,7 +436,7 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
de = __f2fs_find_entry(dir, &fname, res_page);
fscrypt_free_filename(&fname);
f2fs_free_filename(&fname);
return de;
}
@ -434,24 +477,47 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
f2fs_put_page(page, 1);
}
static void init_dent_inode(const struct qstr *name, struct page *ipage)
static void init_dent_inode(struct inode *dir, struct inode *inode,
const struct f2fs_filename *fname,
struct page *ipage)
{
struct f2fs_inode *ri;
if (!fname) /* tmpfile case? */
return;
f2fs_wait_on_page_writeback(ipage, NODE, true, true);
/* copy name info. to this inode page */
ri = F2FS_INODE(ipage);
ri->i_namelen = cpu_to_le32(name->len);
memcpy(ri->i_name, name->name, name->len);
ri->i_namelen = cpu_to_le32(fname->disk_name.len);
memcpy(ri->i_name, fname->disk_name.name, fname->disk_name.len);
if (IS_ENCRYPTED(dir)) {
file_set_enc_name(inode);
/*
* Roll-forward recovery doesn't have encryption keys available,
* so it can't compute the dirhash for encrypted+casefolded
* filenames. Append it to i_name if possible. Else, disable
* roll-forward recovery of the dentry (i.e., make fsync'ing the
* file force a checkpoint) by setting LOST_PINO.
*/
if (IS_CASEFOLDED(dir)) {
if (fname->disk_name.len + sizeof(f2fs_hash_t) <=
F2FS_NAME_LEN)
put_unaligned(fname->hash, (f2fs_hash_t *)
&ri->i_name[fname->disk_name.len]);
else
file_lost_pino(inode);
}
}
set_page_dirty(ipage);
}
void f2fs_do_make_empty_dir(struct inode *inode, struct inode *parent,
struct f2fs_dentry_ptr *d)
{
struct qstr dot = QSTR_INIT(".", 1);
struct qstr dotdot = QSTR_INIT("..", 2);
struct fscrypt_str dot = FSTR_INIT(".", 1);
struct fscrypt_str dotdot = FSTR_INIT("..", 2);
/* update dirent of "." */
f2fs_update_dentry(inode->i_ino, inode->i_mode, d, &dot, 0, 0);
@ -485,8 +551,7 @@ static int make_empty_dir(struct inode *inode,
}
struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
const struct qstr *new_name, const struct qstr *orig_name,
struct page *dpage)
const struct f2fs_filename *fname, struct page *dpage)
{
struct page *page;
int err;
@ -511,7 +576,8 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
if (err)
goto put_error;
err = f2fs_init_security(inode, dir, orig_name, page);
err = f2fs_init_security(inode, dir,
fname ? fname->usr_fname : NULL, page);
if (err)
goto put_error;
@ -526,11 +592,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
return page;
}
if (new_name) {
init_dent_inode(new_name, page);
if (IS_ENCRYPTED(dir))
file_set_enc_name(inode);
}
init_dent_inode(dir, inode, fname, page);
/*
* This file should be checkpointed during fsync.
@ -595,11 +657,11 @@ int f2fs_room_for_filename(const void *bitmap, int slots, int max_slots)
}
bool f2fs_has_enough_room(struct inode *dir, struct page *ipage,
struct fscrypt_name *fname)
const struct f2fs_filename *fname)
{
struct f2fs_dentry_ptr d;
unsigned int bit_pos;
int slots = GET_DENTRY_SLOTS(fname_len(fname));
int slots = GET_DENTRY_SLOTS(fname->disk_name.len);
make_dentry_ptr_inline(dir, &d, inline_data_addr(dir, ipage));
@ -609,8 +671,8 @@ bool f2fs_has_enough_room(struct inode *dir, struct page *ipage,
}
void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d,
const struct qstr *name, f2fs_hash_t name_hash,
unsigned int bit_pos)
const struct fscrypt_str *name, f2fs_hash_t name_hash,
unsigned int bit_pos)
{
struct f2fs_dir_entry *de;
int slots = GET_DENTRY_SLOTS(name->len);
@ -630,10 +692,8 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d,
}
}
int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
const struct qstr *orig_name,
f2fs_hash_t dentry_hash,
struct inode *inode, nid_t ino, umode_t mode)
int f2fs_add_regular_entry(struct inode *dir, const struct f2fs_filename *fname,
struct inode *inode, nid_t ino, umode_t mode)
{
unsigned int bit_pos;
unsigned int level;
@ -647,10 +707,10 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
int slots, err = 0;
level = 0;
slots = GET_DENTRY_SLOTS(new_name->len);
slots = GET_DENTRY_SLOTS(fname->disk_name.len);
current_depth = F2FS_I(dir)->i_current_depth;
if (F2FS_I(dir)->chash == dentry_hash) {
if (F2FS_I(dir)->chash == fname->hash) {
level = F2FS_I(dir)->clevel;
F2FS_I(dir)->chash = 0;
}
@ -672,7 +732,7 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
nblock = bucket_blocks(level);
bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level,
(le32_to_cpu(dentry_hash) % nbucket));
(le32_to_cpu(fname->hash) % nbucket));
for (block = bidx; block <= (bidx + nblock - 1); block++) {
dentry_page = f2fs_get_new_data_page(dir, NULL, block, true);
@ -696,8 +756,7 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
if (inode) {
down_write(&F2FS_I(inode)->i_sem);
page = f2fs_init_inode_metadata(inode, dir, new_name,
orig_name, NULL);
page = f2fs_init_inode_metadata(inode, dir, fname, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
@ -705,7 +764,8 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
}
make_dentry_ptr_block(NULL, &d, dentry_blk);
f2fs_update_dentry(ino, mode, &d, new_name, dentry_hash, bit_pos);
f2fs_update_dentry(ino, mode, &d, &fname->disk_name, fname->hash,
bit_pos);
set_page_dirty(dentry_page);
@ -729,23 +789,15 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
return err;
}
int f2fs_add_dentry(struct inode *dir, struct fscrypt_name *fname,
struct inode *inode, nid_t ino, umode_t mode)
int f2fs_add_dentry(struct inode *dir, const struct f2fs_filename *fname,
struct inode *inode, nid_t ino, umode_t mode)
{
struct qstr new_name;
f2fs_hash_t dentry_hash;
int err = -EAGAIN;
new_name.name = fname_name(fname);
new_name.len = fname_len(fname);
if (f2fs_has_inline_dentry(dir))
err = f2fs_add_inline_entry(dir, &new_name, fname,
inode, ino, mode);
dentry_hash = f2fs_dentry_hash(dir, &new_name, fname);
err = f2fs_add_inline_entry(dir, fname, inode, ino, mode);
if (err == -EAGAIN)
err = f2fs_add_regular_entry(dir, &new_name, fname->usr_fname,
dentry_hash, inode, ino, mode);
err = f2fs_add_regular_entry(dir, fname, inode, ino, mode);
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
return err;
@ -758,12 +810,12 @@ int f2fs_add_dentry(struct inode *dir, struct fscrypt_name *fname,
int f2fs_do_add_link(struct inode *dir, const struct qstr *name,
struct inode *inode, nid_t ino, umode_t mode)
{
struct fscrypt_name fname;
struct f2fs_filename fname;
struct page *page = NULL;
struct f2fs_dir_entry *de = NULL;
int err;
err = fscrypt_setup_filename(dir, name, 0, &fname);
err = f2fs_setup_filename(dir, name, 0, &fname);
if (err)
return err;
@ -786,7 +838,7 @@ int f2fs_do_add_link(struct inode *dir, const struct qstr *name,
} else {
err = f2fs_add_dentry(dir, &fname, inode, ino, mode);
}
fscrypt_free_filename(&fname);
f2fs_free_filename(&fname);
return err;
}
@ -796,7 +848,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
int err = 0;
down_write(&F2FS_I(inode)->i_sem);
page = f2fs_init_inode_metadata(inode, dir, NULL, NULL, NULL);
page = f2fs_init_inode_metadata(inode, dir, NULL, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;

View file

@ -141,6 +141,7 @@ struct f2fs_mount_info {
#ifdef CONFIG_FS_ENCRYPTION
bool inlinecrypt; /* inline encryption enabled */
#endif
block_t unusable_cap_perc; /* percentage for cap */
block_t unusable_cap; /* Amount of space allowed to be
* unusable when disabling checkpoint
*/
@ -508,6 +509,44 @@ static inline int get_inline_xattr_addrs(struct inode *inode);
* For INODE and NODE manager
*/
/* for directory operations */
struct f2fs_filename {
/*
* The filename the user specified. This is NULL for some
* filesystem-internal operations, e.g. converting an inline directory
* to a non-inline one, or roll-forward recovering an encrypted dentry.
*/
const struct qstr *usr_fname;
/*
* The on-disk filename. For encrypted directories, this is encrypted.
* This may be NULL for lookups in an encrypted dir without the key.
*/
struct fscrypt_str disk_name;
/* The dirhash of this filename */
f2fs_hash_t hash;
#ifdef CONFIG_FS_ENCRYPTION
/*
* For lookups in encrypted directories: either the buffer backing
* disk_name, or a buffer that holds the decoded no-key name.
*/
struct fscrypt_str crypto_buf;
#endif
#ifdef CONFIG_UNICODE
/*
* For casefolded directories: the casefolded name, but it's left NULL
* if the original name is not valid Unicode, if the directory is both
* casefolded and encrypted and its encryption key is unavailable, or if
* the filesystem is doing an internal operation where usr_fname is also
* NULL. In all these cases we fall back to treating the name as an
* opaque byte sequence.
*/
struct fscrypt_str cf_name;
#endif
};
struct f2fs_dentry_ptr {
struct inode *inode;
void *bitmap;
@ -2919,12 +2958,12 @@ static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
return is_set_ckpt_flags(sbi, CP_ERROR_FLAG);
}
static inline bool is_dot_dotdot(const struct qstr *str)
static inline bool is_dot_dotdot(const u8 *name, size_t len)
{
if (str->len == 1 && str->name[0] == '.')
if (len == 1 && name[0] == '.')
return true;
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
if (len == 2 && name[0] == '.' && name[1] == '.')
return true;
return false;
@ -3143,22 +3182,28 @@ struct dentry *f2fs_get_parent(struct dentry *child);
* dir.c
*/
unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de);
struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname,
f2fs_hash_t namehash, int *max_slots,
struct f2fs_dentry_ptr *d);
int f2fs_init_casefolded_name(const struct inode *dir,
struct f2fs_filename *fname);
int f2fs_setup_filename(struct inode *dir, const struct qstr *iname,
int lookup, struct f2fs_filename *fname);
int f2fs_prepare_lookup(struct inode *dir, struct dentry *dentry,
struct f2fs_filename *fname);
void f2fs_free_filename(struct f2fs_filename *fname);
struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d,
const struct f2fs_filename *fname, int *max_slots);
int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
unsigned int start_pos, struct fscrypt_str *fstr);
void f2fs_do_make_empty_dir(struct inode *inode, struct inode *parent,
struct f2fs_dentry_ptr *d);
struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
const struct qstr *new_name,
const struct qstr *orig_name, struct page *dpage);
const struct f2fs_filename *fname, struct page *dpage);
void f2fs_update_parent_metadata(struct inode *dir, struct inode *inode,
unsigned int current_depth);
int f2fs_room_for_filename(const void *bitmap, int slots, int max_slots);
void f2fs_drop_nlink(struct inode *dir, struct inode *inode);
struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
struct fscrypt_name *fname, struct page **res_page);
const struct f2fs_filename *fname,
struct page **res_page);
struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
const struct qstr *child, struct page **res_page);
struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p);
@ -3167,14 +3212,13 @@ ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr,
void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
struct page *page, struct inode *inode);
bool f2fs_has_enough_room(struct inode *dir, struct page *ipage,
struct fscrypt_name *fname);
const struct f2fs_filename *fname);
void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d,
const struct qstr *name, f2fs_hash_t name_hash,
const struct fscrypt_str *name, f2fs_hash_t name_hash,
unsigned int bit_pos);
int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
const struct qstr *orig_name, f2fs_hash_t dentry_hash,
int f2fs_add_regular_entry(struct inode *dir, const struct f2fs_filename *fname,
struct inode *inode, nid_t ino, umode_t mode);
int f2fs_add_dentry(struct inode *dir, struct fscrypt_name *fname,
int f2fs_add_dentry(struct inode *dir, const struct f2fs_filename *fname,
struct inode *inode, nid_t ino, umode_t mode);
int f2fs_do_add_link(struct inode *dir, const struct qstr *name,
struct inode *inode, nid_t ino, umode_t mode);
@ -3204,8 +3248,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi);
/*
* hash.c
*/
f2fs_hash_t f2fs_dentry_hash(const struct inode *dir,
const struct qstr *name_info, const struct fscrypt_name *fname);
void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname);
/*
* node.c
@ -3711,11 +3754,11 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry);
int f2fs_write_inline_data(struct inode *inode, struct page *page);
bool f2fs_recover_inline_data(struct inode *inode, struct page *npage);
struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
struct fscrypt_name *fname, struct page **res_page);
const struct f2fs_filename *fname,
struct page **res_page);
int f2fs_make_empty_inline_dir(struct inode *inode, struct inode *parent,
struct page *ipage);
int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
const struct fscrypt_name *fname,
int f2fs_add_inline_entry(struct inode *dir, const struct f2fs_filename *fname,
struct inode *inode, nid_t ino, umode_t mode);
void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry,
struct page *page, struct inode *dir,

View file

@ -68,28 +68,9 @@ static void str2hashbuf(const unsigned char *msg, size_t len,
*buf++ = pad;
}
static f2fs_hash_t __f2fs_dentry_hash(const struct inode *dir,
const struct qstr *name_info,
const struct fscrypt_name *fname)
static u32 TEA_hash_name(const u8 *p, size_t len)
{
__u32 hash;
f2fs_hash_t f2fs_hash;
const unsigned char *p;
__u32 in[8], buf[4];
const unsigned char *name = name_info->name;
size_t len = name_info->len;
/* encrypted bigname case */
if (fname && fname->is_ciphertext_name)
return cpu_to_le32(fname->hash);
if (is_dot_dotdot(name_info))
return 0;
if (IS_CASEFOLDED(dir) && IS_ENCRYPTED(dir)) {
f2fs_hash = cpu_to_le32(fscrypt_fname_siphash(dir, name_info));
return f2fs_hash;
}
/* Initialize the default seed for the hash checksum functions */
buf[0] = 0x67452301;
@ -97,7 +78,6 @@ static f2fs_hash_t __f2fs_dentry_hash(const struct inode *dir,
buf[2] = 0x98badcfe;
buf[3] = 0x10325476;
p = name;
while (1) {
str2hashbuf(p, len, in, 4);
TEA_transform(buf, in);
@ -106,44 +86,52 @@ static f2fs_hash_t __f2fs_dentry_hash(const struct inode *dir,
break;
len -= 16;
}
hash = buf[0];
f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
return f2fs_hash;
return buf[0] & ~F2FS_HASH_COL_BIT;
}
f2fs_hash_t f2fs_dentry_hash(const struct inode *dir,
const struct qstr *name_info, const struct fscrypt_name *fname)
/*
* Compute @fname->hash. For all directories, @fname->disk_name must be set.
* For casefolded directories, @fname->usr_fname must be set, and also
* @fname->cf_name if the filename is valid Unicode.
*/
void f2fs_hash_filename(const struct inode *dir, struct f2fs_filename *fname)
{
#ifdef CONFIG_UNICODE
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
const struct unicode_map *um = dir->i_sb->s_encoding;
int r, dlen;
unsigned char *buff;
struct qstr folded;
const struct qstr *name = fname ? fname->usr_fname : name_info;
const u8 *name = fname->disk_name.name;
size_t len = fname->disk_name.len;
if (!name_info->len || !IS_CASEFOLDED(dir))
goto opaque_seq;
WARN_ON_ONCE(!name);
if (IS_ENCRYPTED(dir) && !fscrypt_has_encryption_key(dir))
goto opaque_seq;
buff = f2fs_kzalloc(sbi, sizeof(char) * PATH_MAX, GFP_KERNEL);
if (!buff)
return -ENOMEM;
dlen = utf8_casefold(um, name, buff, PATH_MAX);
if (dlen < 0) {
kvfree(buff);
goto opaque_seq;
if (is_dot_dotdot(name, len)) {
fname->hash = 0;
return;
}
folded.name = buff;
folded.len = dlen;
r = __f2fs_dentry_hash(dir, &folded, fname);
kvfree(buff);
return r;
#ifdef CONFIG_UNICODE
if (IS_CASEFOLDED(dir)) {
/*
* If the casefolded name is provided, hash it instead of the
* on-disk name. If the casefolded name is *not* provided, that
* should only be because the name wasn't valid Unicode, so fall
* back to treating the name as an opaque byte sequence. Note
* that to handle encrypted directories, the fallback must use
* usr_fname (plaintext) rather than disk_name (ciphertext).
*/
WARN_ON_ONCE(!fname->usr_fname->name);
if (fname->cf_name.name) {
name = fname->cf_name.name;
len = fname->cf_name.len;
} else {
name = fname->usr_fname->name;
len = fname->usr_fname->len;
}
if (IS_ENCRYPTED(dir)) {
struct qstr tmp = QSTR_INIT(name, len);
opaque_seq:
fname->hash =
cpu_to_le32(fscrypt_fname_siphash(dir, &tmp));
return;
}
}
#endif
return __f2fs_dentry_hash(dir, name_info, fname);
fname->hash = cpu_to_le32(TEA_hash_name(name, len));
}

View file

@ -323,15 +323,14 @@ bool f2fs_recover_inline_data(struct inode *inode, struct page *npage)
}
struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
struct fscrypt_name *fname, struct page **res_page)
const struct f2fs_filename *fname,
struct page **res_page)
{
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
struct qstr name = FSTR_TO_QSTR(&fname->disk_name);
struct f2fs_dir_entry *de;
struct f2fs_dentry_ptr d;
struct page *ipage;
void *inline_dentry;
f2fs_hash_t namehash;
ipage = f2fs_get_node_page(sbi, dir->i_ino);
if (IS_ERR(ipage)) {
@ -339,12 +338,10 @@ struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
return NULL;
}
namehash = f2fs_dentry_hash(dir, &name, fname);
inline_dentry = inline_data_addr(dir, ipage);
make_dentry_ptr_inline(dir, &d, inline_dentry);
de = f2fs_find_target_dentry(fname, namehash, NULL, &d);
de = f2fs_find_target_dentry(&d, fname, NULL);
unlock_page(ipage);
if (de)
*res_page = ipage;
@ -461,7 +458,7 @@ static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry)
while (bit_pos < d.max) {
struct f2fs_dir_entry *de;
struct qstr new_name;
struct f2fs_filename fname;
nid_t ino;
umode_t fake_mode;
@ -477,14 +474,19 @@ static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry)
continue;
}
new_name.name = d.filename[bit_pos];
new_name.len = le16_to_cpu(de->name_len);
/*
* We only need the disk_name and hash to move the dentry.
* We don't need the original or casefolded filenames.
*/
memset(&fname, 0, sizeof(fname));
fname.disk_name.name = d.filename[bit_pos];
fname.disk_name.len = le16_to_cpu(de->name_len);
fname.hash = de->hash_code;
ino = le32_to_cpu(de->ino);
fake_mode = f2fs_get_de_type(de) << S_SHIFT;
err = f2fs_add_regular_entry(dir, &new_name, NULL,
de->hash_code, NULL, ino, fake_mode);
err = f2fs_add_regular_entry(dir, &fname, NULL, ino, fake_mode);
if (err)
goto punch_dentry_pages;
@ -561,7 +563,7 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
struct page *ipage;
struct fscrypt_name fname;
struct f2fs_filename fname;
void *inline_dentry = NULL;
int err = 0;
@ -570,19 +572,19 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry)
f2fs_lock_op(sbi);
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &fname);
err = f2fs_setup_filename(dir, &dentry->d_name, 0, &fname);
if (err)
goto out;
ipage = f2fs_get_node_page(sbi, dir->i_ino);
if (IS_ERR(ipage)) {
err = PTR_ERR(ipage);
goto out;
goto out_fname;
}
if (f2fs_has_enough_room(dir, ipage, &fname)) {
f2fs_put_page(ipage, 1);
goto out;
goto out_fname;
}
inline_dentry = inline_data_addr(dir, ipage);
@ -590,24 +592,23 @@ int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry)
err = do_convert_inline_dir(dir, ipage, inline_dentry);
if (!err)
f2fs_put_page(ipage, 1);
out_fname:
f2fs_free_filename(&fname);
out:
f2fs_unlock_op(sbi);
return err;
}
int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
const struct fscrypt_name *fname,
struct inode *inode, nid_t ino, umode_t mode)
int f2fs_add_inline_entry(struct inode *dir, const struct f2fs_filename *fname,
struct inode *inode, nid_t ino, umode_t mode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
struct page *ipage;
unsigned int bit_pos;
f2fs_hash_t name_hash;
void *inline_dentry = NULL;
struct f2fs_dentry_ptr d;
int slots = GET_DENTRY_SLOTS(new_name->len);
int slots = GET_DENTRY_SLOTS(fname->disk_name.len);
struct page *page = NULL;
const struct qstr *orig_name = fname->usr_fname;
int err = 0;
ipage = f2fs_get_node_page(sbi, dir->i_ino);
@ -628,8 +629,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
if (inode) {
down_write(&F2FS_I(inode)->i_sem);
page = f2fs_init_inode_metadata(inode, dir, new_name,
orig_name, ipage);
page = f2fs_init_inode_metadata(inode, dir, fname, ipage);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
@ -638,8 +638,8 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
f2fs_wait_on_page_writeback(ipage, NODE, true, true);
name_hash = f2fs_dentry_hash(dir, new_name, fname);
f2fs_update_dentry(ino, mode, &d, new_name, name_hash, bit_pos);
f2fs_update_dentry(ino, mode, &d, &fname->disk_name, fname->hash,
bit_pos);
set_page_dirty(ipage);

View file

@ -482,7 +482,7 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
nid_t ino = -1;
int err = 0;
unsigned int root_ino = F2FS_ROOT_INO(F2FS_I_SB(dir));
struct fscrypt_name fname;
struct f2fs_filename fname;
trace_f2fs_lookup_start(dir, dentry, flags);
@ -491,14 +491,14 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
goto out;
}
err = fscrypt_prepare_lookup(dir, dentry, &fname);
err = f2fs_prepare_lookup(dir, dentry, &fname);
generic_set_encrypted_ci_d_ops(dir, dentry);
if (err == -ENOENT)
goto out_splice;
if (err)
goto out;
de = __f2fs_find_entry(dir, &fname, &page);
fscrypt_free_filename(&fname);
f2fs_free_filename(&fname);
if (!de) {
if (IS_ERR(page)) {

View file

@ -5,6 +5,7 @@
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*/
#include <asm/unaligned.h>
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
#include "f2fs.h"
@ -107,13 +108,60 @@ static void del_fsync_inode(struct fsync_inode_entry *entry, int drop)
kmem_cache_free(fsync_entry_slab, entry);
}
static int init_recovered_filename(const struct inode *dir,
struct f2fs_inode *raw_inode,
struct f2fs_filename *fname,
struct qstr *usr_fname)
{
int err;
memset(fname, 0, sizeof(*fname));
fname->disk_name.len = le32_to_cpu(raw_inode->i_namelen);
fname->disk_name.name = raw_inode->i_name;
if (WARN_ON(fname->disk_name.len > F2FS_NAME_LEN))
return -ENAMETOOLONG;
if (!IS_ENCRYPTED(dir)) {
usr_fname->name = fname->disk_name.name;
usr_fname->len = fname->disk_name.len;
fname->usr_fname = usr_fname;
}
/* Compute the hash of the filename */
if (IS_ENCRYPTED(dir) && IS_CASEFOLDED(dir)) {
/*
* In this case the hash isn't computable without the key, so it
* was saved on-disk.
*/
if (fname->disk_name.len + sizeof(f2fs_hash_t) > F2FS_NAME_LEN)
return -EINVAL;
fname->hash = get_unaligned((f2fs_hash_t *)
&raw_inode->i_name[fname->disk_name.len]);
} else if (IS_CASEFOLDED(dir)) {
err = f2fs_init_casefolded_name(dir, fname);
if (err)
return err;
f2fs_hash_filename(dir, fname);
#ifdef CONFIG_UNICODE
/* Case-sensitive match is fine for recovery */
kfree(fname->cf_name.name);
fname->cf_name.name = NULL;
#endif
} else {
f2fs_hash_filename(dir, fname);
}
return 0;
}
static int recover_dentry(struct inode *inode, struct page *ipage,
struct list_head *dir_list)
{
struct f2fs_inode *raw_inode = F2FS_INODE(ipage);
nid_t pino = le32_to_cpu(raw_inode->i_pino);
struct f2fs_dir_entry *de;
struct fscrypt_name fname;
struct f2fs_filename fname;
struct qstr usr_fname;
struct page *page;
struct inode *dir, *einode;
struct fsync_inode_entry *entry;
@ -132,16 +180,9 @@ static int recover_dentry(struct inode *inode, struct page *ipage,
}
dir = entry->inode;
memset(&fname, 0, sizeof(struct fscrypt_name));
fname.disk_name.len = le32_to_cpu(raw_inode->i_namelen);
fname.disk_name.name = raw_inode->i_name;
if (unlikely(fname.disk_name.len > F2FS_NAME_LEN)) {
WARN_ON(1);
err = -ENAMETOOLONG;
err = init_recovered_filename(dir, raw_inode, &fname, &usr_fname);
if (err)
goto out;
}
retry:
de = __f2fs_find_entry(dir, &fname, &page);
if (de && inode->i_ino == le32_to_cpu(de->ino))

View file

@ -285,6 +285,22 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
F2FS_OPTION(sbi).s_resgid));
}
static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
{
if (!F2FS_OPTION(sbi).unusable_cap_perc)
return;
if (F2FS_OPTION(sbi).unusable_cap_perc == 100)
F2FS_OPTION(sbi).unusable_cap = sbi->user_block_count;
else
F2FS_OPTION(sbi).unusable_cap = (sbi->user_block_count / 100) *
F2FS_OPTION(sbi).unusable_cap_perc;
f2fs_info(sbi, "Adjust unusable cap for checkpoint=disable = %u / %u%%",
F2FS_OPTION(sbi).unusable_cap,
F2FS_OPTION(sbi).unusable_cap_perc);
}
static void init_once(void *foo)
{
struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
@ -803,12 +819,7 @@ static int parse_options(struct super_block *sb, char *options)
return -EINVAL;
if (arg < 0 || arg > 100)
return -EINVAL;
if (arg == 100)
F2FS_OPTION(sbi).unusable_cap =
sbi->user_block_count;
else
F2FS_OPTION(sbi).unusable_cap =
(sbi->user_block_count / 100) * arg;
F2FS_OPTION(sbi).unusable_cap_perc = arg;
set_opt(sbi, DISABLE_CHECKPOINT);
break;
case Opt_checkpoint_disable_cap:
@ -1866,6 +1877,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
(test_opt(sbi, POSIX_ACL) ? SB_POSIXACL : 0);
limit_reserve_root(sbi);
adjust_unusable_cap_perc(sbi);
*flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
return 0;
restore_gc:
@ -3584,6 +3596,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
sbi->reserved_blocks = 0;
sbi->current_reserved_blocks = 0;
limit_reserve_root(sbi);
adjust_unusable_cap_perc(sbi);
for (i = 0; i < NR_INODE_TYPE; i++) {
INIT_LIST_HEAD(&sbi->inode_list[i]);