mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-26 06:33:19 -04:00
Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-5.4.y' into android-5.4-stable
* aosp/upstream-f2fs-stable-linux-5.4.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
f2fs: fix quota_sync failure due to f2fs_lock_op
f2fs: support read iostat
f2fs: Fix the accounting of dcc->undiscard_blks
f2fs: fix to handle error path of f2fs_ra_meta_pages()
f2fs: report the discard cmd errors properly
f2fs: fix long latency due to discard during umount
f2fs: add tracepoint for f2fs iostat
f2fs: introduce sysfs/data_io_flag to attach REQ_META/FUA
ubifs: wire up FS_IOC_GET_ENCRYPTION_NONCE
f2fs: wire up FS_IOC_GET_ENCRYPTION_NONCE
ext4: wire up FS_IOC_GET_ENCRYPTION_NONCE
fscrypt: add FS_IOC_GET_ENCRYPTION_NONCE ioctl
f2fs: keep inline_data when compression conversion
f2fs: fix to disable compression on directory
f2fs: add missing CONFIG_F2FS_FS_COMPRESSION
f2fs: switch discard_policy.timeout to bool type
f2fs: fix to verify tpage before releasing in f2fs_free_dic()
f2fs: show compression in statx
f2fs: clean up dic->tpages assignment
f2fs: compress: support zstd compress algorithm
f2fs: compress: add .{init,destroy}_decompress_ctx callback
f2fs: compress: fix to call missing destroy_compress_ctx()
f2fs: change default compression algorithm
f2fs: clean up {cic,dic}.ref handling
f2fs: fix to use f2fs_readpage_limit() in f2fs_read_multi_pages()
f2fs: xattr.h: Make stub helpers inline
f2fs: fix to avoid double unlock
f2fs: fix potential .flags overflow on 32bit architecture
f2fs: fix NULL pointer dereference in f2fs_verity_work()
f2fs: fix to clear PG_error if fsverity failed
f2fs: don't call fscrypt_get_encryption_info() explicitly in f2fs_tmpfile()
f2fs: don't trigger data flush in foreground operation
f2fs: fix NULL pointer dereference in f2fs_write_begin()
f2fs: clean up f2fs_may_encrypt()
f2fs: fix to avoid potential deadlock
f2fs: don't change inode status under page lock
f2fs: fix potential deadlock on compressed quota file
f2fs: delete DIO read lock
f2fs: don't mark compressed inode dirty during f2fs_iget()
f2fs: fix to account compressed blocks in f2fs_compressed_blocks()
f2fs: xattr.h: Replace zero-length array with flexible-array member
f2fs: fix to update f2fs_super_block fields under sb_lock
f2fs: Add a new CP flag to help fsck fix resize SPO issues
f2fs: Fix mount failure due to SPO after a successful online resize FS
f2fs: use kmem_cache pool during inline xattr lookups
f2fs: skip migration only when BG_GC is called
f2fs: fix to show tracepoint correctly
f2fs: avoid __GFP_NOFAIL in f2fs_bio_alloc
f2fs: introduce F2FS_IOC_GET_COMPRESS_BLOCKS
f2fs: fix to avoid triggering IO in write path
f2fs: add prefix for f2fs slab cache name
f2fs: introduce DEFAULT_IO_TIMEOUT
f2fs: skip GC when section is full
f2fs: add migration count iff migration happens
f2fs: clean up bggc mount option
f2fs: clean up lfs/adaptive mount option
f2fs: fix to show norecovery mount option
f2fs: clean up parameter of macro XATTR_SIZE()
f2fs: clean up codes with {f2fs_,}data_blkaddr()
f2fs: show mounted time
f2fs: Use scnprintf() for avoiding potential buffer overflow
f2fs: allow to clear F2FS_COMPR_FL flag
f2fs: fix to check dirty pages during compressed inode conversion
f2fs: fix to account compressed inode correctly
f2fs: fix wrong check on F2FS_IOC_FSSETXATTR
f2fs: fix to avoid use-after-free in f2fs_write_multi_pages()
f2fs: fix to avoid using uninitialized variable
f2fs: fix inconsistent comments
f2fs: remove i_sem lock coverage in f2fs_setxattr()
f2fs: cover last_disk_size update with spinlock
f2fs: fix to check i_compr_blocks correctly
f2fs: fix to avoid potential deadlock
f2fs: add missing function name in kernel message
f2fs: recycle unused compress_data.chksum feild
f2fs: fix to avoid NULL pointer dereference
f2fs: fix leaking uninitialized memory in compressed clusters
f2fs: fix the panic in do_checkpoint()
f2fs: fix to wait all node page writeback
mm/swapfile.c: move inode_lock out of claim_swapfile
fscrypt: don't evict dirty inodes after removing key
Conflicts:
Documentation/ABI/testing/sysfs-fs-f2fs
fs/f2fs/checkpoint.c
fs/f2fs/compress.c
fs/f2fs/data.c
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:
commit
57b59aec93
17 changed files with 699 additions and 313 deletions
|
|
@ -323,3 +323,18 @@ What: /sys/fs/f2fs/<disk>/mounted_time_sec
|
|||
Date: February 2020
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: Show the mounted time in secs of this partition.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/data_io_flag
|
||||
Date: April 2020
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: Give a way to attach REQ_META|FUA to data writes
|
||||
given temperature-based bits. Now the bits indicate:
|
||||
* REQ_META | REQ_FUA |
|
||||
* 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
* Cold | Warm | Hot | Cold | Warm | Hot |
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/iostat_period_ms
|
||||
Date: April 2020
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: Give a way to change iostat_period time. 3secs by default.
|
||||
The new iostat trace gives stats gap given the period.
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ repeat:
|
|||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
f2fs_update_iostat(sbi, FS_META_READ_IO, F2FS_BLKSIZE);
|
||||
|
||||
lock_page(page);
|
||||
if (unlikely(page->mapping != mapping)) {
|
||||
f2fs_put_page(page, 1);
|
||||
|
|
@ -220,6 +222,7 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
|||
.is_por = (type == META_POR),
|
||||
};
|
||||
struct blk_plug plug;
|
||||
int err;
|
||||
|
||||
if (unlikely(type == META_POR))
|
||||
fio.op_flags &= ~REQ_META;
|
||||
|
|
@ -263,8 +266,11 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
|||
}
|
||||
|
||||
fio.page = page;
|
||||
f2fs_submit_page_bio(&fio);
|
||||
f2fs_put_page(page, 0);
|
||||
err = f2fs_submit_page_bio(&fio);
|
||||
f2fs_put_page(page, err ? 1 : 0);
|
||||
|
||||
if (!err)
|
||||
f2fs_update_iostat(sbi, FS_META_READ_IO, F2FS_BLKSIZE);
|
||||
}
|
||||
out:
|
||||
blk_finish_plug(&plug);
|
||||
|
|
@ -1260,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);
|
||||
|
|
|
|||
|
|
@ -985,7 +985,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
|||
loff_t psize;
|
||||
int i, err;
|
||||
|
||||
if (!f2fs_trylock_op(sbi))
|
||||
if (!IS_NOQUOTA(inode) && !f2fs_trylock_op(sbi))
|
||||
return -EAGAIN;
|
||||
|
||||
set_new_dnode(&dn, cc->inode, NULL, NULL, 0);
|
||||
|
|
|
|||
|
|
@ -545,6 +545,28 @@ void f2fs_submit_bio(struct f2fs_sb_info *sbi,
|
|||
__submit_bio(sbi, bio, type);
|
||||
}
|
||||
|
||||
static void __attach_data_io_flag(struct f2fs_io_info *fio)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = fio->sbi;
|
||||
unsigned int temp_mask = (1 << NR_TEMP_TYPE) - 1;
|
||||
unsigned int fua_flag = sbi->data_io_flag & temp_mask;
|
||||
unsigned int meta_flag = (sbi->data_io_flag >> NR_TEMP_TYPE) &
|
||||
temp_mask;
|
||||
/*
|
||||
* data io flag bits per temp:
|
||||
* REQ_META | REQ_FUA |
|
||||
* 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
* Cold | Warm | Hot | Cold | Warm | Hot |
|
||||
*/
|
||||
if (fio->type != DATA)
|
||||
return;
|
||||
|
||||
if ((1 << fio->temp) & meta_flag)
|
||||
fio->op_flags |= REQ_META;
|
||||
if ((1 << fio->temp) & fua_flag)
|
||||
fio->op_flags |= REQ_FUA;
|
||||
}
|
||||
|
||||
static void __submit_merged_bio(struct f2fs_bio_info *io)
|
||||
{
|
||||
struct f2fs_io_info *fio = &io->fio;
|
||||
|
|
@ -552,6 +574,7 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)
|
|||
if (!io->bio)
|
||||
return;
|
||||
|
||||
__attach_data_io_flag(fio);
|
||||
bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
|
||||
|
||||
if (is_read_io(fio->op))
|
||||
|
|
@ -1059,6 +1082,7 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
|
|||
}
|
||||
ClearPageError(page);
|
||||
inc_page_count(sbi, F2FS_RD_DATA);
|
||||
f2fs_update_iostat(sbi, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
||||
__submit_bio(sbi, bio, DATA);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2065,6 +2089,7 @@ submit_and_realloc:
|
|||
goto submit_and_realloc;
|
||||
|
||||
inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), FS_DATA_READ_IO, F2FS_BLKSIZE);
|
||||
ClearPageError(page);
|
||||
*last_block_in_bio = block_nr;
|
||||
goto out;
|
||||
|
|
@ -2201,6 +2226,7 @@ submit_and_realloc:
|
|||
goto submit_and_realloc;
|
||||
|
||||
inc_page_count(sbi, F2FS_RD_DATA);
|
||||
f2fs_update_iostat(sbi, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
||||
ClearPageError(page);
|
||||
*last_block_in_bio = blkaddr;
|
||||
}
|
||||
|
|
@ -2687,8 +2713,8 @@ write:
|
|||
f2fs_available_free_memory(sbi, BASE_CHECK))))
|
||||
goto redirty_out;
|
||||
|
||||
/* Dentry blocks are controlled by checkpoint */
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
/* Dentry/quota blocks are controlled by checkpoint */
|
||||
if (S_ISDIR(inode->i_mode) || IS_NOQUOTA(inode)) {
|
||||
fio.need_lock = LOCK_DONE;
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
goto done;
|
||||
|
|
@ -3591,6 +3617,9 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
} else if (err < 0) {
|
||||
f2fs_write_failed(mapping, offset + count);
|
||||
}
|
||||
} else {
|
||||
if (err > 0)
|
||||
f2fs_update_iostat(sbi, APP_DIRECT_READ_IO, err);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
|||
372
fs/f2fs/dir.c
372
fs/f2fs/dir.c
|
|
@ -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 @@ next:
|
|||
}
|
||||
|
||||
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 @@ start:
|
|||
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 @@ add_dentry:
|
|||
|
||||
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 @@ add_dentry:
|
|||
}
|
||||
|
||||
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 @@ fail:
|
|||
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;
|
||||
|
|
|
|||
133
fs/f2fs/f2fs.h
133
fs/f2fs/f2fs.h
|
|
@ -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;
|
||||
|
|
@ -1090,8 +1129,9 @@ enum cp_reason_type {
|
|||
};
|
||||
|
||||
enum iostat_type {
|
||||
APP_DIRECT_IO, /* app direct IOs */
|
||||
APP_BUFFERED_IO, /* app buffered IOs */
|
||||
/* WRITE IO */
|
||||
APP_DIRECT_IO, /* app direct write IOs */
|
||||
APP_BUFFERED_IO, /* app buffered write IOs */
|
||||
APP_WRITE_IO, /* app write IOs */
|
||||
APP_MAPPED_IO, /* app mapped IOs */
|
||||
FS_DATA_IO, /* data IOs from kworker/fsync/reclaimer */
|
||||
|
|
@ -1102,6 +1142,17 @@ enum iostat_type {
|
|||
FS_CP_DATA_IO, /* data IOs from checkpoint */
|
||||
FS_CP_NODE_IO, /* node IOs from checkpoint */
|
||||
FS_CP_META_IO, /* meta IOs from checkpoint */
|
||||
|
||||
/* READ IO */
|
||||
APP_DIRECT_READ_IO, /* app direct read IOs */
|
||||
APP_BUFFERED_READ_IO, /* app buffered read IOs */
|
||||
APP_READ_IO, /* app read IOs */
|
||||
APP_MAPPED_READ_IO, /* app mapped read IOs */
|
||||
FS_DATA_READ_IO, /* data read IOs */
|
||||
FS_NODE_READ_IO, /* node read IOs */
|
||||
FS_META_READ_IO, /* meta read IOs */
|
||||
|
||||
/* other */
|
||||
FS_DISCARD, /* discard */
|
||||
NR_IO_TYPE,
|
||||
};
|
||||
|
|
@ -1502,8 +1553,14 @@ struct f2fs_sb_info {
|
|||
|
||||
/* For app/fs IO statistics */
|
||||
spinlock_t iostat_lock;
|
||||
unsigned long long write_iostat[NR_IO_TYPE];
|
||||
unsigned long long rw_iostat[NR_IO_TYPE];
|
||||
unsigned long long prev_rw_iostat[NR_IO_TYPE];
|
||||
bool iostat_enable;
|
||||
unsigned long iostat_next_period;
|
||||
unsigned int iostat_period_ms;
|
||||
|
||||
/* to attach REQ_META|REQ_FUA flags */
|
||||
unsigned int data_io_flag;
|
||||
|
||||
/* For sysfs suppport */
|
||||
struct kobject s_kobj;
|
||||
|
|
@ -2900,12 +2957,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;
|
||||
|
|
@ -2994,29 +3051,45 @@ static inline int get_inline_xattr_addrs(struct inode *inode)
|
|||
sizeof((f2fs_inode)->field)) \
|
||||
<= (F2FS_OLD_ATTRIBUTE_SIZE + (extra_isize))) \
|
||||
|
||||
#define DEFAULT_IOSTAT_PERIOD_MS 3000
|
||||
#define MIN_IOSTAT_PERIOD_MS 100
|
||||
/* maximum period of iostat tracing is 1 day */
|
||||
#define MAX_IOSTAT_PERIOD_MS 8640000
|
||||
|
||||
static inline void f2fs_reset_iostat(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int i;
|
||||
|
||||
spin_lock(&sbi->iostat_lock);
|
||||
for (i = 0; i < NR_IO_TYPE; i++)
|
||||
sbi->write_iostat[i] = 0;
|
||||
for (i = 0; i < NR_IO_TYPE; i++) {
|
||||
sbi->rw_iostat[i] = 0;
|
||||
sbi->prev_rw_iostat[i] = 0;
|
||||
}
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
}
|
||||
|
||||
extern void f2fs_record_iostat(struct f2fs_sb_info *sbi);
|
||||
|
||||
static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
|
||||
enum iostat_type type, unsigned long long io_bytes)
|
||||
{
|
||||
if (!sbi->iostat_enable)
|
||||
return;
|
||||
spin_lock(&sbi->iostat_lock);
|
||||
sbi->write_iostat[type] += io_bytes;
|
||||
sbi->rw_iostat[type] += io_bytes;
|
||||
|
||||
if (type == APP_WRITE_IO || type == APP_DIRECT_IO)
|
||||
sbi->write_iostat[APP_BUFFERED_IO] =
|
||||
sbi->write_iostat[APP_WRITE_IO] -
|
||||
sbi->write_iostat[APP_DIRECT_IO];
|
||||
sbi->rw_iostat[APP_BUFFERED_IO] =
|
||||
sbi->rw_iostat[APP_WRITE_IO] -
|
||||
sbi->rw_iostat[APP_DIRECT_IO];
|
||||
|
||||
if (type == APP_READ_IO || type == APP_DIRECT_READ_IO)
|
||||
sbi->rw_iostat[APP_BUFFERED_READ_IO] =
|
||||
sbi->rw_iostat[APP_READ_IO] -
|
||||
sbi->rw_iostat[APP_DIRECT_READ_IO];
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
|
||||
f2fs_record_iostat(sbi);
|
||||
}
|
||||
|
||||
#define __is_large_section(sbi) ((sbi)->segs_per_sec > 1)
|
||||
|
|
@ -3108,22 +3181,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);
|
||||
|
|
@ -3132,14 +3211,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);
|
||||
|
|
@ -3169,8 +3247,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
|
||||
|
|
@ -3678,11 +3755,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,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
|
|||
ret = filemap_fault(vmf);
|
||||
up_read(&F2FS_I(inode)->i_mmap_sem);
|
||||
|
||||
if (!ret)
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_MAPPED_READ_IO,
|
||||
F2FS_BLKSIZE);
|
||||
|
||||
trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)ret);
|
||||
|
||||
return ret;
|
||||
|
|
@ -3510,11 +3514,17 @@ static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
|||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
int ret;
|
||||
|
||||
if (!f2fs_is_compress_backend_ready(inode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return generic_file_read_iter(iocb, iter);
|
||||
ret = generic_file_read_iter(iocb, iter);
|
||||
|
||||
if (ret > 0)
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_READ_IO, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
|
|
|
|||
|
|
@ -737,6 +737,9 @@ got_it:
|
|||
goto put_encrypted_page;
|
||||
f2fs_put_page(fio.encrypted_page, 0);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
f2fs_update_iostat(sbi, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
||||
|
||||
return 0;
|
||||
put_encrypted_page:
|
||||
f2fs_put_page(fio.encrypted_page, 1);
|
||||
|
|
@ -840,6 +843,9 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
|||
f2fs_put_page(mpage, 1);
|
||||
goto up_out;
|
||||
}
|
||||
|
||||
f2fs_update_iostat(fio.sbi, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
||||
|
||||
lock_page(mpage);
|
||||
if (unlikely(mpage->mapping != META_MAPPING(fio.sbi) ||
|
||||
!PageUptodate(mpage))) {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -323,15 +323,14 @@ process_inline:
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -1300,7 +1300,13 @@ static int read_node_page(struct page *page, int op_flags)
|
|||
}
|
||||
|
||||
fio.new_blkaddr = fio.old_blkaddr = ni.blk_addr;
|
||||
return f2fs_submit_page_bio(&fio);
|
||||
|
||||
err = f2fs_submit_page_bio(&fio);
|
||||
|
||||
if (!err)
|
||||
f2fs_update_iostat(sbi, FS_NODE_READ_IO, F2FS_BLKSIZE);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -1029,9 +1029,9 @@ static void f2fs_submit_discard_endio(struct bio *bio)
|
|||
struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private;
|
||||
unsigned long flags;
|
||||
|
||||
dc->error = blk_status_to_errno(bio->bi_status);
|
||||
|
||||
spin_lock_irqsave(&dc->lock, flags);
|
||||
if (!dc->error)
|
||||
dc->error = blk_status_to_errno(bio->bi_status);
|
||||
dc->bio_ref--;
|
||||
if (!dc->bio_ref && dc->state == D_SUBMIT) {
|
||||
dc->state = D_DONE;
|
||||
|
|
@ -1101,7 +1101,6 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
|||
} else if (discard_type == DPOLICY_FSTRIM) {
|
||||
dpolicy->io_aware = false;
|
||||
} else if (discard_type == DPOLICY_UMOUNT) {
|
||||
dpolicy->max_requests = UINT_MAX;
|
||||
dpolicy->io_aware = false;
|
||||
/* we need to issue all to keep CP_TRIMMED_FLAG */
|
||||
dpolicy->granularity = 1;
|
||||
|
|
@ -1215,8 +1214,10 @@ submit:
|
|||
len = total_len;
|
||||
}
|
||||
|
||||
if (!err && len)
|
||||
if (!err && len) {
|
||||
dcc->undiscard_blks -= len;
|
||||
__update_discard_tree_range(sbi, bdev, lstart, start, len);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1463,6 +1464,8 @@ next:
|
|||
|
||||
return issued;
|
||||
}
|
||||
static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
struct discard_policy *dpolicy);
|
||||
|
||||
static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
struct discard_policy *dpolicy)
|
||||
|
|
@ -1471,12 +1474,14 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
|
|||
struct list_head *pend_list;
|
||||
struct discard_cmd *dc, *tmp;
|
||||
struct blk_plug plug;
|
||||
int i, issued = 0;
|
||||
int i, issued;
|
||||
bool io_interrupted = false;
|
||||
|
||||
if (dpolicy->timeout)
|
||||
f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT);
|
||||
|
||||
retry:
|
||||
issued = 0;
|
||||
for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
|
||||
if (dpolicy->timeout &&
|
||||
f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT))
|
||||
|
|
@ -1523,6 +1528,11 @@ next:
|
|||
break;
|
||||
}
|
||||
|
||||
if (dpolicy->type == DPOLICY_UMOUNT && issued) {
|
||||
__wait_all_discard_cmd(sbi, dpolicy);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (!issued && io_interrupted)
|
||||
issued = -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -1858,6 +1869,7 @@ skip:
|
|||
(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:
|
||||
|
|
@ -3457,6 +3469,7 @@ try_onemore:
|
|||
/* init iostat info */
|
||||
spin_lock_init(&sbi->iostat_lock);
|
||||
sbi->iostat_enable = false;
|
||||
sbi->iostat_period_ms = DEFAULT_IOSTAT_PERIOD_MS;
|
||||
|
||||
for (i = 0; i < NR_PAGE_TYPE; i++) {
|
||||
int n = (i == META) ? 1: NR_TEMP_TYPE;
|
||||
|
|
@ -3554,6 +3567,7 @@ try_onemore:
|
|||
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]);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "f2fs.h"
|
||||
#include "segment.h"
|
||||
#include "gc.h"
|
||||
#include <trace/events/f2fs.h>
|
||||
|
||||
static struct proc_dir_entry *f2fs_proc_root;
|
||||
|
||||
|
|
@ -374,7 +375,6 @@ out:
|
|||
return count;
|
||||
}
|
||||
|
||||
|
||||
if (!strcmp(a->attr.name, "iostat_enable")) {
|
||||
sbi->iostat_enable = !!t;
|
||||
if (!sbi->iostat_enable)
|
||||
|
|
@ -382,6 +382,15 @@ out:
|
|||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(a->attr.name, "iostat_period_ms")) {
|
||||
if (t < MIN_IOSTAT_PERIOD_MS || t > MAX_IOSTAT_PERIOD_MS)
|
||||
return -EINVAL;
|
||||
spin_lock(&sbi->iostat_lock);
|
||||
sbi->iostat_period_ms = (unsigned int)t;
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
*ui = (unsigned int)t;
|
||||
|
||||
return count;
|
||||
|
|
@ -538,6 +547,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle_interval, interval_time[GC_TIME]);
|
|||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info,
|
||||
umount_discard_timeout, interval_time[UMOUNT_DISCARD_TIMEOUT]);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_period_ms, iostat_period_ms);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list);
|
||||
|
|
@ -545,6 +555,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list);
|
|||
F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
|
||||
F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
|
||||
#endif
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, data_io_flag, data_io_flag);
|
||||
F2FS_GENERAL_RO_ATTR(dirty_segments);
|
||||
F2FS_GENERAL_RO_ATTR(free_segments);
|
||||
F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
|
||||
|
|
@ -617,6 +628,7 @@ static struct attribute *f2fs_attrs[] = {
|
|||
ATTR_LIST(gc_idle_interval),
|
||||
ATTR_LIST(umount_discard_timeout),
|
||||
ATTR_LIST(iostat_enable),
|
||||
ATTR_LIST(iostat_period_ms),
|
||||
ATTR_LIST(readdir_ra),
|
||||
ATTR_LIST(gc_pin_file_thresh),
|
||||
ATTR_LIST(extension_list),
|
||||
|
|
@ -624,6 +636,7 @@ static struct attribute *f2fs_attrs[] = {
|
|||
ATTR_LIST(inject_rate),
|
||||
ATTR_LIST(inject_type),
|
||||
#endif
|
||||
ATTR_LIST(data_io_flag),
|
||||
ATTR_LIST(dirty_segments),
|
||||
ATTR_LIST(free_segments),
|
||||
ATTR_LIST(unusable),
|
||||
|
|
@ -752,6 +765,33 @@ static int __maybe_unused segment_bits_seq_show(struct seq_file *seq,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void f2fs_record_iostat(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
unsigned long long iostat_diff[NR_IO_TYPE];
|
||||
int i;
|
||||
|
||||
if (time_is_after_jiffies(sbi->iostat_next_period))
|
||||
return;
|
||||
|
||||
/* Need double check under the lock */
|
||||
spin_lock(&sbi->iostat_lock);
|
||||
if (time_is_after_jiffies(sbi->iostat_next_period)) {
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
return;
|
||||
}
|
||||
sbi->iostat_next_period = jiffies +
|
||||
msecs_to_jiffies(sbi->iostat_period_ms);
|
||||
|
||||
for (i = 0; i < NR_IO_TYPE; i++) {
|
||||
iostat_diff[i] = sbi->rw_iostat[i] -
|
||||
sbi->prev_rw_iostat[i];
|
||||
sbi->prev_rw_iostat[i] = sbi->rw_iostat[i];
|
||||
}
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
|
||||
trace_f2fs_iostat(sbi, iostat_diff);
|
||||
}
|
||||
|
||||
static int __maybe_unused iostat_info_seq_show(struct seq_file *seq,
|
||||
void *offset)
|
||||
{
|
||||
|
|
@ -764,33 +804,51 @@ static int __maybe_unused iostat_info_seq_show(struct seq_file *seq,
|
|||
|
||||
seq_printf(seq, "time: %-16llu\n", now);
|
||||
|
||||
/* print app IOs */
|
||||
/* print app write IOs */
|
||||
seq_printf(seq, "app buffered: %-16llu\n",
|
||||
sbi->write_iostat[APP_BUFFERED_IO]);
|
||||
sbi->rw_iostat[APP_BUFFERED_IO]);
|
||||
seq_printf(seq, "app direct: %-16llu\n",
|
||||
sbi->write_iostat[APP_DIRECT_IO]);
|
||||
sbi->rw_iostat[APP_DIRECT_IO]);
|
||||
seq_printf(seq, "app mapped: %-16llu\n",
|
||||
sbi->write_iostat[APP_MAPPED_IO]);
|
||||
sbi->rw_iostat[APP_MAPPED_IO]);
|
||||
|
||||
/* print fs IOs */
|
||||
/* print fs write IOs */
|
||||
seq_printf(seq, "fs data: %-16llu\n",
|
||||
sbi->write_iostat[FS_DATA_IO]);
|
||||
sbi->rw_iostat[FS_DATA_IO]);
|
||||
seq_printf(seq, "fs node: %-16llu\n",
|
||||
sbi->write_iostat[FS_NODE_IO]);
|
||||
sbi->rw_iostat[FS_NODE_IO]);
|
||||
seq_printf(seq, "fs meta: %-16llu\n",
|
||||
sbi->write_iostat[FS_META_IO]);
|
||||
sbi->rw_iostat[FS_META_IO]);
|
||||
seq_printf(seq, "fs gc data: %-16llu\n",
|
||||
sbi->write_iostat[FS_GC_DATA_IO]);
|
||||
sbi->rw_iostat[FS_GC_DATA_IO]);
|
||||
seq_printf(seq, "fs gc node: %-16llu\n",
|
||||
sbi->write_iostat[FS_GC_NODE_IO]);
|
||||
sbi->rw_iostat[FS_GC_NODE_IO]);
|
||||
seq_printf(seq, "fs cp data: %-16llu\n",
|
||||
sbi->write_iostat[FS_CP_DATA_IO]);
|
||||
sbi->rw_iostat[FS_CP_DATA_IO]);
|
||||
seq_printf(seq, "fs cp node: %-16llu\n",
|
||||
sbi->write_iostat[FS_CP_NODE_IO]);
|
||||
sbi->rw_iostat[FS_CP_NODE_IO]);
|
||||
seq_printf(seq, "fs cp meta: %-16llu\n",
|
||||
sbi->write_iostat[FS_CP_META_IO]);
|
||||
sbi->rw_iostat[FS_CP_META_IO]);
|
||||
|
||||
/* print app read IOs */
|
||||
seq_printf(seq, "app buffered: %-16llu\n",
|
||||
sbi->rw_iostat[APP_BUFFERED_READ_IO]);
|
||||
seq_printf(seq, "app direct: %-16llu\n",
|
||||
sbi->rw_iostat[APP_DIRECT_READ_IO]);
|
||||
seq_printf(seq, "app mapped: %-16llu\n",
|
||||
sbi->rw_iostat[APP_MAPPED_READ_IO]);
|
||||
|
||||
/* print fs read IOs */
|
||||
seq_printf(seq, "fs data: %-16llu\n",
|
||||
sbi->rw_iostat[FS_DATA_READ_IO]);
|
||||
seq_printf(seq, "fs node: %-16llu\n",
|
||||
sbi->rw_iostat[FS_NODE_READ_IO]);
|
||||
seq_printf(seq, "fs meta: %-16llu\n",
|
||||
sbi->rw_iostat[FS_META_READ_IO]);
|
||||
|
||||
/* print other IOs */
|
||||
seq_printf(seq, "fs discard: %-16llu\n",
|
||||
sbi->write_iostat[FS_DISCARD]);
|
||||
sbi->rw_iostat[FS_DISCARD]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1812,6 +1812,77 @@ DEFINE_EVENT(f2fs_zip_end, f2fs_decompress_pages_end,
|
|||
TP_ARGS(inode, cluster_idx, compressed_size, ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(f2fs_iostat,
|
||||
|
||||
TP_PROTO(struct f2fs_sb_info *sbi, unsigned long long *iostat),
|
||||
|
||||
TP_ARGS(sbi, iostat),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(unsigned long long, app_dio)
|
||||
__field(unsigned long long, app_bio)
|
||||
__field(unsigned long long, app_wio)
|
||||
__field(unsigned long long, app_mio)
|
||||
__field(unsigned long long, fs_dio)
|
||||
__field(unsigned long long, fs_nio)
|
||||
__field(unsigned long long, fs_mio)
|
||||
__field(unsigned long long, fs_gc_dio)
|
||||
__field(unsigned long long, fs_gc_nio)
|
||||
__field(unsigned long long, fs_cp_dio)
|
||||
__field(unsigned long long, fs_cp_nio)
|
||||
__field(unsigned long long, fs_cp_mio)
|
||||
__field(unsigned long long, app_drio)
|
||||
__field(unsigned long long, app_brio)
|
||||
__field(unsigned long long, app_rio)
|
||||
__field(unsigned long long, app_mrio)
|
||||
__field(unsigned long long, fs_drio)
|
||||
__field(unsigned long long, fs_nrio)
|
||||
__field(unsigned long long, fs_mrio)
|
||||
__field(unsigned long long, fs_discard)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = sbi->sb->s_dev;
|
||||
__entry->app_dio = iostat[APP_DIRECT_IO];
|
||||
__entry->app_bio = iostat[APP_BUFFERED_IO];
|
||||
__entry->app_wio = iostat[APP_WRITE_IO];
|
||||
__entry->app_mio = iostat[APP_MAPPED_IO];
|
||||
__entry->fs_dio = iostat[FS_DATA_IO];
|
||||
__entry->fs_nio = iostat[FS_NODE_IO];
|
||||
__entry->fs_mio = iostat[FS_META_IO];
|
||||
__entry->fs_gc_dio = iostat[FS_GC_DATA_IO];
|
||||
__entry->fs_gc_nio = iostat[FS_GC_NODE_IO];
|
||||
__entry->fs_cp_dio = iostat[FS_CP_DATA_IO];
|
||||
__entry->fs_cp_nio = iostat[FS_CP_NODE_IO];
|
||||
__entry->fs_cp_mio = iostat[FS_CP_META_IO];
|
||||
__entry->app_drio = iostat[APP_DIRECT_READ_IO];
|
||||
__entry->app_brio = iostat[APP_BUFFERED_READ_IO];
|
||||
__entry->app_rio = iostat[APP_READ_IO];
|
||||
__entry->app_mrio = iostat[APP_MAPPED_READ_IO];
|
||||
__entry->fs_drio = iostat[FS_DATA_READ_IO];
|
||||
__entry->fs_nrio = iostat[FS_NODE_READ_IO];
|
||||
__entry->fs_mrio = iostat[FS_META_READ_IO];
|
||||
__entry->fs_discard = iostat[FS_DISCARD];
|
||||
),
|
||||
|
||||
TP_printk("dev = (%d,%d), "
|
||||
"app [write=%llu (direct=%llu, buffered=%llu), mapped=%llu], "
|
||||
"fs [data=%llu, node=%llu, meta=%llu, discard=%llu], "
|
||||
"gc [data=%llu, node=%llu], "
|
||||
"cp [data=%llu, node=%llu, meta=%llu], "
|
||||
"app [read=%llu (direct=%llu, buffered=%llu), mapped=%llu], "
|
||||
"fs [data=%llu, node=%llu, meta=%llu]",
|
||||
show_dev(__entry->dev), __entry->app_wio, __entry->app_dio,
|
||||
__entry->app_bio, __entry->app_mio, __entry->fs_dio,
|
||||
__entry->fs_nio, __entry->fs_mio, __entry->fs_discard,
|
||||
__entry->fs_gc_dio, __entry->fs_gc_nio, __entry->fs_cp_dio,
|
||||
__entry->fs_cp_nio, __entry->fs_cp_mio,
|
||||
__entry->app_rio, __entry->app_drio, __entry->app_brio,
|
||||
__entry->app_mrio, __entry->fs_drio, __entry->fs_nrio,
|
||||
__entry->fs_mrio)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_F2FS_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
|
|
|||
Loading…
Reference in a new issue