Merge branch 'linux-4.19.y' of https://github.com/jaegeuk/f2fs-stable into skizo-x
This commit is contained in:
commit
c1c5a45275
@ -96,6 +96,12 @@ 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_ordered_discard
|
||||
Date: October 2022
|
||||
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||
Description: Controls the maximum ordered discard, the unit size is one block(4KB).
|
||||
Set it to 16 by default.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_discard_request
|
||||
Date: December 2021
|
||||
Contact: "Konstantin Vyshetsky" <vkon@google.com>
|
||||
@ -232,7 +238,7 @@ Description: Shows total written kbytes issued to disk.
|
||||
What: /sys/fs/f2fs/<disk>/features
|
||||
Date: July 2017
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: <deprecated: should use /sys/fs/f2fs/<disk>/feature_list/
|
||||
Description: <deprecated: should use /sys/fs/f2fs/<disk>/feature_list/>
|
||||
Shows all enabled features in current device.
|
||||
Supported features:
|
||||
encryption, blkzoned, extra_attr, projquota, inode_checksum,
|
||||
@ -573,10 +579,10 @@ Description: With "mode=fragment:block" mount options, we can scatter block allo
|
||||
in the length of 1..<max_fragment_hole> by turns. This value can be set
|
||||
between 1..512 and the default value is 4.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_urgent_high_remaining
|
||||
Date: December 2021
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: You can set the trial count limit for GC urgent high mode with this value.
|
||||
What: /sys/fs/f2fs/<disk>/gc_remaining_trials
|
||||
Date: October 2022
|
||||
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||
Description: You can set the trial count limit for GC urgent and idle 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.
|
||||
|
||||
@ -609,3 +615,9 @@ Date: July 2022
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: Show the accumulated total revoked atomic write block count after boot.
|
||||
If you write "0" here, you can initialize to "0".
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_mode
|
||||
Date: October 2022
|
||||
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||
Description: Show the current gc_mode as a string.
|
||||
This is a read-only entry.
|
||||
|
@ -154,6 +154,8 @@ nobarrier This option can be used if underlying storage guarantees
|
||||
If this option is set, no cache_flush commands are issued
|
||||
but f2fs still guarantees the write ordering of all the
|
||||
data writes.
|
||||
barrier If this option is set, cache_flush commands are allowed to be
|
||||
issued.
|
||||
fastboot This option is used when a system wants to reduce mount
|
||||
time as much as possible, even though normal performance
|
||||
can be sacrificed.
|
||||
@ -199,6 +201,7 @@ fault_type=%d Support configuring fault injection type, should be
|
||||
FAULT_SLAB_ALLOC 0x000008000
|
||||
FAULT_DQUOT_INIT 0x000010000
|
||||
FAULT_LOCK_OP 0x000020000
|
||||
FAULT_BLKADDR 0x000040000
|
||||
=================== ===========
|
||||
mode=%s Control block allocation mode which supports "adaptive"
|
||||
and "lfs". In "lfs" mode, there should be no random
|
||||
|
@ -171,6 +171,11 @@ static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr,
|
||||
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type)
|
||||
{
|
||||
if (time_to_inject(sbi, FAULT_BLKADDR)) {
|
||||
f2fs_show_injection_info(sbi, FAULT_BLKADDR);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case META_NAT:
|
||||
break;
|
||||
@ -1897,8 +1902,10 @@ int f2fs_start_ckpt_thread(struct f2fs_sb_info *sbi)
|
||||
cprc->f2fs_issue_ckpt = kthread_run(issue_checkpoint_thread, sbi,
|
||||
"f2fs_ckpt-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(cprc->f2fs_issue_ckpt)) {
|
||||
int err = PTR_ERR(cprc->f2fs_issue_ckpt);
|
||||
|
||||
cprc->f2fs_issue_ckpt = NULL;
|
||||
return -ENOMEM;
|
||||
return err;
|
||||
}
|
||||
|
||||
set_task_ioprio(cprc->f2fs_issue_ckpt, cprc->ckpt_thread_ioprio);
|
||||
|
@ -1258,7 +1258,8 @@ int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
|
||||
}
|
||||
|
||||
struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
int op_flags, bool for_write)
|
||||
int op_flags, bool for_write,
|
||||
pgoff_t *next_pgofs)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct dnode_of_data dn;
|
||||
@ -1284,12 +1285,17 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
||||
if (err)
|
||||
if (err) {
|
||||
if (err == -ENOENT && next_pgofs)
|
||||
*next_pgofs = f2fs_get_next_page_offset(&dn, index);
|
||||
goto put_err;
|
||||
}
|
||||
f2fs_put_dnode(&dn);
|
||||
|
||||
if (unlikely(dn.data_blkaddr == NULL_ADDR)) {
|
||||
err = -ENOENT;
|
||||
if (next_pgofs)
|
||||
*next_pgofs = index + 1;
|
||||
goto put_err;
|
||||
}
|
||||
if (dn.data_blkaddr != NEW_ADDR &&
|
||||
@ -1333,7 +1339,8 @@ put_err:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index)
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index,
|
||||
pgoff_t *next_pgofs)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
@ -1343,7 +1350,7 @@ struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index)
|
||||
return page;
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
page = f2fs_get_read_data_page(inode, index, 0, false);
|
||||
page = f2fs_get_read_data_page(inode, index, 0, false, next_pgofs);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
|
||||
@ -1369,7 +1376,7 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index,
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
repeat:
|
||||
page = f2fs_get_read_data_page(inode, index, 0, for_write);
|
||||
page = f2fs_get_read_data_page(inode, index, 0, for_write, NULL);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
|
||||
@ -3609,6 +3616,9 @@ static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
|
||||
else if (*blk_addr != NULL_ADDR)
|
||||
return 0;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_ATOMIC_REPLACE))
|
||||
goto reserve_block;
|
||||
|
||||
/* Look for the block in the original inode */
|
||||
err = __find_data_block(inode, index, &ori_blk_addr);
|
||||
if (err)
|
||||
|
@ -340,6 +340,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
unsigned int bidx, end_block;
|
||||
struct page *dentry_page;
|
||||
struct f2fs_dir_entry *de = NULL;
|
||||
pgoff_t next_pgofs;
|
||||
bool room = false;
|
||||
int max_slots;
|
||||
|
||||
@ -350,12 +351,13 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
le32_to_cpu(fname->hash) % nbucket);
|
||||
end_block = bidx + nblock;
|
||||
|
||||
for (; bidx < end_block; bidx++) {
|
||||
while (bidx < end_block) {
|
||||
/* no need to allocate new dentry pages to all the indices */
|
||||
dentry_page = f2fs_find_data_page(dir, bidx);
|
||||
dentry_page = f2fs_find_data_page(dir, bidx, &next_pgofs);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
if (PTR_ERR(dentry_page) == -ENOENT) {
|
||||
room = true;
|
||||
bidx = next_pgofs;
|
||||
continue;
|
||||
} else {
|
||||
*res_page = dentry_page;
|
||||
@ -376,6 +378,8 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
if (max_slots >= s)
|
||||
room = true;
|
||||
f2fs_put_page(dentry_page, 0);
|
||||
|
||||
bidx++;
|
||||
}
|
||||
|
||||
if (!de && room && F2FS_I(dir)->chash != fname->hash) {
|
||||
@ -958,7 +962,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
|
||||
bool f2fs_empty_dir(struct inode *dir)
|
||||
{
|
||||
unsigned long bidx;
|
||||
unsigned long bidx = 0;
|
||||
struct page *dentry_page;
|
||||
unsigned int bit_pos;
|
||||
struct f2fs_dentry_block *dentry_blk;
|
||||
@ -967,13 +971,17 @@ bool f2fs_empty_dir(struct inode *dir)
|
||||
if (f2fs_has_inline_dentry(dir))
|
||||
return f2fs_empty_inline_dir(dir);
|
||||
|
||||
for (bidx = 0; bidx < nblock; bidx++) {
|
||||
dentry_page = f2fs_get_lock_data_page(dir, bidx, false);
|
||||
while (bidx < nblock) {
|
||||
pgoff_t next_pgofs;
|
||||
|
||||
dentry_page = f2fs_find_data_page(dir, bidx, &next_pgofs);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
if (PTR_ERR(dentry_page) == -ENOENT)
|
||||
if (PTR_ERR(dentry_page) == -ENOENT) {
|
||||
bidx = next_pgofs;
|
||||
continue;
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dentry_blk = page_address(dentry_page);
|
||||
@ -985,10 +993,12 @@ bool f2fs_empty_dir(struct inode *dir)
|
||||
NR_DENTRY_IN_BLOCK,
|
||||
bit_pos);
|
||||
|
||||
f2fs_put_page(dentry_page, 1);
|
||||
f2fs_put_page(dentry_page, 0);
|
||||
|
||||
if (bit_pos < NR_DENTRY_IN_BLOCK)
|
||||
return false;
|
||||
|
||||
bidx++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1106,7 +1116,8 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
for (; n < npages; n++, ctx->pos = n * NR_DENTRY_IN_BLOCK) {
|
||||
for (; n < npages; ctx->pos = n * NR_DENTRY_IN_BLOCK) {
|
||||
pgoff_t next_pgofs;
|
||||
|
||||
/* allow readdir() to be interrupted */
|
||||
if (fatal_signal_pending(current)) {
|
||||
@ -1120,11 +1131,12 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
page_cache_sync_readahead(inode->i_mapping, ra, file, n,
|
||||
min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));
|
||||
|
||||
dentry_page = f2fs_find_data_page(inode, n);
|
||||
dentry_page = f2fs_find_data_page(inode, n, &next_pgofs);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
err = PTR_ERR(dentry_page);
|
||||
if (err == -ENOENT) {
|
||||
err = 0;
|
||||
n = next_pgofs;
|
||||
continue;
|
||||
} else {
|
||||
goto out_free;
|
||||
@ -1143,6 +1155,8 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
}
|
||||
|
||||
f2fs_put_page(dentry_page, 0);
|
||||
|
||||
n++;
|
||||
}
|
||||
out_free:
|
||||
fscrypt_fname_free_buffer(&fstr);
|
||||
|
@ -56,6 +56,7 @@ enum {
|
||||
FAULT_SLAB_ALLOC,
|
||||
FAULT_DQUOT_INIT,
|
||||
FAULT_LOCK_OP,
|
||||
FAULT_BLKADDR,
|
||||
FAULT_MAX,
|
||||
};
|
||||
|
||||
@ -329,6 +330,8 @@ struct discard_entry {
|
||||
|
||||
/* default discard granularity of inner discard thread, unit: block count */
|
||||
#define DEFAULT_DISCARD_GRANULARITY 16
|
||||
/* default maximum discard granularity of ordered discard, unit: block count */
|
||||
#define DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY 16
|
||||
|
||||
/* max discard pend list number */
|
||||
#define MAX_PLIST_NUM 512
|
||||
@ -408,6 +411,7 @@ struct discard_cmd_control {
|
||||
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 max_ordered_discard; /* maximum discard granularity issued by lba order */
|
||||
unsigned int undiscard_blks; /* # of undiscard blocks */
|
||||
unsigned int next_pos; /* next discard position */
|
||||
atomic_t issued_discard; /* # of issued discard */
|
||||
@ -763,6 +767,8 @@ enum {
|
||||
FI_COMPRESS_RELEASED, /* compressed blocks were released */
|
||||
FI_ALIGNED_WRITE, /* enable aligned write */
|
||||
FI_COW_FILE, /* indicate COW file */
|
||||
FI_ATOMIC_COMMITTED, /* indicate atomic commit completed except disk sync */
|
||||
FI_ATOMIC_REPLACE, /* indicate atomic replace */
|
||||
FI_MAX, /* max flag, never be used */
|
||||
};
|
||||
|
||||
@ -823,6 +829,7 @@ struct f2fs_inode_info {
|
||||
unsigned int i_cluster_size; /* cluster size */
|
||||
|
||||
unsigned int atomic_write_cnt;
|
||||
loff_t original_i_size; /* original i_size before atomic write */
|
||||
};
|
||||
|
||||
static inline void get_extent_info(struct extent_info *ext,
|
||||
@ -1063,9 +1070,6 @@ struct f2fs_sm_info {
|
||||
/* a threshold to reclaim prefree segments */
|
||||
unsigned int rec_prefree_segments;
|
||||
|
||||
/* for batched trimming */
|
||||
unsigned int trim_sections; /* # of sections to trim */
|
||||
|
||||
struct list_head sit_entry_set; /* sit entry set list */
|
||||
|
||||
unsigned int ipu_policy; /* in-place-update policy */
|
||||
@ -1314,6 +1318,7 @@ enum {
|
||||
MAX_TIME,
|
||||
};
|
||||
|
||||
/* Note that you need to keep synchronization with this gc_mode_names array */
|
||||
enum {
|
||||
GC_NORMAL,
|
||||
GC_IDLE_CB,
|
||||
@ -1736,8 +1741,9 @@ struct f2fs_sb_info {
|
||||
unsigned int cur_victim_sec; /* current victim section num */
|
||||
unsigned int gc_mode; /* current GC state */
|
||||
unsigned int next_victim_seg[2]; /* next segment in victim section */
|
||||
spinlock_t gc_urgent_high_lock;
|
||||
unsigned int gc_urgent_high_remaining; /* remaining trial count for GC_URGENT_HIGH */
|
||||
spinlock_t gc_remaining_trials_lock;
|
||||
/* remaining trial count for GC_URGENT_* and GC_IDLE_* */
|
||||
unsigned int gc_remaining_trials;
|
||||
|
||||
/* for skip statistic */
|
||||
unsigned long long skipped_gc_rwsem; /* FG_GC only */
|
||||
@ -3084,6 +3090,8 @@ static inline void f2fs_i_blocks_write(struct inode *inode,
|
||||
set_inode_flag(inode, FI_AUTO_RECOVER);
|
||||
}
|
||||
|
||||
static inline bool f2fs_is_atomic_file(struct inode *inode);
|
||||
|
||||
static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size)
|
||||
{
|
||||
bool clean = !is_inode_flag_set(inode, FI_DIRTY_INODE);
|
||||
@ -3093,6 +3101,10 @@ static inline void f2fs_i_size_write(struct inode *inode, loff_t i_size)
|
||||
return;
|
||||
|
||||
i_size_write(inode, i_size);
|
||||
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
return;
|
||||
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
if (clean || recover)
|
||||
set_inode_flag(inode, FI_AUTO_RECOVER);
|
||||
@ -3842,8 +3854,9 @@ int f2fs_mpage_readpages(struct address_space *mapping,
|
||||
struct list_head *pages, struct page *page,
|
||||
unsigned nr_pages, bool is_readahead);
|
||||
struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
int op_flags, bool for_write);
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index);
|
||||
int op_flags, bool for_write, pgoff_t *next_pgofs);
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index,
|
||||
pgoff_t *next_pgofs);
|
||||
struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index,
|
||||
bool for_write);
|
||||
struct page *f2fs_get_new_data_page(struct inode *inode,
|
||||
|
@ -604,7 +604,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
raw_node = F2FS_NODE(dn->node_page);
|
||||
addr = blkaddr_in_node(raw_node) + base + ofs;
|
||||
|
||||
/* Assumption: truncateion starts with cluster */
|
||||
/* Assumption: truncation starts with cluster */
|
||||
for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) {
|
||||
block_t blkaddr = le32_to_cpu(*addr);
|
||||
|
||||
@ -1906,6 +1906,10 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
|
||||
if (!f2fs_disable_compressed_file(inode))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
/* try to convert inline_data to support compression */
|
||||
int err = f2fs_convert_inline_inode(inode);
|
||||
if (err)
|
||||
return err;
|
||||
if (!f2fs_may_compress(inode))
|
||||
return -EINVAL;
|
||||
if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))
|
||||
@ -2079,12 +2083,13 @@ static int f2fs_ioc_getversion(struct file *filp, unsigned long arg)
|
||||
return put_user(inode->i_generation, (int __user *)arg);
|
||||
}
|
||||
|
||||
static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct inode *pinode;
|
||||
loff_t isize;
|
||||
int ret;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
@ -2143,13 +2148,25 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
goto out;
|
||||
}
|
||||
f2fs_i_size_write(fi->cow_inode, i_size_read(inode));
|
||||
|
||||
f2fs_write_inode(inode, NULL);
|
||||
|
||||
stat_inc_atomic_inode(inode);
|
||||
|
||||
set_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
set_inode_flag(fi->cow_inode, FI_COW_FILE);
|
||||
clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
|
||||
|
||||
isize = i_size_read(inode);
|
||||
fi->original_i_size = isize;
|
||||
if (truncate) {
|
||||
set_inode_flag(inode, FI_ATOMIC_REPLACE);
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
f2fs_i_size_write(inode, 0);
|
||||
isize = 0;
|
||||
}
|
||||
f2fs_i_size_write(fi->cow_inode, isize);
|
||||
|
||||
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
|
||||
f2fs_update_time(sbi, REQ_TIME);
|
||||
@ -2180,16 +2197,14 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
|
||||
|
||||
if (f2fs_is_atomic_file(inode)) {
|
||||
ret = f2fs_commit_atomic_write(inode);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
|
||||
if (!ret)
|
||||
f2fs_abort_atomic_write(inode, false);
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
|
||||
|
||||
f2fs_abort_atomic_write(inode, ret);
|
||||
} else {
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
|
||||
}
|
||||
unlock_out:
|
||||
|
||||
inode_unlock(inode);
|
||||
mnt_drop_write_file(filp);
|
||||
return ret;
|
||||
@ -4253,7 +4268,9 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
case FS_IOC_GETVERSION:
|
||||
return f2fs_ioc_getversion(filp, arg);
|
||||
case F2FS_IOC_START_ATOMIC_WRITE:
|
||||
return f2fs_ioc_start_atomic_write(filp);
|
||||
return f2fs_ioc_start_atomic_write(filp, false);
|
||||
case F2FS_IOC_START_ATOMIC_REPLACE:
|
||||
return f2fs_ioc_start_atomic_write(filp, true);
|
||||
case F2FS_IOC_COMMIT_ATOMIC_WRITE:
|
||||
return f2fs_ioc_commit_atomic_write(filp);
|
||||
case F2FS_IOC_ABORT_ATOMIC_WRITE:
|
||||
|
44
fs/f2fs/gc.c
44
fs/f2fs/gc.c
@ -96,16 +96,6 @@ static int gc_thread_func(void *data)
|
||||
* invalidated soon after by user update or deletion.
|
||||
* So, I'd like to wait some time to collect dirty segments.
|
||||
*/
|
||||
if (sbi->gc_mode == GC_URGENT_HIGH) {
|
||||
spin_lock(&sbi->gc_urgent_high_lock);
|
||||
if (sbi->gc_urgent_high_remaining) {
|
||||
sbi->gc_urgent_high_remaining--;
|
||||
if (!sbi->gc_urgent_high_remaining)
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
}
|
||||
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;
|
||||
@ -162,6 +152,15 @@ do_gc:
|
||||
/* balancing f2fs's metadata periodically */
|
||||
f2fs_balance_fs_bg(sbi, true);
|
||||
next:
|
||||
if (sbi->gc_mode != GC_NORMAL) {
|
||||
spin_lock(&sbi->gc_remaining_trials_lock);
|
||||
if (sbi->gc_remaining_trials) {
|
||||
sbi->gc_remaining_trials--;
|
||||
if (!sbi->gc_remaining_trials)
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
}
|
||||
spin_unlock(&sbi->gc_remaining_trials_lock);
|
||||
}
|
||||
sb_end_write(sbi->sb);
|
||||
|
||||
} while (!kthread_should_stop());
|
||||
@ -172,13 +171,10 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_gc_kthread *gc_th;
|
||||
dev_t dev = sbi->sb->s_bdev->bd_dev;
|
||||
int err = 0;
|
||||
|
||||
gc_th = f2fs_kmalloc(sbi, sizeof(struct f2fs_gc_kthread), GFP_KERNEL);
|
||||
if (!gc_th) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!gc_th)
|
||||
return -ENOMEM;
|
||||
|
||||
gc_th->urgent_sleep_time = DEF_GC_THREAD_URGENT_SLEEP_TIME;
|
||||
gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME;
|
||||
@ -193,12 +189,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)
|
||||
sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi,
|
||||
"f2fs_gc-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(gc_th->f2fs_gc_task)) {
|
||||
err = PTR_ERR(gc_th->f2fs_gc_task);
|
||||
int err = PTR_ERR(gc_th->f2fs_gc_task);
|
||||
|
||||
kfree(gc_th);
|
||||
sbi->gc_thread = NULL;
|
||||
return err;
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi)
|
||||
@ -1110,6 +1108,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
if (ofs_in_node >= max_addrs) {
|
||||
f2fs_err(sbi, "Inconsistent ofs_in_node:%u in summary, ino:%u, nid:%u, max:%u",
|
||||
ofs_in_node, dni->ino, dni->nid, max_addrs);
|
||||
f2fs_put_page(node_page, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1562,8 +1561,8 @@ next_step:
|
||||
continue;
|
||||
}
|
||||
|
||||
data_page = f2fs_get_read_data_page(inode,
|
||||
start_bidx, REQ_RAHEAD, true);
|
||||
data_page = f2fs_get_read_data_page(inode, start_bidx,
|
||||
REQ_RAHEAD, true, NULL);
|
||||
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
if (IS_ERR(data_page)) {
|
||||
iput(inode);
|
||||
@ -2132,8 +2131,6 @@ out_unlock:
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
set_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
|
||||
freeze_super(sbi->sb);
|
||||
f2fs_down_write(&sbi->gc_lock);
|
||||
f2fs_down_write(&sbi->cp_global_sem);
|
||||
@ -2149,6 +2146,7 @@ out_unlock:
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
set_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
err = free_segment_range(sbi, secs, false);
|
||||
if (err)
|
||||
goto recover_out;
|
||||
@ -2172,6 +2170,7 @@ out_unlock:
|
||||
f2fs_commit_super(sbi, false);
|
||||
}
|
||||
recover_out:
|
||||
clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_err(sbi, "resize_fs failed, should run fsck to repair!");
|
||||
@ -2184,6 +2183,5 @@ out_err:
|
||||
f2fs_up_write(&sbi->cp_global_sem);
|
||||
f2fs_up_write(&sbi->gc_lock);
|
||||
thaw_super(sbi->sb);
|
||||
clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
return err;
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ struct victim_entry {
|
||||
struct victim_info vi; /* victim info */
|
||||
};
|
||||
struct list_head list;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* inline functions
|
||||
|
@ -621,9 +621,12 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
|
||||
ri->i_uid = cpu_to_le32(i_uid_read(inode));
|
||||
ri->i_gid = cpu_to_le32(i_gid_read(inode));
|
||||
ri->i_links = cpu_to_le32(inode->i_nlink);
|
||||
ri->i_size = cpu_to_le64(i_size_read(inode));
|
||||
ri->i_blocks = cpu_to_le64(SECTOR_TO_BLOCK(inode->i_blocks) + 1);
|
||||
|
||||
if (!f2fs_is_atomic_file(inode) ||
|
||||
is_inode_flag_set(inode, FI_ATOMIC_COMMITTED))
|
||||
ri->i_size = cpu_to_le64(i_size_read(inode));
|
||||
|
||||
if (et) {
|
||||
read_lock(&et->lock);
|
||||
set_raw_extent(&et->largest, &ri->i_ext);
|
||||
|
392
fs/f2fs/namei.c
392
fs/f2fs/namei.c
@ -22,7 +22,185 @@
|
||||
#include "acl.h"
|
||||
#include <trace/events/f2fs.h>
|
||||
|
||||
static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
static inline int is_extension_exist(const unsigned char *s, const char *sub,
|
||||
bool tmp_ext)
|
||||
{
|
||||
size_t slen = strlen(s);
|
||||
size_t sublen = strlen(sub);
|
||||
int i;
|
||||
|
||||
if (sublen == 1 && *sub == '*')
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* filename format of multimedia file should be defined as:
|
||||
* "filename + '.' + extension + (optional: '.' + temp extension)".
|
||||
*/
|
||||
if (slen < sublen + 2)
|
||||
return 0;
|
||||
|
||||
if (!tmp_ext) {
|
||||
/* file has no temp extension */
|
||||
if (s[slen - sublen - 1] != '.')
|
||||
return 0;
|
||||
return !strncasecmp(s + slen - sublen, sub, sublen);
|
||||
}
|
||||
|
||||
for (i = 1; i < slen - sublen; i++) {
|
||||
if (s[i] != '.')
|
||||
continue;
|
||||
if (!strncasecmp(s + i + 1, sub, sublen))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
bool hot, bool set)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
int hot_count = sbi->raw_super->hot_ext_count;
|
||||
int total_count = cold_count + hot_count;
|
||||
int start, count;
|
||||
int i;
|
||||
|
||||
if (set) {
|
||||
if (total_count == F2FS_MAX_EXTENSION)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!hot && !cold_count)
|
||||
return -EINVAL;
|
||||
if (hot && !hot_count)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hot) {
|
||||
start = cold_count;
|
||||
count = total_count;
|
||||
} else {
|
||||
start = 0;
|
||||
count = cold_count;
|
||||
}
|
||||
|
||||
for (i = start; i < count; i++) {
|
||||
if (strcmp(name, extlist[i]))
|
||||
continue;
|
||||
|
||||
if (set)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(extlist[i], extlist[i + 1],
|
||||
F2FS_EXTENSION_LEN * (total_count - i - 1));
|
||||
memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
|
||||
if (hot)
|
||||
sbi->raw_super->hot_ext_count = hot_count - 1;
|
||||
else
|
||||
sbi->raw_super->extension_count =
|
||||
cpu_to_le32(cold_count - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!set)
|
||||
return -EINVAL;
|
||||
|
||||
if (hot) {
|
||||
memcpy(extlist[count], name, strlen(name));
|
||||
sbi->raw_super->hot_ext_count = hot_count + 1;
|
||||
} else {
|
||||
char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
|
||||
|
||||
memcpy(buf, &extlist[cold_count],
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
|
||||
memcpy(extlist[cold_count], name, strlen(name));
|
||||
memcpy(&extlist[cold_count + 1], buf,
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
|
||||
struct inode *inode, const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
unsigned char (*noext)[F2FS_EXTENSION_LEN] =
|
||||
F2FS_OPTION(sbi).noextensions;
|
||||
unsigned char (*ext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).extensions;
|
||||
unsigned char ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
|
||||
unsigned char noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
if (!f2fs_sb_has_compression(sbi) || !name)
|
||||
return;
|
||||
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
|
||||
return;
|
||||
|
||||
/* Inherit the compression flag in directory */
|
||||
if ((F2FS_I(dir)->i_flags & F2FS_COMPR_FL)) {
|
||||
set_compress_context(inode);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start to check extension list */
|
||||
if (!ext_cnt)
|
||||
return;
|
||||
|
||||
/* Don't compress hot files. */
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
for (i = cold_count; i < cold_count + hot_count; i++)
|
||||
if (is_extension_exist(name, extlist[i], false))
|
||||
break;
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
if (i < (cold_count + hot_count))
|
||||
return;
|
||||
|
||||
/* Don't compress unallowed extension. */
|
||||
for (i = 0; i < noext_cnt; i++)
|
||||
if (is_extension_exist(name, noext[i], false))
|
||||
return;
|
||||
|
||||
/* Compress wanting extension. */
|
||||
for (i = 0; i < ext_cnt; i++) {
|
||||
if (is_extension_exist(name, ext[i], false)) {
|
||||
set_compress_context(inode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set file's temperature for hot/cold data separation
|
||||
*/
|
||||
static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
for (i = 0; i < cold_count + hot_count; i++)
|
||||
if (is_extension_exist(name, extlist[i], true))
|
||||
break;
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
|
||||
if (i == cold_count + hot_count)
|
||||
return;
|
||||
|
||||
if (i < cold_count)
|
||||
file_set_cold(inode);
|
||||
else
|
||||
file_set_hot(inode);
|
||||
}
|
||||
|
||||
static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode,
|
||||
const char *name)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
|
||||
nid_t ino;
|
||||
@ -108,17 +286,16 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL)
|
||||
set_inode_flag(inode, FI_PROJ_INHERIT);
|
||||
|
||||
if (f2fs_sb_has_compression(sbi)) {
|
||||
/* Inherit the compression flag in directory */
|
||||
if ((F2FS_I(dir)->i_flags & F2FS_COMPR_FL) &&
|
||||
f2fs_may_compress(inode))
|
||||
set_compress_context(inode);
|
||||
}
|
||||
/* Check compression first. */
|
||||
set_compress_new_inode(sbi, dir, inode, name);
|
||||
|
||||
/* Should enable inline_data after compression set */
|
||||
if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
|
||||
set_inode_flag(inode, FI_INLINE_DATA);
|
||||
|
||||
if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
|
||||
set_file_temperature(sbi, inode, name);
|
||||
|
||||
stat_inc_inline_xattr(inode);
|
||||
stat_inc_inline_inode(inode);
|
||||
stat_inc_inline_dir(inode);
|
||||
@ -147,188 +324,6 @@ fail_drop:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static inline int is_extension_exist(const unsigned char *s, const char *sub,
|
||||
bool tmp_ext)
|
||||
{
|
||||
size_t slen = strlen(s);
|
||||
size_t sublen = strlen(sub);
|
||||
int i;
|
||||
|
||||
if (sublen == 1 && *sub == '*')
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* filename format of multimedia file should be defined as:
|
||||
* "filename + '.' + extension + (optional: '.' + temp extension)".
|
||||
*/
|
||||
if (slen < sublen + 2)
|
||||
return 0;
|
||||
|
||||
if (!tmp_ext) {
|
||||
/* file has no temp extension */
|
||||
if (s[slen - sublen - 1] != '.')
|
||||
return 0;
|
||||
return !strncasecmp(s + slen - sublen, sub, sublen);
|
||||
}
|
||||
|
||||
for (i = 1; i < slen - sublen; i++) {
|
||||
if (s[i] != '.')
|
||||
continue;
|
||||
if (!strncasecmp(s + i + 1, sub, sublen))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set file's temperature for hot/cold data separation
|
||||
*/
|
||||
static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
|
||||
for (i = 0; i < cold_count + hot_count; i++) {
|
||||
if (is_extension_exist(name, extlist[i], true))
|
||||
break;
|
||||
}
|
||||
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
|
||||
if (i == cold_count + hot_count)
|
||||
return;
|
||||
|
||||
if (i < cold_count)
|
||||
file_set_cold(inode);
|
||||
else
|
||||
file_set_hot(inode);
|
||||
}
|
||||
|
||||
int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
bool hot, bool set)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
int hot_count = sbi->raw_super->hot_ext_count;
|
||||
int total_count = cold_count + hot_count;
|
||||
int start, count;
|
||||
int i;
|
||||
|
||||
if (set) {
|
||||
if (total_count == F2FS_MAX_EXTENSION)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!hot && !cold_count)
|
||||
return -EINVAL;
|
||||
if (hot && !hot_count)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hot) {
|
||||
start = cold_count;
|
||||
count = total_count;
|
||||
} else {
|
||||
start = 0;
|
||||
count = cold_count;
|
||||
}
|
||||
|
||||
for (i = start; i < count; i++) {
|
||||
if (strcmp(name, extlist[i]))
|
||||
continue;
|
||||
|
||||
if (set)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(extlist[i], extlist[i + 1],
|
||||
F2FS_EXTENSION_LEN * (total_count - i - 1));
|
||||
memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
|
||||
if (hot)
|
||||
sbi->raw_super->hot_ext_count = hot_count - 1;
|
||||
else
|
||||
sbi->raw_super->extension_count =
|
||||
cpu_to_le32(cold_count - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!set)
|
||||
return -EINVAL;
|
||||
|
||||
if (hot) {
|
||||
memcpy(extlist[count], name, strlen(name));
|
||||
sbi->raw_super->hot_ext_count = hot_count + 1;
|
||||
} else {
|
||||
char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
|
||||
|
||||
memcpy(buf, &extlist[cold_count],
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
|
||||
memcpy(extlist[cold_count], name, strlen(name));
|
||||
memcpy(&extlist[cold_count + 1], buf,
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
unsigned char (*noext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).noextensions;
|
||||
unsigned char (*ext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).extensions;
|
||||
unsigned char ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
|
||||
unsigned char noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
if (!f2fs_sb_has_compression(sbi) ||
|
||||
F2FS_I(inode)->i_flags & F2FS_NOCOMP_FL ||
|
||||
!f2fs_may_compress(inode) ||
|
||||
(!ext_cnt && !noext_cnt))
|
||||
return;
|
||||
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
|
||||
for (i = cold_count; i < cold_count + hot_count; i++) {
|
||||
if (is_extension_exist(name, extlist[i], false)) {
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
|
||||
for (i = 0; i < noext_cnt; i++) {
|
||||
if (is_extension_exist(name, noext[i], false)) {
|
||||
f2fs_disable_compressed_file(inode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_inode_flag_set(inode, FI_COMPRESSED_FILE))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ext_cnt; i++) {
|
||||
if (!is_extension_exist(name, ext[i], false))
|
||||
continue;
|
||||
|
||||
/* Do not use inline_data with compression */
|
||||
stat_dec_inline_inode(inode);
|
||||
clear_inode_flag(inode, FI_INLINE_DATA);
|
||||
set_compress_context(inode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
bool excl)
|
||||
{
|
||||
@ -346,15 +341,10 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(dir, mode);
|
||||
inode = f2fs_new_inode(dir, mode, dentry->d_name.name);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
|
||||
set_file_temperature(sbi, inode, dentry->d_name.name);
|
||||
|
||||
set_compress_inode(sbi, inode, dentry->d_name.name);
|
||||
|
||||
inode->i_op = &f2fs_file_inode_operations;
|
||||
inode->i_fop = &f2fs_file_operations;
|
||||
inode->i_mapping->a_ops = &f2fs_dblock_aops;
|
||||
@ -627,6 +617,8 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
goto fail;
|
||||
}
|
||||
f2fs_delete_entry(de, page, dir, inode);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
/* VFS negative dentries are incompatible with Encoding and
|
||||
* Case-insensitiveness. Eventually we'll want avoid
|
||||
@ -637,8 +629,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
if (IS_CASEFOLDED(dir))
|
||||
d_invalidate(dentry);
|
||||
#endif
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
if (IS_DIRSYNC(dir))
|
||||
f2fs_sync_fs(sbi->sb, 1);
|
||||
fail:
|
||||
@ -684,7 +674,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
|
||||
inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
@ -754,7 +744,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(dir, S_IFDIR | mode);
|
||||
inode = f2fs_new_inode(dir, S_IFDIR | mode, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
@ -811,7 +801,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(dir, mode);
|
||||
inode = f2fs_new_inode(dir, mode, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
@ -850,7 +840,7 @@ static int __f2fs_tmpfile(struct inode *dir,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(dir, mode);
|
||||
inode = f2fs_new_inode(dir, mode, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
|
@ -1358,8 +1358,7 @@ static int read_node_page(struct page *page, int op_flags)
|
||||
return err;
|
||||
|
||||
/* NEW_ADDR can be seen, after cp_error drops some dirty node pages */
|
||||
if (unlikely(ni.blk_addr == NULL_ADDR || ni.blk_addr == NEW_ADDR) ||
|
||||
is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN)) {
|
||||
if (unlikely(ni.blk_addr == NULL_ADDR || ni.blk_addr == NEW_ADDR)) {
|
||||
ClearPageUptodate(page);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -191,14 +191,19 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)
|
||||
if (!f2fs_is_atomic_file(inode))
|
||||
return;
|
||||
|
||||
if (clean)
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
clear_inode_flag(fi->cow_inode, FI_COW_FILE);
|
||||
iput(fi->cow_inode);
|
||||
fi->cow_inode = NULL;
|
||||
release_atomic_write_cnt(inode);
|
||||
clear_inode_flag(inode, FI_ATOMIC_COMMITTED);
|
||||
clear_inode_flag(inode, FI_ATOMIC_REPLACE);
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
stat_dec_atomic_inode(inode);
|
||||
|
||||
if (clean) {
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
f2fs_i_size_write(inode, fi->original_i_size);
|
||||
}
|
||||
}
|
||||
|
||||
static int __replace_atomic_write_block(struct inode *inode, pgoff_t index,
|
||||
@ -256,14 +261,24 @@ static void __complete_revoke_list(struct inode *inode, struct list_head *head,
|
||||
bool revoke)
|
||||
{
|
||||
struct revoke_entry *cur, *tmp;
|
||||
pgoff_t start_index = 0;
|
||||
bool truncate = is_inode_flag_set(inode, FI_ATOMIC_REPLACE);
|
||||
|
||||
list_for_each_entry_safe(cur, tmp, head, list) {
|
||||
if (revoke)
|
||||
if (revoke) {
|
||||
__replace_atomic_write_block(inode, cur->index,
|
||||
cur->old_addr, NULL, true);
|
||||
} else if (truncate) {
|
||||
f2fs_truncate_hole(inode, start_index, cur->index);
|
||||
start_index = cur->index + 1;
|
||||
}
|
||||
|
||||
list_del(&cur->list);
|
||||
kmem_cache_free(revoke_entry_slab, cur);
|
||||
}
|
||||
|
||||
if (!revoke && truncate)
|
||||
f2fs_do_truncate_blocks(inode, start_index * PAGE_SIZE, false);
|
||||
}
|
||||
|
||||
static int __f2fs_commit_atomic_write(struct inode *inode)
|
||||
@ -334,10 +349,12 @@ next:
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sbi->revoked_atomic_block += fi->atomic_write_cnt;
|
||||
else
|
||||
} else {
|
||||
sbi->committed_atomic_block += fi->atomic_write_cnt;
|
||||
set_inode_flag(inode, FI_ATOMIC_COMMITTED);
|
||||
}
|
||||
|
||||
__complete_revoke_list(inode, &revoke_list, ret ? true : false);
|
||||
|
||||
@ -619,12 +636,11 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
dev_t dev = sbi->sb->s_bdev->bd_dev;
|
||||
struct flush_cmd_control *fcc;
|
||||
int err = 0;
|
||||
|
||||
if (SM_I(sbi)->fcc_info) {
|
||||
fcc = SM_I(sbi)->fcc_info;
|
||||
if (fcc->f2fs_issue_flush)
|
||||
return err;
|
||||
return 0;
|
||||
goto init_thread;
|
||||
}
|
||||
|
||||
@ -637,19 +653,20 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
||||
init_llist_head(&fcc->issue_list);
|
||||
SM_I(sbi)->fcc_info = fcc;
|
||||
if (!test_opt(sbi, FLUSH_MERGE))
|
||||
return err;
|
||||
return 0;
|
||||
|
||||
init_thread:
|
||||
fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
|
||||
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(fcc->f2fs_issue_flush)) {
|
||||
err = PTR_ERR(fcc->f2fs_issue_flush);
|
||||
int err = PTR_ERR(fcc->f2fs_issue_flush);
|
||||
|
||||
kfree(fcc);
|
||||
SM_I(sbi)->fcc_info = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
|
||||
@ -855,7 +872,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi)
|
||||
}
|
||||
mutex_unlock(&dirty_i->seglist_lock);
|
||||
|
||||
unusable = holes[DATA] > holes[NODE] ? holes[DATA] : holes[NODE];
|
||||
unusable = max(holes[DATA], holes[NODE]);
|
||||
if (unusable > ovp_holes)
|
||||
return unusable - ovp_holes;
|
||||
return 0;
|
||||
@ -1449,7 +1466,7 @@ retry:
|
||||
if (i + 1 < dpolicy->granularity)
|
||||
break;
|
||||
|
||||
if (i < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered)
|
||||
if (i + 1 < dcc->max_ordered_discard && dpolicy->ordered)
|
||||
return __issue_discard_cmd_orderly(sbi, dpolicy);
|
||||
|
||||
pend_list = &dcc->pend_list[i];
|
||||
@ -2025,8 +2042,10 @@ int f2fs_start_discard_thread(struct f2fs_sb_info *sbi)
|
||||
|
||||
dcc->f2fs_issue_discard = kthread_run(issue_discard_thread, sbi,
|
||||
"f2fs_discard-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(dcc->f2fs_issue_discard))
|
||||
if (IS_ERR(dcc->f2fs_issue_discard)) {
|
||||
err = PTR_ERR(dcc->f2fs_issue_discard);
|
||||
dcc->f2fs_issue_discard = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -2046,6 +2065,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
|
||||
return -ENOMEM;
|
||||
|
||||
dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;
|
||||
dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY;
|
||||
if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT)
|
||||
dcc->discard_granularity = sbi->blocks_per_seg;
|
||||
else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
|
||||
|
@ -59,6 +59,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
|
||||
[FAULT_SLAB_ALLOC] = "slab alloc",
|
||||
[FAULT_DQUOT_INIT] = "dquot initialize",
|
||||
[FAULT_LOCK_OP] = "lock_op",
|
||||
[FAULT_BLKADDR] = "invalid blkaddr",
|
||||
};
|
||||
|
||||
void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
|
||||
@ -108,6 +109,7 @@ enum {
|
||||
Opt_noinline_dentry,
|
||||
Opt_flush_merge,
|
||||
Opt_noflush_merge,
|
||||
Opt_barrier,
|
||||
Opt_nobarrier,
|
||||
Opt_fastboot,
|
||||
Opt_extent_cache,
|
||||
@ -184,6 +186,7 @@ static match_table_t f2fs_tokens = {
|
||||
{Opt_noinline_dentry, "noinline_dentry"},
|
||||
{Opt_flush_merge, "flush_merge"},
|
||||
{Opt_noflush_merge, "noflush_merge"},
|
||||
{Opt_barrier, "barrier"},
|
||||
{Opt_nobarrier, "nobarrier"},
|
||||
{Opt_fastboot, "fastboot"},
|
||||
{Opt_extent_cache, "extent_cache"},
|
||||
@ -799,6 +802,9 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
|
||||
case Opt_nobarrier:
|
||||
set_opt(sbi, NOBARRIER);
|
||||
break;
|
||||
case Opt_barrier:
|
||||
clear_opt(sbi, NOBARRIER);
|
||||
break;
|
||||
case Opt_fastboot:
|
||||
set_opt(sbi, FASTBOOT);
|
||||
break;
|
||||
@ -1332,6 +1338,12 @@ default_check:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((f2fs_sb_has_readonly(sbi) || f2fs_readonly(sbi->sb))
|
||||
&& test_opt(sbi, FLUSH_MERGE)) {
|
||||
f2fs_err(sbi, "FLUSH_MERGE not compatible with readonly mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
|
||||
f2fs_err(sbi, "Allow to mount readonly mode only");
|
||||
return -EROFS;
|
||||
@ -1928,10 +1940,14 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
|
||||
seq_puts(seq, ",inline_dentry");
|
||||
else
|
||||
seq_puts(seq, ",noinline_dentry");
|
||||
if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE))
|
||||
if (test_opt(sbi, FLUSH_MERGE))
|
||||
seq_puts(seq, ",flush_merge");
|
||||
else
|
||||
seq_puts(seq, ",noflush_merge");
|
||||
if (test_opt(sbi, NOBARRIER))
|
||||
seq_puts(seq, ",nobarrier");
|
||||
else
|
||||
seq_puts(seq, ",barrier");
|
||||
if (test_opt(sbi, FASTBOOT))
|
||||
seq_puts(seq, ",fastboot");
|
||||
if (test_opt(sbi, EXTENT_CACHE))
|
||||
@ -2061,7 +2077,8 @@ static void default_options(struct f2fs_sb_info *sbi)
|
||||
set_opt(sbi, MERGE_CHECKPOINT);
|
||||
F2FS_OPTION(sbi).unusable_cap = 0;
|
||||
sbi->sb->s_flags |= SB_LAZYTIME;
|
||||
set_opt(sbi, FLUSH_MERGE);
|
||||
if (!(f2fs_sb_has_readonly(sbi) || f2fs_readonly(sbi->sb)))
|
||||
set_opt(sbi, FLUSH_MERGE);
|
||||
if (f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi))
|
||||
set_opt(sbi, DISCARD);
|
||||
if (f2fs_sb_has_blkzoned(sbi)) {
|
||||
@ -3627,7 +3644,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
|
||||
sbi->migration_granularity = sbi->segs_per_sec;
|
||||
sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
|
||||
sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
|
||||
spin_lock_init(&sbi->gc_urgent_high_lock);
|
||||
spin_lock_init(&sbi->gc_remaining_trials_lock);
|
||||
atomic64_set(&sbi->current_atomic_write, 0);
|
||||
|
||||
sbi->dir_level = DEF_DIR_LEVEL;
|
||||
@ -4093,6 +4110,24 @@ try_onemore:
|
||||
|
||||
sbi->sb = sb;
|
||||
|
||||
/* initialize locks within allocated memory */
|
||||
init_f2fs_rwsem(&sbi->gc_lock);
|
||||
mutex_init(&sbi->writepages);
|
||||
init_f2fs_rwsem(&sbi->cp_global_sem);
|
||||
init_f2fs_rwsem(&sbi->node_write);
|
||||
init_f2fs_rwsem(&sbi->node_change);
|
||||
spin_lock_init(&sbi->stat_lock);
|
||||
init_f2fs_rwsem(&sbi->cp_rwsem);
|
||||
init_f2fs_rwsem(&sbi->quota_sem);
|
||||
init_waitqueue_head(&sbi->cp_wait);
|
||||
spin_lock_init(&sbi->error_lock);
|
||||
|
||||
for (i = 0; i < NR_INODE_TYPE; i++) {
|
||||
INIT_LIST_HEAD(&sbi->inode_list[i]);
|
||||
spin_lock_init(&sbi->inode_lock[i]);
|
||||
}
|
||||
mutex_init(&sbi->flush_lock);
|
||||
|
||||
/* Load the checksum driver */
|
||||
sbi->s_chksum_driver = crypto_alloc_shash("crc32", 0, 0);
|
||||
if (IS_ERR(sbi->s_chksum_driver)) {
|
||||
@ -4116,6 +4151,8 @@ try_onemore:
|
||||
sb->s_fs_info = sbi;
|
||||
sbi->raw_super = raw_super;
|
||||
|
||||
memcpy(sbi->errors, raw_super->s_errors, MAX_F2FS_ERRORS);
|
||||
|
||||
/* precompute checksum seed for metadata */
|
||||
if (f2fs_sb_has_inode_chksum(sbi))
|
||||
sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid,
|
||||
@ -4172,23 +4209,14 @@ try_onemore:
|
||||
|
||||
/* init f2fs-specific super block info */
|
||||
sbi->valid_super_block = valid_super_block;
|
||||
init_f2fs_rwsem(&sbi->gc_lock);
|
||||
mutex_init(&sbi->writepages);
|
||||
init_f2fs_rwsem(&sbi->cp_global_sem);
|
||||
init_f2fs_rwsem(&sbi->node_write);
|
||||
init_f2fs_rwsem(&sbi->node_change);
|
||||
|
||||
/* disallow all the data/node/meta page writes */
|
||||
set_sbi_flag(sbi, SBI_POR_DOING);
|
||||
spin_lock_init(&sbi->stat_lock);
|
||||
|
||||
err = f2fs_init_write_merge_io(sbi);
|
||||
if (err)
|
||||
goto free_bio_info;
|
||||
|
||||
init_f2fs_rwsem(&sbi->cp_rwsem);
|
||||
init_f2fs_rwsem(&sbi->quota_sem);
|
||||
init_waitqueue_head(&sbi->cp_wait);
|
||||
init_sb_info(sbi);
|
||||
|
||||
err = f2fs_init_iostat(sbi);
|
||||
@ -4253,9 +4281,6 @@ try_onemore:
|
||||
goto free_devices;
|
||||
}
|
||||
|
||||
spin_lock_init(&sbi->error_lock);
|
||||
memcpy(sbi->errors, raw_super->s_errors, MAX_F2FS_ERRORS);
|
||||
|
||||
sbi->total_valid_node_count =
|
||||
le32_to_cpu(sbi->ckpt->valid_node_count);
|
||||
percpu_counter_set(&sbi->total_valid_inode_count,
|
||||
@ -4269,12 +4294,6 @@ try_onemore:
|
||||
limit_reserve_root(sbi);
|
||||
adjust_unusable_cap_perc(sbi);
|
||||
|
||||
for (i = 0; i < NR_INODE_TYPE; i++) {
|
||||
INIT_LIST_HEAD(&sbi->inode_list[i]);
|
||||
spin_lock_init(&sbi->inode_lock[i]);
|
||||
}
|
||||
mutex_init(&sbi->flush_lock);
|
||||
|
||||
f2fs_init_extent_cache_info(sbi);
|
||||
|
||||
f2fs_init_ino_entry_info(sbi);
|
||||
@ -4510,9 +4529,9 @@ free_nm:
|
||||
f2fs_destroy_node_manager(sbi);
|
||||
free_sm:
|
||||
f2fs_destroy_segment_manager(sbi);
|
||||
f2fs_destroy_post_read_wq(sbi);
|
||||
stop_ckpt_thread:
|
||||
f2fs_stop_ckpt_thread(sbi);
|
||||
f2fs_destroy_post_read_wq(sbi);
|
||||
free_devices:
|
||||
destroy_device_list(sbi);
|
||||
kvfree(sbi->ckpt);
|
||||
|
@ -143,6 +143,12 @@ static ssize_t pending_discard_show(struct f2fs_attr *a,
|
||||
&SM_I(sbi)->dcc_info->discard_cmd_cnt));
|
||||
}
|
||||
|
||||
static ssize_t gc_mode_show(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", gc_mode_names[sbi->gc_mode]);
|
||||
}
|
||||
|
||||
static ssize_t features_show(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi, char *buf)
|
||||
{
|
||||
@ -340,10 +346,6 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
gc_mode_names[sbi->gc_mode]);
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_segment_mode"))
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
gc_mode_names[sbi->gc_segment_mode]);
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_reclaimed_segments")) {
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
||||
sbi->gc_reclaimed_segs[sbi->gc_segment_mode]);
|
||||
@ -491,14 +493,20 @@ out:
|
||||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(a->attr.name, "max_ordered_discard")) {
|
||||
if (t == 0 || t > MAX_PLIST_NUM)
|
||||
return -EINVAL;
|
||||
if (!f2fs_block_unit_discard(sbi))
|
||||
return -EINVAL;
|
||||
*ui = t;
|
||||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(a->attr.name, "migration_granularity")) {
|
||||
if (t == 0 || t > sbi->segs_per_sec)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(a->attr.name, "trim_sections"))
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_urgent")) {
|
||||
if (t == 0) {
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
@ -539,10 +547,10 @@ out:
|
||||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_urgent_high_remaining")) {
|
||||
spin_lock(&sbi->gc_urgent_high_lock);
|
||||
sbi->gc_urgent_high_remaining = t;
|
||||
spin_unlock(&sbi->gc_urgent_high_lock);
|
||||
if (!strcmp(a->attr.name, "gc_remaining_trials")) {
|
||||
spin_lock(&sbi->gc_remaining_trials_lock);
|
||||
sbi->gc_remaining_trials = t;
|
||||
spin_unlock(&sbi->gc_remaining_trials_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -789,8 +797,8 @@ F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, min_discard_issue_time, min_discard_
|
||||
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(DCC_INFO, discard_cmd_control, max_ordered_discard, max_ordered_discard);
|
||||
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);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
|
||||
@ -825,7 +833,7 @@ 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_RW_ATTR(F2FS_SBI, f2fs_sb_info, node_io_flag, node_io_flag);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent_high_remaining, gc_urgent_high_remaining);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_remaining_trials, gc_remaining_trials);
|
||||
F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, ckpt_thread_ioprio, ckpt_thread_ioprio);
|
||||
F2FS_GENERAL_RO_ATTR(dirty_segments);
|
||||
F2FS_GENERAL_RO_ATTR(free_segments);
|
||||
@ -838,6 +846,7 @@ F2FS_GENERAL_RO_ATTR(encoding);
|
||||
F2FS_GENERAL_RO_ATTR(mounted_time_sec);
|
||||
F2FS_GENERAL_RO_ATTR(main_blkaddr);
|
||||
F2FS_GENERAL_RO_ATTR(pending_discard);
|
||||
F2FS_GENERAL_RO_ATTR(gc_mode);
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_foreground_calls, cp_count);
|
||||
F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_background_calls, bg_cp_count);
|
||||
@ -915,8 +924,9 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(mid_discard_issue_time),
|
||||
ATTR_LIST(max_discard_issue_time),
|
||||
ATTR_LIST(discard_granularity),
|
||||
ATTR_LIST(max_ordered_discard),
|
||||
ATTR_LIST(pending_discard),
|
||||
ATTR_LIST(batched_trim_sections),
|
||||
ATTR_LIST(gc_mode),
|
||||
ATTR_LIST(ipu_policy),
|
||||
ATTR_LIST(min_ipu_util),
|
||||
ATTR_LIST(min_fsync_blocks),
|
||||
@ -949,7 +959,7 @@ static struct attribute *f2fs_attrs[] = {
|
||||
#endif
|
||||
ATTR_LIST(data_io_flag),
|
||||
ATTR_LIST(node_io_flag),
|
||||
ATTR_LIST(gc_urgent_high_remaining),
|
||||
ATTR_LIST(gc_remaining_trials),
|
||||
ATTR_LIST(ckpt_thread_ioprio),
|
||||
ATTR_LIST(dirty_segments),
|
||||
ATTR_LIST(free_segments),
|
||||
@ -1232,6 +1242,44 @@ static int __maybe_unused victim_bits_seq_show(struct seq_file *seq,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused discard_plist_seq_show(struct seq_file *seq,
|
||||
void *offset)
|
||||
{
|
||||
struct super_block *sb = seq->private;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||
int i, count;
|
||||
|
||||
seq_puts(seq, "Discard pend list(Show diacrd_cmd count on each entry, .:not exist):\n");
|
||||
if (!f2fs_realtime_discard_enable(sbi))
|
||||
return 0;
|
||||
|
||||
if (dcc) {
|
||||
mutex_lock(&dcc->cmd_lock);
|
||||
for (i = 0; i < MAX_PLIST_NUM; i++) {
|
||||
struct list_head *pend_list;
|
||||
struct discard_cmd *dc, *tmp;
|
||||
|
||||
if (i % 8 == 0)
|
||||
seq_printf(seq, " %-3d", i);
|
||||
count = 0;
|
||||
pend_list = &dcc->pend_list[i];
|
||||
list_for_each_entry_safe(dc, tmp, pend_list, list)
|
||||
count++;
|
||||
if (count)
|
||||
seq_printf(seq, " %7d", count);
|
||||
else
|
||||
seq_puts(seq, " .");
|
||||
if (i % 8 == 7)
|
||||
seq_putc(seq, '\n');
|
||||
}
|
||||
seq_putc(seq, '\n');
|
||||
mutex_unlock(&dcc->cmd_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init f2fs_init_sysfs(void)
|
||||
{
|
||||
int ret;
|
||||
@ -1302,6 +1350,8 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi)
|
||||
#endif
|
||||
proc_create_single_data("victim_bits", 0444, sbi->s_proc,
|
||||
victim_bits_seq_show, sb);
|
||||
proc_create_single_data("discard_plist_info", 0444, sbi->s_proc,
|
||||
discard_plist_seq_show, sb);
|
||||
}
|
||||
return 0;
|
||||
put_feature_list_kobj:
|
||||
@ -1325,6 +1375,7 @@ void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi)
|
||||
remove_proc_entry("segment_info", sbi->s_proc);
|
||||
remove_proc_entry("segment_bits", sbi->s_proc);
|
||||
remove_proc_entry("victim_bits", sbi->s_proc);
|
||||
remove_proc_entry("discard_plist_info", sbi->s_proc);
|
||||
remove_proc_entry(sbi->sb->s_id, f2fs_proc_root);
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@
|
||||
struct f2fs_comp_option)
|
||||
#define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23)
|
||||
#define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24)
|
||||
#define F2FS_IOC_START_ATOMIC_REPLACE _IO(F2FS_IOCTL_MAGIC, 25)
|
||||
|
||||
/*
|
||||
* should be same as XFS_IOC_GOINGDOWN.
|
||||
|
Loading…
Reference in New Issue
Block a user