[f2fs-dev] [PATCH] f2fs: fix to create selinux label during whiteout initialization
generic/700 - output mismatch (see /media/fstests/results//generic/700.out.bad) --- tests/generic/700.out 2023-03-28 10:40:42.735529223 + +++ /media/fstests/results//generic/700.out.bad 2024-02-06 04:37:56.0 + @@ -1,2 +1,4 @@ QA output created by 700 +/mnt/scratch_f2fs/f1: security.selinux: No such attribute +/mnt/scratch_f2fs/f2: security.selinux: No such attribute Silence is golden ... (Run 'diff -u /media/fstests/tests/generic/700.out /media/fstests/results//generic/700.out.bad' to see the entire diff) HINT: You _MAY_ be missing kernel fix: 70b589a37e1a xfs: add selinux labels to whiteout inodes Previously, it missed to create selinux labels during whiteout inode initialization, fix this issue. Fixes: 7e01e7ad746b ("f2fs: support RENAME_WHITEOUT") Signed-off-by: Chao Yu --- fs/f2fs/dir.c | 5 +++-- fs/f2fs/f2fs.h | 3 ++- fs/f2fs/namei.c | 25 + 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 3f20d94e12f9..02c9355176d3 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -830,13 +830,14 @@ int f2fs_do_add_link(struct inode *dir, const struct qstr *name, return err; } -int f2fs_do_tmpfile(struct inode *inode, struct inode *dir) +int f2fs_do_tmpfile(struct inode *inode, struct inode *dir, + struct f2fs_filename *fname) { struct page *page; int err = 0; f2fs_down_write(_I(inode)->i_sem); - page = f2fs_init_inode_metadata(inode, dir, NULL, NULL); + page = f2fs_init_inode_metadata(inode, dir, fname, NULL); if (IS_ERR(page)) { err = PTR_ERR(page); goto fail; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d44e2c43d8ab..af766404f454 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3589,7 +3589,8 @@ int f2fs_do_add_link(struct inode *dir, const struct qstr *name, struct inode *inode, nid_t ino, umode_t mode); void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, struct inode *dir, struct inode *inode); -int f2fs_do_tmpfile(struct inode *inode, struct inode *dir); +int f2fs_do_tmpfile(struct inode *inode, struct inode *dir, + struct f2fs_filename *fname); bool f2fs_empty_dir(struct inode *dir); static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index ba11298b7837..0875602e2406 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -852,7 +852,7 @@ static int f2fs_mknod(struct mnt_idmap *idmap, struct inode *dir, static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, struct file *file, umode_t mode, bool is_whiteout, - struct inode **new_inode) + struct inode **new_inode, struct f2fs_filename *fname) { struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; @@ -880,7 +880,7 @@ static int __f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, if (err) goto out; - err = f2fs_do_tmpfile(inode, dir); + err = f2fs_do_tmpfile(inode, dir, fname); if (err) goto release_out; @@ -931,22 +931,24 @@ static int f2fs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, if (!f2fs_is_checkpoint_ready(sbi)) return -ENOSPC; - err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL); + err = __f2fs_tmpfile(idmap, dir, file, mode, false, NULL, NULL); return finish_open_simple(file, err); } static int f2fs_create_whiteout(struct mnt_idmap *idmap, - struct inode *dir, struct inode **whiteout) + struct inode *dir, struct inode **whiteout, + struct f2fs_filename *fname) { - return __f2fs_tmpfile(idmap, dir, NULL, - S_IFCHR | WHITEOUT_MODE, true, whiteout); + return __f2fs_tmpfile(idmap, dir, NULL, S_IFCHR | WHITEOUT_MODE, + true, whiteout, fname); } int f2fs_get_tmpfile(struct mnt_idmap *idmap, struct inode *dir, struct inode **new_inode) { - return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG, false, new_inode); + return __f2fs_tmpfile(idmap, dir, NULL, S_IFREG, + false, new_inode, NULL); } static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, @@ -990,7 +992,14 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir, } if (flags & RENAME_WHITEOUT) { - err = f2fs_create_whiteout(idmap, old_dir, ); + struct f2fs_filename fname; + + err = f2fs_setup_filename(old_dir, _dentry->d_name, +
[f2fs-dev] [RESEND PATCH v9 2/2] f2fs: Simplify the handling of cached insensitive names
From: Gabriel Krisman Bertazi Keeping it as qstr avoids the unnecessary conversion in f2fs_match Reviewed-by: Eric Biggers Signed-off-by: Gabriel Krisman Bertazi [eugen.hris...@collabora.com: port to 6.8-rc3] Signed-off-by: Eugen Hristev --- fs/f2fs/dir.c | 53 ++ fs/f2fs/f2fs.h | 17 ++- fs/f2fs/recovery.c | 5 + 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 3f20d94e12f9..f5b65cf36393 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -42,35 +42,49 @@ static unsigned int bucket_blocks(unsigned int level) return 4; } +#if IS_ENABLED(CONFIG_UNICODE) /* If @dir is casefolded, initialize @fname->cf_name from @fname->usr_fname. */ int f2fs_init_casefolded_name(const struct inode *dir, struct f2fs_filename *fname) { -#if IS_ENABLED(CONFIG_UNICODE) struct super_block *sb = dir->i_sb; + unsigned char *buf; + int len; if (IS_CASEFOLDED(dir) && !is_dot_dotdot(fname->usr_fname->name, fname->usr_fname->len)) { - fname->cf_name.name = f2fs_kmem_cache_alloc(f2fs_cf_name_slab, - GFP_NOFS, false, F2FS_SB(sb)); - if (!fname->cf_name.name) + buf = f2fs_kmem_cache_alloc(f2fs_cf_name_slab, + GFP_NOFS, false, F2FS_SB(sb)); + if (!buf) return -ENOMEM; - fname->cf_name.len = utf8_casefold(sb->s_encoding, - fname->usr_fname, - fname->cf_name.name, - F2FS_NAME_LEN); - if ((int)fname->cf_name.len <= 0) { - kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name); - fname->cf_name.name = NULL; + + len = utf8_casefold(sb->s_encoding, fname->usr_fname, + buf, F2FS_NAME_LEN); + if (len <= 0) { + kmem_cache_free(f2fs_cf_name_slab, buf); if (sb_has_strict_encoding(sb)) return -EINVAL; /* fall back to treating name as opaque byte sequence */ + return 0; } + fname->cf_name.name = buf; + fname->cf_name.len = len; } -#endif + return 0; } +void f2fs_free_casefolded_name(struct f2fs_filename *fname) +{ + unsigned char *buf = (unsigned char *)fname->cf_name.name; + + if (buf) { + kmem_cache_free(f2fs_cf_name_slab, buf); + fname->cf_name.name = NULL; + } +} +#endif /* CONFIG_UNICODE */ + static int __f2fs_setup_filename(const struct inode *dir, const struct fscrypt_name *crypt_name, struct f2fs_filename *fname) @@ -142,12 +156,7 @@ void f2fs_free_filename(struct f2fs_filename *fname) kfree(fname->crypto_buf.name); fname->crypto_buf.name = NULL; #endif -#if IS_ENABLED(CONFIG_UNICODE) - if (fname->cf_name.name) { - kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name); - fname->cf_name.name = NULL; - } -#endif + f2fs_free_casefolded_name(fname); } static unsigned long dir_block_index(unsigned int level, @@ -235,11 +244,9 @@ static inline int f2fs_match_name(const struct inode *dir, struct fscrypt_name f; #if IS_ENABLED(CONFIG_UNICODE) - if (fname->cf_name.name) { - struct qstr cf = FSTR_TO_QSTR(>cf_name); - - return f2fs_match_ci_name(dir, , de_name, de_name_len); - } + if (fname->cf_name.name) + return f2fs_match_ci_name(dir, >cf_name, + de_name, de_name_len); #endif f.usr_fname = fname->usr_fname; f.disk_name = fname->disk_name; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 84c9fead3ad4..2ff8e52642ec 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -530,7 +530,7 @@ struct f2fs_filename { * internal operation where usr_fname is also NULL. In all these cases * we fall back to treating the name as an opaque byte sequence. */ - struct fscrypt_str cf_name; + struct qstr cf_name; #endif }; @@ -3533,8 +3533,23 @@ int f2fs_get_tmpfile(struct mnt_idmap *idmap, struct inode *dir, /* * dir.c */ +unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de); +#if IS_ENABLED(CONFIG_UNICODE) int f2fs_init_casefolded_name(const struct inode *dir, struct f2fs_filename *fname); +void f2fs_free_casefolded_name(struct f2fs_filename *fname); +#else +static inline int f2fs_init_casefolded_name(const struct inode *dir, +
[f2fs-dev] [RESEND PATCH v9 1/2] ext4: Simplify the handling of cached insensitive names
From: Gabriel Krisman Bertazi Keeping it as qstr avoids the unnecessary conversion in ext4_match Reviewed-by: Eric Biggers Signed-off-by: Gabriel Krisman Bertazi [eugen.hris...@collabora.com: port to 6.8-rc3] Signed-off-by: Eugen Hristev --- fs/ext4/ext4.h | 2 +- fs/ext4/namei.c | 23 +++ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 023571f8dd1b..932bae88b4a7 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2508,7 +2508,7 @@ struct ext4_filename { struct fscrypt_str crypto_buf; #endif #if IS_ENABLED(CONFIG_UNICODE) - struct fscrypt_str cf_name; + struct qstr cf_name; #endif }; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 05b647e6bc19..e554c5a62ba9 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1445,7 +1445,8 @@ static int ext4_ci_compare(const struct inode *parent, const struct qstr *name, int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, struct ext4_filename *name) { - struct fscrypt_str *cf_name = >cf_name; + struct qstr *cf_name = >cf_name; + unsigned char *buf; struct dx_hash_info *hinfo = >hinfo; int len; @@ -1455,18 +1456,18 @@ int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, return 0; } - cf_name->name = kmalloc(EXT4_NAME_LEN, GFP_NOFS); - if (!cf_name->name) + buf = kmalloc(EXT4_NAME_LEN, GFP_NOFS); + if (!buf) return -ENOMEM; - len = utf8_casefold(dir->i_sb->s_encoding, - iname, cf_name->name, - EXT4_NAME_LEN); + len = utf8_casefold(dir->i_sb->s_encoding, iname, buf, EXT4_NAME_LEN); if (len <= 0) { - kfree(cf_name->name); - cf_name->name = NULL; + kfree(buf); + buf = NULL; } + cf_name->name = buf; cf_name->len = (unsigned) len; + if (!IS_ENCRYPTED(dir)) return 0; @@ -1503,8 +1504,6 @@ static bool ext4_match(struct inode *parent, if (IS_CASEFOLDED(parent) && (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) { if (fname->cf_name.name) { - struct qstr cf = {.name = fname->cf_name.name, - .len = fname->cf_name.len}; if (IS_ENCRYPTED(parent)) { if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) || fname->hinfo.minor_hash != @@ -1513,8 +1512,8 @@ static bool ext4_match(struct inode *parent, return false; } } - return !ext4_ci_compare(parent, , de->name, - de->name_len, true); + return !ext4_ci_compare(parent, >cf_name, + de->name, de->name_len, true); } return !ext4_ci_compare(parent, fname->usr_fname, de->name, de->name_len, false); -- 2.34.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [RESEND PATCH v9 0/2] Minor cleanup for case insensitive path
Hello, I am trying to respin the series here : https://www.spinics.net/lists/linux-ext4/msg85081.html To make it easier to apply I split it into smaller chunks which address one single thing. This series will just convert to qstr the storage of the filename currently using fscrypt_str . Gabriel Krisman Bertazi (2): ext4: Simplify the handling of cached insensitive names f2fs: Simplify the handling of cached insensitive names fs/ext4/ext4.h | 2 +- fs/ext4/namei.c| 23 ++-- fs/f2fs/dir.c | 53 ++ fs/f2fs/f2fs.h | 16 +- fs/f2fs/recovery.c | 5 + 5 files changed, 58 insertions(+), 41 deletions(-) -- 2.34.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH] f2fs: support compress extension update via sysfs interface
Introduce /sys/fs/f2fs//compress_extension to support adding/deleting compress extension via sysfs interface, in comparison to mount option, it's more easy to use and less authority issue for applications. Usage: - Query: cat /sys/fs/f2fs//compress_extension - Add: echo '[c|n]extension' > /sys/fs/f2fs//compress_extension - Del: echo '[c|n]!extension' > /sys/fs/f2fs//compress_extension - [c] means add/del compress extension - [n] means add/del nocompress extension Signed-off-by: Sheng Yong Signed-off-by: Chao Yu --- Documentation/ABI/testing/sysfs-fs-f2fs | 10 Documentation/filesystems/f2fs.rst | 6 ++- fs/f2fs/compress.c | 61 +++ fs/f2fs/f2fs.h | 4 +- fs/f2fs/sysfs.c | 65 +++-- 5 files changed, 139 insertions(+), 7 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 48c135e24eb5..1f2cc0913e45 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -762,3 +762,13 @@ Date: November 2023 Contact: "Chao Yu" Description: It controls to enable/disable IO aware feature for background discard. By default, the value is 1 which indicates IO aware is on. + +What: /sys/fs/f2fs//compress_extension +Date: October 2023 +Contact: "Chao Yu" +Description: Used to control configure [|no]compress_extension list: + - Query: cat /sys/fs/f2fs//compress_extension + - Add: echo '[c|n]extension' > /sys/fs/f2fs//compress_extension + - Del: echo '[c|n]!extension' > /sys/fs/f2fs//compress_extension + - [c] means add/del compress extension + - [n] means add/del nocompress extension diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index 32cbfa864f38..c82a8fd7316b 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -821,17 +821,19 @@ Compression implementation all logical blocks in cluster contain valid data and compress ratio of cluster data is lower than specified threshold. -- To enable compression on regular inode, there are four ways: +- To enable compression on regular inode, there are five ways: * chattr +c file * chattr +c dir; touch dir/file * mount w/ -o compress_extension=ext; touch file.ext * mount w/ -o compress_extension=*; touch any_file + * echo '[c]ext' > /sys/fs/f2fs//compress_extension; touch file.ext -- To disable compression on regular inode, there are two ways: +- To disable compression on regular inode, there are three ways: * chattr -c file * mount w/ -o nocompress_extension=ext; touch file.ext + * echo '[n]ext' > /sys/fs/f2fs//compress_extension; touch file.ext - Priority in between FS_COMPR_FL, FS_NOCOMP_FS, extensions: diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 3dc488ce882b..a5257882c772 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -20,6 +20,67 @@ #include "segment.h" #include +static int is_compress_extension_exist(struct f2fs_sb_info *sbi, + unsigned char (*ext)[F2FS_EXTENSION_LEN], + int ext_cnt, unsigned char *new_ext) +{ + int i; + + for (i = 0; i < ext_cnt; i++) { + if (!strcasecmp(new_ext, ext[i])) + return i; + } + return -1; +} + +int f2fs_update_compress_extension(struct f2fs_sb_info *sbi, + unsigned char *new_ext, bool is_ext, bool set) +{ + unsigned char (*ext)[F2FS_EXTENSION_LEN]; + unsigned char *ext_cnt; + + if (is_ext) { + ext = F2FS_OPTION(sbi).extensions; + ext_cnt = _OPTION(sbi).compress_ext_cnt; + } else { + ext = F2FS_OPTION(sbi).noextensions; + ext_cnt = _OPTION(sbi).nocompress_ext_cnt; + } + + if (set) { + if (*ext_cnt >= COMPRESS_EXT_NUM) + return -EINVAL; + + if (is_compress_extension_exist(sbi, + F2FS_OPTION(sbi).extensions, + F2FS_OPTION(sbi).compress_ext_cnt, + new_ext) >= 0) + return -EEXIST; + + if (is_compress_extension_exist(sbi, + F2FS_OPTION(sbi).noextensions, + F2FS_OPTION(sbi).nocompress_ext_cnt, + new_ext) >= 0) + return -EEXIST; + + strcpy(ext[*ext_cnt], new_ext); + (*ext_cnt)++; + } else { + int pos = is_compress_extension_exist(sbi, ext, + *ext_cnt, new_ext); + if (pos < 0) +
Re: [f2fs-dev] [PATCH 3/3] f2fs: kill zone-capacity support
On 02/06, Jaegeuk Kim wrote: > Since we don't see any user, let's kill. > > Signed-off-by: Jaegeuk Kim > --- > Documentation/ABI/testing/sysfs-fs-f2fs | 6 -- > fs/f2fs/debug.c | 7 +- > fs/f2fs/f2fs.h | 5 -- > fs/f2fs/file.c | 6 +- > fs/f2fs/gc.c| 33 +++-- > fs/f2fs/gc.h| 26 --- > fs/f2fs/segment.c | 93 +++-- > fs/f2fs/segment.h | 41 --- > fs/f2fs/super.c | 16 + > fs/f2fs/sysfs.c | 6 -- > 10 files changed, 43 insertions(+), 196 deletions(-) > > diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs > b/Documentation/ABI/testing/sysfs-fs-f2fs > index 48c135e24eb5..dff8c87d87dd 100644 > --- a/Documentation/ABI/testing/sysfs-fs-f2fs > +++ b/Documentation/ABI/testing/sysfs-fs-f2fs > @@ -628,12 +628,6 @@ Contact: "Jaegeuk Kim" > Description: Controls max # of node block writes to be used for roll forward > recovery. This can limit the roll forward recovery time. > > -What:/sys/fs/f2fs//unusable_blocks_per_sec > -Date:June 2022 > -Contact: "Jaegeuk Kim" > -Description: Shows the number of unusable blocks in a section which was > defined by > - the zone capacity reported by underlying zoned device. > - > What:/sys/fs/f2fs//current_atomic_write > Date:July 2022 > Contact: "Daeho Jeong" > diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c > index 0d02224b99b7..6617195bd27e 100644 > --- a/fs/f2fs/debug.c > +++ b/fs/f2fs/debug.c > @@ -32,21 +32,20 @@ static struct dentry *f2fs_debugfs_root; > void f2fs_update_sit_info(struct f2fs_sb_info *sbi) > { > struct f2fs_stat_info *si = F2FS_STAT(sbi); > - unsigned long long blks_per_sec, hblks_per_sec, total_vblocks; > + unsigned long long hblks_per_sec, total_vblocks; > unsigned long long bimodal, dist; > unsigned int segno, vblocks; > int ndirty = 0; > > bimodal = 0; > total_vblocks = 0; > - blks_per_sec = CAP_BLKS_PER_SEC(sbi); > - hblks_per_sec = blks_per_sec / 2; > + hblks_per_sec = BLKS_PER_SEC(sbi) / 2; > for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) { > vblocks = get_valid_blocks(sbi, segno, true); > dist = abs(vblocks - hblks_per_sec); > bimodal += dist * dist; > > - if (vblocks > 0 && vblocks < blks_per_sec) { > + if (vblocks > 0 && vblocks < BLKS_PER_SEC(sbi)) { > total_vblocks += vblocks; > ndirty++; > } > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > index 9a9e858083af..34d718301392 100644 > --- a/fs/f2fs/f2fs.h > +++ b/fs/f2fs/f2fs.h > @@ -1618,7 +1618,6 @@ struct f2fs_sb_info { > unsigned int meta_ino_num; /* meta inode number*/ > unsigned int log_blocks_per_seg;/* log2 blocks per segment */ > unsigned int blocks_per_seg;/* blocks per segment */ > - unsigned int unusable_blocks_per_sec; /* unusable blocks per section > */ > unsigned int segs_per_sec; /* segments per section */ > unsigned int secs_per_zone; /* sections per zone */ > unsigned int total_sections;/* total section count */ > @@ -3743,10 +3742,6 @@ void f2fs_destroy_segment_manager(struct f2fs_sb_info > *sbi); > int __init f2fs_create_segment_manager_caches(void); > void f2fs_destroy_segment_manager_caches(void); > int f2fs_rw_hint_to_seg_type(enum rw_hint hint); > -unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi, > - unsigned int segno); > -unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi, > - unsigned int segno); > > #define DEF_FRAGMENT_SIZE4 > #define MIN_FRAGMENT_SIZE1 > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > index b0be576b2090..2c13b340c8a0 100644 > --- a/fs/f2fs/file.c > +++ b/fs/f2fs/file.c > @@ -1717,7 +1717,7 @@ static int f2fs_expand_inode_data(struct inode *inode, > loff_t offset, > return 0; > > if (f2fs_is_pinned_file(inode)) { > - block_t sec_blks = CAP_BLKS_PER_SEC(sbi); > + block_t sec_blks = BLKS_PER_SEC(sbi); > block_t sec_len = roundup(map.m_len, sec_blks); > > map.m_len = sec_blks; > @@ -2525,7 +2525,7 @@ static int __f2fs_ioc_gc_range(struct file *filp, > struct f2fs_gc_range *range) > ret = -EAGAIN; > goto out; > } > - range->start += CAP_BLKS_PER_SEC(sbi); > + range->start += BLKS_PER_SEC(sbi); > if (range->start <= end) > goto do_more; > out: > @@ -2654,7 +2654,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info > *sbi, >
[f2fs-dev] [PATCH v2 2/4] f2fs: fix panic issue in update_sit_entry
When CONFIG_F2FS_CHECK_FS is not enabled, f2fs_bug_on just printing warning, get_new_segment may get an out-of-bounds segment when there is no free segments. Then a block is allocated from this invalid segment, update_sit_entry will access the invalid bitmap address, cause system panic. Just as below call stack: f2fs_allocate_data_block get a block address with 0x4000 and partition size is 64MB [ 13.401997] Unable to handle kernel NULL pointer dereference at virtual address [ 13.402003] Mem abort info: [ 13.402006] ESR = 0x9605 [ 13.402009] EC = 0x25: DABT (current EL), IL = 32 bits [ 13.402015] SET = 0, FnV = 0 [ 13.402018] EA = 0, S1PTW = 0 [ 13.402021] FSC = 0x05: level 1 translation fault [ 13.402025] Data abort info: [ 13.402027] ISV = 0, ISS = 0x0005 [ 13.402030] CM = 0, WnR = 0 [ 13.402034] user pgtable: 4k pages, 39-bit VAs, pgdp=0001066ab000 [ 13.402038] [] pgd=, p4d=, pud= [ 13.402052] Internal error: Oops: 9605 [#1] PREEMPT SMP [ 13.489854] pc : update_sit_entry+0x128/0x420 [ 13.490497] lr : f2fs_allocate_data_block+0x6b0/0xc2c [ 13.491218] sp : ffc00e023440 [ 13.501530] Call trace: [ 13.501930] update_sit_entry+0x128/0x420 [ 13.502523] f2fs_allocate_data_block+0x6b0/0xc2c [ 13.503203] do_write_page+0xf0/0x1d4 [ 13.503752] f2fs_outplace_write_data+0x68/0xfc [ 13.504408] f2fs_do_write_data_page+0x3a8/0x65c [ 13.505076] move_data_page+0x294/0x7a8 [ 13.505647] gc_data_segment+0x4b8/0x800 [ 13.506229] do_garbage_collect+0x354/0x674 [ 13.506843] f2fs_gc+0x280/0x68c [ 13.507340] f2fs_balance_fs+0x104/0x144 [ 13.507921] f2fs_create+0x310/0x3d8 [ 13.508458] path_openat+0x53c/0xc28 [ 13.508997] do_filp_open+0xbc/0x16c [ 13.509535] do_sys_openat2+0xa0/0x2a0 So sanity check should be add in update_sit_entry. Also remove some redundant judgment code. Signed-off-by: Zhiguo Niu --- fs/f2fs/segment.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ad6511f..f373ff7 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2399,6 +2399,8 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) #endif segno = GET_SEGNO(sbi, blkaddr); + if (segno == NULL_SEGNO) + return; se = get_seg_entry(sbi, segno); new_vblocks = se->valid_blocks + del; @@ -3464,8 +3466,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, * since SSR needs latest valid block information. */ update_sit_entry(sbi, *new_blkaddr, 1); - if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) - update_sit_entry(sbi, old_blkaddr, -1); + update_sit_entry(sbi, old_blkaddr, -1); /* * If the current segment is full, flush it out and replace it with a -- 1.9.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH v2 1/4] f2fs: correct counting methods of free_segments in __set_inuse
There is a corner scenario on a small-capacity partition with 64MB size: 1. The main area has a total of 24 segments, and there are no free segments left shown from the free_segmap bitmap and free_secmap in free_segmap_info. - bitmap value: - 2. When doing gc, an out-of-bounds segment with segno=24 is allocated. Because CONFIG_F2FS_CHECK_FS is not enabled, f2fs_bug_on in get_new_segment just print warning log but the subsequent process continues to run. - got_it: /* set it as dirty segment in free segmap */ f2fs_bug_on(sbi, test_bit(segno, free_i->free_segmap)); __set_inuse(sbi, segno); -- 3. __set_inuse directly sets free_i->free_segments--, As a result, free_i->free_segments=-1, as shown in the following coredump information: -- crash_arm64> struct free_segmap_info 0xff8084d9a000 -x struct free_segmap_info { start_segno = 0x7, free_segments = 0x, free_sections = 0x0, -- This is unreasonable and will cause free_segments and free_sections counts mismatch if there are segments released as free. So same counting methods like free_sections should be used to free_segments. Signed-off-by: Zhiguo Niu --- fs/f2fs/segment.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 8129be7..f2847f1 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -463,8 +463,8 @@ static inline void __set_inuse(struct f2fs_sb_info *sbi, struct free_segmap_info *free_i = FREE_I(sbi); unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); - set_bit(segno, free_i->free_segmap); - free_i->free_segments--; + if (!test_and_set_bit(segno, free_i->free_segmap)) + free_i->free_segments--; if (!test_and_set_bit(secno, free_i->free_secmap)) free_i->free_sections--; } -- 1.9.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH v2 3/4] f2fs: enhance judgment conditions of GET_SEGNO
NULL_SEGNO should also be returned when the blk_addr value is out-of-bound main area even __is_valid_data_blkaddr return true. For example, a 64MB partition with total 24 main segments has no any free segments left, then a new wrtie request use get_new_segment may get a out-of-bound segno 24 if CONFIG_F2FS_CHECK_FS is not enabled. GET_SEGNO should also return NULL_SEGNO in this case rather than treating is as valid segment. Besides, if the caller of GET_SEGNO does not ensure blk_addr pass to GET_SEGNO is valid, it should do sanity check about return value of GET_SEGNO, avoid causing some unexpected problems later. Signed-off-by: Zhiguo Niu --- fs/f2fs/file.c| 7 ++- fs/f2fs/segment.c | 4 +++- fs/f2fs/segment.h | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 23cd6a1..2cd3cd9 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2985,9 +2985,14 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) if (ret) return ret; - if (range.dev_num != 0) + if (range.dev_num != 0) { dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk); + if (dev_start_segno == NULL_SEGNO) + return -EINVAL; + } dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk); + if (dev_end_segno == NULL_SEGNO) + return -EINVAL; start_segno = sm->last_victim[FLUSH_DEVICE]; if (start_segno < dev_start_segno || start_segno >= dev_end_segno) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f373ff7..6772ad4 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2496,7 +2496,7 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) struct sit_info *sit_i = SIT_I(sbi); f2fs_bug_on(sbi, addr == NULL_ADDR); - if (addr == NEW_ADDR || addr == COMPRESS_ADDR) + if (segno == NULL_SEGNO) return; f2fs_invalidate_internal_cache(sbi, addr); @@ -3708,6 +3708,8 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, unsigned char old_alloc_type; segno = GET_SEGNO(sbi, new_blkaddr); + if (segno == NULL_SEGNO) + return; se = get_seg_entry(sbi, segno); type = se->type; diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index f2847f1..b0ea315 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -96,7 +96,8 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi, (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1)) #define GET_SEGNO(sbi, blk_addr) \ - ((!__is_valid_data_blkaddr(blk_addr)) ? \ + ((!__is_valid_data_blkaddr(blk_addr) || \ + !f2fs_is_valid_blkaddr(sbi, blk_addr, DATA_GENERIC)) ? \ NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \ GET_SEGNO_FROM_SEG0(sbi, blk_addr))) #define BLKS_PER_SEC(sbi) \ -- 1.9.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH v2 4/4] f2fs: stop checkpoint when get a out-of-bounds segment
There is low probability that an out-of-bounds segment will be got on a small-capacity device. In order to prevent subsequent write requests allocating block address from this invalid segment, which may cause unexpected issue, stop checkpoint should be performed. Also introduce a new stop cp reason: STOP_CP_REASON_OUTOF_RAGNE. Signed-off-by: Zhiguo Niu --- fs/f2fs/segment.c | 12 ++-- include/linux/f2fs_fs.h | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 6772ad4..6fe2baf 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2666,7 +2666,11 @@ static void get_new_segment(struct f2fs_sb_info *sbi, if (dir == ALLOC_RIGHT) { secno = find_first_zero_bit(free_i->free_secmap, MAIN_SECS(sbi)); - f2fs_bug_on(sbi, secno >= MAIN_SECS(sbi)); + if (secno >= MAIN_SECS(sbi)) { + f2fs_stop_checkpoint(sbi, false, + STOP_CP_REASON_OUTOF_RAGNE); + f2fs_bug_on(sbi, 1); + } } else { go_left = 1; left_start = hint - 1; @@ -2682,7 +2686,11 @@ static void get_new_segment(struct f2fs_sb_info *sbi, } left_start = find_first_zero_bit(free_i->free_secmap, MAIN_SECS(sbi)); - f2fs_bug_on(sbi, left_start >= MAIN_SECS(sbi)); + if (left_start >= MAIN_SECS(sbi)) { + f2fs_stop_checkpoint(sbi, false, + STOP_CP_REASON_OUTOF_RAGNE); + f2fs_bug_on(sbi, 1); + } break; } secno = left_start; diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 053137a0..72c6782 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -81,6 +81,7 @@ enum stop_cp_reason { STOP_CP_REASON_CORRUPTED_SUMMARY, STOP_CP_REASON_UPDATE_INODE, STOP_CP_REASON_FLUSH_FAIL, + STOP_CP_REASON_OUTOF_RAGNE, STOP_CP_REASON_MAX, }; -- 1.9.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH v2 0/4] f2fs: fix panic issue in small capacity device
A panic issue happened in a reboot test in small capacity device as following: 1.The device size is 64MB, and main area has 24 segments, and CONFIG_F2FS_CHECK_FS is not enabled. 2.There is no any free segments left shown in free_segmap_info, then another write request cause get_new_segment get a out-of-bound segment with segno 24. 3.panic happen in update_sit_entry because access invalid bitmap pointer. More detail shown in following patch sets. The three patches are splited here because the modifications are relatively independent and more readable. --- Changes of v2: stop checkpoint when get a out-of-bound segment --- Zhiguo Niu (4): f2fs: correct counting methods of free_segments in __set_inuse f2fs: fix panic issue in update_sit_entry f2fs: enhance judgment conditions of GET_SEGNO f2fs: stop checkpoint when get a out-of-bounds segment fs/f2fs/file.c | 7 ++- fs/f2fs/segment.c | 21 - fs/f2fs/segment.h | 7 --- include/linux/f2fs_fs.h | 1 + 4 files changed, 27 insertions(+), 9 deletions(-) -- 1.9.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH 1/3] f2fs: deprecate io_bits
Let's deprecate an unused io_bits feature to save CPU cycles and memory. Signed-off-by: Jaegeuk Kim --- Documentation/filesystems/f2fs.rst | 2 - fs/f2fs/data.c | 73 + fs/f2fs/f2fs.h | 25 ++--- fs/f2fs/file.c | 2 - fs/f2fs/gc.c | 10 +--- fs/f2fs/segment.c | 9 +-- fs/f2fs/super.c| 88 +- include/linux/f2fs_fs.h| 6 -- 8 files changed, 10 insertions(+), 205 deletions(-) diff --git a/Documentation/filesystems/f2fs.rst b/Documentation/filesystems/f2fs.rst index 32cbfa864f38..9ac5083dae8e 100644 --- a/Documentation/filesystems/f2fs.rst +++ b/Documentation/filesystems/f2fs.rst @@ -229,8 +229,6 @@ mode=%s Control block allocation mode which supports "adaptive" option for more randomness. Please, use these options for your experiments and we strongly recommend to re-format the filesystem after using these options. -io_bits=%u Set the bit size of write IO requests. It should be set -with "mode=lfs". usrquotaEnable plain user disk quota accounting. grpquotaEnable plain group disk quota accounting. prjquotaEnable plain project quota accounting. diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 05158f89ef32..828c797cd47c 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -338,17 +338,6 @@ static void f2fs_write_end_io(struct bio *bio) struct page *page = bvec->bv_page; enum count_type type = WB_DATA_TYPE(page, false); - if (page_private_dummy(page)) { - clear_page_private_dummy(page); - unlock_page(page); - mempool_free(page, sbi->write_io_dummy); - - if (unlikely(bio->bi_status)) - f2fs_stop_checkpoint(sbi, true, - STOP_CP_REASON_WRITE_FAIL); - continue; - } - fscrypt_finalize_bounce_page(); #ifdef CONFIG_F2FS_FS_COMPRESSION @@ -522,50 +511,13 @@ void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio, submit_bio(bio); } -static void f2fs_align_write_bio(struct f2fs_sb_info *sbi, struct bio *bio) -{ - unsigned int start = - (bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS) % F2FS_IO_SIZE(sbi); - - if (start == 0) - return; - - /* fill dummy pages */ - for (; start < F2FS_IO_SIZE(sbi); start++) { - struct page *page = - mempool_alloc(sbi->write_io_dummy, - GFP_NOIO | __GFP_NOFAIL); - f2fs_bug_on(sbi, !page); - - lock_page(page); - - zero_user_segment(page, 0, PAGE_SIZE); - set_page_private_dummy(page); - - if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) - f2fs_bug_on(sbi, 1); - } -} - static void f2fs_submit_write_bio(struct f2fs_sb_info *sbi, struct bio *bio, enum page_type type) { WARN_ON_ONCE(is_read_io(bio_op(bio))); - if (type == DATA || type == NODE) { - if (f2fs_lfs_mode(sbi) && current->plug) - blk_finish_plug(current->plug); - - if (F2FS_IO_ALIGNED(sbi)) { - f2fs_align_write_bio(sbi, bio); - /* -* In the NODE case, we lose next block address chain. -* So, we need to do checkpoint in f2fs_sync_file. -*/ - if (type == NODE) - set_sbi_flag(sbi, SBI_NEED_CP); - } - } + if (f2fs_lfs_mode(sbi) && current->plug && PAGE_TYPE_ON_MAIN(type)) + blk_finish_plug(current->plug); trace_f2fs_submit_write_bio(sbi->sb, type, bio); iostat_update_submit_ctx(bio, type); @@ -794,16 +746,6 @@ static bool io_is_mergeable(struct f2fs_sb_info *sbi, struct bio *bio, block_t last_blkaddr, block_t cur_blkaddr) { - if (F2FS_IO_ALIGNED(sbi) && (fio->type == DATA || fio->type == NODE)) { - unsigned int filled_blocks = - F2FS_BYTES_TO_BLK(bio->bi_iter.bi_size); - unsigned int io_size = F2FS_IO_SIZE(sbi); - unsigned int left_vecs = bio->bi_max_vecs - bio->bi_vcnt; - - /* IOs in bio is aligned and left space of vectors is not enough */ - if (!(filled_blocks % io_size) && left_vecs < io_size) - return false; - } if
[f2fs-dev] [PATCH 3/3] f2fs: kill zone-capacity support
Since we don't see any user, let's kill. Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 6 -- fs/f2fs/debug.c | 7 +- fs/f2fs/f2fs.h | 5 -- fs/f2fs/file.c | 6 +- fs/f2fs/gc.c| 33 +++-- fs/f2fs/gc.h| 26 --- fs/f2fs/segment.c | 93 +++-- fs/f2fs/segment.h | 41 --- fs/f2fs/super.c | 16 + fs/f2fs/sysfs.c | 6 -- 10 files changed, 43 insertions(+), 196 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 48c135e24eb5..dff8c87d87dd 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -628,12 +628,6 @@ Contact: "Jaegeuk Kim" Description: Controls max # of node block writes to be used for roll forward recovery. This can limit the roll forward recovery time. -What: /sys/fs/f2fs//unusable_blocks_per_sec -Date: June 2022 -Contact: "Jaegeuk Kim" -Description: Shows the number of unusable blocks in a section which was defined by - the zone capacity reported by underlying zoned device. - What: /sys/fs/f2fs//current_atomic_write Date: July 2022 Contact: "Daeho Jeong" diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 0d02224b99b7..6617195bd27e 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -32,21 +32,20 @@ static struct dentry *f2fs_debugfs_root; void f2fs_update_sit_info(struct f2fs_sb_info *sbi) { struct f2fs_stat_info *si = F2FS_STAT(sbi); - unsigned long long blks_per_sec, hblks_per_sec, total_vblocks; + unsigned long long hblks_per_sec, total_vblocks; unsigned long long bimodal, dist; unsigned int segno, vblocks; int ndirty = 0; bimodal = 0; total_vblocks = 0; - blks_per_sec = CAP_BLKS_PER_SEC(sbi); - hblks_per_sec = blks_per_sec / 2; + hblks_per_sec = BLKS_PER_SEC(sbi) / 2; for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) { vblocks = get_valid_blocks(sbi, segno, true); dist = abs(vblocks - hblks_per_sec); bimodal += dist * dist; - if (vblocks > 0 && vblocks < blks_per_sec) { + if (vblocks > 0 && vblocks < BLKS_PER_SEC(sbi)) { total_vblocks += vblocks; ndirty++; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 9a9e858083af..34d718301392 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1618,7 +1618,6 @@ struct f2fs_sb_info { unsigned int meta_ino_num; /* meta inode number*/ unsigned int log_blocks_per_seg;/* log2 blocks per segment */ unsigned int blocks_per_seg;/* blocks per segment */ - unsigned int unusable_blocks_per_sec; /* unusable blocks per section */ unsigned int segs_per_sec; /* segments per section */ unsigned int secs_per_zone; /* sections per zone */ unsigned int total_sections;/* total section count */ @@ -3743,10 +3742,6 @@ void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi); int __init f2fs_create_segment_manager_caches(void); void f2fs_destroy_segment_manager_caches(void); int f2fs_rw_hint_to_seg_type(enum rw_hint hint); -unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi, - unsigned int segno); -unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi, - unsigned int segno); #define DEF_FRAGMENT_SIZE 4 #define MIN_FRAGMENT_SIZE 1 diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index b0be576b2090..2c13b340c8a0 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1717,7 +1717,7 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset, return 0; if (f2fs_is_pinned_file(inode)) { - block_t sec_blks = CAP_BLKS_PER_SEC(sbi); + block_t sec_blks = BLKS_PER_SEC(sbi); block_t sec_len = roundup(map.m_len, sec_blks); map.m_len = sec_blks; @@ -2525,7 +2525,7 @@ static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range) ret = -EAGAIN; goto out; } - range->start += CAP_BLKS_PER_SEC(sbi); + range->start += BLKS_PER_SEC(sbi); if (range->start <= end) goto do_more; out: @@ -2654,7 +2654,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, goto out; } - sec_num = DIV_ROUND_UP(total, CAP_BLKS_PER_SEC(sbi)); + sec_num = DIV_ROUND_UP(total, BLKS_PER_SEC(sbi)); /* * make sure there
[f2fs-dev] [PATCH 2/3] f2fs: use BLKS_PER_SEG, BLKS_PER_SEC, and SEGS_PER_SEC
No functional change. Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 10 ++-- fs/f2fs/debug.c | 6 +-- fs/f2fs/f2fs.h | 19 +--- fs/f2fs/file.c | 12 ++--- fs/f2fs/gc.c | 40 fs/f2fs/node.c | 4 +- fs/f2fs/node.h | 4 +- fs/f2fs/recovery.c | 2 +- fs/f2fs/segment.c| 109 +-- fs/f2fs/segment.h| 18 --- fs/f2fs/super.c | 8 ++-- fs/f2fs/sysfs.c | 6 +-- 12 files changed, 119 insertions(+), 119 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index b85820e70f5e..a09a9609e228 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -900,7 +900,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi, cp_blocks = le32_to_cpu(cp_block->cp_pack_total_block_count); - if (cp_blocks > sbi->blocks_per_seg || cp_blocks <= F2FS_CP_PACKS) { + if (cp_blocks > BLKS_PER_SEG(sbi) || 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; @@ -1335,7 +1335,7 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (cpc->reason & CP_UMOUNT) { if (le32_to_cpu(ckpt->cp_pack_total_block_count) + - NM_I(sbi)->nat_bits_blocks > sbi->blocks_per_seg) { + NM_I(sbi)->nat_bits_blocks > BLKS_PER_SEG(sbi)) { clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG); f2fs_notice(sbi, "Disable nat_bits due to no space"); } else if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG) && @@ -1538,7 +1538,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) cp_ver |= ((__u64)crc32 << 32); *(__le64 *)nm_i->nat_bits = cpu_to_le64(cp_ver); - blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks; + blk = start_blk + BLKS_PER_SEG(sbi) - nm_i->nat_bits_blocks; for (i = 0; i < nm_i->nat_bits_blocks; i++) f2fs_update_meta_page(sbi, nm_i->nat_bits + (i << F2FS_BLKSIZE_BITS), blk + i); @@ -1741,9 +1741,9 @@ void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi) im->ino_num = 0; } - sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS - + sbi->max_orphans = (BLKS_PER_SEG(sbi) - F2FS_CP_PACKS - NR_CURSEG_PERSIST_TYPE - __cp_payload(sbi)) * - F2FS_ORPHANS_PER_BLOCK; + F2FS_ORPHANS_PER_BLOCK; } int __init f2fs_create_checkpoint_caches(void) diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index fdbf994f1271..0d02224b99b7 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -41,7 +41,7 @@ void f2fs_update_sit_info(struct f2fs_sb_info *sbi) total_vblocks = 0; blks_per_sec = CAP_BLKS_PER_SEC(sbi); hblks_per_sec = blks_per_sec / 2; - for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) { + for (segno = 0; segno < MAIN_SEGS(sbi); segno += SEGS_PER_SEC(sbi)) { vblocks = get_valid_blocks(sbi, segno, true); dist = abs(vblocks - hblks_per_sec); bimodal += dist * dist; @@ -135,7 +135,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) si->cur_ckpt_time = sbi->cprc_info.cur_time; si->peak_ckpt_time = sbi->cprc_info.peak_time; spin_unlock(>cprc_info.stat_lock); - si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg; + si->total_count = (int)sbi->user_block_count / BLKS_PER_SEG(sbi); si->rsvd_segs = reserved_segments(sbi); si->overp_segs = overprovision_segments(sbi); si->valid_count = valid_user_blocks(sbi); @@ -208,7 +208,7 @@ static void update_general_status(struct f2fs_sb_info *sbi) if (!blks) continue; - if (blks == sbi->blocks_per_seg) + if (blks == BLKS_PER_SEG(sbi)) si->full_seg[type]++; else si->dirty_seg[type]++; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 4c52136cbc10..9a9e858083af 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1813,6 +1813,14 @@ struct f2fs_sb_info { #endif }; +/* Definitions to access f2fs_sb_info */ +#define BLKS_PER_SEG(sbi) \ + ((sbi)->blocks_per_seg) +#define BLKS_PER_SEC(sbi) \ + ((sbi)->segs_per_sec << (sbi)->log_blocks_per_seg) +#define SEGS_PER_SEC(sbi) \ + ((sbi)->segs_per_sec) + __printf(3, 4) void f2fs_printk(struct f2fs_sb_info *sbi, bool limit_rate, const char *fmt, ...);
Re: [f2fs-dev] [PATCH v7] f2fs: unify the error handling of f2fs_is_valid_blkaddr
On Tue, Feb 6, 2024 at 11:36 AM Chao Yu wrote: > > On 2024/2/6 11:32, Jaegeuk Kim wrote: > > On 02/05, Chao Yu wrote: > >> On 2024/2/5 11:30, Zhiguo Niu wrote: > >>> There are some cases of f2fs_is_valid_blkaddr not handled as > >>> ERROR_INVALID_BLKADDR,so unify the error handling about all of > >>> f2fs_is_valid_blkaddr. > >>> > >>> Signed-off-by: Zhiguo Niu > >>> Signed-off-by: Chao Yu > >>> --- > >>> changes of v7: update patch according to sync with Chao > >>> -restore some code to original > >>> -modify err handle of __is_bitmap_valid for covering all cases > >>> changes of v6: improve patch according to Chao's suggestions > >>> -restore dump_stack to original position > >>> -adjuest code sequence of __is_bitmap_check_valid > >>> changes of v5: improve patch according to Jaegeuk's suggestiongs > >>> -restore return value of some f2fs_is_valid_blkaddr error case to > >>> original > >>> -move cp_err checking to outermost for unified processing > >>> -return true directly for case (type=DATA_GENERIC_ENHANCE_READ) in > >>> __is_bitmap_valid to avoid meaningless flow > >>> -rename __is_bitmap_valid to __is_bitmap_check_valid for avoiding > >>> ambiguity > >>> and handling its return value in the caller uniformly, also cooperate > >>> switch checking true to false for error case of > >>> f2fs_is_valid_blkaddr(type=DATA_GENERIC_ENHANCE_UPDATE) in > >>> do_recover_data > >>> for more readable > >>> changes of v4: update according to the latest code > >>> changes of v3: > >>> -rebase patch to dev-test > >>> -correct return value for some f2fs_is_valid_blkaddr error case > >>> changes of v2: improve patch according Chao's suggestions. > >>> --- > >>> --- > >>>fs/f2fs/checkpoint.c | 33 ++--- > >>>fs/f2fs/data.c | 22 +++--- > >>>fs/f2fs/extent_cache.c | 5 + > >>>fs/f2fs/file.c | 16 +++- > >>>fs/f2fs/gc.c | 2 -- > >>>fs/f2fs/recovery.c | 4 > >>>fs/f2fs/segment.c | 2 -- > >>>7 files changed, 25 insertions(+), 59 deletions(-) > >>> > >>> diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c > >>> index b85820e..3335619 100644 > >>> --- a/fs/f2fs/checkpoint.c > >>> +++ b/fs/f2fs/checkpoint.c > >>> @@ -154,46 +154,43 @@ static bool __is_bitmap_valid(struct f2fs_sb_info > >>> *sbi, block_t blkaddr, > >>> if (unlikely(f2fs_cp_error(sbi))) > >>> return exist; > >>> - if (exist && type == DATA_GENERIC_ENHANCE_UPDATE) { > >>> - f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d", > >>> -blkaddr, exist); > >>> - set_sbi_flag(sbi, SBI_NEED_FSCK); > >>> - return exist; > >>> - } > >>> - > >>> - if (!exist && type == DATA_GENERIC_ENHANCE) { > >>> + if ((exist && type == DATA_GENERIC_ENHANCE_UPDATE) || > >>> + (!exist && type == DATA_GENERIC_ENHANCE)) { > >>> f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d", > >>> blkaddr, exist); > >>> set_sbi_flag(sbi, SBI_NEED_FSCK); > >>> dump_stack(); > >>> } > >>> + > >> > >> No need to add one blank line. > >> > >> Otherwise, it looks good to me. > >> > >> Reviewed-by: Chao Yu > >> > >> Thanks, > >> > >>> return exist; > >>>} > >>>static bool __f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, > >>> block_t blkaddr, int type) > >>>{ > >>> + bool valid = false; > >>> + > >>> switch (type) { > >>> case META_NAT: > >>> break; > >>> case META_SIT: > >>> if (unlikely(blkaddr >= SIT_BLK_CNT(sbi))) > >>> - return false; > >>> + goto err; > >>> break; > >>> case META_SSA: > >>> if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) || > >>> blkaddr < SM_I(sbi)->ssa_blkaddr)) > >>> - return false; > >>> + goto err; > >>> break; > >>> case META_CP: > >>> if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr || > >>> blkaddr < __start_cp_addr(sbi))) > >>> - return false; > >>> + goto err; > >>> break; > >>> case META_POR: > >>> if (unlikely(blkaddr >= MAX_BLKADDR(sbi) || > >>> blkaddr < MAIN_BLKADDR(sbi))) > >>> - return false; > >>> + goto err; > >>> break; > >>> case DATA_GENERIC: > >>> case DATA_GENERIC_ENHANCE: > >>> @@ -210,21 +207,27 @@ static bool __f2fs_is_valid_blkaddr(struct > >>> f2fs_sb_info *sbi, > >>> blkaddr); > >>> set_sbi_flag(sbi, SBI_NEED_FSCK); > >>> dump_stack(); > >>> - return false; > >>> + goto err; > >>> } else
[f2fs-dev] [PATCH 3/3] f2fs: support swap file pinning for zoned devices
From: Daeho Jeong Support swap file pinning for zoned devices Signed-off-by: Daeho Jeong Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 54 -- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 05158f89ef32..5d8ee6e73dbe 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -3905,28 +3905,40 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, unsigned int blkcnt) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_map_blocks map = { .m_next_pgofs = NULL, + .m_next_extent = NULL, .m_seg_type = CURSEG_COLD_DATA_PINNED, + .m_may_create = true }; unsigned int blkofs; unsigned int blk_per_sec = BLKS_PER_SEC(sbi); unsigned int secidx = start_blk / blk_per_sec; - unsigned int end_sec = secidx + blkcnt / blk_per_sec; + unsigned int end_sec; int ret = 0; + if (!blkcnt) + return 0; + end_sec = secidx + (blkcnt - 1) / blk_per_sec; + f2fs_down_write(_I(inode)->i_gc_rwsem[WRITE]); filemap_invalidate_lock(inode->i_mapping); set_inode_flag(inode, FI_ALIGNED_WRITE); set_inode_flag(inode, FI_OPU_WRITE); - for (; secidx < end_sec; secidx++) { + for (; secidx <= end_sec; secidx++) { + unsigned int blkofs_end = secidx == end_sec ? + (blkcnt - 1) % blk_per_sec : blk_per_sec - 1; + f2fs_down_write(>pin_sem); - f2fs_lock_op(sbi); - f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); - f2fs_unlock_op(sbi); + ret = f2fs_allocate_pinning_section(sbi); + if (ret) { + f2fs_up_write(>pin_sem); + break; + } set_inode_flag(inode, FI_SKIP_WRITES); - for (blkofs = 0; blkofs < blk_per_sec; blkofs++) { + for (blkofs = 0; blkofs <= blkofs_end; blkofs++) { struct page *page; unsigned int blkidx = secidx * blk_per_sec + blkofs; @@ -3944,6 +3956,12 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk, clear_inode_flag(inode, FI_SKIP_WRITES); ret = filemap_fdatawrite(inode->i_mapping); + if (!ret && blkofs != blk_per_sec) { + map.m_lblk = secidx * blk_per_sec + blkofs; + map.m_len = blk_per_sec - blkofs; + ret = f2fs_map_blocks(inode, , + F2FS_GET_BLOCK_PRE_DIO); + } f2fs_up_write(>pin_sem); @@ -4015,19 +4033,17 @@ static int check_swap_activate(struct swap_info_struct *sis, nr_pblocks = map.m_len; if ((pblock - SM_I(sbi)->main_blkaddr) & sec_blks_mask || - nr_pblocks & sec_blks_mask) { + nr_pblocks & sec_blks_mask || + !f2fs_valid_pinned_area(sbi, pblock)) { not_aligned++; nr_pblocks = roundup(nr_pblocks, blks_per_sec); if (cur_lblock + nr_pblocks > sis->max) nr_pblocks -= blks_per_sec; - if (!nr_pblocks) { - /* this extent is last one */ - nr_pblocks = map.m_len; - f2fs_warn(sbi, "Swapfile: last extent is not aligned to section"); - goto next; - } + /* this extent is last one */ + if (!nr_pblocks) + nr_pblocks = last_lblock - cur_lblock; ret = f2fs_migrate_blocks(inode, cur_lblock, nr_pblocks); @@ -4035,7 +4051,7 @@ static int check_swap_activate(struct swap_info_struct *sis, goto out; goto retry; } -next: + if (cur_lblock + nr_pblocks >= sis->max) nr_pblocks = sis->max - cur_lblock; @@ -4073,17 +4089,17 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file, sector_t *span) { struct inode *inode = file_inode(file); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int ret; if (!S_ISREG(inode->i_mode)) return -EINVAL; - if (f2fs_readonly(F2FS_I_SB(inode)->sb)) + if (f2fs_readonly(sbi->sb)) return -EROFS; - if (f2fs_lfs_mode(F2FS_I_SB(inode))) { - f2fs_err(F2FS_I_SB(inode), -
[f2fs-dev] [PATCH 2/3] f2fs: support file pinning for zoned devices
From: Daeho Jeong Support file pinning with conventional storage area for zoned devices Signed-off-by: Daeho Jeong Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h| 14 +- fs/f2fs/file.c| 24 fs/f2fs/gc.c | 14 +++--- fs/f2fs/segment.c | 71 +-- fs/f2fs/segment.h | 10 +++ 5 files changed, 114 insertions(+), 19 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 543898482f8b..9b8b4d6a0d61 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3708,7 +3708,8 @@ void f2fs_get_new_segment(struct f2fs_sb_info *sbi, unsigned int *newseg, bool new_sec, int dir); void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, unsigned int start, unsigned int end); -void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force); +int f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force); +int f2fs_allocate_pinning_section(struct f2fs_sb_info *sbi); void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi); int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range); bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi, @@ -3886,6 +3887,9 @@ void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi); block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode); int f2fs_gc(struct f2fs_sb_info *sbi, struct f2fs_gc_control *gc_control); void f2fs_build_gc_manager(struct f2fs_sb_info *sbi); +int f2fs_gc_range(struct f2fs_sb_info *sbi, + unsigned int start_seg, unsigned int end_seg, + bool dry_run, unsigned int dry_run_sections); int f2fs_resize_fs(struct file *filp, __u64 block_count); int __init f2fs_create_garbage_collection_cache(void); void f2fs_destroy_garbage_collection_cache(void); @@ -4540,6 +4544,14 @@ static inline bool f2fs_lfs_mode(struct f2fs_sb_info *sbi) return F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS; } +static inline bool f2fs_valid_pinned_area(struct f2fs_sb_info *sbi, + block_t blkaddr) +{ + int devi = f2fs_target_device_index(sbi, blkaddr); + + return !bdev_is_zoned(FDEV(devi).bdev); +} + static inline bool f2fs_low_mem_mode(struct f2fs_sb_info *sbi) { return F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 25b119cf3499..4078e7616aef 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1735,9 +1735,11 @@ static int f2fs_expand_inode_data(struct inode *inode, loff_t offset, f2fs_down_write(>pin_sem); - f2fs_lock_op(sbi); - f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false); - f2fs_unlock_op(sbi); + err = f2fs_allocate_pinning_section(sbi); + if (err) { + f2fs_up_write(>pin_sem); + goto out_err; + } map.m_seg_type = CURSEG_COLD_DATA_PINNED; err = f2fs_map_blocks(inode, , F2FS_GET_BLOCK_PRE_DIO); @@ -3187,6 +3189,7 @@ int f2fs_pin_file_control(struct inode *inode, bool inc) static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); __u32 pin; int ret = 0; @@ -3196,7 +3199,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) if (!S_ISREG(inode->i_mode)) return -EINVAL; - if (f2fs_readonly(F2FS_I_SB(inode)->sb)) + if (f2fs_readonly(sbi->sb)) return -EROFS; ret = mnt_want_write_file(filp); @@ -3209,9 +3212,18 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) clear_inode_flag(inode, FI_PIN_FILE); f2fs_i_gc_failures_write(inode, 0); goto done; + } else if (f2fs_is_pinned_file(inode)) { + goto done; } - if (f2fs_should_update_outplace(inode, NULL)) { + if (f2fs_sb_has_blkzoned(sbi) && F2FS_HAS_BLOCKS(inode)) { + ret = -EFBIG; + goto out; + } + + /* Let's allow file pinning on zoned device. */ + if (!f2fs_sb_has_blkzoned(sbi) && + f2fs_should_update_outplace(inode, NULL)) { ret = -EINVAL; goto out; } @@ -3233,7 +3245,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg) set_inode_flag(inode, FI_PIN_FILE); ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]; done: - f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); + f2fs_update_time(sbi, REQ_TIME); out: inode_unlock(inode); mnt_drop_write_file(filp); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index a46d5053f965..100695540087 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1983,10 +1983,12
[f2fs-dev] [PATCH 1/3] f2fs: separate f2fs_gc_range() to use GC for a range
From: Daeho Jeong Make f2fs_gc_range() an extenal function to use it for GC for a range. Signed-off-by: Daeho Jeong Signed-off-by: Jaegeuk Kim --- fs/f2fs/gc.c | 49 - 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index a079eebfb080..a46d5053f965 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1983,10 +1983,34 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi) init_atgc_management(sbi); } +static int f2fs_gc_range(struct f2fs_sb_info *sbi, + unsigned int start_seg, unsigned int end_seg, bool dry_run) +{ + unsigned int segno; + + for (segno = start_seg; segno <= end_seg; segno += sbi->segs_per_sec) { + struct gc_inode_list gc_list = { + .ilist = LIST_HEAD_INIT(gc_list.ilist), + .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS), + }; + + do_garbage_collect(sbi, segno, _list, FG_GC, true); + put_gc_inode(_list); + + if (!dry_run && get_valid_blocks(sbi, segno, true)) + return -EAGAIN; + + if (fatal_signal_pending(current)) + return -ERESTARTSYS; + } + + return 0; +} + static int free_segment_range(struct f2fs_sb_info *sbi, - unsigned int secs, bool gc_only) + unsigned int secs, bool dry_run) { - unsigned int segno, next_inuse, start, end; + unsigned int next_inuse, start, end; struct cp_control cpc = { CP_RESIZE, 0, 0, 0 }; int gc_mode, gc_type; int err = 0; @@ -2012,25 +2036,8 @@ static int free_segment_range(struct f2fs_sb_info *sbi, f2fs_allocate_segment_for_resize(sbi, type, start, end); /* do GC to move out valid blocks in the range */ - for (segno = start; segno <= end; segno += sbi->segs_per_sec) { - struct gc_inode_list gc_list = { - .ilist = LIST_HEAD_INIT(gc_list.ilist), - .iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS), - }; - - do_garbage_collect(sbi, segno, _list, FG_GC, true); - put_gc_inode(_list); - - if (!gc_only && get_valid_blocks(sbi, segno, true)) { - err = -EAGAIN; - goto out; - } - if (fatal_signal_pending(current)) { - err = -ERESTARTSYS; - goto out; - } - } - if (gc_only) + err = f2fs_gc_range(sbi, start, end, dry_run); + if (err || dry_run) goto out; stat_inc_cp_call_count(sbi, TOTAL_CALL); -- 2.43.0.594.gd9cf4e227d-goog ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel