Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- fs/f2fs/Kconfig | 13 +++-
- fs/f2fs/checkpoint.c | 44 +++++++++++--
- fs/f2fs/data.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
- fs/f2fs/dir.c | 23 ++++++-
- fs/f2fs/f2fs.h | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
- fs/f2fs/file.c | 54 +++++++++++++---
- fs/f2fs/gc.c | 40 ++++++++++--
- fs/f2fs/inline.c | 18 ++++++
- fs/f2fs/inode.c | 14 +++++
- fs/f2fs/namei.c | 28 ++++++---
- fs/f2fs/node.c | 54 +++++++++++++---
- fs/f2fs/segment.c | 80 ++++++++++++++++++++----
- fs/f2fs/segment.h | 3 +
- fs/f2fs/super.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
- fs/f2fs/sysfs.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
- 15 files changed, 1109 insertions(+), 91 deletions(-)
- diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig
- index 378c221d68a92..02c0616c8181d 100644
- --- a/fs/f2fs/Kconfig
- +++ b/fs/f2fs/Kconfig
- @@ -68,12 +68,23 @@ config F2FS_FS_SECURITY
- config F2FS_CHECK_FS
- bool "F2FS consistency checking feature"
- - depends on F2FS_FS
- + depends on F2FS_FS && SEC_FACTORY
- + default y
- help
- Enables BUG_ONs which check the filesystem consistency in runtime.
- If you want to improve the performance, say N.
- +config F2FS_STRICT_BUG_ON
- + bool "F2FS consistency checking feature"
- + depends on F2FS_FS
- + default y
- + help
- + Use BUG_ON() instead of WARN_ON(), when there is an error
- + in the filesystem consistency.
- +
- + Default Y.
- +
- config F2FS_FS_ENCRYPTION
- bool "F2FS Encryption"
- depends on F2FS_FS
- diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
- index 6d72a47162699..f451c7e5207fd 100644
- --- a/fs/f2fs/checkpoint.c
- +++ b/fs/f2fs/checkpoint.c
- @@ -22,6 +22,8 @@
- static struct kmem_cache *ino_entry_slab;
- struct kmem_cache *f2fs_inode_entry_slab;
- +unsigned long long priv_cp_time;
- +unsigned long long curr_cp_time;
- void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
- {
- @@ -345,7 +347,7 @@ long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
- blk_start_plug(&plug);
- while ((nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
- - PAGECACHE_TAG_DIRTY))) {
- + PAGECACHE_TAG_DIRTY, PAGEVEC_SIZE))) {
- int i;
- for (i = 0; i < nr_pages; i++) {
- @@ -680,6 +682,8 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
- nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
- err = recover_orphan_inode(sbi, ino);
- if (err) {
- + print_block_data(sbi->sb, start_blk + i,
- + page_address(page), 0, F2FS_BLKSIZE);
- f2fs_put_page(page, 1);
- goto out;
- }
- @@ -777,18 +781,22 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
- f2fs_put_page(*cp_page, 1);
- f2fs_msg(sbi->sb, KERN_WARNING,
- "invalid crc_offset: %zu", crc_offset);
- - return -EINVAL;
- + goto error;
- }
- crc = cur_cp_crc(*cp_block);
- if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
- f2fs_put_page(*cp_page, 1);
- f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
- - return -EINVAL;
- + goto error;
- }
- *version = cur_cp_version(*cp_block);
- return 0;
- +
- +error:
- + print_block_data(sbi->sb, cp_addr, page_address(*cp_page), 0, blk_size);
- + return -EINVAL;
- }
- static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
- @@ -881,8 +889,13 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
- sbi->cur_cp_pack = 2;
- /* Sanity checking of checkpoint */
- - if (f2fs_sanity_check_ckpt(sbi))
- + if (f2fs_sanity_check_ckpt(sbi)) {
- + print_block_data(sbi->sb, cur_page->index,
- + page_address(cur_page), 0, blk_size);
- goto free_fail_no_cp;
- + }
- +
- + f2fs_get_fsck_stat(sbi);
- if (cp_blks <= 1)
- goto done;
- @@ -1141,6 +1154,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
- err = f2fs_sync_dirty_inodes(sbi, DIR_INODE);
- if (err)
- goto out;
- + blk_flush_plug(current);
- cond_resched();
- goto retry_flush_quotas;
- }
- @@ -1163,6 +1177,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
- err = f2fs_sync_inode_meta(sbi);
- if (err)
- goto out;
- + blk_flush_plug(current);
- cond_resched();
- goto retry_flush_quotas;
- }
- @@ -1180,6 +1195,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
- f2fs_unlock_all(sbi);
- goto out;
- }
- + blk_flush_plug(current);
- cond_resched();
- goto retry_flush_nodes;
- }
- @@ -1492,6 +1508,24 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
- return unlikely(f2fs_cp_error(sbi)) ? -EIO : 0;
- }
- +#define CP_TIME_RECORD_UNIT 1000000
- +static void f2fs_update_max_cp_interval(struct f2fs_sb_info *sbi)
- +{
- + unsigned long long cp_interval = 0;
- +
- + curr_cp_time = local_clock();
- + if (!priv_cp_time)
- + goto out;
- +
- + cp_interval = ((curr_cp_time - priv_cp_time) / CP_TIME_RECORD_UNIT) ?
- + ((curr_cp_time - priv_cp_time) / CP_TIME_RECORD_UNIT) : 1;
- +
- + if (sbi->sec_stat.cp_max_interval < cp_interval)
- + sbi->sec_stat.cp_max_interval = cp_interval;
- +out:
- + priv_cp_time = curr_cp_time;
- +}
- +
- /*
- * We guarantee that this checkpoint procedure will not fail.
- */
- @@ -1573,6 +1607,8 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
- stop:
- unblock_operations(sbi);
- stat_inc_cp_count(sbi->stat_info);
- + sbi->sec_stat.cp_cnt[STAT_CP_ALL]++;
- + f2fs_update_max_cp_interval(sbi);
- if (cpc->reason & CP_RECOVERY)
- f2fs_msg(sbi->sb, KERN_NOTICE,
- diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
- index 15a4a5703a39c..94ff230c26e4e 100644
- --- a/fs/f2fs/data.c
- +++ b/fs/f2fs/data.c
- @@ -24,6 +24,7 @@
- #include "segment.h"
- #include "trace.h"
- #include <trace/events/f2fs.h>
- +#include <trace/events/android_fs.h>
- #define NUM_PREALLOC_POST_READ_CTXS 128
- @@ -82,6 +83,77 @@ struct bio_post_read_ctx {
- unsigned int enabled_steps;
- };
- +#ifdef CONFIG_FS_INLINE_ENCRYPTION
- +static inline bool f2fs_inline_encrypted(struct inode *inode,
- + struct f2fs_io_info *fio)
- +{
- + if (fio && (fio->type != DATA || fio->encrypted_page))
- + return false;
- +
- + return (f2fs_encrypted_file(inode) &&
- + fscrypt_inline_encrypted(inode));
- +}
- +
- +static inline bool __bio_inline_encrypted(struct bio *bio)
- +{
- + if (!bio)
- + return false;
- +
- + if (bio->bi_opf & REQ_CRYPT)
- + return true;
- +
- + return false;
- +}
- +
- +static bool try_merge_bio_encrypted(struct bio *bio, u64 dun, void *ci, bool encrypted)
- +{
- + if (!bio)
- + return true;
- +
- + /* if both of them are not encrypted, no further check is needed */
- + if (!__bio_inline_encrypted(bio) && !encrypted)
- + return true;
- +
- + if (bio->bi_cryptd != ci)
- + return false;
- +
- +#ifdef CONFIG_BLK_DEV_CRYPT_DUN
- + if (bio_end_dun(bio) != dun)
- + return false;
- +#endif
- + return true;
- +}
- +
- +static inline void set_fio_inline_encrypted(struct f2fs_io_info *fio, int set)
- +{
- + if (!fio)
- + return;
- +
- + if (set) {
- + fio->op_flags |= REQ_CRYPT;
- + return;
- + }
- +
- + fio->op_flags &= ~REQ_CRYPT;
- +}
- +#else /* !defined(CONFIG_FS_INLINE_ENCRYPTION) */
- +static inline bool f2fs_inline_encrypted(struct inode *inode,
- + struct f2fs_io_info *fio)
- +{
- + return false;
- +}
- +
- +static bool try_merge_bio_encrypted(struct bio *bio, u64 dun, void *ci, bool encrypted)
- +{
- + return true;
- +}
- +
- +static inline void set_fio_inline_encrypted(struct f2fs_io_info *fio, int set)
- +{
- + /* DO NOTHING */
- +}
- +#endif
- +
- static void __read_end_io(struct bio *bio)
- {
- struct page *page;
- @@ -188,8 +260,10 @@ static void f2fs_write_end_io(struct bio *bio)
- if (unlikely(bio->bi_status)) {
- mapping_set_error(page->mapping, -EIO);
- - if (type == F2FS_WB_CP_DATA)
- + if (type == F2FS_WB_CP_DATA) {
- f2fs_stop_checkpoint(sbi, true);
- + f2fs_bug_on(sbi, 1);
- + }
- }
- f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
- @@ -319,6 +393,15 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
- trace_f2fs_submit_read_bio(sbi->sb, type, bio);
- else
- trace_f2fs_submit_write_bio(sbi->sb, type, bio);
- +
- +#ifdef CONFIG_DDAR
- + if (type == DATA) {
- + if (fscrypt_dd_may_submit_bio(bio) == -EOPNOTSUPP)
- + submit_bio(bio);
- + return;
- + }
- +#endif
- +
- submit_bio(bio);
- }
- @@ -461,6 +544,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
- struct bio *bio;
- struct page *page = fio->encrypted_page ?
- fio->encrypted_page : fio->page;
- + struct inode *inode = fio->page->mapping->host;
- if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
- __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
- @@ -486,6 +570,9 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
- inc_page_count(fio->sbi, is_read_io(fio->op) ?
- __read_io_type(page): WB_DATA_TYPE(fio->page));
- + if (f2fs_inline_encrypted(inode, fio))
- + fscrypt_set_bio_cryptd_dun(inode, bio, FSCRYPT_PG_DUN(inode, fio->page));
- +
- __submit_bio(fio->sbi, bio, fio->type);
- return 0;
- }
- @@ -496,6 +583,9 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
- enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
- struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
- struct page *bio_page;
- + struct inode *inode;
- + bool enc;
- + u64 dun;
- f2fs_bug_on(sbi, is_read_io(fio->op));
- @@ -518,6 +608,10 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
- verify_block_addr(fio, fio->new_blkaddr);
- bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
- + inode = fio->page->mapping->host;
- + dun = FSCRYPT_PG_DUN(inode, fio->page);
- + enc = f2fs_inline_encrypted(inode, fio);
- + set_fio_inline_encrypted(fio, enc);
- /* set submitted = true as a return value */
- fio->submitted = true;
- @@ -528,17 +622,30 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
- (io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) ||
- !__same_bdev(sbi, fio->new_blkaddr, io->bio)))
- __submit_merged_bio(io);
- +
- + if (!try_merge_bio_encrypted(io->bio, dun, fscrypt_get_bio_cryptd(inode), enc))
- + __submit_merged_bio(io);
- +#ifdef CONFIG_DDAR
- + /* DDAR support */
- + if (!fscrypt_dd_can_merge_bio(io->bio, fio->page->mapping))
- + __submit_merged_bio(io);
- +#endif
- +
- alloc_new:
- if (io->bio == NULL) {
- if ((fio->type == DATA || fio->type == NODE) &&
- fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) {
- dec_page_count(sbi, WB_DATA_TYPE(bio_page));
- fio->retry = true;
- + set_fio_inline_encrypted(fio, false);
- goto skip;
- }
- io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
- BIO_MAX_PAGES, false,
- fio->type, fio->temp);
- + if (enc)
- + fscrypt_set_bio_cryptd_dun(inode, io->bio, dun);
- +
- io->fio = *fio;
- }
- @@ -582,7 +689,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
- bio->bi_end_io = f2fs_read_end_io;
- bio_set_op_attrs(bio, REQ_OP_READ, op_flag);
- - if (f2fs_encrypted_file(inode))
- + if (f2fs_encrypted_file(inode) && !fscrypt_inline_encrypted(inode))
- post_read_steps |= 1 << STEP_DECRYPT;
- if (post_read_steps) {
- ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS);
- @@ -616,6 +723,10 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
- }
- ClearPageError(page);
- inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
- +
- + if (f2fs_inline_encrypted(inode, NULL))
- + fscrypt_set_bio_cryptd_dun(inode, bio, FSCRYPT_PG_DUN(inode, page));
- +
- __submit_bio(F2FS_I_SB(inode), bio, DATA);
- return 0;
- }
- @@ -1516,6 +1627,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
- sector_t last_block_in_file;
- sector_t block_nr;
- struct f2fs_map_blocks map;
- + bool enc;
- + u64 dun;
- map.m_pblk = 0;
- map.m_lblk = 0;
- @@ -1597,6 +1710,20 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
- __submit_bio(F2FS_I_SB(inode), bio, DATA);
- bio = NULL;
- }
- +
- + dun = FSCRYPT_PG_DUN(inode, page);
- + enc = f2fs_inline_encrypted(inode, NULL);
- + if (!try_merge_bio_encrypted(bio, dun, fscrypt_get_bio_cryptd(inode), enc)) {
- + __submit_bio(F2FS_I_SB(inode), bio, DATA);
- + bio = NULL;
- + }
- +
- + /* DDAR changes */
- + if (!fscrypt_dd_can_merge_bio(bio, mapping)) {
- + __submit_bio(F2FS_I_SB(inode), bio, DATA);
- + bio = NULL;
- + }
- +
- if (bio == NULL) {
- bio = f2fs_grab_read_bio(inode, block_nr, nr_pages,
- is_readahead ? REQ_RAHEAD : 0);
- @@ -1604,6 +1731,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
- bio = NULL;
- goto set_error_page;
- }
- + if (f2fs_inline_encrypted(inode, NULL))
- + fscrypt_set_bio_cryptd_dun(inode, bio, dun);
- }
- /*
- @@ -1684,6 +1813,14 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
- f2fs_wait_on_block_writeback(inode, fio->old_blkaddr);
- retry_encrypt:
- + if (fscrypt_inline_encrypted(inode))
- + return 0;
- +
- +#ifdef CONFIG_DDAR
- + if (fscrypt_dd_encrypted_inode(inode))
- + return 0;
- +#endif
- +
- fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
- PAGE_SIZE, 0, fio->page->index, gfp_flags);
- if (IS_ERR(fio->encrypted_page)) {
- @@ -1838,6 +1975,14 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
- err = -EFAULT;
- goto out_writepage;
- }
- +
- + if (file_is_hot(inode))
- + F2FS_I_SB(inode)->sec_stat.hot_file_written_blocks++;
- + else if (file_is_cold(inode))
- + F2FS_I_SB(inode)->sec_stat.cold_file_written_blocks++;
- + else
- + F2FS_I_SB(inode)->sec_stat.warm_file_written_blocks++;
- +
- /*
- * If current allocation needs SSR,
- * it had better in-place writes for updated data.
- @@ -2107,8 +2252,8 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
- while (!done && (index <= end)) {
- int i;
- - nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end,
- - tag);
- + nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
- + min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1);
- if (nr_pages == 0)
- break;
- @@ -2116,6 +2261,11 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
- struct page *page = pvec.pages[i];
- bool submitted = false;
- + if (page->index > end) {
- + done = 1;
- + break;
- + }
- +
- /* give a priority to WB_SYNC threads */
- if (atomic_read(&sbi->wb_sync_req[DATA]) &&
- wbc->sync_mode == WB_SYNC_NONE) {
- @@ -2290,6 +2440,12 @@ static int f2fs_write_data_pages(struct address_space *mapping,
- {
- struct inode *inode = mapping->host;
- + /* W/A - prevent panic while shutdown */
- + if (unlikely(ignore_fs_panic)) {
- + //pr_err("%s: Ignore panic\n", __func__);
- + return -EIO;
- + }
- +
- return __f2fs_write_data_pages(mapping, wbc,
- F2FS_I(inode)->cp_task == current ?
- FS_CP_DATA_IO : FS_DATA_IO);
- @@ -2401,6 +2557,16 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
- block_t blkaddr = NULL_ADDR;
- int err = 0;
- + if (trace_android_fs_datawrite_start_enabled()) {
- + char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
- +
- + path = android_fstrace_get_pathname(pathbuf,
- + MAX_TRACE_PATHBUF_LEN,
- + inode);
- + trace_android_fs_datawrite_start(inode, pos, len,
- + current->pid, path,
- + current->comm);
- + }
- trace_f2fs_write_begin(inode, pos, len, flags);
- err = f2fs_is_checkpoint_ready(sbi);
- @@ -2501,6 +2667,7 @@ static int f2fs_write_end(struct file *file,
- {
- struct inode *inode = page->mapping->host;
- + trace_android_fs_datawrite_end(inode, pos, len);
- trace_f2fs_write_end(inode, pos, len, copied);
- /*
- @@ -2572,6 +2739,28 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
- trace_f2fs_direct_IO_enter(inode, offset, count, rw);
- + if (trace_android_fs_dataread_start_enabled() &&
- + (rw == READ)) {
- + char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
- +
- + path = android_fstrace_get_pathname(pathbuf,
- + MAX_TRACE_PATHBUF_LEN,
- + inode);
- + trace_android_fs_dataread_start(inode, offset,
- + count, current->pid, path,
- + current->comm);
- + }
- + if (trace_android_fs_datawrite_start_enabled() &&
- + (rw == WRITE)) {
- + char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
- +
- + path = android_fstrace_get_pathname(pathbuf,
- + MAX_TRACE_PATHBUF_LEN,
- + inode);
- + trace_android_fs_datawrite_start(inode, offset, count,
- + current->pid, path,
- + current->comm);
- + }
- if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
- iocb->ki_hint = WRITE_LIFE_NOT_SET;
- @@ -2612,8 +2801,14 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
- f2fs_write_failed(mapping, offset + count);
- }
- }
- -
- out:
- + if (trace_android_fs_dataread_start_enabled() &&
- + (rw == READ))
- + trace_android_fs_dataread_end(inode, offset, count);
- + if (trace_android_fs_datawrite_start_enabled() &&
- + (rw == WRITE))
- + trace_android_fs_datawrite_end(inode, offset, count);
- +
- trace_f2fs_direct_IO_exit(inode, offset, count, rw, err);
- return err;
- diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
- index 2ef84b4590ead..d9cfd31b3819c 100644
- --- a/fs/f2fs/dir.c
- +++ b/fs/f2fs/dir.c
- @@ -808,6 +808,18 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
- de_name.name = d->filename[bit_pos];
- de_name.len = le16_to_cpu(de->name_len);
- + /* check memory boundary before moving forward */
- + bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
- + if (unlikely(bit_pos > d->max ||
- + le16_to_cpu(de->name_len) > F2FS_NAME_LEN)) {
- + f2fs_msg(sbi->sb, KERN_WARNING,
- + "%s: corrupted namelen=%d, run fsck to fix.",
- + __func__, le16_to_cpu(de->name_len));
- + set_sbi_flag(sbi, SBI_NEED_FSCK);
- + err = -EINVAL;
- + goto out;
- + }
- +
- if (f2fs_encrypted_inode(d->inode)) {
- int save_len = fstr->len;
- @@ -830,7 +842,6 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
- if (readdir_ra)
- f2fs_ra_node_page(sbi, le32_to_cpu(de->ino));
- - bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
- ctx->pos = start_pos + bit_pos;
- }
- out:
- @@ -867,6 +878,9 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
- goto out_free;
- }
- + if (IS_I_VERSION(inode) && file->f_version != inode->i_version)
- + file->f_version = inode->i_version;
- +
- for (; n < npages; n++, ctx->pos = n * NR_DENTRY_IN_BLOCK) {
- /* allow readdir() to be interrupted */
- @@ -899,6 +913,13 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
- err = f2fs_fill_dentries(ctx, &d,
- n * NR_DENTRY_IN_BLOCK, &fstr);
- if (err) {
- + struct f2fs_sb_info *sbi = F2FS_P_SB(dentry_page);
- +
- + if (err == -EINVAL) {
- + print_block_data(sbi->sb, n,
- + page_address(dentry_page), 0, F2FS_BLKSIZE);
- + f2fs_bug_on(sbi, 1);
- + }
- f2fs_put_page(dentry_page, 1);
- break;
- }
- diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
- index 9c7510c98481e..f796c31a6d53d 100644
- --- a/fs/f2fs/f2fs.h
- +++ b/fs/f2fs/f2fs.h
- @@ -24,22 +24,40 @@
- #include <linux/quotaops.h>
- #include <crypto/hash.h>
- #include <linux/overflow.h>
- +#include <linux/android_aid.h>
- +#include <linux/ctype.h>
- +#include "../mount.h"
- #define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_F2FS_FS_ENCRYPTION)
- #include <linux/fscrypt.h>
- -#ifdef CONFIG_F2FS_CHECK_FS
- -#define f2fs_bug_on(sbi, condition) BUG_ON(condition)
- +#ifdef CONFIG_F2FS_STRICT_BUG_ON
- +#define BUG_ON_CHKFS BUG_ON
- #else
- -#define f2fs_bug_on(sbi, condition) \
- - do { \
- - if (unlikely(condition)) { \
- - WARN_ON(1); \
- - set_sbi_flag(sbi, SBI_NEED_FSCK); \
- - } \
- - } while (0)
- +#define BUG_ON_CHKFS WARN_ON
- #endif
- +extern int ignore_fs_panic;
- +extern void (*ufs_debug_func)(void *);
- +
- +#define f2fs_bug_on(sbi, condition) \
- + do { \
- + if (unlikely(condition)) { \
- + if (ufs_debug_func) \
- + ufs_debug_func(NULL); \
- + if (is_sbi_flag_set(sbi, SBI_POR_DOING)) { \
- + set_sbi_flag(sbi, SBI_NEED_FSCK); \
- + sbi->sec_stat.fs_por_error++; \
- + WARN_ON(1); \
- + } else if (unlikely(!ignore_fs_panic)) { \
- + f2fs_set_sb_extra_flag(sbi, \
- + F2FS_SEC_EXTRA_FSCK_MAGIC); \
- + sbi->sec_stat.fs_error++; \
- + BUG_ON_CHKFS(1); \
- + } \
- + } \
- + } while (0)
- +
- enum {
- FAULT_KMALLOC,
- FAULT_KVMALLOC,
- @@ -121,6 +139,7 @@ struct f2fs_mount_info {
- unsigned int opt;
- int write_io_size_bits; /* Write IO size bits */
- block_t root_reserved_blocks; /* root reserved blocks */
- + block_t core_reserved_blocks; /* core reserved blocks */
- kuid_t s_resuid; /* reserved blocks for uid */
- kgid_t s_resgid; /* reserved blocks for gid */
- int active_logs; /* # of active logs */
- @@ -191,6 +210,7 @@ enum {
- #define DEF_CP_INTERVAL 60 /* 60 secs */
- #define DEF_IDLE_INTERVAL 5 /* 5 secs */
- #define DEF_DISABLE_INTERVAL 5 /* 5 secs */
- +#define DEF_UMOUNT_DISCARD_TIMEOUT 5 /* 5 secs */
- struct cp_control {
- int reason;
- @@ -310,6 +330,7 @@ struct discard_policy {
- bool sync; /* submit discard with REQ_SYNC flag */
- bool ordered; /* issue discard by lba order */
- unsigned int granularity; /* discard granularity */
- + int timeout; /* discard timeout for put_super */
- };
- struct discard_cmd_control {
- @@ -383,6 +404,8 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,
- #define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS
- #define F2FS_IOC_GETVERSION FS_IOC_GETVERSION
- +#define F2FS_CORE_FILE_FL 0x40000000
- +
- #define F2FS_IOCTL_MAGIC 0xf5
- #define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
- #define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
- @@ -430,6 +453,12 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,
- #define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR
- #define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR
- +#ifdef CONFIG_DDAR
- +#define F2FS_IOC_GET_DD_POLICY FS_IOC_GET_DD_POLICY
- +#define F2FS_IOC_SET_DD_POLICY FS_IOC_SET_DD_POLICY
- +#endif
- +
- +
- struct f2fs_gc_range {
- u32 sync;
- u64 start;
- @@ -773,6 +802,72 @@ static inline void __try_update_largest_extent(struct extent_tree *et,
- }
- }
- +static inline void print_block_data(struct super_block *sb, sector_t blocknr,
- + unsigned char *data_to_dump, int start, int len)
- +{
- + int i, j;
- + int bh_offset = (start / 16) * 16;
- + char row_data[17] = { 0, };
- + char row_hex[50] = { 0, };
- + char ch;
- + struct mount *mnt = NULL;
- +
- + if (ignore_fs_panic)
- + return;
- +
- + printk(KERN_ERR "As F2FS-fs error, printing data in hex\n");
- + printk(KERN_ERR " [partition info] s_id : %s, start sector# : %lu\n"
- + , sb->s_id, sb->s_bdev->bd_part->start_sect);
- + printk(KERN_ERR " dump block# : %lu, start offset(byte) : %d\n"
- + , blocknr, start);
- + printk(KERN_ERR " length(byte) : %d, data_to_dump 0x%p\n"
- + , len, (void *)data_to_dump);
- + if (!list_empty(&sb->s_mounts)) {
- + mnt = list_first_entry(&sb->s_mounts, struct mount, mnt_instance);
- + if (mnt)
- + printk(KERN_ERR " mountpoint : %s\n"
- + , mnt->mnt_mountpoint->d_name.name);
- + }
- + printk(KERN_ERR "-------------------------------------------------\n");
- + for (i = 0; i < (len + 15) / 16; i++) {
- + for (j = 0; j < 16; j++) {
- + ch = *(data_to_dump + bh_offset + j);
- + if (start <= bh_offset + j
- + && start + len > bh_offset + j) {
- +
- + if (isascii(ch) && isprint(ch))
- + sprintf(row_data + j, "%c", ch);
- + else
- + sprintf(row_data + j, ".");
- +
- + sprintf(row_hex + (j * 3), "%2.2x ", ch);
- + } else {
- + sprintf(row_data + j, " ");
- + sprintf(row_hex + (j * 3), "-- ");
- + }
- + }
- + printk(KERN_ERR "0x%4.4x : %s | %s\n"
- + , bh_offset, row_hex, row_data);
- + bh_offset += 16;
- + }
- + printk(KERN_ERR "-------------------------------------------------\n");
- +}
- +
- +
- +static inline void print_bh(struct super_block *sb, struct buffer_head *bh
- + , int start, int len)
- +{
- + if (bh) {
- + printk(KERN_ERR " print_bh: bh %p,"
- + " bh->b_size %lu, bh->b_data %p\n",
- + (void *) bh, bh->b_size, (void *) bh->b_data);
- + print_block_data(sb, bh->b_blocknr, bh->b_data, start, len);
- +
- + } else {
- + printk(KERN_ERR " print_bh: bh is null!\n");
- + }
- +}
- +
- /*
- * For free nid management
- */
- @@ -1010,6 +1105,7 @@ enum cp_reason_type {
- CP_FASTBOOT_MODE,
- CP_SPEC_LOG_NUM,
- CP_RECOVER_DIR,
- + NR_CP_REASON,
- };
- enum iostat_type {
- @@ -1114,6 +1210,7 @@ enum {
- DISCARD_TIME,
- GC_TIME,
- DISABLE_TIME,
- + UMOUNT_DISCARD_TIMEOUT,
- MAX_TIME,
- };
- @@ -1148,6 +1245,51 @@ enum fsync_mode {
- #define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
- #endif
- +enum sec_stat_cp_type {
- + STAT_CP_ALL,
- + STAT_CP_BG,
- + STAT_CP_FSYNC,
- + NR_STAT_CP,
- +};
- +
- +struct f2fs_sec_stat_info {
- + u64 gc_count[2]; /* FG_GC, BG_GC */
- + u64 gc_node_seg_count[2];
- + u64 gc_data_seg_count[2];
- + u64 gc_node_blk_count[2];
- + u64 gc_data_blk_count[2];
- + u64 gc_ttime[2];
- +
- + u64 cp_cnt[NR_STAT_CP]; /* total, balance, fsync */
- + u64 cpr_cnt[NR_CP_REASON]; /* cp reason by fsync */
- + u64 cp_max_interval; /* max checkpoint interval */
- + u64 alloc_seg_type[2]; /* LFS, SSR */
- + u64 alloc_blk_count[2];
- + atomic64_t inplace_count; /* atomic */
- + u64 fsync_count;
- + u64 fsync_dirty_pages;
- + u64 hot_file_written_blocks; /* db, db-journal, db-wal, db-shm */
- + u64 cold_file_written_blocks;
- + u64 warm_file_written_blocks;
- +
- + u64 max_inmem_pages; /* get_pages(sbi, F2FS_INMEM_PAGES) */
- + u64 drop_inmem_all;
- + u64 drop_inmem_files;
- + u64 kwritten_byte;
- + u32 fs_por_error;
- + u32 fs_error;
- + u32 max_undiscard_blks; /* # of undiscard blocks */
- +};
- +
- +struct f2fs_sec_fsck_info {
- + u64 fsck_read_bytes;
- + u64 fsck_written_bytes;
- + u64 fsck_elapsed_time;
- + u32 fsck_exit_code;
- + u32 valid_node_count;
- + u32 valid_inode_count;
- +};
- +
- struct f2fs_sb_info {
- struct super_block *sb; /* pointer to VFS super block */
- struct proc_dir_entry *s_proc; /* proc entry */
- @@ -1329,6 +1471,17 @@ struct f2fs_sb_info {
- /* Precomputed FS UUID checksum for seeding other checksums */
- __u32 s_chksum_seed;
- +
- + struct f2fs_sec_stat_info sec_stat;
- + struct f2fs_sec_fsck_info sec_fsck_stat;
- +
- + /* To gather information of fragmentation */
- + unsigned int s_sec_part_best_extents;
- + unsigned int s_sec_part_current_extents;
- + unsigned int s_sec_part_score;
- + unsigned int s_sec_defrag_writes_kb;
- + unsigned int s_sec_num_apps;
- + unsigned int s_sec_capacity_apps_kb;
- };
- #ifdef CONFIG_F2FS_FAULT_INJECTION
- @@ -1402,6 +1555,19 @@ static inline unsigned int f2fs_time_to_wait(struct f2fs_sb_info *sbi,
- return wait_ms;
- }
- +/*
- + * SEC Specific Patch
- + * <------ SB -----><----------- CP -------------><-------- .... ----->
- + * [SB0][SB1]....[ ][CP1][CP Payload...]...[CP2]....
- + * ^ (cp_blkaddr - 1) Reserved block for extra flags
- + * - struct f2fs_sb_extra_flag_blk
- + * - need_fsck : force fsck request flags - F2FS_SEC_EXTRA_FSC_MAGIC
- + * - spo_counter : count by fsck (!CP_UMOUNT)
- + * - rsvd
- + */
- +void f2fs_set_sb_extra_flag(struct f2fs_sb_info *sbi, int flag);
- +void f2fs_get_fsck_stat(struct f2fs_sb_info *sbi);
- +
- /*
- * Inline functions
- */
- @@ -1609,7 +1775,11 @@ static inline void disable_nat_bits(struct f2fs_sb_info *sbi, bool lock)
- {
- unsigned long flags;
- - set_sbi_flag(sbi, SBI_NEED_FSCK);
- + /*
- + * In order to re-enable nat_bits we need to call fsck.f2fs by
- + * set_sbi_flag(sbi, SBI_NEED_FSCK). But it may give huge cost,
- + * so let's rely on regular fsck or unclean shutdown.
- + */
- if (lock)
- spin_lock_irqsave(&sbi->cp_lock, flags);
- @@ -1738,8 +1908,13 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
- avail_user_block_count = sbi->user_block_count -
- sbi->current_reserved_blocks;
- - if (!__allow_reserved_blocks(sbi, inode, true))
- + if (!__allow_reserved_blocks(sbi, inode, true)) {
- avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
- +
- + if (!(F2FS_I(inode)->i_flags & F2FS_CORE_FILE_FL))
- + avail_user_block_count -= F2FS_OPTION(sbi).core_reserved_blocks;
- + }
- +
- if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
- avail_user_block_count -= sbi->unusable_block_count;
- if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
- @@ -1954,8 +2129,12 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
- valid_block_count = sbi->total_valid_block_count +
- sbi->current_reserved_blocks + 1;
- - if (!__allow_reserved_blocks(sbi, inode, false))
- + if (!__allow_reserved_blocks(sbi, inode, false)) {
- valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
- + if (!(F2FS_I(inode)->i_flags & F2FS_CORE_FILE_FL))
- + valid_block_count += F2FS_OPTION(sbi).core_reserved_blocks;
- + }
- +
- if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
- valid_block_count += sbi->unusable_block_count;
- @@ -2976,7 +3155,7 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr);
- bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
- void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi);
- void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi);
- -bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi);
- +bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi);
- void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
- struct cp_control *cpc);
- void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi);
- @@ -3559,7 +3738,8 @@ static inline bool f2fs_force_buffered_io(struct inode *inode,
- struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- int rw = iov_iter_rw(iter);
- - if (f2fs_post_read_required(inode))
- + if (f2fs_post_read_required(inode) &&
- + !fscrypt_inline_encrypted(inode))
- return true;
- if (sbi->s_ndevs)
- return true;
- diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
- index ad83382078806..5b86e4da2a0a7 100644
- --- a/fs/f2fs/file.c
- +++ b/fs/f2fs/file.c
- @@ -30,6 +30,10 @@
- #include "trace.h"
- #include <trace/events/f2fs.h>
- +#ifdef CONFIG_FSCRYPT_SDP
- +#include <linux/fscrypto_sdp_ioctl.h>
- +#endif
- +
- static int f2fs_filemap_fault(struct vm_fault *vmf)
- {
- struct inode *inode = file_inode(vmf->vma->vm_file);
- @@ -167,6 +171,8 @@ static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
- TRANS_DIR_INO))
- cp_reason = CP_RECOVER_DIR;
- + sbi->sec_stat.cpr_cnt[cp_reason]++;
- +
- return cp_reason;
- }
- @@ -216,6 +222,9 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
- trace_f2fs_sync_file_enter(inode);
- + sbi->sec_stat.fsync_count++;
- + sbi->sec_stat.fsync_dirty_pages += get_dirty_pages(inode);
- +
- /* if fdatasync is triggered, let's do in-place-update */
- if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
- set_inode_flag(inode, FI_NEED_IPU);
- @@ -268,6 +277,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
- try_to_fix_pino(inode);
- clear_inode_flag(inode, FI_APPEND_WRITE);
- clear_inode_flag(inode, FI_UPDATE_WRITE);
- + sbi->sec_stat.cp_cnt[STAT_CP_FSYNC]++;
- goto out;
- }
- sync_nodes:
- @@ -1648,7 +1658,7 @@ static int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
- if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
- flags |= F2FS_INLINE_DATA_FL;
- - flags &= F2FS_FL_USER_VISIBLE;
- + flags &= (F2FS_FL_USER_VISIBLE | F2FS_CORE_FILE_FL);
- return put_user(flags, (int __user *)arg);
- }
- @@ -1670,8 +1680,8 @@ static int __f2fs_ioc_setflags(struct inode *inode, unsigned int flags)
- if (!capable(CAP_LINUX_IMMUTABLE))
- return -EPERM;
- - flags = flags & F2FS_FL_USER_MODIFIABLE;
- - flags |= oldflags & ~F2FS_FL_USER_MODIFIABLE;
- + flags = flags & (F2FS_FL_USER_MODIFIABLE | F2FS_CORE_FILE_FL);
- + flags |= oldflags & ~(F2FS_FL_USER_MODIFIABLE | F2FS_CORE_FILE_FL);
- fi->i_flags = flags;
- if (fi->i_flags & F2FS_PROJINHERIT_FL)
- @@ -1746,10 +1756,12 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
- down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
- - if (!get_dirty_pages(inode))
- - goto skip_flush;
- -
- - f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
- + /*
- + * Should wait end_io to count F2FS_WB_CP_DATA correctly by
- + * f2fs_is_atomic_file.
- + */
- + if (get_dirty_pages(inode))
- + f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
- "Unexpected flush for atomic writes: ino=%lu, npages=%u",
- inode->i_ino, get_dirty_pages(inode));
- ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
- @@ -1757,7 +1769,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
- up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
- goto out;
- }
- -skip_flush:
- +
- set_inode_flag(inode, FI_ATOMIC_FILE);
- clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
- up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
- @@ -3010,6 +3022,20 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- return f2fs_ioc_set_pin_file(filp, arg);
- case F2FS_IOC_PRECACHE_EXTENTS:
- return f2fs_ioc_precache_extents(filp, arg);
- +#ifdef CONFIG_FSCRYPT_SDP
- + case FS_IOC_GET_SDP_INFO:
- + case FS_IOC_SET_SDP_POLICY:
- + case FS_IOC_SET_SENSITIVE:
- + case FS_IOC_SET_PROTECTED:
- + case FS_IOC_ADD_CHAMBER:
- + case FS_IOC_REMOVE_CHAMBER:
- + return fscrypt_sdp_ioctl(filp, cmd, arg);
- +#endif
- +#ifdef CONFIG_DDAR
- + case F2FS_IOC_GET_DD_POLICY:
- + case F2FS_IOC_SET_DD_POLICY:
- + return fscrypt_dd_ioctl(cmd, &arg, file_inode(filp));
- +#endif
- default:
- return -ENOTTY;
- }
- @@ -3117,6 +3143,18 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- case F2FS_IOC_GET_PIN_FILE:
- case F2FS_IOC_SET_PIN_FILE:
- case F2FS_IOC_PRECACHE_EXTENTS:
- +#ifdef CONFIG_FSCRYPT_SDP
- + case FS_IOC_GET_SDP_INFO:
- + case FS_IOC_SET_SDP_POLICY:
- + case FS_IOC_SET_SENSITIVE:
- + case FS_IOC_SET_PROTECTED:
- + case FS_IOC_ADD_CHAMBER:
- + case FS_IOC_REMOVE_CHAMBER:
- +#endif
- +#ifdef CONFIG_DDAR
- + case F2FS_IOC_GET_DD_POLICY:
- + case F2FS_IOC_SET_DD_POLICY:
- +#endif
- break;
- default:
- return -ENOIOCTLCMD;
- diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
- index 12394086b8488..95ad4bcc1e49d 100644
- --- a/fs/f2fs/gc.c
- +++ b/fs/f2fs/gc.c
- @@ -376,6 +376,9 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
- goto next;
- if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
- goto next;
- + /* W/A for FG_GC failure due to Atomic Write File */
- + if (test_bit(secno, dirty_i->blacklist_victim_secmap))
- + goto next;
- cost = get_gc_cost(sbi, segno, &p);
- @@ -540,6 +543,7 @@ static int gc_node_segment(struct f2fs_sb_info *sbi,
- if (!err && gc_type == FG_GC)
- submitted++;
- stat_inc_node_blk_count(sbi, 1, gc_type);
- + sbi->sec_stat.gc_node_blk_count[gc_type]++;
- }
- if (++phase < 3)
- @@ -716,6 +720,9 @@ static int move_data_block(struct inode *inode, block_t bidx,
- }
- if (f2fs_is_atomic_file(inode)) {
- + /* W/A for FG_GC failure due to Atomic Write File */
- + set_bit(GET_SEC_FROM_SEG(F2FS_I_SB(inode), segno),
- + DIRTY_I(F2FS_I_SB(inode))->blacklist_victim_secmap);
- F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC]++;
- F2FS_I_SB(inode)->skipped_atomic_files[gc_type]++;
- err = -EAGAIN;
- @@ -861,6 +868,9 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
- }
- if (f2fs_is_atomic_file(inode)) {
- + /* W/A for FG_GC failure due to Atomic Write File */
- + set_bit(GET_SEC_FROM_SEG(F2FS_I_SB(inode), segno),
- + DIRTY_I(F2FS_I_SB(inode))->blacklist_victim_secmap);
- F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC]++;
- F2FS_I_SB(inode)->skipped_atomic_files[gc_type]++;
- err = -EAGAIN;
- @@ -1062,6 +1072,7 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
- }
- stat_inc_data_blk_count(sbi, 1, gc_type);
- + sbi->sec_stat.gc_data_blk_count[gc_type]++;
- }
- }
- @@ -1151,13 +1162,15 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
- * - down_read(sentry_lock) - change_curseg()
- * - lock_page(sum_page)
- */
- - if (type == SUM_TYPE_NODE)
- + if (type == SUM_TYPE_NODE) {
- submitted += gc_node_segment(sbi, sum->entries, segno,
- gc_type);
- - else
- + sbi->sec_stat.gc_node_seg_count[gc_type]++;
- + } else {
- submitted += gc_data_segment(sbi, sum->entries, gc_list,
- segno, gc_type);
- -
- + sbi->sec_stat.gc_data_seg_count[gc_type]++;
- + }
- stat_inc_seg_count(sbi, type, gc_type);
- if (gc_type == FG_GC &&
- @@ -1178,6 +1191,17 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
- return seg_freed;
- }
- +/* For record miliseconds */
- +#define GC_TIME_RECORD_UNIT 1000000
- +static void f2fs_update_gc_total_time(struct f2fs_sb_info *sbi,
- + unsigned long long start, unsigned long long end, int gc_type)
- +{
- + if (!((end - start) / GC_TIME_RECORD_UNIT))
- + sbi->sec_stat.gc_ttime[gc_type]++;
- + else
- + sbi->sec_stat.gc_ttime[gc_type] += ((end - start) / GC_TIME_RECORD_UNIT);
- +}
- +
- int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
- bool background, unsigned int segno)
- {
- @@ -1191,7 +1215,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
- .iroot = RADIX_TREE_INIT(GFP_NOFS),
- };
- unsigned long long last_skipped = sbi->skipped_atomic_files[FG_GC];
- - unsigned long long first_skipped;
- + unsigned long long first_skipped, gc_start_time = 0, gc_end_time = 0;
- unsigned int skipped_round = 0, round = 0;
- trace_f2fs_gc_begin(sbi->sb, sync, background,
- @@ -1203,6 +1227,11 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
- reserved_segments(sbi),
- prefree_segments(sbi));
- + gc_start_time = local_clock();
- + /* W/A for FG_GC failure due to Atomic Write File */
- + memset(DIRTY_I(sbi)->blacklist_victim_secmap, 0,
- + f2fs_bitmap_size(MAIN_SECS(sbi)));
- +
- cpc.reason = __get_cp_reason(sbi);
- sbi->skipped_gc_rwsem = 0;
- first_skipped = last_skipped;
- @@ -1282,6 +1311,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
- SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0;
- SIT_I(sbi)->last_victim[FLUSH_DEVICE] = init_segno;
- + gc_end_time = local_clock();
- trace_f2fs_gc_end(sbi->sb, ret, total_freed, sec_freed,
- get_pages(sbi, F2FS_DIRTY_NODES),
- get_pages(sbi, F2FS_DIRTY_DENTS),
- @@ -1291,6 +1321,8 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
- reserved_segments(sbi),
- prefree_segments(sbi));
- + sbi->sec_stat.gc_count[gc_type]++;
- + f2fs_update_gc_total_time(sbi, gc_start_time, gc_end_time, gc_type);
- mutex_unlock(&sbi->gc_mutex);
- put_gc_inode(&gc_list);
- diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
- index cb31a719b0488..36389278beebc 100644
- --- a/fs/f2fs/inline.c
- +++ b/fs/f2fs/inline.c
- @@ -11,6 +11,7 @@
- #include "f2fs.h"
- #include "node.h"
- +#include <trace/events/android_fs.h>
- bool f2fs_may_inline_data(struct inode *inode)
- {
- @@ -84,14 +85,29 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
- {
- struct page *ipage;
- + if (trace_android_fs_dataread_start_enabled()) {
- + char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
- +
- + path = android_fstrace_get_pathname(pathbuf,
- + MAX_TRACE_PATHBUF_LEN,
- + inode);
- + trace_android_fs_dataread_start(inode, page_offset(page),
- + PAGE_SIZE, current->pid,
- + path, current->comm);
- + }
- +
- ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
- if (IS_ERR(ipage)) {
- + trace_android_fs_dataread_end(inode, page_offset(page),
- + PAGE_SIZE);
- unlock_page(page);
- return PTR_ERR(ipage);
- }
- if (!f2fs_has_inline_data(inode)) {
- f2fs_put_page(ipage, 1);
- + trace_android_fs_dataread_end(inode, page_offset(page),
- + PAGE_SIZE);
- return -EAGAIN;
- }
- @@ -103,6 +119,8 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
- if (!PageUptodate(page))
- SetPageUptodate(page);
- f2fs_put_page(ipage, 1);
- + trace_android_fs_dataread_end(inode, page_offset(page),
- + PAGE_SIZE);
- unlock_page(page);
- return 0;
- }
- diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
- index 91ceee0ed4c40..b216783c5d05e 100644
- --- a/fs/f2fs/inode.c
- +++ b/fs/f2fs/inode.c
- @@ -22,6 +22,9 @@ void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync)
- if (is_inode_flag_set(inode, FI_NEW_INODE))
- return;
- + if (IS_I_VERSION(inode))
- + inode_inc_iversion(inode);
- +
- if (f2fs_inode_dirtied(inode, sync))
- return;
- @@ -320,6 +323,10 @@ static int do_read_inode(struct inode *inode)
- inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
- inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
- inode->i_generation = le32_to_cpu(ri->i_generation);
- +
- + if (IS_I_VERSION(inode))
- + inode->i_version++;
- +
- if (S_ISDIR(inode->i_mode))
- fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
- else if (S_ISREG(inode->i_mode))
- @@ -407,6 +414,13 @@ static int do_read_inode(struct inode *inode)
- F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
- F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
- F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
- +
- + if (unlikely((inode->i_mode & S_IFMT) == 0)) {
- + print_block_data(sbi->sb, inode->i_ino, page_address(node_page),
- + 0, F2FS_BLKSIZE);
- + f2fs_bug_on(sbi, 1);
- + }
- +
- f2fs_put_page(node_page, 1);
- stat_inc_inline_xattr(inode);
- diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
- index aa53748e426a0..178176e7fccc3 100644
- --- a/fs/f2fs/namei.c
- +++ b/fs/f2fs/namei.c
- @@ -48,6 +48,10 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
- inode->i_ino = ino;
- inode->i_blocks = 0;
- +
- + if (IS_I_VERSION(inode))
- + inode->i_version++;
- +
- inode->i_mtime = inode->i_atime = inode->i_ctime =
- F2FS_I(inode)->i_crtime = current_time(inode);
- inode->i_generation = sbi->s_next_generation++;
- @@ -299,8 +303,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
- f2fs_alloc_nid_done(sbi, ino);
- - unlock_new_inode(inode);
- - d_instantiate(dentry, inode);
- + d_instantiate_new(dentry, inode);
- if (IS_DIRSYNC(dir))
- f2fs_sync_fs(sbi->sb, 1);
- @@ -458,13 +461,23 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
- }
- ino = le32_to_cpu(de->ino);
- - f2fs_put_page(page, 0);
- inode = f2fs_iget(dir->i_sb, ino);
- if (IS_ERR(inode)) {
- + if (PTR_ERR(inode) != -ENOMEM) {
- + struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
- +
- + printk_ratelimited(KERN_ERR "F2FS-fs: Invalid inode referenced: %u"
- + "at parent inode : %lu\n",ino, dir->i_ino);
- + print_block_data(sbi->sb, page->index,
- + page_address(page), 0, F2FS_BLKSIZE);
- + f2fs_bug_on(sbi, 1);
- + }
- + f2fs_put_page(page, 0);
- err = PTR_ERR(inode);
- goto out;
- }
- + f2fs_put_page(page, 0);
- if ((dir->i_ino == root_ino) && f2fs_has_inline_dots(dir)) {
- err = __recover_dot_dentries(dir, root_ino);
- @@ -608,8 +621,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
- err = page_symlink(inode, disk_link.name, disk_link.len);
- err_out:
- - unlock_new_inode(inode);
- - d_instantiate(dentry, inode);
- + d_instantiate_new(dentry, inode);
- /*
- * Let's flush symlink data in order to avoid broken symlink as much as
- @@ -672,8 +684,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
- f2fs_alloc_nid_done(sbi, inode->i_ino);
- - unlock_new_inode(inode);
- - d_instantiate(dentry, inode);
- + d_instantiate_new(dentry, inode);
- if (IS_DIRSYNC(dir))
- f2fs_sync_fs(sbi->sb, 1);
- @@ -727,8 +738,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
- f2fs_alloc_nid_done(sbi, inode->i_ino);
- - unlock_new_inode(inode);
- - d_instantiate(dentry, inode);
- + d_instantiate_new(dentry, inode);
- if (IS_DIRSYNC(dir))
- f2fs_sync_fs(sbi->sb, 1);
- diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
- index bea66bd7fdcb1..ebb71c5072a02 100644
- --- a/fs/f2fs/node.c
- +++ b/fs/f2fs/node.c
- @@ -88,9 +88,9 @@ bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type)
- sizeof(struct extent_node)) >> PAGE_SHIFT;
- res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
- } else if (type == INMEM_PAGES) {
- - /* it allows 20% / total_ram for inmemory pages */
- + /* it allows 50% / total_ram for inmemory pages */
- mem_size = get_pages(sbi, F2FS_INMEM_PAGES);
- - res = mem_size < (val.totalram / 5);
- + res = mem_size < (val.totalram / 2);
- } else {
- if (!sbi->sb->s_bdi->wb.dirty_exceeded)
- return true;
- @@ -1372,6 +1372,10 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
- next_blkaddr_of_node(page));
- err = -EINVAL;
- out_err:
- + if (PageUptodate(page)) {
- + print_block_data(sbi->sb, nid, page_address(page), 0, F2FS_BLKSIZE);
- + f2fs_bug_on(sbi, 1);
- + }
- ClearPageUptodate(page);
- f2fs_put_page(page, 1);
- return ERR_PTR(err);
- @@ -1439,7 +1443,7 @@ static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)
- index = 0;
- while ((nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
- - PAGECACHE_TAG_DIRTY))) {
- + PAGECACHE_TAG_DIRTY, PAGEVEC_SIZE))) {
- int i;
- for (i = 0; i < nr_pages; i++) {
- @@ -1655,7 +1659,7 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
- index = 0;
- while ((nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
- - PAGECACHE_TAG_DIRTY))) {
- + PAGECACHE_TAG_DIRTY, PAGEVEC_SIZE))) {
- int i;
- for (i = 0; i < nr_pages; i++) {
- @@ -1768,8 +1772,8 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
- next_step:
- index = 0;
- - while (!done && (nr_pages = pagevec_lookup_tag(&pvec,
- - NODE_MAPPING(sbi), &index, PAGECACHE_TAG_DIRTY))) {
- + while (!done && (nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
- + PAGECACHE_TAG_DIRTY, PAGEVEC_SIZE))) {
- int i;
- for (i = 0; i < nr_pages; i++) {
- @@ -1918,6 +1922,12 @@ static int f2fs_write_node_pages(struct address_space *mapping,
- if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
- goto skip_write;
- + /* W/A - prevent panic while shutdown */
- + if (unlikely(ignore_fs_panic)) {
- + //pr_err("%s: Ignore panic\n", __func__);
- + return -EIO;
- + }
- +
- /* balancing f2fs's metadata in background */
- f2fs_balance_fs_bg(sbi);
- @@ -2171,8 +2181,11 @@ static int scan_nat_page(struct f2fs_sb_info *sbi,
- blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
- - if (blk_addr == NEW_ADDR)
- + if (blk_addr == NEW_ADDR) {
- + print_block_data(sbi->sb, current_nat_addr(sbi, start_nid),
- + page_address(nat_page), 0, F2FS_BLKSIZE);
- return -EINVAL;
- + }
- if (blk_addr == NULL_ADDR) {
- add_free_nid(sbi, start_nid, true, true);
- @@ -2324,6 +2337,30 @@ int f2fs_build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
- return ret;
- }
- +/*
- + * f2fs_has_free_inodes()
- + * @sbi: in-core super block structure.
- + *
- + * Check if filesystem has inodes available for allocation.
- + * On success return 1, return 0 on failure.
- + */
- +static inline bool f2fs_has_free_inodes(struct f2fs_sb_info *sbi)
- +{
- + struct f2fs_nm_info *nm_i = NM_I(sbi);
- +
- +#define F2FS_DEF_RESERVE_INODE 8192
- + if (likely(nm_i->available_nids > F2FS_DEF_RESERVE_INODE))
- + return true;
- +
- + /* Hm, nope. Are (enough) root reserved inodes available? */
- + if (uid_eq(F2FS_OPTION(sbi).s_resuid, current_fsuid()) ||
- + (!gid_eq(F2FS_OPTION(sbi).s_resgid, GLOBAL_ROOT_GID) &&
- + in_group_p(F2FS_OPTION(sbi).s_resgid)) ||
- + capable(CAP_SYS_RESOURCE))
- + return true;
- + return false;
- +}
- +
- /*
- * If this function returns success, caller can obtain a new nid
- * from second parameter of this function.
- @@ -2341,7 +2378,8 @@ bool f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
- spin_lock(&nm_i->nid_list_lock);
- - if (unlikely(nm_i->available_nids == 0)) {
- + if (unlikely(nm_i->available_nids == 0)
- + || f2fs_has_free_inodes(sbi) == 0) {
- spin_unlock(&nm_i->nid_list_lock);
- return false;
- }
- diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
- index 6edcf8391dd3d..fd8db93a6ee2a 100644
- --- a/fs/f2fs/segment.c
- +++ b/fs/f2fs/segment.c
- @@ -84,6 +84,14 @@ static inline unsigned long __reverse_ffs(unsigned long word)
- return num;
- }
- +static inline void update_max_undiscard_blks(struct f2fs_sb_info *sbi)
- +{
- + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
- +
- + if (dcc->undiscard_blks > sbi->sec_stat.max_undiscard_blks)
- + sbi->sec_stat.max_undiscard_blks = dcc->undiscard_blks;
- +}
- +
- /*
- * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because
- * f2fs_set_bit makes MSB and LSB reversed in a byte.
- @@ -209,6 +217,8 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page)
- list_add_tail(&fi->inmem_ilist, &sbi->inode_list[ATOMIC_FILE]);
- spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
- inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
- + if (F2FS_I_SB(inode)->sec_stat.max_inmem_pages < get_pages(sbi, F2FS_INMEM_PAGES))
- + F2FS_I_SB(inode)->sec_stat.max_inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
- mutex_unlock(&fi->inmem_lock);
- trace_f2fs_register_inmem_page(page, INMEM);
- @@ -286,6 +296,8 @@ void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)
- struct list_head *head = &sbi->inode_list[ATOMIC_FILE];
- struct inode *inode;
- struct f2fs_inode_info *fi;
- +
- + sbi->sec_stat.drop_inmem_all++;
- next:
- spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
- if (list_empty(head)) {
- @@ -294,6 +306,7 @@ void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)
- }
- fi = list_first_entry(head, struct f2fs_inode_info, inmem_ilist);
- inode = igrab(&fi->vfs_inode);
- + sbi->sec_stat.drop_inmem_files++;
- spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
- if (inode) {
- @@ -535,6 +548,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
- }
- f2fs_sync_fs(sbi->sb, true);
- stat_inc_bg_cp_count(sbi->stat_info);
- + sbi->sec_stat.cp_cnt[STAT_CP_BG]++;
- }
- }
- @@ -915,6 +929,7 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi,
- dc->bio_ref = 0;
- atomic_inc(&dcc->discard_cmd_cnt);
- dcc->undiscard_blks += len;
- + update_max_undiscard_blks(sbi);
- return dc;
- }
- @@ -1033,13 +1048,18 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
- dpolicy->granularity = granularity;
- dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
- - dpolicy->io_aware_gran = MAX_PLIST_NUM;
- + dpolicy->io_aware_gran = MAX_PLIST_NUM - 1;
- + dpolicy->timeout = 0;
- if (discard_type == DPOLICY_BG) {
- dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
- dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME;
- dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
- +#ifdef CONFIG_F2FS_CHECK_FS
- dpolicy->io_aware = true;
- +#else
- + dpolicy->io_aware = false;
- +#endif
- dpolicy->sync = false;
- dpolicy->ordered = true;
- if (utilization(sbi) > DEF_DISCARD_URGENT_UTIL) {
- @@ -1222,6 +1242,7 @@ static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
- if (blkaddr > di.lstart) {
- dc->len = blkaddr - dc->lstart;
- dcc->undiscard_blks += dc->len;
- + update_max_undiscard_blks(sbi);
- __relocate_discard_cmd(dcc, dc);
- modified = true;
- }
- @@ -1237,6 +1258,7 @@ static void __punch_discard_cmd(struct f2fs_sb_info *sbi,
- dc->len--;
- dc->start++;
- dcc->undiscard_blks += dc->len;
- + update_max_undiscard_blks(sbi);
- __relocate_discard_cmd(dcc, dc);
- }
- }
- @@ -1299,6 +1321,7 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
- max_discard_blocks)) {
- prev_dc->di.len += di.len;
- dcc->undiscard_blks += di.len;
- + update_max_undiscard_blks(sbi);
- __relocate_discard_cmd(dcc, prev_dc);
- di = prev_dc->di;
- tdc = prev_dc;
- @@ -1313,6 +1336,7 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
- next_dc->di.len += di.len;
- next_dc->di.start = di.start;
- dcc->undiscard_blks += di.len;
- + update_max_undiscard_blks(sbi);
- __relocate_discard_cmd(dcc, next_dc);
- if (tdc)
- __remove_discard_cmd(sbi, tdc);
- @@ -1421,11 +1445,18 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
- int i, issued = 0;
- bool io_interrupted = false;
- + if (dpolicy->timeout != 0)
- + f2fs_update_time(sbi, dpolicy->timeout);
- +
- for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
- + if (dpolicy->timeout != 0 &&
- + f2fs_time_over(sbi, dpolicy->timeout))
- + break;
- +
- if (i + 1 < dpolicy->granularity)
- break;
- - if (i < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered)
- + if (i + 1 < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered)
- return __issue_discard_cmd_orderly(sbi, dpolicy);
- pend_list = &dcc->pend_list[i];
- @@ -1608,7 +1639,7 @@ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)
- }
- /* This comes from f2fs_put_super */
- -bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi)
- +bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
- {
- struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
- struct discard_policy dpolicy;
- @@ -1616,6 +1647,7 @@ bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi)
- __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT,
- dcc->discard_granularity);
- + dpolicy.timeout = UMOUNT_DISCARD_TIMEOUT;
- __issue_discard_cmd(sbi, &dpolicy);
- dropped = __drop_discard_cmd(sbi);
- @@ -2516,6 +2548,13 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type)
- sum_page = f2fs_get_sum_page(sbi, new_segno);
- f2fs_bug_on(sbi, IS_ERR(sum_page));
- +
- + /* W/A - prevent panic while shutdown */
- + if (unlikely(ignore_fs_panic && IS_ERR(sum_page))) {
- + //pr_err("%s: Ignore panic err=%ld\n", __func__, PTR_ERR(sum_page));
- + return;
- + }
- +
- sum_node = (struct f2fs_summary_block *)page_address(sum_page);
- memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
- f2fs_put_page(sum_page, 1);
- @@ -2597,6 +2636,7 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
- new_curseg(sbi, type, false);
- stat_inc_seg_type(sbi, curseg);
- + sbi->sec_stat.alloc_seg_type[curseg->alloc_type]++;
- }
- void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
- @@ -2773,10 +2813,10 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
- __init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen);
- trimmed = __issue_discard_cmd_range(sbi, &dpolicy,
- - start_block, end_block);
- + start_block, end_block);
- trimmed += __wait_discard_cmd_range(sbi, &dpolicy,
- - start_block, end_block);
- + start_block, end_block);
- out:
- if (!err)
- range->len = F2FS_BLK_TO_BYTES(trimmed);
- @@ -2998,7 +3038,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
- __refresh_next_blkoff(sbi, curseg);
- stat_inc_block_count(sbi, curseg);
- -
- + sbi->sec_stat.alloc_blk_count[curseg->alloc_type]++;
- /*
- * SIT information should be updated before segment allocation,
- * since SSR needs latest valid block information.
- @@ -3155,6 +3195,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
- GET_SEGNO(sbi, fio->new_blkaddr))->type));
- stat_inc_inplace_blocks(fio->sbi);
- + atomic64_inc(&(sbi->sec_stat.inplace_count));
- err = f2fs_submit_page_bio(fio);
- if (!err)
- @@ -3748,6 +3789,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
- unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK,
- (unsigned long)MAIN_SEGS(sbi));
- unsigned int segno = start_segno;
- + int err = 0;
- if (to_journal &&
- !__has_cursum_space(journal, ses->entry_cnt, SIT_JOURNAL))
- @@ -3785,16 +3827,16 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
- cpu_to_le32(segno);
- seg_info_to_raw_sit(se,
- &sit_in_journal(journal, offset));
- - check_block_count(sbi, segno,
- + err = check_block_count(sbi, segno,
- &sit_in_journal(journal, offset));
- } else {
- sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
- seg_info_to_raw_sit(se,
- &raw_sit->entries[sit_offset]);
- - check_block_count(sbi, segno,
- + err = check_block_count(sbi, segno,
- &raw_sit->entries[sit_offset]);
- }
- -
- + f2fs_bug_on(sbi, err);
- __clear_bit(segno, bitmap);
- sit_i->dirty_sentries--;
- ses->entry_cnt--;
- @@ -4016,8 +4058,11 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
- f2fs_put_page(page, 1);
- err = check_block_count(sbi, start, &sit);
- - if (err)
- + if (err) {
- + print_block_data(sbi->sb, current_sit_addr(sbi, start),
- + page_address(page), 0, F2FS_BLKSIZE);
- return err;
- + }
- seg_info_from_raw_sit(se, &sit);
- if (IS_NODESEG(se->type))
- total_node_blocks += se->valid_blocks;
- @@ -4064,8 +4109,11 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
- total_node_blocks -= old_valid_blocks;
- err = check_block_count(sbi, start, &sit);
- - if (err)
- + if (err) {
- + print_block_data(sbi->sb, 0, (void *)&sit, 0,
- + sizeof(struct f2fs_sit_entry));
- break;
- + }
- seg_info_from_raw_sit(se, &sit);
- if (IS_NODESEG(se->type))
- total_node_blocks += se->valid_blocks;
- @@ -4154,6 +4202,13 @@ static int init_victim_secmap(struct f2fs_sb_info *sbi)
- dirty_i->victim_secmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
- if (!dirty_i->victim_secmap)
- return -ENOMEM;
- +
- + /* W/A for FG_GC failure due to Atomic Write File */
- + dirty_i->blacklist_victim_secmap = f2fs_kvzalloc(sbi, bitmap_size,
- + GFP_KERNEL);
- + if (!dirty_i->blacklist_victim_secmap)
- + return -ENOMEM;
- +
- return 0;
- }
- @@ -4298,6 +4353,9 @@ static void destroy_victim_secmap(struct f2fs_sb_info *sbi)
- {
- struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
- kvfree(dirty_i->victim_secmap);
- +
- + /* W/A for FG_GC failure due to Atomic Write File */
- + kvfree(dirty_i->blacklist_victim_secmap);
- }
- static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
- diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
- index ab3465faddf13..00ea8f3decada 100644
- --- a/fs/f2fs/segment.h
- +++ b/fs/f2fs/segment.h
- @@ -277,6 +277,9 @@ struct dirty_seglist_info {
- struct mutex seglist_lock; /* lock for segment bitmaps */
- int nr_dirty[NR_DIRTY_TYPE]; /* # of dirty segments */
- unsigned long *victim_secmap; /* background GC victims */
- +
- + /* W/A for FG_GC failure due to Atomic Write File */
- + unsigned long *blacklist_victim_secmap; /* GC Failed Bitmap */
- };
- /* victim selection function for cleaning and SSR */
- diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
- index ec91486957644..eb86d6b680fbd 100644
- --- a/fs/f2fs/super.c
- +++ b/fs/f2fs/super.c
- @@ -34,6 +34,10 @@
- #define CREATE_TRACE_POINTS
- #include <trace/events/f2fs.h>
- +#ifdef CONFIG_FSCRYPT_SDP
- +#include <linux/fscrypto_sdp_cache.h>
- +#endif
- +
- static struct kmem_cache *f2fs_inode_cachep;
- #ifdef CONFIG_F2FS_FAULT_INJECTION
- @@ -110,6 +114,7 @@ enum {
- Opt_noinline_data,
- Opt_data_flush,
- Opt_reserve_root,
- + Opt_reserve_core,
- Opt_resgid,
- Opt_resuid,
- Opt_mode,
- @@ -169,6 +174,7 @@ static match_table_t f2fs_tokens = {
- {Opt_noinline_data, "noinline_data"},
- {Opt_data_flush, "data_flush"},
- {Opt_reserve_root, "reserve_root=%u"},
- + {Opt_reserve_core, "reserve_core=%u"},
- {Opt_resgid, "resgid=%u"},
- {Opt_resuid, "resuid=%u"},
- {Opt_mode, "mode=%s"},
- @@ -211,11 +217,107 @@ void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...)
- va_end(args);
- }
- +void f2fs_set_sb_extra_flag(struct f2fs_sb_info *sbi, int flag)
- +{
- + struct f2fs_super_block *fsb = sbi->raw_super;
- + unsigned long long extra_flag_blk_no = le32_to_cpu(fsb->cp_blkaddr) - 1;
- +
- + struct buffer_head *bh;
- + struct f2fs_sb_extra_flag_blk *extra_blk;
- +
- + if (extra_flag_blk_no < 2) {
- + // 0 -> SB 0, 1 -> SB 1,
- + // 2 or more : RSVD
- + f2fs_msg(sbi->sb, KERN_WARNING,
- + "extra_flag: No free blks for extra flags");
- + return;
- + }
- +
- + bh = sb_bread(sbi->sb, (sector_t)extra_flag_blk_no);
- + if(!bh) {
- + f2fs_msg(sbi->sb, KERN_WARNING,
- + "extra_flag: Fail to allocate buffer_head");
- + return;
- + }
- +
- + lock_buffer(bh);
- + extra_blk = (struct f2fs_sb_extra_flag_blk*)bh->b_data;
- +
- + switch(flag) {
- + case F2FS_SEC_EXTRA_FSCK_MAGIC:
- + if (extra_blk->need_fsck ==
- + cpu_to_le32(F2FS_SEC_EXTRA_FSCK_MAGIC))
- + goto out_unlock;
- +
- + extra_blk->need_fsck = cpu_to_le32(F2FS_SEC_EXTRA_FSCK_MAGIC);
- + break;
- + default:
- + f2fs_msg(sbi->sb, KERN_WARNING,
- + "extra_flag: Undefined flag - %x", flag);
- + goto out_unlock;
- + }
- +
- + set_buffer_uptodate(bh);
- + set_buffer_dirty(bh);
- + unlock_buffer(bh);
- +
- + if (__sync_dirty_buffer(bh, REQ_SYNC | REQ_FUA))
- + f2fs_msg(sbi->sb, KERN_WARNING, "extra_flag: EIO");
- +
- + brelse(bh);
- +
- + return;
- +
- +out_unlock:
- + unlock_buffer(bh);
- + brelse(bh);
- +
- + return;
- +}
- +
- +void f2fs_get_fsck_stat(struct f2fs_sb_info *sbi)
- +{
- + struct f2fs_super_block *fsb = sbi->raw_super;
- + unsigned long long extra_flag_blk_no = le32_to_cpu(fsb->cp_blkaddr) - 1;
- +
- + struct buffer_head *bh;
- + struct f2fs_sb_extra_flag_blk *extra_blk;
- +
- + if (extra_flag_blk_no < 2) {
- + f2fs_msg(sbi->sb, KERN_WARNING,
- + "extra_flag: No free blks for extra flags");
- + return;
- + }
- +
- + bh = sb_bread(sbi->sb, (sector_t)extra_flag_blk_no);
- + if (!bh) {
- + f2fs_msg(sbi->sb, KERN_WARNING,
- + "extra_flag: Fail to allocate buffer_head");
- + return;
- + }
- +
- + extra_blk = (struct f2fs_sb_extra_flag_blk*)bh->b_data;
- + sbi->sec_fsck_stat.fsck_elapsed_time =
- + le64_to_cpu(extra_blk->fsck_elapsed_time);
- + sbi->sec_fsck_stat.fsck_read_bytes =
- + le64_to_cpu(extra_blk->fsck_read_bytes);
- + sbi->sec_fsck_stat.fsck_written_bytes =
- + le64_to_cpu(extra_blk->fsck_written_bytes);
- + sbi->sec_fsck_stat.fsck_exit_code =
- + le32_to_cpu(extra_blk->fsck_exit_code);
- + sbi->sec_fsck_stat.valid_node_count =
- + le32_to_cpu(extra_blk->valid_node_count);
- + sbi->sec_fsck_stat.valid_inode_count =
- + le32_to_cpu(extra_blk->valid_inode_count);
- +
- + brelse(bh);
- +}
- +
- static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
- {
- - block_t limit = (sbi->user_block_count << 1) / 1000;
- + block_t limit = sbi->user_block_count / 100;
- - /* limit is 0.2% */
- + /* limit is 1.0% */
- if (test_opt(sbi, RESERVE_ROOT) &&
- F2FS_OPTION(sbi).root_reserved_blocks > limit) {
- F2FS_OPTION(sbi).root_reserved_blocks = limit;
- @@ -223,17 +325,26 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
- "Reduce reserved blocks for root = %u",
- F2FS_OPTION(sbi).root_reserved_blocks);
- }
- + if (test_opt(sbi, RESERVE_ROOT) &&
- + F2FS_OPTION(sbi).core_reserved_blocks > limit) {
- + F2FS_OPTION(sbi).core_reserved_blocks = limit;
- + f2fs_msg(sbi->sb, KERN_INFO,
- + "Reduce reserved blocks for core = %u",
- + F2FS_OPTION(sbi).core_reserved_blocks);
- + }
- if (!test_opt(sbi, RESERVE_ROOT) &&
- (!uid_eq(F2FS_OPTION(sbi).s_resuid,
- make_kuid(&init_user_ns, F2FS_DEF_RESUID)) ||
- !gid_eq(F2FS_OPTION(sbi).s_resgid,
- - make_kgid(&init_user_ns, F2FS_DEF_RESGID))))
- + make_kgid(&init_user_ns, F2FS_DEF_RESGID)) ||
- + F2FS_OPTION(sbi).core_reserved_blocks != 0))
- f2fs_msg(sbi->sb, KERN_INFO,
- - "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
- + "Ignore s_resuid=%u, s_resgid=%u reserve_core=%u w/o reserve_root",
- from_kuid_munged(&init_user_ns,
- F2FS_OPTION(sbi).s_resuid),
- from_kgid_munged(&init_user_ns,
- - F2FS_OPTION(sbi).s_resgid));
- + F2FS_OPTION(sbi).s_resgid),
- + F2FS_OPTION(sbi).core_reserved_blocks);
- }
- static void init_once(void *foo)
- @@ -537,6 +648,11 @@ static int parse_options(struct super_block *sb, char *options)
- set_opt(sbi, RESERVE_ROOT);
- }
- break;
- + case Opt_reserve_core:
- + if (args->from && match_int(args, &arg))
- + return -EINVAL;
- + F2FS_OPTION(sbi).core_reserved_blocks = arg;
- + break;
- case Opt_resuid:
- if (args->from && match_int(args, &arg))
- return -EINVAL;
- @@ -871,6 +987,9 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
- init_once((void *) fi);
- /* Initialize f2fs-specific inode info */
- + /* F2FS doesn't write value of i_version to disk and
- + it will be reinitialize after a reboot.*/
- + fi->vfs_inode.i_version = 1;
- atomic_set(&fi->dirty_pages, 0);
- init_rwsem(&fi->i_sem);
- INIT_LIST_HEAD(&fi->dirty_list);
- @@ -927,6 +1046,12 @@ static int f2fs_drop_inode(struct inode *inode)
- return 0;
- }
- ret = generic_drop_inode(inode);
- +#ifdef CONFIG_FSCRYPT_SDP
- + if (!ret && fscrypt_sdp_is_locked_sensitive_inode(inode)) {
- + fscrypt_sdp_drop_inode(inode);
- + ret = 1;
- + }
- +#endif
- trace_f2fs_drop_inode(inode, ret);
- return ret;
- }
- @@ -1048,7 +1173,7 @@ static void f2fs_put_super(struct super_block *sb)
- }
- /* be sure to wait for any on-going discard commands */
- - dropped = f2fs_wait_discard_bios(sbi);
- + dropped = f2fs_issue_discard_timeout(sbi);
- if ((f2fs_hw_support_discard(sbi) || f2fs_hw_should_discard(sbi)) &&
- !sbi->discard_blks && !dropped) {
- @@ -1078,7 +1203,10 @@ static void f2fs_put_super(struct super_block *sb)
- f2fs_bug_on(sbi, sbi->fsync_node_num);
- iput(sbi->node_inode);
- + sbi->node_inode = NULL;
- +
- iput(sbi->meta_inode);
- + sbi->meta_inode = NULL;
- /* destroy f2fs internal modules */
- f2fs_destroy_node_manager(sbi);
- @@ -1218,9 +1346,11 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
- else
- buf->f_bfree -= sbi->unusable_block_count;
- - if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks)
- + if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks +
- + F2FS_OPTION(sbi).core_reserved_blocks)
- buf->f_bavail = buf->f_bfree -
- - F2FS_OPTION(sbi).root_reserved_blocks;
- + F2FS_OPTION(sbi).root_reserved_blocks -
- + F2FS_OPTION(sbi).core_reserved_blocks;
- else
- buf->f_bavail = 0;
- @@ -1355,8 +1485,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
- seq_puts(seq, "lfs");
- seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
- if (test_opt(sbi, RESERVE_ROOT))
- - seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
- + seq_printf(seq, ",reserve_root=%u,reserve_core=%u,resuid=%u,resgid=%u",
- F2FS_OPTION(sbi).root_reserved_blocks,
- + F2FS_OPTION(sbi).core_reserved_blocks,
- from_kuid_munged(&init_user_ns,
- F2FS_OPTION(sbi).s_resuid),
- from_kgid_munged(&init_user_ns,
- @@ -1429,7 +1560,8 @@ static void default_options(struct f2fs_sb_info *sbi)
- set_opt(sbi, NOHEAP);
- sbi->sb->s_flags |= MS_LAZYTIME;
- clear_opt(sbi, DISABLE_CHECKPOINT);
- - set_opt(sbi, FLUSH_MERGE);
- + /* P190412-00841 diable flush_merge by default */
- + //set_opt(sbi, FLUSH_MERGE);
- set_opt(sbi, DISCARD);
- if (f2fs_sb_has_blkzoned(sbi->sb))
- set_opt_mode(sbi, F2FS_MOUNT_LFS);
- @@ -1457,19 +1589,16 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
- sbi->sb->s_flags |= SB_ACTIVE;
- - mutex_lock(&sbi->gc_mutex);
- f2fs_update_time(sbi, DISABLE_TIME);
- while (!f2fs_time_over(sbi, DISABLE_TIME)) {
- + mutex_lock(&sbi->gc_mutex);
- err = f2fs_gc(sbi, true, false, NULL_SEGNO);
- if (err == -ENODATA)
- break;
- - if (err && err != -EAGAIN) {
- - mutex_unlock(&sbi->gc_mutex);
- + if (err && err != -EAGAIN)
- return err;
- - }
- }
- - mutex_unlock(&sbi->gc_mutex);
- err = sync_filesystem(sbi->sb);
- if (err)
- @@ -1500,7 +1629,8 @@ static void f2fs_enable_checkpoint(struct f2fs_sb_info *sbi)
- f2fs_sync_fs(sbi->sb, 1);
- }
- -static int f2fs_remount(struct super_block *sb, int *flags, char *data)
- +static int f2fs_remount(struct vfsmount *mnt, struct super_block *sb,
- + int *flags, char *data)
- {
- struct f2fs_sb_info *sbi = F2FS_SB(sb);
- struct f2fs_mount_info org_mount_opt;
- @@ -1567,15 +1697,18 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
- #ifdef CONFIG_QUOTA
- if (!f2fs_readonly(sb) && (*flags & MS_RDONLY)) {
- - err = dquot_suspend(sb, -1);
- - if (err < 0)
- - goto restore_opts;
- + if (!IS_ERR(mnt)) {
- + err = dquot_suspend(sb, -1);
- + if (err < 0)
- + goto restore_opts;
- + }
- } else if (f2fs_readonly(sb) && !(*flags & SB_RDONLY)) {
- /* dquot_resume needs RW */
- sb->s_flags &= ~MS_RDONLY;
- if (sb_any_quota_suspended(sb)) {
- dquot_resume(sb, -1);
- - } else if (f2fs_sb_has_quota_ino(sb)) {
- + } else if (!sb_any_quota_loaded(sb) &&
- + f2fs_sb_has_quota_ino(sb)) {
- err = f2fs_enable_quotas(sb);
- if (err)
- goto restore_opts;
- @@ -1659,6 +1792,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
- limit_reserve_root(sbi);
- *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
- + f2fs_msg(sb, KERN_NOTICE, "re-mounted. Opts: %s", data);
- +
- return 0;
- restore_gc:
- if (need_restart_gc) {
- @@ -2151,7 +2286,7 @@ static const struct super_operations f2fs_sops = {
- .freeze_fs = f2fs_freeze,
- .unfreeze_fs = f2fs_unfreeze,
- .statfs = f2fs_statfs,
- - .remount_fs = f2fs_remount,
- + .remount_fs2 = f2fs_remount,
- };
- #ifdef CONFIG_F2FS_FS_ENCRYPTION
- @@ -2182,6 +2317,20 @@ static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
- ctx, len, fs_data, XATTR_CREATE);
- }
- +#if defined(CONFIG_DDAR) || defined(CONFIG_FSCRYPT_SDP)
- +static int f2fs_get_knox_context(struct inode *inode, const char *name, void *val, size_t len)
- +{
- + return f2fs_getxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
- + name, val, len, NULL);
- +}
- +
- +static int f2fs_set_knox_context(struct inode *inode, const char *name, const void *val, size_t len, void *fs_data)
- +{
- + return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
- + name ? name : F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, val, len, fs_data, 0);
- +}
- +#endif
- +
- static bool f2fs_dummy_context(struct inode *inode)
- {
- return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode));
- @@ -2191,6 +2340,13 @@ static const struct fscrypt_operations f2fs_cryptops = {
- .key_prefix = "f2fs:",
- .get_context = f2fs_get_context,
- .set_context = f2fs_set_context,
- +#if defined(CONFIG_DDAR) || defined(CONFIG_FSCRYPT_SDP)
- + .get_knox_context = f2fs_get_knox_context,
- + .set_knox_context = f2fs_set_knox_context,
- +#endif
- +#ifdef CONFIG_FS_INLINE_ENCRYPTION
- + .get_dun = __fscrypt_make_dun,
- +#endif
- .dummy_context = f2fs_dummy_context,
- .empty_dir = f2fs_empty_dir,
- .max_namelen = F2FS_NAME_LEN,
- @@ -2700,6 +2856,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
- sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL;
- sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL;
- sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL;
- + sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] =
- + DEF_UMOUNT_DISCARD_TIMEOUT;
- clear_sbi_flag(sbi, SBI_NEED_FSCK);
- for (i = 0; i < NR_COUNT_TYPE; i++)
- @@ -2814,7 +2972,7 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
- */
- static int read_raw_super_block(struct f2fs_sb_info *sbi,
- struct f2fs_super_block **raw_super,
- - int *valid_super_block, int *recovery)
- + int *valid_super_block, int *recovery, bool verbose)
- {
- struct super_block *sb = sbi->sb;
- int block;
- @@ -2841,6 +2999,8 @@ static int read_raw_super_block(struct f2fs_sb_info *sbi,
- "Can't find valid F2FS filesystem in %dth superblock",
- block + 1);
- err = -EINVAL;
- + if (verbose)
- + print_bh(sb, bh, 0, sb->s_blocksize);
- brelse(bh);
- continue;
- }
- @@ -3024,6 +3184,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
- int err;
- bool retry = true, need_fsck = false;
- char *options = NULL;
- + char *orig_data = kstrdup(data, GFP_KERNEL);
- int recovery, i, valid_super_block;
- struct curseg_info *seg_i;
- @@ -3056,7 +3217,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
- }
- err = read_raw_super_block(sbi, &raw_super, &valid_super_block,
- - &recovery);
- + &recovery, retry);
- if (err)
- goto free_sbi;
- @@ -3125,6 +3286,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
- sb->s_time_gran = 1;
- sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
- (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
- +#ifdef CONFIG_FIVE
- + sb->s_flags |= SB_I_VERSION;
- +#endif
- memcpy(&sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
- sb->s_iflags |= SB_I_CGROUPWB;
- @@ -3382,8 +3546,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
- f2fs_tuning_parameters(sbi);
- - f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx",
- - cur_cp_version(F2FS_CKPT(sbi)));
- + f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx"
- + "Opts: %s", cur_cp_version(F2FS_CKPT(sbi)), orig_data);
- + kfree(orig_data);
- +
- f2fs_update_time(sbi, CP_TIME);
- f2fs_update_time(sbi, REQ_TIME);
- return 0;
- @@ -3411,6 +3577,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
- f2fs_release_ino_entry(sbi, true);
- truncate_inode_pages_final(NODE_MAPPING(sbi));
- iput(sbi->node_inode);
- + sbi->node_inode = NULL;
- free_nm:
- f2fs_destroy_node_manager(sbi);
- free_sm:
- @@ -3421,6 +3588,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
- free_meta_inode:
- make_bad_inode(sbi->meta_inode);
- iput(sbi->meta_inode);
- + sbi->meta_inode = NULL;
- free_io_dummy:
- mempool_destroy(sbi->write_io_dummy);
- free_percpu:
- @@ -3447,6 +3615,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
- shrink_dcache_sb(sb);
- goto try_onemore;
- }
- + kfree(orig_data);
- return err;
- }
- diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
- index db89741b219b1..cb145c09a899e 100644
- --- a/fs/f2fs/sysfs.c
- +++ b/fs/f2fs/sysfs.c
- @@ -10,6 +10,7 @@
- #include <linux/proc_fs.h>
- #include <linux/f2fs_fs.h>
- #include <linux/seq_file.h>
- +#include <linux/statfs.h>
- #include "f2fs.h"
- #include "segment.h"
- @@ -81,6 +82,38 @@ static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a,
- BD_PART_WRITTEN(sbi)));
- }
- +static ssize_t sec_fs_stat_show(struct f2fs_attr *a,
- + struct f2fs_sb_info *sbi, char *buf)
- +{
- + struct dentry *root = sbi->sb->s_root;
- + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
- + struct kstatfs statbuf;
- + int ret;
- +
- + if (!root->d_sb->s_op->statfs)
- + goto errout;
- +
- + ret = root->d_sb->s_op->statfs(root, &statbuf);
- + if (ret)
- + goto errout;
- +
- + return snprintf(buf, PAGE_SIZE, "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%u\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%u\",\"%s\":\"%u\"\n",
- + "F_BLOCKS", statbuf.f_blocks,
- + "F_BFREE", statbuf.f_bfree,
- + "F_SFREE", free_sections(sbi),
- + "F_FILES", statbuf.f_files,
- + "F_FFREE", statbuf.f_ffree,
- + "F_FUSED", ckpt->valid_inode_count,
- + "F_NUSED", ckpt->valid_node_count);
- +
- +errout:
- + return snprintf(buf, PAGE_SIZE, "\"%s\":\"%d\",\"%s\":\"%d\",\"%s\":\"%d\","
- + "\"%s\":\"%d\",\"%s\":\"%d\",\"%s\":\"%d\",\"%s\":\"%d\"\n",
- + "F_BLOCKS", 0, "F_BFREE", 0, "F_SFREE", 0, "F_FILES", 0,
- + "F_FFREE", 0, "F_FUSED", 0, "F_NUSED", 0);
- +}
- +
- static ssize_t features_show(struct f2fs_attr *a,
- struct f2fs_sb_info *sbi, char *buf)
- {
- @@ -159,6 +192,80 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
- len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
- extlist[i]);
- return len;
- + } else if (!strcmp(a->attr.name, "sec_gc_stat")) {
- + return snprintf(buf, PAGE_SIZE, "\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\"\n",
- + "FGGC", sbi->sec_stat.gc_count[FG_GC],
- + "FGGC_NSEG", sbi->sec_stat.gc_node_seg_count[FG_GC],
- + "FGGC_NBLK", sbi->sec_stat.gc_node_blk_count[FG_GC],
- + "FGGC_DSEG", sbi->sec_stat.gc_data_seg_count[FG_GC],
- + "FGGC_DBLK", sbi->sec_stat.gc_data_blk_count[FG_GC],
- + "FGGC_TTIME", sbi->sec_stat.gc_ttime[FG_GC],
- + "BGGC", sbi->sec_stat.gc_count[BG_GC],
- + "BGGC_NSEG", sbi->sec_stat.gc_node_seg_count[BG_GC],
- + "BGGC_NBLK", sbi->sec_stat.gc_node_blk_count[BG_GC],
- + "BGGC_DSEG", sbi->sec_stat.gc_data_seg_count[BG_GC],
- + "BGGC_DBLK", sbi->sec_stat.gc_data_blk_count[BG_GC],
- + "BGGC_TTIME", sbi->sec_stat.gc_ttime[BG_GC]);
- + } else if (!strcmp(a->attr.name, "sec_io_stat")) {
- + u64 kbytes_written = 0;
- +
- + if (sbi->sb->s_bdev->bd_part)
- + kbytes_written = BD_PART_WRITTEN(sbi) -
- + sbi->sec_stat.kwritten_byte;
- +
- + return snprintf(buf, PAGE_SIZE, "\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\","
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%u\","
- + "\"%s\":\"%u\",\"%s\":\"%u\"\n",
- + "CP", sbi->sec_stat.cp_cnt[STAT_CP_ALL],
- + "CPBG", sbi->sec_stat.cp_cnt[STAT_CP_BG],
- + "CPSYNC", sbi->sec_stat.cp_cnt[STAT_CP_FSYNC],
- + "CPNONRE", sbi->sec_stat.cpr_cnt[CP_NON_REGULAR],
- + "CPSBNEED", sbi->sec_stat.cpr_cnt[CP_SB_NEED_CP],
- + "CPWPINO", sbi->sec_stat.cpr_cnt[CP_WRONG_PINO],
- + "CP_MAX_INT", sbi->sec_stat.cp_max_interval,
- + "LFSSEG", sbi->sec_stat.alloc_seg_type[LFS],
- + "SSRSEG", sbi->sec_stat.alloc_seg_type[SSR],
- + "LFSBLK", sbi->sec_stat.alloc_blk_count[LFS],
- + "SSRBLK", sbi->sec_stat.alloc_blk_count[SSR],
- + "IPU", (u64)atomic64_read(&sbi->sec_stat.inplace_count),
- + "FSYNC", sbi->sec_stat.fsync_count,
- + "FSYNC_MB", sbi->sec_stat.fsync_dirty_pages >> 8,
- + "HOT_DATA", sbi->sec_stat.hot_file_written_blocks >> 8,
- + "COLD_DATA", sbi->sec_stat.cold_file_written_blocks >> 8,
- + "WARM_DATA", sbi->sec_stat.warm_file_written_blocks >> 8,
- + "MAX_INMEM", sbi->sec_stat.max_inmem_pages,
- + "DROP_INMEM", sbi->sec_stat.drop_inmem_all,
- + "DROP_INMEMF", sbi->sec_stat.drop_inmem_files,
- + "WRITE_MB", (u64)(kbytes_written >> 10),
- + "FS_PERROR", sbi->sec_stat.fs_por_error,
- + "FS_ERROR", sbi->sec_stat.fs_error,
- + "MAX_UNDSCD", sbi->sec_stat.max_undiscard_blks);
- + } else if (!strcmp(a->attr.name, "sec_fsck_stat")) {
- + return snprintf(buf, PAGE_SIZE,
- + "\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%llu\",\"%s\":\"%u\","
- + "\"%s\":\"%u\",\"%s\":\"%u\"\n",
- + "FSCK_RBYTES", sbi->sec_fsck_stat.fsck_read_bytes,
- + "FSCK_WBYTES", sbi->sec_fsck_stat.fsck_written_bytes,
- + "FSCK_TIME_MS", sbi->sec_fsck_stat.fsck_elapsed_time,
- + "FSCK_EXIT", sbi->sec_fsck_stat.fsck_exit_code,
- + "FSCK_VNODES", sbi->sec_fsck_stat.valid_node_count,
- + "FSCK_VINODES", sbi->sec_fsck_stat.valid_inode_count);
- + } else if (!strcmp(a->attr.name, "sec_defrag_stat")) {
- + return snprintf(buf, PAGE_SIZE,
- + "\"%s\":\"%u\",\"%s\":\"%u\",\"%s\":\"%u\",\"%s\":\"%u\",\"%s\":\"%u\",\"%s\":\"%u\"\n",
- + "BESTEXT", sbi->s_sec_part_best_extents,
- + "CUREXT", sbi->s_sec_part_current_extents,
- + "DEFSCORE", sbi->s_sec_part_score,
- + "DEFWRITE", sbi->s_sec_defrag_writes_kb,
- + "NUMAPP", sbi->s_sec_num_apps,
- + "CAPAPP", sbi->s_sec_capacity_apps_kb);
- }
- ui = (unsigned int *)(ptr + a->offset);
- @@ -174,6 +281,7 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
- unsigned long t;
- unsigned int *ui;
- ssize_t ret;
- + unsigned int i = 0;
- ptr = __struct_ptr(sbi, a->struct_type);
- if (!ptr)
- @@ -212,6 +320,62 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
- out:
- up_write(&sbi->sb_lock);
- return ret ? ret : count;
- + } else if(!strcmp(a->attr.name, "sec_gc_stat")) {
- + sbi->sec_stat.gc_count[BG_GC] = 0;
- + sbi->sec_stat.gc_count[FG_GC] = 0;
- + sbi->sec_stat.gc_node_seg_count[BG_GC] = 0;
- + sbi->sec_stat.gc_node_seg_count[FG_GC] = 0;
- + sbi->sec_stat.gc_data_seg_count[BG_GC] = 0;
- + sbi->sec_stat.gc_data_seg_count[FG_GC] = 0;
- + sbi->sec_stat.gc_node_blk_count[BG_GC] = 0;
- + sbi->sec_stat.gc_node_blk_count[FG_GC] = 0;
- + sbi->sec_stat.gc_data_blk_count[BG_GC] = 0;
- + sbi->sec_stat.gc_data_blk_count[FG_GC] = 0;
- + sbi->sec_stat.gc_ttime[BG_GC] = 0;
- + sbi->sec_stat.gc_ttime[FG_GC] = 0;
- + return count;
- + } else if (!strcmp(a->attr.name, "sec_io_stat")) {
- + sbi->sec_stat.cp_cnt[STAT_CP_ALL] = 0;
- + sbi->sec_stat.cp_cnt[STAT_CP_BG] = 0;
- + sbi->sec_stat.cp_cnt[STAT_CP_FSYNC] = 0;
- + for (i = 0; i < NR_CP_REASON; i++)
- + sbi->sec_stat.cpr_cnt[i] = 0;
- + sbi->sec_stat.cp_max_interval= 0;
- + sbi->sec_stat.alloc_seg_type[LFS] = 0;
- + sbi->sec_stat.alloc_seg_type[SSR] = 0;
- + sbi->sec_stat.alloc_blk_count[LFS] = 0;
- + sbi->sec_stat.alloc_blk_count[SSR] = 0;
- + atomic64_set(&sbi->sec_stat.inplace_count, 0);
- + sbi->sec_stat.fsync_count = 0;
- + sbi->sec_stat.fsync_dirty_pages = 0;
- + sbi->sec_stat.hot_file_written_blocks = 0;
- + sbi->sec_stat.cold_file_written_blocks = 0;
- + sbi->sec_stat.warm_file_written_blocks = 0;
- + sbi->sec_stat.max_inmem_pages = 0;
- + sbi->sec_stat.drop_inmem_all = 0;
- + sbi->sec_stat.drop_inmem_files = 0;
- + if (sbi->sb->s_bdev->bd_part)
- + sbi->sec_stat.kwritten_byte = BD_PART_WRITTEN(sbi);
- + sbi->sec_stat.fs_por_error = 0;
- + sbi->sec_stat.fs_error = 0;
- + sbi->sec_stat.max_undiscard_blks = 0;
- + return count;
- + } else if (!strcmp(a->attr.name, "sec_fsck_stat")) {
- + sbi->sec_fsck_stat.fsck_read_bytes = 0;
- + sbi->sec_fsck_stat.fsck_written_bytes = 0;
- + sbi->sec_fsck_stat.fsck_elapsed_time = 0;
- + sbi->sec_fsck_stat.fsck_exit_code = 0;
- + sbi->sec_fsck_stat.valid_node_count = 0;
- + sbi->sec_fsck_stat.valid_inode_count = 0;
- + return count;
- + } else if (!strcmp(a->attr.name, "sec_defrag_stat")) {
- + sbi->s_sec_part_best_extents = 0;
- + sbi->s_sec_part_current_extents = 0;
- + sbi->s_sec_part_score = 0;
- + sbi->s_sec_defrag_writes_kb = 0;
- + sbi->s_sec_num_apps = 0;
- + sbi->s_sec_capacity_apps_kb = 0;
- + return count;
- }
- ui = (unsigned int *)(ptr + a->offset);
- @@ -226,7 +390,8 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
- if (a->struct_type == RESERVED_BLOCKS) {
- spin_lock(&sbi->stat_lock);
- if (t > (unsigned long)(sbi->user_block_count -
- - F2FS_OPTION(sbi).root_reserved_blocks)) {
- + F2FS_OPTION(sbi).root_reserved_blocks -
- + F2FS_OPTION(sbi).core_reserved_blocks)) {
- spin_unlock(&sbi->stat_lock);
- return -EINVAL;
- }
- @@ -412,6 +577,8 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, discard_idle_interval,
- interval_time[DISCARD_TIME]);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle_interval, interval_time[GC_TIME]);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info,
- + umount_discard_timeout, interval_time[UMOUNT_DISCARD_TIMEOUT]);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra);
- F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);
- @@ -420,8 +587,19 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list);
- F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
- F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
- #endif
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_gc_stat, sec_stat);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_io_stat, sec_stat);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_fsck_stat, sec_fsck_stat);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_part_best_extents, s_sec_part_best_extents);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_part_current_extents, s_sec_part_current_extents);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_part_score, s_sec_part_score);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_defrag_writes_kb, s_sec_defrag_writes_kb);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_num_apps, s_sec_num_apps);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_capacity_apps_kb, s_sec_capacity_apps_kb);
- +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, sec_defrag_stat, s_sec_part_best_extents);
- F2FS_GENERAL_RO_ATTR(dirty_segments);
- F2FS_GENERAL_RO_ATTR(lifetime_write_kbytes);
- +F2FS_GENERAL_RO_ATTR(sec_fs_stat);
- F2FS_GENERAL_RO_ATTR(features);
- F2FS_GENERAL_RO_ATTR(current_reserved_blocks);
- @@ -468,16 +646,28 @@ static struct attribute *f2fs_attrs[] = {
- ATTR_LIST(idle_interval),
- ATTR_LIST(discard_idle_interval),
- ATTR_LIST(gc_idle_interval),
- + ATTR_LIST(umount_discard_timeout),
- ATTR_LIST(iostat_enable),
- ATTR_LIST(readdir_ra),
- ATTR_LIST(gc_pin_file_thresh),
- ATTR_LIST(extension_list),
- + ATTR_LIST(sec_gc_stat),
- + ATTR_LIST(sec_io_stat),
- + ATTR_LIST(sec_fsck_stat),
- + ATTR_LIST(sec_part_best_extents),
- + ATTR_LIST(sec_part_current_extents),
- + ATTR_LIST(sec_part_score),
- + ATTR_LIST(sec_defrag_writes_kb),
- + ATTR_LIST(sec_num_apps),
- + ATTR_LIST(sec_capacity_apps_kb),
- + ATTR_LIST(sec_defrag_stat),
- #ifdef CONFIG_F2FS_FAULT_INJECTION
- ATTR_LIST(inject_rate),
- ATTR_LIST(inject_type),
- #endif
- ATTR_LIST(dirty_segments),
- ATTR_LIST(lifetime_write_kbytes),
- + ATTR_LIST(sec_fs_stat),
- ATTR_LIST(features),
- ATTR_LIST(reserved_blocks),
- ATTR_LIST(current_reserved_blocks),
- @@ -706,6 +896,10 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi)
- if (err)
- return err;
- + err = sysfs_create_link(&f2fs_kset.kobj, &sbi->s_kobj, "userdata");
- + if (err)
- + printk(KERN_ERR "Can not create sysfs link for userdata(%d)\n", err);
- +
- if (f2fs_proc_root)
- sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
- @@ -731,5 +925,6 @@ void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi)
- remove_proc_entry("victim_bits", sbi->s_proc);
- remove_proc_entry(sbi->sb->s_id, f2fs_proc_root);
- }
- + sysfs_delete_link(&f2fs_kset.kobj, &sbi->s_kobj, "userdata");
- kobject_del(&sbi->s_kobj);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement