mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 12:00:22 +09:00
Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-5.10.y' into android13-5.10
* aosp/upstream-f2fs-stable-linux-5.10.y: fscrypt: update documentation for direct I/O support f2fs: support direct I/O with fscrypt using blk-crypto ext4: support direct I/O with fscrypt using blk-crypto iomap: support direct I/O with fscrypt using blk-crypto fscrypt: add functions for direct I/O support f2fs: fix to do sanity check on .cp_pack_total_block_count f2fs: make gc_urgent and gc_segment_mode sysfs node readable f2fs: use aggressive GC policy during f2fs_disable_checkpoint() f2fs: fix compressed file start atomic write may cause data corruption f2fs: initialize sbi->gc_mode explicitly f2fs: introduce gc_urgent_mid mode f2fs: compress: fix to print raw data size in error path of lz4 decompression f2fs: remove redundant parameter judgment f2fs: use spin_lock to avoid hang f2fs: don't get FREEZE lock in f2fs_evict_inode in frozen fs f2fs: remove unnecessary read for F2FS_FITS_IN_INODE f2fs: introduce F2FS_UNFAIR_RWSEM to support unfair rwsem f2fs: avoid an infinite loop in f2fs_sync_dirty_inodes f2fs: fix to do sanity check on curseg->alloc_type f2fs: fix to avoid potential deadlock f2fs: quota: fix loop condition at f2fs_quota_sync() f2fs: Restore rwsem lockdep support f2fs: fix missing free nid in f2fs_handle_failed_inode f2fs: add a way to limit roll forward recovery time f2fs: introduce F2FS_IPU_HONOR_OPU_WRITE ipu policy f2fs: adjust readahead block number during recovery f2fs: fix to unlock page correctly in error path of is_alive() f2fs: expose discard related parameters in sysfs f2fs: move discard parameters into discard_cmd_control f2fs: fix to enable ATGC correctly via gc_idle sysfs interface f2fs: move f2fs to use reader-unfair rwsems Bug: 216636351 Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@google.com> Change-Id: I53cc37765ba69df2a9b7b9c070e4938822354f05
This commit is contained in:
@@ -55,8 +55,9 @@ Description: Controls the in-place-update policy.
|
||||
0x04 F2FS_IPU_UTIL
|
||||
0x08 F2FS_IPU_SSR_UTIL
|
||||
0x10 F2FS_IPU_FSYNC
|
||||
0x20 F2FS_IPU_ASYNC,
|
||||
0x20 F2FS_IPU_ASYNC
|
||||
0x40 F2FS_IPU_NOCACHE
|
||||
0x80 F2FS_IPU_HONOR_OPU_WRITE
|
||||
==== =================
|
||||
|
||||
Refer segment.h for details.
|
||||
@@ -98,6 +99,33 @@ Description: Controls the issue rate of discard commands that consist of small
|
||||
checkpoint is triggered, and issued during the checkpoint.
|
||||
By default, it is disabled with 0.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_discard_request
|
||||
Date: December 2021
|
||||
Contact: "Konstantin Vyshetsky" <vkon@google.com>
|
||||
Description: Controls the number of discards a thread will issue at a time.
|
||||
Higher number will allow the discard thread to finish its work
|
||||
faster, at the cost of higher latency for incomming I/O.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/min_discard_issue_time
|
||||
Date: December 2021
|
||||
Contact: "Konstantin Vyshetsky" <vkon@google.com>
|
||||
Description: Controls the interval the discard thread will wait between
|
||||
issuing discard requests when there are discards to be issued and
|
||||
no I/O aware interruptions occur.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/mid_discard_issue_time
|
||||
Date: December 2021
|
||||
Contact: "Konstantin Vyshetsky" <vkon@google.com>
|
||||
Description: Controls the interval the discard thread will wait between
|
||||
issuing discard requests when there are discards to be issued and
|
||||
an I/O aware interruption occurs.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_discard_issue_time
|
||||
Date: December 2021
|
||||
Contact: "Konstantin Vyshetsky" <vkon@google.com>
|
||||
Description: Controls the interval the discard thread will wait when there are
|
||||
no discard operations to be issued.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/discard_granularity
|
||||
Date: July 2017
|
||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
@@ -269,11 +297,16 @@ Description: Shows current reserved blocks in system, it may be temporarily
|
||||
What: /sys/fs/f2fs/<disk>/gc_urgent
|
||||
Date: August 2017
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: Do background GC agressively when set. When gc_urgent = 1,
|
||||
background thread starts to do GC by given gc_urgent_sleep_time
|
||||
interval. When gc_urgent = 2, F2FS will lower the bar of
|
||||
checking idle in order to process outstanding discard commands
|
||||
and GC a little bit aggressively. It is set to 0 by default.
|
||||
Description: Do background GC aggressively when set. Set to 0 by default.
|
||||
gc urgent high(1): does GC forcibly in a period of given
|
||||
gc_urgent_sleep_time and ignores I/O idling check. uses greedy
|
||||
GC approach and turns SSR mode on.
|
||||
gc urgent low(2): lowers the bar of checking I/O idling in
|
||||
order to process outstanding discard commands and GC a
|
||||
little bit aggressively. uses cost benefit GC approach.
|
||||
gc urgent mid(3): does GC forcibly in a period of given
|
||||
gc_urgent_sleep_time and executes a mid level of I/O idling check.
|
||||
uses cost benefit GC approach.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_urgent_sleep_time
|
||||
Date: August 2017
|
||||
@@ -430,6 +463,7 @@ Description: Show status of f2fs superblock in real time.
|
||||
0x800 SBI_QUOTA_SKIP_FLUSH skip flushing quota in current CP
|
||||
0x1000 SBI_QUOTA_NEED_REPAIR quota file may be corrupted
|
||||
0x2000 SBI_IS_RESIZEFS resizefs is in process
|
||||
0x4000 SBI_IS_FREEZING freefs is in process
|
||||
====== ===================== =================================
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/ckpt_thread_ioprio
|
||||
@@ -503,7 +537,7 @@ Date: July 2021
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: Show how many segments have been reclaimed by GC during a specific
|
||||
GC mode (0: GC normal, 1: GC idle CB, 2: GC idle greedy,
|
||||
3: GC idle AT, 4: GC urgent high, 5: GC urgent low)
|
||||
3: GC idle AT, 4: GC urgent high, 5: GC urgent low 6: GC urgent mid)
|
||||
You can re-initialize this value to "0".
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_segment_mode
|
||||
@@ -540,3 +574,9 @@ Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: You can set the trial count limit for GC urgent high mode with this value.
|
||||
If GC thread gets to the limit, the mode will turn back to GC normal mode.
|
||||
By default, the value is zero, which means there is no limit like before.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_roll_forward_node_blocks
|
||||
Date: January 2022
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: Controls max # of node block writes to be used for roll forward
|
||||
recovery. This can limit the roll forward recovery time.
|
||||
|
||||
@@ -1047,8 +1047,8 @@ astute users may notice some differences in behavior:
|
||||
may be used to overwrite the source files but isn't guaranteed to be
|
||||
effective on all filesystems and storage devices.
|
||||
|
||||
- Direct I/O is not supported on encrypted files. Attempts to use
|
||||
direct I/O on such files will fall back to buffered I/O.
|
||||
- Direct I/O is supported on encrypted files only under some
|
||||
circumstances. For details, see `Direct I/O support`_.
|
||||
|
||||
- The fallocate operations FALLOC_FL_COLLAPSE_RANGE and
|
||||
FALLOC_FL_INSERT_RANGE are not supported on encrypted files and will
|
||||
@@ -1179,6 +1179,27 @@ Inline encryption doesn't affect the ciphertext or other aspects of
|
||||
the on-disk format, so users may freely switch back and forth between
|
||||
using "inlinecrypt" and not using "inlinecrypt".
|
||||
|
||||
Direct I/O support
|
||||
==================
|
||||
|
||||
For direct I/O on an encrypted file to work, the following conditions
|
||||
must be met (in addition to the conditions for direct I/O on an
|
||||
unencrypted file):
|
||||
|
||||
* The file must be using inline encryption. Usually this means that
|
||||
the filesystem must be mounted with ``-o inlinecrypt`` and inline
|
||||
encryption hardware must be present. However, a software fallback
|
||||
is also available. For details, see `Inline encryption support`_.
|
||||
|
||||
* The I/O request must be fully aligned to the filesystem block size.
|
||||
This means that the file position the I/O is targeting, the lengths
|
||||
of all I/O segments, and the memory addresses of all I/O buffers
|
||||
must be multiples of this value. Note that the filesystem block
|
||||
size may be greater than the logical block size of the block device.
|
||||
|
||||
If either of the above conditions is not met, then direct I/O on the
|
||||
encrypted file will fall back to buffered I/O.
|
||||
|
||||
Implementation details
|
||||
======================
|
||||
|
||||
|
||||
@@ -345,6 +345,10 @@ EXPORT_SYMBOL_GPL(fscrypt_set_bio_crypt_ctx_bh);
|
||||
*
|
||||
* fscrypt_set_bio_crypt_ctx() must have already been called on the bio.
|
||||
*
|
||||
* This function isn't required in cases where crypto-mergeability is ensured in
|
||||
* another way, such as I/O targeting only a single file (and thus a single key)
|
||||
* combined with fscrypt_limit_io_blocks() to ensure DUN contiguity.
|
||||
*
|
||||
* This function also returns false if the next part of the I/O would need to
|
||||
* have a different value for the bi_skip_dm_default_key flag.
|
||||
*
|
||||
@@ -402,12 +406,15 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio,
|
||||
EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh);
|
||||
|
||||
/**
|
||||
* fscrypt_dio_supported() - check whether a direct I/O request is unsupported
|
||||
* due to encryption constraints
|
||||
* fscrypt_dio_supported() - check whether a DIO (direct I/O) request is
|
||||
* supported as far as encryption is concerned
|
||||
* @iocb: the file and position the I/O is targeting
|
||||
* @iter: the I/O data segment(s)
|
||||
*
|
||||
* Return: true if direct I/O is supported
|
||||
* Return: %true if there are no encryption constraints that prevent DIO from
|
||||
* being supported; %false if DIO is unsupported. (Note that in the
|
||||
* %true case, the filesystem might have other, non-encryption-related
|
||||
* constraints that prevent DIO from actually being supported.)
|
||||
*/
|
||||
bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
@@ -418,13 +425,22 @@ bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter)
|
||||
if (!fscrypt_needs_contents_encryption(inode))
|
||||
return true;
|
||||
|
||||
/* We only support direct I/O with inline crypto, not fs-layer crypto */
|
||||
/* We only support DIO with inline crypto, not fs-layer crypto. */
|
||||
if (!fscrypt_inode_uses_inline_crypto(inode))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Since the granularity of encryption is filesystem blocks, the I/O
|
||||
* must be block aligned -- not just disk sector aligned.
|
||||
* Since the granularity of encryption is filesystem blocks, the file
|
||||
* position and total I/O length must be aligned to the filesystem block
|
||||
* size -- not just to the block device's logical block size as is
|
||||
* traditionally the case for DIO on many filesystems.
|
||||
*
|
||||
* We require that the user-provided memory buffers be filesystem block
|
||||
* aligned too. It is simpler to have a single alignment value required
|
||||
* for all properties of the I/O, as is normally the case for DIO.
|
||||
* Also, allowing less aligned buffers would imply that data units could
|
||||
* cross bvecs, which would greatly complicate the I/O stack, which
|
||||
* assumes that bios can be split at any bvec boundary.
|
||||
*/
|
||||
if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize))
|
||||
return false;
|
||||
@@ -437,24 +453,25 @@ EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
|
||||
* fscrypt_limit_io_blocks() - limit I/O blocks to avoid discontiguous DUNs
|
||||
* @inode: the file on which I/O is being done
|
||||
* @lblk: the block at which the I/O is being started from
|
||||
* @nr_blocks: the number of blocks we want to submit starting at @pos
|
||||
* @nr_blocks: the number of blocks we want to submit starting at @lblk
|
||||
*
|
||||
* Determine the limit to the number of blocks that can be submitted in the bio
|
||||
* targeting @pos without causing a data unit number (DUN) discontinuity.
|
||||
* Determine the limit to the number of blocks that can be submitted in a bio
|
||||
* targeting @lblk without causing a data unit number (DUN) discontiguity.
|
||||
*
|
||||
* This is normally just @nr_blocks, as normally the DUNs just increment along
|
||||
* with the logical blocks. (Or the file is not encrypted.)
|
||||
*
|
||||
* In rare cases, fscrypt can be using an IV generation method that allows the
|
||||
* DUN to wrap around within logically continuous blocks, and that wraparound
|
||||
* DUN to wrap around within logically contiguous blocks, and that wraparound
|
||||
* will occur. If this happens, a value less than @nr_blocks will be returned
|
||||
* so that the wraparound doesn't occur in the middle of the bio.
|
||||
* so that the wraparound doesn't occur in the middle of a bio, which would
|
||||
* cause encryption/decryption to produce wrong results.
|
||||
*
|
||||
* Return: the actual number of blocks that can be submitted
|
||||
*/
|
||||
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
|
||||
{
|
||||
const struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
const struct fscrypt_info *ci;
|
||||
u32 dun;
|
||||
|
||||
if (!fscrypt_inode_uses_inline_crypto(inode))
|
||||
@@ -463,6 +480,7 @@ u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks)
|
||||
if (nr_blocks <= 1)
|
||||
return nr_blocks;
|
||||
|
||||
ci = inode->i_crypt_info;
|
||||
if (!(fscrypt_policy_flags(&ci->ci_policy) &
|
||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32))
|
||||
return nr_blocks;
|
||||
|
||||
@@ -3517,10 +3517,9 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
out:
|
||||
|
||||
/*
|
||||
* When inline encryption is enabled, sometimes I/O to an encrypted file
|
||||
* has to be broken up to guarantee DUN contiguity. Handle this by
|
||||
* has to be broken up to guarantee DUN contiguity. Handle this by
|
||||
* limiting the length of the mapping returned.
|
||||
*/
|
||||
map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len);
|
||||
|
||||
@@ -143,3 +143,10 @@ config F2FS_IOSTAT
|
||||
Support getting IO statistics through sysfs and printing out periodic
|
||||
IO statistics tracepoint events. You have to turn on "iostat_enable"
|
||||
sysfs node to enable this feature.
|
||||
|
||||
config F2FS_UNFAIR_RWSEM
|
||||
bool "F2FS unfair rw_semaphore"
|
||||
depends on F2FS_FS && BLK_CGROUP
|
||||
help
|
||||
Use unfair rw_semaphore, if system configured IO priority by block
|
||||
cgroup.
|
||||
|
||||
@@ -98,6 +98,13 @@ repeat:
|
||||
}
|
||||
|
||||
if (unlikely(!PageUptodate(page))) {
|
||||
if (page->index == sbi->metapage_eio_ofs &&
|
||||
sbi->metapage_eio_cnt++ == MAX_RETRY_META_PAGE_EIO) {
|
||||
set_ckpt_flags(sbi, CP_ERROR_FLAG);
|
||||
} else {
|
||||
sbi->metapage_eio_ofs = page->index;
|
||||
sbi->metapage_eio_cnt = 0;
|
||||
}
|
||||
f2fs_put_page(page, 1);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
@@ -282,18 +289,22 @@ out:
|
||||
return blkno - start;
|
||||
}
|
||||
|
||||
void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index,
|
||||
unsigned int ra_blocks)
|
||||
{
|
||||
struct page *page;
|
||||
bool readahead = false;
|
||||
|
||||
if (ra_blocks == RECOVERY_MIN_RA_BLOCKS)
|
||||
return;
|
||||
|
||||
page = find_get_page(META_MAPPING(sbi), index);
|
||||
if (!page || !PageUptodate(page))
|
||||
readahead = true;
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
if (readahead)
|
||||
f2fs_ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true);
|
||||
f2fs_ra_meta_pages(sbi, index, ra_blocks, META_POR, true);
|
||||
}
|
||||
|
||||
static int __f2fs_write_meta_page(struct page *page,
|
||||
@@ -864,6 +875,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
|
||||
struct page *cp_page_1 = NULL, *cp_page_2 = NULL;
|
||||
struct f2fs_checkpoint *cp_block = NULL;
|
||||
unsigned long long cur_version = 0, pre_version = 0;
|
||||
unsigned int cp_blocks;
|
||||
int err;
|
||||
|
||||
err = get_checkpoint_version(sbi, cp_addr, &cp_block,
|
||||
@@ -871,15 +883,16 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
|
||||
sbi->blocks_per_seg) {
|
||||
cp_blocks = le32_to_cpu(cp_block->cp_pack_total_block_count);
|
||||
|
||||
if (cp_blocks > sbi->blocks_per_seg || cp_blocks <= F2FS_CP_PACKS) {
|
||||
f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u",
|
||||
le32_to_cpu(cp_block->cp_pack_total_block_count));
|
||||
goto invalid_cp;
|
||||
}
|
||||
pre_version = *version;
|
||||
|
||||
cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
|
||||
cp_addr += cp_blocks - 1;
|
||||
err = get_checkpoint_version(sbi, cp_addr, &cp_block,
|
||||
&cp_page_2, version);
|
||||
if (err)
|
||||
@@ -1543,6 +1556,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
/* update user_block_counts */
|
||||
sbi->last_valid_block_count = sbi->total_valid_block_count;
|
||||
percpu_counter_set(&sbi->alloc_valid_block_count, 0);
|
||||
percpu_counter_set(&sbi->rf_node_block_count, 0);
|
||||
|
||||
/* Here, we have one bio having CP pack except cp pack 2 page */
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
|
||||
@@ -313,10 +313,9 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
|
||||
}
|
||||
|
||||
if (ret != PAGE_SIZE << dic->log_cluster_size) {
|
||||
printk_ratelimited("%sF2FS-fs (%s): lz4 invalid rlen:%zu, "
|
||||
printk_ratelimited("%sF2FS-fs (%s): lz4 invalid ret:%d, "
|
||||
"expected:%lu\n", KERN_ERR,
|
||||
F2FS_I_SB(dic->inode)->sb->s_id,
|
||||
dic->rlen,
|
||||
F2FS_I_SB(dic->inode)->sb->s_id, ret,
|
||||
PAGE_SIZE << dic->log_cluster_size);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -2488,6 +2488,9 @@ static inline bool check_inplace_update_policy(struct inode *inode,
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
unsigned int policy = SM_I(sbi)->ipu_policy;
|
||||
|
||||
if (policy & (0x1 << F2FS_IPU_HONOR_OPU_WRITE) &&
|
||||
is_inode_flag_set(inode, FI_OPU_WRITE))
|
||||
return false;
|
||||
if (policy & (0x1 << F2FS_IPU_FORCE))
|
||||
return true;
|
||||
if (policy & (0x1 << F2FS_IPU_SSR) && f2fs_need_SSR(sbi))
|
||||
@@ -2558,6 +2561,9 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
|
||||
return true;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_OPU_WRITE))
|
||||
return true;
|
||||
|
||||
if (fio) {
|
||||
if (page_private_gcing(fio->page))
|
||||
return true;
|
||||
@@ -3182,8 +3188,8 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
f2fs_available_free_memory(sbi, DIRTY_DENTS))
|
||||
goto skip_write;
|
||||
|
||||
/* skip writing during file defragment */
|
||||
if (is_inode_flag_set(inode, FI_DO_DEFRAG))
|
||||
/* skip writing in file defragment preparing stage */
|
||||
if (is_inode_flag_set(inode, FI_SKIP_WRITES))
|
||||
goto skip_write;
|
||||
|
||||
trace_f2fs_writepages(mapping->host, wbc, DATA);
|
||||
@@ -3191,8 +3197,12 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
/* to avoid spliting IOs due to mixed WB_SYNC_ALL and WB_SYNC_NONE */
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
atomic_inc(&sbi->wb_sync_req[DATA]);
|
||||
else if (atomic_read(&sbi->wb_sync_req[DATA]))
|
||||
else if (atomic_read(&sbi->wb_sync_req[DATA])) {
|
||||
/* to avoid potential deadlock */
|
||||
if (current->plug)
|
||||
blk_finish_plug(current->plug);
|
||||
goto skip_write;
|
||||
}
|
||||
|
||||
if (__should_serialize_io(inode, wbc)) {
|
||||
mutex_lock(&sbi->writepages);
|
||||
@@ -3397,7 +3407,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
|
||||
*fsdata = NULL;
|
||||
|
||||
if (len == PAGE_SIZE)
|
||||
if (len == PAGE_SIZE && !(f2fs_is_atomic_file(inode)))
|
||||
goto repeat;
|
||||
|
||||
ret = f2fs_prepare_compress_overwrite(inode, pagep,
|
||||
@@ -3770,6 +3780,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
|
||||
f2fs_down_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
|
||||
set_inode_flag(inode, FI_ALIGNED_WRITE);
|
||||
set_inode_flag(inode, FI_OPU_WRITE);
|
||||
|
||||
for (; secidx < end_sec; secidx++) {
|
||||
f2fs_down_write(&sbi->pin_sem);
|
||||
@@ -3778,7 +3789,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
|
||||
f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
set_inode_flag(inode, FI_DO_DEFRAG);
|
||||
set_inode_flag(inode, FI_SKIP_WRITES);
|
||||
|
||||
for (blkofs = 0; blkofs < blk_per_sec; blkofs++) {
|
||||
struct page *page;
|
||||
@@ -3795,7 +3806,7 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
|
||||
clear_inode_flag(inode, FI_DO_DEFRAG);
|
||||
clear_inode_flag(inode, FI_SKIP_WRITES);
|
||||
|
||||
ret = filemap_fdatawrite(inode->i_mapping);
|
||||
|
||||
@@ -3806,7 +3817,8 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
|
||||
}
|
||||
|
||||
done:
|
||||
clear_inode_flag(inode, FI_DO_DEFRAG);
|
||||
clear_inode_flag(inode, FI_SKIP_WRITES);
|
||||
clear_inode_flag(inode, FI_OPU_WRITE);
|
||||
clear_inode_flag(inode, FI_ALIGNED_WRITE);
|
||||
|
||||
f2fs_up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "gc.h"
|
||||
|
||||
static LIST_HEAD(f2fs_stat_list);
|
||||
static DEFINE_MUTEX(f2fs_stat_mutex);
|
||||
static DEFINE_RAW_SPINLOCK(f2fs_stat_lock);
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static struct dentry *f2fs_debugfs_root;
|
||||
#endif
|
||||
@@ -338,14 +338,16 @@ static char *s_flag[] = {
|
||||
[SBI_QUOTA_SKIP_FLUSH] = " quota_skip_flush",
|
||||
[SBI_QUOTA_NEED_REPAIR] = " quota_need_repair",
|
||||
[SBI_IS_RESIZEFS] = " resizefs",
|
||||
[SBI_IS_FREEZING] = " freezefs",
|
||||
};
|
||||
|
||||
static int stat_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct f2fs_stat_info *si;
|
||||
int i = 0, j = 0;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&f2fs_stat_mutex);
|
||||
raw_spin_lock_irqsave(&f2fs_stat_lock, flags);
|
||||
list_for_each_entry(si, &f2fs_stat_list, stat_list) {
|
||||
update_general_status(si->sbi);
|
||||
|
||||
@@ -474,12 +476,14 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
si->node_segs, si->bg_node_segs);
|
||||
seq_printf(s, " - Reclaimed segs : Normal (%d), Idle CB (%d), "
|
||||
"Idle Greedy (%d), Idle AT (%d), "
|
||||
"Urgent High (%d), Urgent Low (%d)\n",
|
||||
"Urgent High (%d), Urgent Mid (%d), "
|
||||
"Urgent Low (%d)\n",
|
||||
si->sbi->gc_reclaimed_segs[GC_NORMAL],
|
||||
si->sbi->gc_reclaimed_segs[GC_IDLE_CB],
|
||||
si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY],
|
||||
si->sbi->gc_reclaimed_segs[GC_IDLE_AT],
|
||||
si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH],
|
||||
si->sbi->gc_reclaimed_segs[GC_URGENT_MID],
|
||||
si->sbi->gc_reclaimed_segs[GC_URGENT_LOW]);
|
||||
seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks,
|
||||
si->bg_data_blks + si->bg_node_blks);
|
||||
@@ -532,6 +536,9 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
si->ndirty_meta, si->meta_pages);
|
||||
seq_printf(s, " - imeta: %4d\n",
|
||||
si->ndirty_imeta);
|
||||
seq_printf(s, " - fsync mark: %4lld\n",
|
||||
percpu_counter_sum_positive(
|
||||
&si->sbi->rf_node_block_count));
|
||||
seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n",
|
||||
si->dirty_nats, si->nats, si->dirty_sits, si->sits);
|
||||
seq_printf(s, " - free_nids: %9d/%9d\n - alloc_nids: %9d\n",
|
||||
@@ -573,7 +580,7 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
seq_printf(s, " - paged : %llu KB\n",
|
||||
si->page_mem >> 10);
|
||||
}
|
||||
mutex_unlock(&f2fs_stat_mutex);
|
||||
raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -584,6 +591,7 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
|
||||
struct f2fs_stat_info *si;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
si = f2fs_kzalloc(sbi, sizeof(struct f2fs_stat_info), GFP_KERNEL);
|
||||
@@ -619,9 +627,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
|
||||
atomic_set(&sbi->max_aw_cnt, 0);
|
||||
atomic_set(&sbi->max_vw_cnt, 0);
|
||||
|
||||
mutex_lock(&f2fs_stat_mutex);
|
||||
raw_spin_lock_irqsave(&f2fs_stat_lock, flags);
|
||||
list_add_tail(&si->stat_list, &f2fs_stat_list);
|
||||
mutex_unlock(&f2fs_stat_mutex);
|
||||
raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -629,10 +637,11 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
|
||||
void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_stat_info *si = F2FS_STAT(sbi);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&f2fs_stat_mutex);
|
||||
raw_spin_lock_irqsave(&f2fs_stat_lock, flags);
|
||||
list_del(&si->stat_list);
|
||||
mutex_unlock(&f2fs_stat_mutex);
|
||||
raw_spin_unlock_irqrestore(&f2fs_stat_lock, flags);
|
||||
|
||||
kfree(si);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,9 @@ typedef u32 nid_t;
|
||||
|
||||
struct f2fs_rwsem {
|
||||
struct rw_semaphore internal_rwsem;
|
||||
#ifdef CONFIG_F2FS_UNFAIR_RWSEM
|
||||
wait_queue_head_t read_waiters;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct f2fs_mount_info {
|
||||
@@ -396,6 +398,10 @@ struct discard_cmd_control {
|
||||
struct mutex cmd_lock;
|
||||
unsigned int nr_discards; /* # of discards in the list */
|
||||
unsigned int max_discards; /* max. discards to be issued */
|
||||
unsigned int max_discard_request; /* max. discard request per round */
|
||||
unsigned int min_discard_issue_time; /* min. interval between discard issue */
|
||||
unsigned int mid_discard_issue_time; /* mid. interval between discard issue */
|
||||
unsigned int max_discard_issue_time; /* max. interval between discard issue */
|
||||
unsigned int discard_granularity; /* discard granularity */
|
||||
unsigned int undiscard_blks; /* # of undiscard blocks */
|
||||
unsigned int next_pos; /* next discard position */
|
||||
@@ -571,6 +577,9 @@ enum {
|
||||
/* maximum retry quota flush count */
|
||||
#define DEFAULT_RETRY_QUOTA_FLUSH_COUNT 8
|
||||
|
||||
/* maximum retry of EIO'ed meta page */
|
||||
#define MAX_RETRY_META_PAGE_EIO 100
|
||||
|
||||
#define F2FS_LINK_MAX 0xffffffff /* maximum link count per file */
|
||||
|
||||
#define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */
|
||||
@@ -584,6 +593,9 @@ enum {
|
||||
/* number of extent info in extent cache we try to shrink */
|
||||
#define EXTENT_CACHE_SHRINK_NUMBER 128
|
||||
|
||||
#define RECOVERY_MAX_RA_BLOCKS BIO_MAX_PAGES
|
||||
#define RECOVERY_MIN_RA_BLOCKS 1
|
||||
|
||||
struct rb_entry {
|
||||
struct rb_node rb_node; /* rb node located in rb-tree */
|
||||
union {
|
||||
@@ -731,7 +743,8 @@ enum {
|
||||
FI_DROP_CACHE, /* drop dirty page cache */
|
||||
FI_DATA_EXIST, /* indicate data exists */
|
||||
FI_INLINE_DOTS, /* indicate inline dot dentries */
|
||||
FI_DO_DEFRAG, /* indicate defragment is running */
|
||||
FI_SKIP_WRITES, /* should skip data page writeback */
|
||||
FI_OPU_WRITE, /* used for opu per file */
|
||||
FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
|
||||
FI_PREALLOCATED_ALL, /* all blocks for write were preallocated */
|
||||
FI_HOT_DATA, /* indicate file is hot */
|
||||
@@ -908,6 +921,7 @@ struct f2fs_nm_info {
|
||||
nid_t max_nid; /* maximum possible node ids */
|
||||
nid_t available_nids; /* # of available node ids */
|
||||
nid_t next_scan_nid; /* the next nid to be scanned */
|
||||
nid_t max_rf_node_blocks; /* max # of nodes for recovery */
|
||||
unsigned int ram_thresh; /* control the memory footprint */
|
||||
unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */
|
||||
unsigned int dirty_nats_ratio; /* control dirty nats ratio threshold */
|
||||
@@ -1278,6 +1292,7 @@ enum {
|
||||
SBI_QUOTA_SKIP_FLUSH, /* skip flushing quota in current CP */
|
||||
SBI_QUOTA_NEED_REPAIR, /* quota file may be corrupted */
|
||||
SBI_IS_RESIZEFS, /* resizefs is in process */
|
||||
SBI_IS_FREEZING, /* freezefs is in process */
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -1297,6 +1312,7 @@ enum {
|
||||
GC_IDLE_AT,
|
||||
GC_URGENT_HIGH,
|
||||
GC_URGENT_LOW,
|
||||
GC_URGENT_MID,
|
||||
MAX_GC_MODE,
|
||||
};
|
||||
|
||||
@@ -1604,6 +1620,8 @@ struct f2fs_sb_info {
|
||||
/* keep migration IO order for LFS mode */
|
||||
struct f2fs_rwsem io_order_lock;
|
||||
mempool_t *write_io_dummy; /* Dummy pages */
|
||||
pgoff_t metapage_eio_ofs; /* EIO page offset */
|
||||
int metapage_eio_cnt; /* EIO count */
|
||||
|
||||
/* for checkpoint */
|
||||
struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
|
||||
@@ -1679,6 +1697,8 @@ struct f2fs_sb_info {
|
||||
atomic_t nr_pages[NR_COUNT_TYPE];
|
||||
/* # of allocated blocks */
|
||||
struct percpu_counter alloc_valid_block_count;
|
||||
/* # of node block writes as roll forward recovery */
|
||||
struct percpu_counter rf_node_block_count;
|
||||
|
||||
/* writeback control */
|
||||
atomic_t wb_sync_req[META]; /* count # of WB_SYNC threads */
|
||||
@@ -2103,10 +2123,20 @@ static inline void clear_ckpt_flags(struct f2fs_sb_info *sbi, unsigned int f)
|
||||
spin_unlock_irqrestore(&sbi->cp_lock, flags);
|
||||
}
|
||||
|
||||
static inline void init_f2fs_rwsem(struct f2fs_rwsem *sem)
|
||||
#define init_f2fs_rwsem(sem) \
|
||||
do { \
|
||||
static struct lock_class_key __key; \
|
||||
\
|
||||
__init_f2fs_rwsem((sem), #sem, &__key); \
|
||||
} while (0)
|
||||
|
||||
static inline void __init_f2fs_rwsem(struct f2fs_rwsem *sem,
|
||||
const char *sem_name, struct lock_class_key *key)
|
||||
{
|
||||
init_rwsem(&sem->internal_rwsem);
|
||||
__init_rwsem(&sem->internal_rwsem, sem_name, key);
|
||||
#ifdef CONFIG_F2FS_UNFAIR_RWSEM
|
||||
init_waitqueue_head(&sem->read_waiters);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int f2fs_rwsem_is_locked(struct f2fs_rwsem *sem)
|
||||
@@ -2121,7 +2151,11 @@ static inline int f2fs_rwsem_is_contended(struct f2fs_rwsem *sem)
|
||||
|
||||
static inline void f2fs_down_read(struct f2fs_rwsem *sem)
|
||||
{
|
||||
#ifdef CONFIG_F2FS_UNFAIR_RWSEM
|
||||
wait_event(sem->read_waiters, down_read_trylock(&sem->internal_rwsem));
|
||||
#else
|
||||
down_read(&sem->internal_rwsem);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int f2fs_down_read_trylock(struct f2fs_rwsem *sem)
|
||||
@@ -2156,7 +2190,9 @@ static inline int f2fs_down_write_trylock(struct f2fs_rwsem *sem)
|
||||
static inline void f2fs_up_write(struct f2fs_rwsem *sem)
|
||||
{
|
||||
up_write(&sem->internal_rwsem);
|
||||
#ifdef CONFIG_F2FS_UNFAIR_RWSEM
|
||||
wake_up_all(&sem->read_waiters);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
|
||||
@@ -2748,6 +2784,9 @@ static inline bool is_idle(struct f2fs_sb_info *sbi, int type)
|
||||
if (is_inflight_io(sbi, type))
|
||||
return false;
|
||||
|
||||
if (sbi->gc_mode == GC_URGENT_MID)
|
||||
return true;
|
||||
|
||||
if (sbi->gc_mode == GC_URGENT_LOW &&
|
||||
(type == DISCARD_TIME || type == GC_TIME))
|
||||
return true;
|
||||
@@ -3642,7 +3681,8 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type);
|
||||
int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
int type, bool sync);
|
||||
void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index,
|
||||
unsigned int ra_blocks);
|
||||
long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
long nr_to_write, enum iostat_type io_type);
|
||||
void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
|
||||
|
||||
@@ -818,7 +818,7 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
|
||||
{
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_inode *ri;
|
||||
struct f2fs_inode *ri = NULL;
|
||||
unsigned int flags;
|
||||
|
||||
if (f2fs_has_extra_attr(inode) &&
|
||||
@@ -2067,7 +2067,10 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
f2fs_disable_compressed_file(inode);
|
||||
if (!f2fs_disable_compressed_file(inode)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (f2fs_is_atomic_file(inode)) {
|
||||
if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST))
|
||||
@@ -2618,10 +2621,6 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
||||
bool fragmented = false;
|
||||
int err;
|
||||
|
||||
/* if in-place-update policy is enabled, don't waste time here */
|
||||
if (f2fs_should_update_inplace(inode, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
pg_start = range->start >> PAGE_SHIFT;
|
||||
pg_end = (range->start + range->len) >> PAGE_SHIFT;
|
||||
|
||||
@@ -2629,6 +2628,13 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
/* if in-place-update policy is enabled, don't waste time here */
|
||||
set_inode_flag(inode, FI_OPU_WRITE);
|
||||
if (f2fs_should_update_inplace(inode, NULL)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* writeback all dirty pages in the range */
|
||||
err = filemap_write_and_wait_range(inode->i_mapping, range->start,
|
||||
range->start + range->len - 1);
|
||||
@@ -2710,7 +2716,7 @@ do_map:
|
||||
goto check;
|
||||
}
|
||||
|
||||
set_inode_flag(inode, FI_DO_DEFRAG);
|
||||
set_inode_flag(inode, FI_SKIP_WRITES);
|
||||
|
||||
idx = map.m_lblk;
|
||||
while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
|
||||
@@ -2735,15 +2741,16 @@ check:
|
||||
if (map.m_lblk < pg_end && cnt < blk_per_seg)
|
||||
goto do_map;
|
||||
|
||||
clear_inode_flag(inode, FI_DO_DEFRAG);
|
||||
clear_inode_flag(inode, FI_SKIP_WRITES);
|
||||
|
||||
err = filemap_fdatawrite(inode->i_mapping);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
clear_out:
|
||||
clear_inode_flag(inode, FI_DO_DEFRAG);
|
||||
clear_inode_flag(inode, FI_SKIP_WRITES);
|
||||
out:
|
||||
clear_inode_flag(inode, FI_OPU_WRITE);
|
||||
inode_unlock(inode);
|
||||
if (!err)
|
||||
range->len = (u64)total << PAGE_SHIFT;
|
||||
@@ -3050,7 +3057,7 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid)
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct page *ipage;
|
||||
struct f2fs_inode *ri = NULL;
|
||||
kprojid_t kprojid;
|
||||
int err;
|
||||
|
||||
@@ -3074,17 +3081,8 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid)
|
||||
if (IS_NOQUOTA(inode))
|
||||
return err;
|
||||
|
||||
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(ipage))
|
||||
return PTR_ERR(ipage);
|
||||
|
||||
if (!F2FS_FITS_IN_INODE(F2FS_INODE(ipage), fi->i_extra_isize,
|
||||
i_projid)) {
|
||||
err = -EOVERFLOW;
|
||||
f2fs_put_page(ipage, 1);
|
||||
return err;
|
||||
}
|
||||
f2fs_put_page(ipage, 1);
|
||||
if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
|
||||
return -EOVERFLOW;
|
||||
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
|
||||
@@ -103,7 +103,10 @@ static int gc_thread_func(void *data)
|
||||
sbi->gc_urgent_high_remaining--;
|
||||
}
|
||||
spin_unlock(&sbi->gc_urgent_high_lock);
|
||||
}
|
||||
|
||||
if (sbi->gc_mode == GC_URGENT_HIGH ||
|
||||
sbi->gc_mode == GC_URGENT_MID) {
|
||||
wait_ms = gc_th->urgent_sleep_time;
|
||||
f2fs_down_write(&sbi->gc_lock);
|
||||
goto do_gc;
|
||||
@@ -1038,8 +1041,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
}
|
||||
|
||||
if (f2fs_check_nid_range(sbi, dni->ino))
|
||||
if (f2fs_check_nid_range(sbi, dni->ino)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
*nofs = ofs_of_node(node_page);
|
||||
source_blkaddr = data_blkaddr(NULL, node_page, ofs_in_node);
|
||||
|
||||
@@ -778,7 +778,8 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
f2fs_remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
||||
f2fs_remove_ino_entry(sbi, inode->i_ino, FLUSH_INO);
|
||||
|
||||
sb_start_intwrite(inode->i_sb);
|
||||
if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING))
|
||||
sb_start_intwrite(inode->i_sb);
|
||||
set_inode_flag(inode, FI_NO_ALLOC);
|
||||
i_size_write(inode, 0);
|
||||
retry:
|
||||
@@ -809,7 +810,8 @@ retry:
|
||||
if (dquot_initialize_needed(inode))
|
||||
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
|
||||
}
|
||||
sb_end_intwrite(inode->i_sb);
|
||||
if (!is_sbi_flag_set(sbi, SBI_IS_FREEZING))
|
||||
sb_end_intwrite(inode->i_sb);
|
||||
no_delete:
|
||||
dquot_drop(inode);
|
||||
|
||||
@@ -885,6 +887,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni, false);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
set_inode_flag(inode, FI_FREE_NID);
|
||||
f2fs_warn(sbi, "May loss orphan inode, run fsck to fix.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1106,8 +1106,7 @@ out_dir:
|
||||
out_old:
|
||||
f2fs_put_page(old_page, 0);
|
||||
out:
|
||||
if (whiteout)
|
||||
iput(whiteout);
|
||||
iput(whiteout);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -1782,6 +1782,7 @@ continue_unlock:
|
||||
|
||||
if (!atomic || page == last_page) {
|
||||
set_fsync_mark(page, 1);
|
||||
percpu_counter_inc(&sbi->rf_node_block_count);
|
||||
if (IS_INODE(page)) {
|
||||
if (is_inode_flag_set(inode,
|
||||
FI_DIRTY_INODE))
|
||||
@@ -2111,8 +2112,12 @@ static int f2fs_write_node_pages(struct address_space *mapping,
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
atomic_inc(&sbi->wb_sync_req[NODE]);
|
||||
else if (atomic_read(&sbi->wb_sync_req[NODE]))
|
||||
else if (atomic_read(&sbi->wb_sync_req[NODE])) {
|
||||
/* to avoid potential deadlock */
|
||||
if (current->plug)
|
||||
blk_finish_plug(current->plug);
|
||||
goto skip_write;
|
||||
}
|
||||
|
||||
trace_f2fs_writepages(mapping->host, wbc, NODE);
|
||||
|
||||
@@ -3218,6 +3223,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
|
||||
nm_i->ram_thresh = DEF_RAM_THRESHOLD;
|
||||
nm_i->ra_nid_pages = DEF_RA_NID_PAGES;
|
||||
nm_i->dirty_nats_ratio = DEF_DIRTY_NAT_RATIO_THRESHOLD;
|
||||
nm_i->max_rf_node_blocks = DEF_RF_NODE_BLOCKS;
|
||||
|
||||
INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC);
|
||||
INIT_LIST_HEAD(&nm_i->free_nid_list);
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
/* control total # of nats */
|
||||
#define DEF_NAT_CACHE_THRESHOLD 100000
|
||||
|
||||
/* control total # of node writes used for roll-fowrad recovery */
|
||||
#define DEF_RF_NODE_BLOCKS 0
|
||||
|
||||
/* vector size for gang look-up from nat cache that consists of radix tree */
|
||||
#define NATVEC_SIZE 64
|
||||
#define SETVEC_SIZE 32
|
||||
|
||||
@@ -55,6 +55,10 @@ bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi)
|
||||
|
||||
if (sbi->last_valid_block_count + nalloc > sbi->user_block_count)
|
||||
return false;
|
||||
if (NM_I(sbi)->max_rf_node_blocks &&
|
||||
percpu_counter_sum_positive(&sbi->rf_node_block_count) >=
|
||||
NM_I(sbi)->max_rf_node_blocks)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -342,6 +346,19 @@ static int recover_inode(struct inode *inode, struct page *page)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int adjust_por_ra_blocks(struct f2fs_sb_info *sbi,
|
||||
unsigned int ra_blocks, unsigned int blkaddr,
|
||||
unsigned int next_blkaddr)
|
||||
{
|
||||
if (blkaddr + 1 == next_blkaddr)
|
||||
ra_blocks = min_t(unsigned int, RECOVERY_MAX_RA_BLOCKS,
|
||||
ra_blocks * 2);
|
||||
else if (next_blkaddr % sbi->blocks_per_seg)
|
||||
ra_blocks = max_t(unsigned int, RECOVERY_MIN_RA_BLOCKS,
|
||||
ra_blocks / 2);
|
||||
return ra_blocks;
|
||||
}
|
||||
|
||||
static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
bool check_only)
|
||||
{
|
||||
@@ -349,6 +366,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
struct page *page = NULL;
|
||||
block_t blkaddr;
|
||||
unsigned int loop_cnt = 0;
|
||||
unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS;
|
||||
unsigned int free_blocks = MAIN_SEGS(sbi) * sbi->blocks_per_seg -
|
||||
valid_user_blocks(sbi);
|
||||
int err = 0;
|
||||
@@ -423,11 +441,14 @@ next:
|
||||
break;
|
||||
}
|
||||
|
||||
ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr,
|
||||
next_blkaddr_of_node(page));
|
||||
|
||||
/* check next segment */
|
||||
blkaddr = next_blkaddr_of_node(page);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr);
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -704,6 +725,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
struct page *page = NULL;
|
||||
int err = 0;
|
||||
block_t blkaddr;
|
||||
unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS;
|
||||
|
||||
/* get node pages in the current segment */
|
||||
curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
|
||||
@@ -715,8 +737,6 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
break;
|
||||
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr);
|
||||
|
||||
page = f2fs_get_tmp_page(sbi, blkaddr);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
@@ -759,9 +779,14 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
if (entry->blkaddr == blkaddr)
|
||||
list_move_tail(&entry->list, tmp_inode_list);
|
||||
next:
|
||||
ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr,
|
||||
next_blkaddr_of_node(page));
|
||||
|
||||
/* check next segment */
|
||||
blkaddr = next_blkaddr_of_node(page);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks);
|
||||
}
|
||||
if (!err)
|
||||
f2fs_allocate_new_segments(sbi);
|
||||
|
||||
@@ -1159,14 +1159,14 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
||||
dpolicy->ordered = false;
|
||||
dpolicy->granularity = granularity;
|
||||
|
||||
dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
|
||||
dpolicy->max_requests = dcc->max_discard_request;
|
||||
dpolicy->io_aware_gran = MAX_PLIST_NUM;
|
||||
dpolicy->timeout = false;
|
||||
|
||||
if (discard_type == DPOLICY_BG) {
|
||||
dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
|
||||
dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME;
|
||||
dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
|
||||
dpolicy->min_interval = dcc->min_discard_issue_time;
|
||||
dpolicy->mid_interval = dcc->mid_discard_issue_time;
|
||||
dpolicy->max_interval = dcc->max_discard_issue_time;
|
||||
dpolicy->io_aware = true;
|
||||
dpolicy->sync = false;
|
||||
dpolicy->ordered = true;
|
||||
@@ -1174,12 +1174,12 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
||||
dpolicy->granularity = 1;
|
||||
if (atomic_read(&dcc->discard_cmd_cnt))
|
||||
dpolicy->max_interval =
|
||||
DEF_MIN_DISCARD_ISSUE_TIME;
|
||||
dcc->min_discard_issue_time;
|
||||
}
|
||||
} else if (discard_type == DPOLICY_FORCE) {
|
||||
dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
|
||||
dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME;
|
||||
dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
|
||||
dpolicy->min_interval = dcc->min_discard_issue_time;
|
||||
dpolicy->mid_interval = dcc->mid_discard_issue_time;
|
||||
dpolicy->max_interval = dcc->max_discard_issue_time;
|
||||
dpolicy->io_aware = false;
|
||||
} else if (discard_type == DPOLICY_FSTRIM) {
|
||||
dpolicy->io_aware = false;
|
||||
@@ -1784,7 +1784,7 @@ static int issue_discard_thread(void *data)
|
||||
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||
wait_queue_head_t *q = &dcc->discard_wait_queue;
|
||||
struct discard_policy dpolicy;
|
||||
unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME;
|
||||
unsigned int wait_ms = dcc->min_discard_issue_time;
|
||||
int issued;
|
||||
|
||||
set_freezable();
|
||||
@@ -2183,6 +2183,10 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
|
||||
atomic_set(&dcc->discard_cmd_cnt, 0);
|
||||
dcc->nr_discards = 0;
|
||||
dcc->max_discards = MAIN_SEGS(sbi) << sbi->log_blocks_per_seg;
|
||||
dcc->max_discard_request = DEF_MAX_DISCARD_REQUEST;
|
||||
dcc->min_discard_issue_time = DEF_MIN_DISCARD_ISSUE_TIME;
|
||||
dcc->mid_discard_issue_time = DEF_MID_DISCARD_ISSUE_TIME;
|
||||
dcc->max_discard_issue_time = DEF_MAX_DISCARD_ISSUE_TIME;
|
||||
dcc->undiscard_blks = 0;
|
||||
dcc->next_pos = 0;
|
||||
dcc->root = RB_ROOT_CACHED;
|
||||
@@ -4792,6 +4796,13 @@ static int sanity_check_curseg(struct f2fs_sb_info *sbi)
|
||||
|
||||
sanity_check_seg_type(sbi, curseg->seg_type);
|
||||
|
||||
if (curseg->alloc_type != LFS && curseg->alloc_type != SSR) {
|
||||
f2fs_err(sbi,
|
||||
"Current segment has invalid alloc_type:%d",
|
||||
curseg->alloc_type);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (f2fs_test_bit(blkofs, se->cur_valid_map))
|
||||
goto out;
|
||||
|
||||
|
||||
@@ -651,7 +651,9 @@ static inline int utilization(struct f2fs_sb_info *sbi)
|
||||
* pages over min_fsync_blocks. (=default option)
|
||||
* F2FS_IPU_ASYNC - do IPU given by asynchronous write requests.
|
||||
* F2FS_IPU_NOCACHE - disable IPU bio cache.
|
||||
* F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode)
|
||||
* F2FS_IPU_HONOR_OPU_WRITE - use OPU write prior to IPU write if inode has
|
||||
* FI_OPU_WRITE flag.
|
||||
* F2FS_IPU_DISABLE - disable IPU. (=default option in LFS mode)
|
||||
*/
|
||||
#define DEF_MIN_IPU_UTIL 70
|
||||
#define DEF_MIN_FSYNC_BLOCKS 8
|
||||
@@ -667,6 +669,7 @@ enum {
|
||||
F2FS_IPU_FSYNC,
|
||||
F2FS_IPU_ASYNC,
|
||||
F2FS_IPU_NOCACHE,
|
||||
F2FS_IPU_HONOR_OPU_WRITE,
|
||||
};
|
||||
|
||||
static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi,
|
||||
|
||||
@@ -1512,8 +1512,9 @@ static void f2fs_free_inode(struct inode *inode)
|
||||
|
||||
static void destroy_percpu_info(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
percpu_counter_destroy(&sbi->alloc_valid_block_count);
|
||||
percpu_counter_destroy(&sbi->total_valid_inode_count);
|
||||
percpu_counter_destroy(&sbi->rf_node_block_count);
|
||||
percpu_counter_destroy(&sbi->alloc_valid_block_count);
|
||||
}
|
||||
|
||||
static void destroy_device_list(struct f2fs_sb_info *sbi)
|
||||
@@ -1673,11 +1674,15 @@ static int f2fs_freeze(struct super_block *sb)
|
||||
/* ensure no checkpoint required */
|
||||
if (!llist_empty(&F2FS_SB(sb)->cprc_info.issue_list))
|
||||
return -EINVAL;
|
||||
|
||||
/* to avoid deadlock on f2fs_evict_inode->SB_FREEZE_FS */
|
||||
set_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f2fs_unfreeze(struct super_block *sb)
|
||||
{
|
||||
clear_sbi_flag(F2FS_SB(sb), SBI_IS_FREEZING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2086,6 +2091,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
unsigned int s_flags = sbi->sb->s_flags;
|
||||
struct cp_control cpc;
|
||||
unsigned int gc_mode;
|
||||
int err = 0;
|
||||
int ret;
|
||||
block_t unusable;
|
||||
@@ -2098,6 +2104,9 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
|
||||
f2fs_update_time(sbi, DISABLE_TIME);
|
||||
|
||||
gc_mode = sbi->gc_mode;
|
||||
sbi->gc_mode = GC_URGENT_HIGH;
|
||||
|
||||
while (!f2fs_time_over(sbi, DISABLE_TIME)) {
|
||||
f2fs_down_write(&sbi->gc_lock);
|
||||
err = f2fs_gc(sbi, true, false, false, NULL_SEGNO);
|
||||
@@ -2135,6 +2144,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
out_unlock:
|
||||
f2fs_up_write(&sbi->gc_lock);
|
||||
restore_flag:
|
||||
sbi->gc_mode = gc_mode;
|
||||
sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */
|
||||
return err;
|
||||
}
|
||||
@@ -2700,7 +2710,7 @@ int f2fs_quota_sync(struct super_block *sb, int type)
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct quota_info *dqopt = sb_dqopt(sb);
|
||||
int cnt;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Now when everything is written we can discard the pagecache so
|
||||
@@ -2711,8 +2721,8 @@ int f2fs_quota_sync(struct super_block *sb, int type)
|
||||
if (type != -1 && cnt != type)
|
||||
continue;
|
||||
|
||||
if (!sb_has_quota_active(sb, type))
|
||||
return 0;
|
||||
if (!sb_has_quota_active(sb, cnt))
|
||||
continue;
|
||||
|
||||
inode_lock(dqopt->files[cnt]);
|
||||
|
||||
@@ -3586,6 +3596,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
|
||||
F2FS_NODE_INO(sbi) = le32_to_cpu(raw_super->node_ino);
|
||||
F2FS_META_INO(sbi) = le32_to_cpu(raw_super->meta_ino);
|
||||
sbi->cur_victim_sec = NULL_SECNO;
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
sbi->next_victim_seg[BG_GC] = NULL_SEGNO;
|
||||
sbi->next_victim_seg[FG_GC] = NULL_SEGNO;
|
||||
sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH;
|
||||
@@ -3631,11 +3642,20 @@ static int init_percpu_info(struct f2fs_sb_info *sbi)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = percpu_counter_init(&sbi->rf_node_block_count, 0, GFP_KERNEL);
|
||||
if (err)
|
||||
goto err_valid_block;
|
||||
|
||||
err = percpu_counter_init(&sbi->total_valid_inode_count, 0,
|
||||
GFP_KERNEL);
|
||||
if (err)
|
||||
percpu_counter_destroy(&sbi->alloc_valid_block_count);
|
||||
goto err_node_block;
|
||||
return 0;
|
||||
|
||||
err_node_block:
|
||||
percpu_counter_destroy(&sbi->rf_node_block_count);
|
||||
err_valid_block:
|
||||
percpu_counter_destroy(&sbi->alloc_valid_block_count);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -3962,7 +3982,8 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
|
||||
F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
|
||||
if (f2fs_block_unit_discard(sbi))
|
||||
sm_i->dcc_info->discard_granularity = 1;
|
||||
sm_i->ipu_policy = 1 << F2FS_IPU_FORCE;
|
||||
sm_i->ipu_policy = 1 << F2FS_IPU_FORCE |
|
||||
1 << F2FS_IPU_HONOR_OPU_WRITE;
|
||||
}
|
||||
|
||||
sbi->readdir_ra = 1;
|
||||
|
||||
@@ -41,6 +41,16 @@ enum {
|
||||
ATGC_INFO, /* struct atgc_management */
|
||||
};
|
||||
|
||||
static const char *gc_mode_names[MAX_GC_MODE] = {
|
||||
"GC_NORMAL",
|
||||
"GC_IDLE_CB",
|
||||
"GC_IDLE_GREEDY",
|
||||
"GC_IDLE_AT",
|
||||
"GC_URGENT_HIGH",
|
||||
"GC_URGENT_LOW",
|
||||
"GC_URGENT_MID"
|
||||
};
|
||||
|
||||
struct f2fs_attr {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);
|
||||
@@ -317,8 +327,13 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
|
||||
return sysfs_emit(buf, "%u\n", sbi->compr_new_inode);
|
||||
#endif
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_urgent"))
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
gc_mode_names[sbi->gc_mode]);
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_segment_mode"))
|
||||
return sysfs_emit(buf, "%u\n", sbi->gc_segment_mode);
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
gc_mode_names[sbi->gc_segment_mode]);
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_reclaimed_segments")) {
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
@@ -469,6 +484,13 @@ out:
|
||||
}
|
||||
} else if (t == 2) {
|
||||
sbi->gc_mode = GC_URGENT_LOW;
|
||||
} else if (t == 3) {
|
||||
sbi->gc_mode = GC_URGENT_MID;
|
||||
if (sbi->gc_thread) {
|
||||
sbi->gc_thread->gc_wake = 1;
|
||||
wake_up_interruptible_all(
|
||||
&sbi->gc_thread->gc_wait_queue_head);
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -482,7 +504,7 @@ out:
|
||||
} else if (t == GC_IDLE_AT) {
|
||||
if (!sbi->am.atgc_enabled)
|
||||
return -EINVAL;
|
||||
sbi->gc_mode = GC_AT;
|
||||
sbi->gc_mode = GC_IDLE_AT;
|
||||
} else {
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
}
|
||||
@@ -717,6 +739,10 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle, gc_mode);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent, gc_mode);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_request, max_discard_request);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, min_discard_issue_time, min_discard_issue_time);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, mid_discard_issue_time, mid_discard_issue_time);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_issue_time, max_discard_issue_time);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity);
|
||||
F2FS_RW_ATTR(RESERVED_BLOCKS, f2fs_sb_info, reserved_blocks, reserved_blocks);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
|
||||
@@ -729,6 +755,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections);
|
||||
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
|
||||
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ra_nid_pages, ra_nid_pages);
|
||||
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, dirty_nats_ratio, dirty_nats_ratio);
|
||||
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, max_roll_forward_node_blocks, max_rf_node_blocks);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, migration_granularity, migration_granularity);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
|
||||
@@ -833,6 +860,10 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(reclaim_segments),
|
||||
ATTR_LIST(main_blkaddr),
|
||||
ATTR_LIST(max_small_discards),
|
||||
ATTR_LIST(max_discard_request),
|
||||
ATTR_LIST(min_discard_issue_time),
|
||||
ATTR_LIST(mid_discard_issue_time),
|
||||
ATTR_LIST(max_discard_issue_time),
|
||||
ATTR_LIST(discard_granularity),
|
||||
ATTR_LIST(pending_discard),
|
||||
ATTR_LIST(batched_trim_sections),
|
||||
@@ -848,6 +879,7 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(ram_thresh),
|
||||
ATTR_LIST(ra_nid_pages),
|
||||
ATTR_LIST(dirty_nats_ratio),
|
||||
ATTR_LIST(max_roll_forward_node_blocks),
|
||||
ATTR_LIST(cp_interval),
|
||||
ATTR_LIST(idle_interval),
|
||||
ATTR_LIST(discard_idle_interval),
|
||||
|
||||
Reference in New Issue
Block a user