Re: [f2fs-dev] [PATCH] f2fs: Support enhanced hot/cold data separation for f2fs

2022-11-28 Thread Yangtao Li via Linux-f2fs-devel
Hi qixiaoyu1,

Thanks for your patchset.

Does this patchset have data related to memory and performance impact?
Can you provide scripts or commands for related tests?

Thx,
Yangtao


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [xfstests-bld PATCH] test_appliance: add f2fs/compress config

2022-11-28 Thread Eric Biggers
From: Eric Biggers 

Add a f2fs/compress configuration which causes all files to be
automatically compressed, similar to how f2fs/encrypt causes all files
to be automatically encrypted.

Signed-off-by: Eric Biggers 
---
 test-appliance/files/root/fs/f2fs/cfg/all.list | 1 +
 test-appliance/files/root/fs/f2fs/cfg/compress | 5 +
 2 files changed, 6 insertions(+)
 create mode 100644 test-appliance/files/root/fs/f2fs/cfg/compress

diff --git a/test-appliance/files/root/fs/f2fs/cfg/all.list 
b/test-appliance/files/root/fs/f2fs/cfg/all.list
index bc796ff..90a7a36 100644
--- a/test-appliance/files/root/fs/f2fs/cfg/all.list
+++ b/test-appliance/files/root/fs/f2fs/cfg/all.list
@@ -1,2 +1,3 @@
 default
 encrypt
+compress
diff --git a/test-appliance/files/root/fs/f2fs/cfg/compress 
b/test-appliance/files/root/fs/f2fs/cfg/compress
new file mode 100644
index 000..6f2b954
--- /dev/null
+++ b/test-appliance/files/root/fs/f2fs/cfg/compress
@@ -0,0 +1,5 @@
+SIZE=small
+export MKFS_OPTIONS="-O compression,extra_attr"
+export F2FS_MOUNT_OPTIONS="compress_extension=*"
+REQUIRE_FEATURE=compression
+TESTNAME="F2FS compression"
-- 
2.38.1



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [PATCH v4] fsverity: stop using PG_error to track error status

2022-11-28 Thread Eric Biggers
On Mon, Nov 28, 2022 at 10:48:41PM -0800, Jaegeuk Kim wrote:
> >  static void f2fs_finish_read_bio(struct bio *bio, bool in_task)
> >  {
> > struct bio_vec *bv;
> > struct bvec_iter_all iter_all;
> > +   struct bio_post_read_ctx *ctx = bio->bi_private;
> >  
> > -   /*
> > -* Update and unlock the bio's pagecache pages, and put the
> > -* decompression context for any compressed pages.
> > -*/
> > bio_for_each_segment_all(bv, bio, iter_all) {
> > struct page *page = bv->bv_page;
> >  
> > if (f2fs_is_compressed_page(page)) {
> > -   if (bio->bi_status)
> > +   if (!ctx->decompression_attempted)
> 
> If seems this causes a panic due to the ctx nullified by f2fs_verify_bio.
> 

Thanks for catching that!  I've sent out v5 that checks for 'ctx &&
!ctx->decompression_attempted' here.  That's the right thing to do, since if ctx
is NULL then decompression must have been attempted.

I'd like to get rid of freeing the bio_post_read_ctx in f2fs_verify_bio().
But I believe it's still needed, at least in theory.

Do you have a suggestion for testing f2fs compression + verity with xfstests?
I missed this because compression isn't covered by the "verity" group tests.
Maybe there should be an "f2fs/compress" config in xfstests-bld that uses mkfs
and mount options that cause all files to be automatically compressed, similar
to how f2fs/encrypt automatically encrypts all files with test_dummy_encryption.

- Eric


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH v5] fsverity: stop using PG_error to track error status

2022-11-28 Thread Eric Biggers
From: Eric Biggers 

As a step towards freeing the PG_error flag for other uses, change ext4
and f2fs to stop using PG_error to track verity errors.  Instead, if a
verity error occurs, just mark the whole bio as failed.  The coarser
granularity isn't really a problem since it isn't any worse than what
the block layer provides, and errors from a multi-page readahead aren't
reported to applications unless a single-page read fails too.

f2fs supports compression, which makes the f2fs changes a bit more
complicated than desired, but the basic premise still works.

Note: there are still a few uses of PageError in f2fs, but they are on
the write path, so they are unrelated and this patch doesn't touch them.

Reviewed-by: Chao Yu 
Acked-by: Jaegeuk Kim 
Signed-off-by: Eric Biggers 
---

v5: Fixed NULL dereference when reading compressed+verity file on f2fs.

v4: Added a comment for decompression_attempted, added a paragraph to
the commit message, and added Chao's Reviewed-by.

v3: made a small simplification to the f2fs changes.  Also dropped the
fscrypt patch since it is upstream now.

 fs/ext4/readpage.c |  8 ++
 fs/f2fs/compress.c | 64 ++
 fs/f2fs/data.c | 53 +++---
 fs/verity/verify.c | 12 -
 4 files changed, 72 insertions(+), 65 deletions(-)

diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 3d21eae267fca..e604ea4e102b7 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -75,14 +75,10 @@ static void __read_end_io(struct bio *bio)
bio_for_each_segment_all(bv, bio, iter_all) {
page = bv->bv_page;
 
-   /* PG_error was set if verity failed. */
-   if (bio->bi_status || PageError(page)) {
+   if (bio->bi_status)
ClearPageUptodate(page);
-   /* will re-read again later */
-   ClearPageError(page);
-   } else {
+   else
SetPageUptodate(page);
-   }
unlock_page(page);
}
if (bio->bi_private)
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index d315c2de136f2..2b7a5cc4ed662 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1711,50 +1711,27 @@ static void f2fs_put_dic(struct decompress_io_ctx *dic, 
bool in_task)
}
 }
 
-/*
- * Update and unlock the cluster's pagecache pages, and release the reference 
to
- * the decompress_io_ctx that was being held for I/O completion.
- */
-static void __f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool 
failed,
-   bool in_task)
+static void f2fs_verify_cluster(struct work_struct *work)
 {
+   struct decompress_io_ctx *dic =
+   container_of(work, struct decompress_io_ctx, verity_work);
int i;
 
+   /* Verify, update, and unlock the decompressed pages. */
for (i = 0; i < dic->cluster_size; i++) {
struct page *rpage = dic->rpages[i];
 
if (!rpage)
continue;
 
-   /* PG_error was set if verity failed. */
-   if (failed || PageError(rpage)) {
-   ClearPageUptodate(rpage);
-   /* will re-read again later */
-   ClearPageError(rpage);
-   } else {
+   if (fsverity_verify_page(rpage))
SetPageUptodate(rpage);
-   }
+   else
+   ClearPageUptodate(rpage);
unlock_page(rpage);
}
 
-   f2fs_put_dic(dic, in_task);
-}
-
-static void f2fs_verify_cluster(struct work_struct *work)
-{
-   struct decompress_io_ctx *dic =
-   container_of(work, struct decompress_io_ctx, verity_work);
-   int i;
-
-   /* Verify the cluster's decompressed pages with fs-verity. */
-   for (i = 0; i < dic->cluster_size; i++) {
-   struct page *rpage = dic->rpages[i];
-
-   if (rpage && !fsverity_verify_page(rpage))
-   SetPageError(rpage);
-   }
-
-   __f2fs_decompress_end_io(dic, false, true);
+   f2fs_put_dic(dic, true);
 }
 
 /*
@@ -1764,6 +1741,8 @@ static void f2fs_verify_cluster(struct work_struct *work)
 void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
bool in_task)
 {
+   int i;
+
if (!failed && dic->need_verity) {
/*
 * Note that to avoid deadlocks, the verity work can't be done
@@ -1773,9 +1752,28 @@ void f2fs_decompress_end_io(struct decompress_io_ctx 
*dic, bool failed,
 */
INIT_WORK(>verity_work, f2fs_verify_cluster);
fsverity_enqueue_verify_work(>verity_work);
-   } else {
-   __f2fs_decompress_end_io(dic, failed, in_task);
+   return;
+   }
+
+   /* Update and unlock 

Re: [f2fs-dev] [PATCH v4] fsverity: stop using PG_error to track error status

2022-11-28 Thread Jaegeuk Kim
On 11/25, Eric Biggers wrote:
> From: Eric Biggers 
> 
> As a step towards freeing the PG_error flag for other uses, change ext4
> and f2fs to stop using PG_error to track verity errors.  Instead, if a
> verity error occurs, just mark the whole bio as failed.  The coarser
> granularity isn't really a problem since it isn't any worse than what
> the block layer provides, and errors from a multi-page readahead aren't
> reported to applications unless a single-page read fails too.
> 
> f2fs supports compression, which makes the f2fs changes a bit more
> complicated than desired, but the basic premise still works.
> 
> Note: there are still a few uses of PageError in f2fs, but they are on
> the write path, so they are unrelated and this patch doesn't touch them.
> 
> Reviewed-by: Chao Yu 
> Signed-off-by: Eric Biggers 
> ---
> 
> v4: Added a comment for decompression_attempted, added a paragraph to
> the commit message, and added Chao's Reviewed-by.
> 
> v3: made a small simplification to the f2fs changes.  Also dropped the
> fscrypt patch since it is upstream now.
> 
>  fs/ext4/readpage.c |  8 ++
>  fs/f2fs/compress.c | 64 ++
>  fs/f2fs/data.c | 53 +++---
>  fs/verity/verify.c | 12 -
>  4 files changed, 72 insertions(+), 65 deletions(-)
> 
> diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
> index 3d21eae267fca..e604ea4e102b7 100644
> --- a/fs/ext4/readpage.c
> +++ b/fs/ext4/readpage.c
> @@ -75,14 +75,10 @@ static void __read_end_io(struct bio *bio)
>   bio_for_each_segment_all(bv, bio, iter_all) {
>   page = bv->bv_page;
>  
> - /* PG_error was set if verity failed. */
> - if (bio->bi_status || PageError(page)) {
> + if (bio->bi_status)
>   ClearPageUptodate(page);
> - /* will re-read again later */
> - ClearPageError(page);
> - } else {
> + else
>   SetPageUptodate(page);
> - }
>   unlock_page(page);
>   }
>   if (bio->bi_private)
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index d315c2de136f2..2b7a5cc4ed662 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -1711,50 +1711,27 @@ static void f2fs_put_dic(struct decompress_io_ctx 
> *dic, bool in_task)
>   }
>  }
>  
> -/*
> - * Update and unlock the cluster's pagecache pages, and release the 
> reference to
> - * the decompress_io_ctx that was being held for I/O completion.
> - */
> -static void __f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool 
> failed,
> - bool in_task)
> +static void f2fs_verify_cluster(struct work_struct *work)
>  {
> + struct decompress_io_ctx *dic =
> + container_of(work, struct decompress_io_ctx, verity_work);
>   int i;
>  
> + /* Verify, update, and unlock the decompressed pages. */
>   for (i = 0; i < dic->cluster_size; i++) {
>   struct page *rpage = dic->rpages[i];
>  
>   if (!rpage)
>   continue;
>  
> - /* PG_error was set if verity failed. */
> - if (failed || PageError(rpage)) {
> - ClearPageUptodate(rpage);
> - /* will re-read again later */
> - ClearPageError(rpage);
> - } else {
> + if (fsverity_verify_page(rpage))
>   SetPageUptodate(rpage);
> - }
> + else
> + ClearPageUptodate(rpage);
>   unlock_page(rpage);
>   }
>  
> - f2fs_put_dic(dic, in_task);
> -}
> -
> -static void f2fs_verify_cluster(struct work_struct *work)
> -{
> - struct decompress_io_ctx *dic =
> - container_of(work, struct decompress_io_ctx, verity_work);
> - int i;
> -
> - /* Verify the cluster's decompressed pages with fs-verity. */
> - for (i = 0; i < dic->cluster_size; i++) {
> - struct page *rpage = dic->rpages[i];
> -
> - if (rpage && !fsverity_verify_page(rpage))
> - SetPageError(rpage);
> - }
> -
> - __f2fs_decompress_end_io(dic, false, true);
> + f2fs_put_dic(dic, true);
>  }
>  
>  /*
> @@ -1764,6 +1741,8 @@ static void f2fs_verify_cluster(struct work_struct 
> *work)
>  void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
>   bool in_task)
>  {
> + int i;
> +
>   if (!failed && dic->need_verity) {
>   /*
>* Note that to avoid deadlocks, the verity work can't be done
> @@ -1773,9 +1752,28 @@ void f2fs_decompress_end_io(struct decompress_io_ctx 
> *dic, bool failed,
>*/
>   INIT_WORK(>verity_work, f2fs_verify_cluster);
>   fsverity_enqueue_verify_work(>verity_work);
> - } else {
> - 

Re: [f2fs-dev] [PATCH] f2fs: Add f2fs bug tracker link

2022-11-28 Thread Yangtao Li via Linux-f2fs-devel
> If you don't mind, let me merge this patch into Chao's patch, since both
> are same topic.

Never mind, feel free. :)

Thx,
Yangtao


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 2/2] f2fs: add support for counting the average time of submit discard cmd

2022-11-28 Thread Yangtao Li via Linux-f2fs-devel
This patch adds support for counting the average time of submit discard
command, and we can see its value in debugfs.

Signed-off-by: Yangtao Li 
---
 fs/f2fs/debug.c   |  7 +--
 fs/f2fs/f2fs.h|  5 +
 fs/f2fs/segment.c | 18 --
 3 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 733b1bd37404..eed3edfc5faf 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -109,6 +109,9 @@ static void update_general_status(struct f2fs_sb_info *sbi)
llist_empty(_I(sbi)->fcc_info->issue_list);
}
if (SM_I(sbi)->dcc_info) {
+   struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
+
+   si->discard_avg = dcc->discard_time_avg;
si->nr_discarded =
atomic_read(_I(sbi)->dcc_info->issued_discard);
si->nr_discarding =
@@ -510,8 +513,8 @@ static int stat_show(struct seq_file *s, void *v)
   si->nr_wb_cp_data, si->nr_wb_data,
   si->nr_flushing, si->nr_flushed,
   si->flush_list_empty);
-   seq_printf(s, "Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n",
-  si->nr_discarding, si->nr_discarded,
+   seq_printf(s, "Discard: (%4d %4d, avg:%4lldns)) cmd: %4d 
undiscard:%4u\n",
+  si->nr_discarding, si->nr_discarded, 
ktime_to_us(si->discard_avg),
   si->nr_discard_cmd, si->undiscard_blks);
seq_printf(s, "  - atomic IO: %4d (Max. %4d)\n",
   si->aw_cnt, si->max_aw_cnt);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index eb8c27c4e5fc..5a99759d10ac 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -370,6 +370,8 @@ struct discard_cmd {
int error;  /* bio error */
spinlock_t lock;/* for state/bio_ref updating */
unsigned short bio_ref; /* bio reference count */
+   struct discard_cmd_control *dcc; /* global discard cmd control */
+   ktime_t submit_start;   /* submit start time */
 };
 
 enum {
@@ -414,6 +416,8 @@ struct discard_cmd_control {
unsigned int max_ordered_discard;   /* maximum discard granularity 
issued by lba order */
unsigned int undiscard_blks;/* # of undiscard blocks */
unsigned int next_pos;  /* next discard position */
+   spinlock_t discard_time_lock;   /* for discard time statistics */
+   ktime_t discard_time_avg;   /* issued discard cmd avg time 
*/
atomic_t issued_discard;/* # of issued discard */
atomic_t queued_discard;/* # of queued discard */
atomic_t discard_cmd_cnt;   /* # of cached cmd count */
@@ -3882,6 +3886,7 @@ struct f2fs_stat_info {
int nr_dio_read, nr_dio_write;
unsigned int io_skip_bggc, other_skip_bggc;
int nr_flushing, nr_flushed, flush_list_empty;
+   ktime_t discard_avg;
int nr_discarding, nr_discarded;
int nr_discard_cmd;
unsigned int undiscard_blks;
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 9486ca49ecb1..bc96b1afb308 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -931,6 +931,7 @@ static struct discard_cmd *__create_discard_cmd(struct 
f2fs_sb_info *sbi,
list_add_tail(>list, pend_list);
spin_lock_init(>lock);
dc->bio_ref = 0;
+   dc->dcc = dcc;
atomic_inc(>discard_cmd_cnt);
dcc->undiscard_blks += len;
 
@@ -1000,9 +1001,13 @@ static void __remove_discard_cmd(struct f2fs_sb_info 
*sbi,
 static void f2fs_submit_discard_endio(struct bio *bio)
 {
struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private;
+   struct discard_cmd_control *dcc = dc->dcc;
unsigned long flags;
+   ktime_t submit_time;
+   int nr_discarded;
 
spin_lock_irqsave(>lock, flags);
+   submit_time = ktime_sub(ktime_get(), dc->submit_start);
if (!dc->error)
dc->error = blk_status_to_errno(bio->bi_status);
dc->bio_ref--;
@@ -1012,6 +1017,14 @@ static void f2fs_submit_discard_endio(struct bio *bio)
}
spin_unlock_irqrestore(>lock, flags);
bio_put(bio);
+
+   spin_lock_irqsave(>discard_time_lock, flags);
+   nr_discarded = atomic_read(>issued_discard);
+   dcc->discard_time_avg = div_u64(ktime_add(nr_discarded * 
dcc->discard_time_avg,
+   
submit_time),
+   
nr_discarded + 1);
+   atomic_inc(>issued_discard);
+   spin_unlock_irqrestore(>discard_time_lock, flags);
 }
 
 static void __check_sit_bitmap(struct f2fs_sb_info *sbi,
@@ -1160,6 +1173,7 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
 * right away

[f2fs-dev] [PATCH 1/2] f2fs: fix some format WARNING in debug.c and sysfs.c

2022-11-28 Thread Yangtao Li via Linux-f2fs-devel
To fix:

WARNING: function definition argument 'struct f2fs_attr *' should also have an 
identifier name
+   ssize_t (*show)(struct f2fs_attr *, struct f2fs_sb_info *, char *);

WARNING: return sysfs_emit(...) formats should include a terminating newline
+   return sysfs_emit(buf, "(none)");

WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
+   unsigned npages = NODE_MAPPING(sbi)->nrpages;

WARNING: Missing a blank line after declarations
+   unsigned npages = COMPRESS_MAPPING(sbi)->nrpages;
+   si->page_mem += (unsigned long long)npages << PAGE_SHIFT;

WARNING: quoted string split across lines
+   seq_printf(s, "CP merge (Queued: %4d, Issued: %4d, Total: %4d, "
+   "Cur time: %4d(ms), Peak time: %4d(ms))\n",

Signed-off-by: Yangtao Li 
---
 fs/f2fs/debug.c | 45 +++--
 fs/f2fs/sysfs.c | 10 +-
 2 files changed, 28 insertions(+), 27 deletions(-)

diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index a216dcdf6941..733b1bd37404 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -301,18 +301,19 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
 
si->page_mem = 0;
if (sbi->node_inode) {
-   unsigned npages = NODE_MAPPING(sbi)->nrpages;
+   unsigned long npages = NODE_MAPPING(sbi)->nrpages;
 
si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
}
if (sbi->meta_inode) {
-   unsigned npages = META_MAPPING(sbi)->nrpages;
+   unsigned long npages = META_MAPPING(sbi)->nrpages;
 
si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
}
 #ifdef CONFIG_F2FS_FS_COMPRESSION
if (sbi->compress_inode) {
-   unsigned npages = COMPRESS_MAPPING(sbi)->nrpages;
+   unsigned long npages = COMPRESS_MAPPING(sbi)->nrpages;
+
si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
}
 #endif
@@ -460,28 +461,28 @@ static int stat_show(struct seq_file *s, void *v)
si->meta_count[META_NAT]);
seq_printf(s, "  - ssa blocks : %u\n",
si->meta_count[META_SSA]);
-   seq_printf(s, "CP merge (Queued: %4d, Issued: %4d, Total: %4d, "
-   "Cur time: %4d(ms), Peak time: %4d(ms))\n",
-   si->nr_queued_ckpt, si->nr_issued_ckpt,
-   si->nr_total_ckpt, si->cur_ckpt_time,
-   si->peak_ckpt_time);
+   seq_puts(s, "CP merge:\n");
+   seq_printf(s, "  - Queued : %4d\n", si->nr_queued_ckpt);
+   seq_printf(s, "  - Issued : %4d\n", si->nr_issued_ckpt);
+   seq_printf(s, "  - Total : %4d\n", si->nr_total_ckpt);
+   seq_printf(s, "  - Cur time : %4d(ms)\n", si->cur_ckpt_time);
+   seq_printf(s, "  - Peak time : %4d(ms)\n", si->peak_ckpt_time);
seq_printf(s, "GC calls: %d (BG: %d)\n",
   si->call_count, si->bg_gc);
seq_printf(s, "  - data segments : %d (%d)\n",
si->data_segs, si->bg_data_segs);
seq_printf(s, "  - node segments : %d (%d)\n",
si->node_segs, si->bg_node_segs);
-   seq_printf(s, "  - Reclaimed segs : Normal (%d), Idle CB (%d), "
-   "Idle Greedy (%d), Idle AT (%d), "
-   "Urgent High (%d), Urgent Mid (%d), "
-   "Urgent Low (%d)\n",
-   si->sbi->gc_reclaimed_segs[GC_NORMAL],
-   si->sbi->gc_reclaimed_segs[GC_IDLE_CB],
-   si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY],
-   si->sbi->gc_reclaimed_segs[GC_IDLE_AT],
-   si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH],
-   si->sbi->gc_reclaimed_segs[GC_URGENT_MID],
-   si->sbi->gc_reclaimed_segs[GC_URGENT_LOW]);
+   seq_puts(s, "  - Reclaimed segs :\n");
+   seq_printf(s, "- Normal : %d\n", 
si->sbi->gc_reclaimed_segs[GC_NORMAL]);
+   seq_printf(s, "- Idle CB : %d\n", 
si->sbi->gc_reclaimed_segs[GC_IDLE_CB]);
+   seq_printf(s, "- Idle Greedy : %d\n",
+   si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY]);
+   seq_printf(s, "- Idle AT : %d\n", 
si->sbi->gc_reclaimed_segs[GC_IDLE_AT]);
+   seq_printf(s, "- Urgent High : %d\n",
+   si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH]);
+   seq_printf(s, "- Urgent Mid : %d\n", 
si->sbi->gc_reclaimed_segs[GC_URGENT_MID]);
+   seq_printf(s, "- Urgent Low : %d\n", 

Re: [f2fs-dev] [PATCH 1/5] f2fs: record total data blocks allocated since mount

2022-11-28 Thread Jaegeuk Kim
On 11/28, qixiaoyu1 wrote:
> From: xiongping1 
> 
> Signed-off-by: xiongping1 
> Signed-off-by: qixiaoyu1 
> ---
>  fs/f2fs/Kconfig |  7 +++
>  fs/f2fs/Makefile|  1 +
>  fs/f2fs/block_age.c | 28 
>  fs/f2fs/debug.c |  7 +++
>  fs/f2fs/f2fs.h  | 15 +++
>  fs/f2fs/segment.c   |  4 
>  fs/f2fs/super.c |  4 
>  7 files changed, 66 insertions(+)
>  create mode 100644 fs/f2fs/block_age.c
> 
> diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig
> index 03ef087537c7..84915f9c6bc8 100644
> --- a/fs/f2fs/Kconfig
> +++ b/fs/f2fs/Kconfig
> @@ -150,3 +150,10 @@ config F2FS_UNFAIR_RWSEM
>   help
> Use unfair rw_semaphore, if system configured IO priority by block
> cgroup.
> +
> +config F2FS_FS_DATA_SEPARATION
> + bool "F2FS hot/cold data separation feature"
> + depends on F2FS_FS
> + help
> +   Enable data blocks separation according to block update frequency.
> +
> diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile
> index 8a7322d229e4..70d8f0e23b46 100644
> --- a/fs/f2fs/Makefile
> +++ b/fs/f2fs/Makefile
> @@ -10,3 +10,4 @@ f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o
>  f2fs-$(CONFIG_FS_VERITY) += verity.o
>  f2fs-$(CONFIG_F2FS_FS_COMPRESSION) += compress.o
>  f2fs-$(CONFIG_F2FS_IOSTAT) += iostat.o
> +f2fs-$(CONFIG_F2FS_FS_DATA_SEPARATION) += block_age.o
> diff --git a/fs/f2fs/block_age.c b/fs/f2fs/block_age.c
> new file mode 100644
> index ..1e8711a03959
> --- /dev/null
> +++ b/fs/f2fs/block_age.c
> @@ -0,0 +1,28 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * fs/f2fs/block_age.c
> + *
> + * Copyright (c) 2022 xiaomi Co., Ltd.
> + * http://www.xiaomi.com/

I don't think this is a right way, since it seems you copied lots of codes
from extent_cache.c which has another copyrights.

I'm thinking to integrate your extent_cache code into the original path in
order to keep the single code path for easy debugging. Stay tuned.

> + */
> +#include 
> +#include 
> +
> +#include "f2fs.h"
> +#include "segment.h"
> +
> +static inline void f2fs_inc_data_block_alloc(struct f2fs_sb_info *sbi)
> +{
> + atomic64_inc(>total_data_alloc);
> +}
> +
> +void f2fs_init_block_age_info(struct f2fs_sb_info *sbi)
> +{
> + atomic64_set(>total_data_alloc, 0);
> +}
> +
> +void f2fs_inc_block_alloc_count(struct f2fs_sb_info *sbi, int type)
> +{
> + if (IS_DATASEG(type))
> + f2fs_inc_data_block_alloc(sbi);
> +}
> diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
> index a216dcdf6941..d24abdac20bb 100644
> --- a/fs/f2fs/debug.c
> +++ b/fs/f2fs/debug.c
> @@ -81,6 +81,9 @@ static void update_general_status(struct f2fs_sb_info *sbi)
>   si->ext_tree = atomic_read(>total_ext_tree);
>   si->zombie_tree = atomic_read(>total_zombie_tree);
>   si->ext_node = atomic_read(>total_ext_node);
> +#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
> + si->total_data_blocks_alloc = atomic64_read(>total_data_alloc);
> +#endif
>   si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
>   si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
>   si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
> @@ -373,6 +376,10 @@ static int stat_show(struct seq_file *s, void *v)
>   seq_printf(s, "Utilization: %u%% (%u valid blocks)\n",
>   si->utilization, si->valid_count);
>  
> +#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
> + seq_printf(s, "  - Data Block Allocated: %llu\n",
> +si->total_data_blocks_alloc);
> +#endif
>   seq_printf(s, "  - Node: %u (Inode: %u, ",
>  si->valid_node_count, si->valid_inode_count);
>   seq_printf(s, "Other: %u)\n  - Data: %u\n",
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index e6355a5683b7..686f09846de4 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -1807,6 +1807,10 @@ struct f2fs_sb_info {
>   u64 sectors_written_start;
>   u64 kbytes_written;
>  
> +#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
> + atomic64_t total_data_alloc;
> +#endif
> +
>   /* Reference to checksum algorithm driver via cryptoapi */
>   struct crypto_shash *s_chksum_driver;
>  
> @@ -3858,6 +3862,9 @@ struct f2fs_stat_info {
>   int main_area_segs, main_area_sections, main_area_zones;
>   unsigned long long hit_largest, hit_cached, hit_rbtree;
>   unsigned long long hit_total, total_ext;
> +#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
> + unsigned long long total_data_blocks_alloc;
> +#endif
>   int ext_tree, zombie_tree, ext_node;
>   int ndirty_node, ndirty_dent, ndirty_meta, ndirty_imeta;
>   int ndirty_data, ndirty_qdata;
> @@ -4166,6 +4173,14 @@ void f2fs_init_extent_cache_info(struct f2fs_sb_info 
> *sbi);
>  int __init f2fs_create_extent_cache(void);
>  void f2fs_destroy_extent_cache(void);
>  
> +#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
> +/*
> + * block_age.c
> + */
> +void f2fs_init_block_age_info(struct f2fs_sb_info *sbi);
> +void 

Re: [f2fs-dev] [PATCH] f2fs: add support for counting the average time of submit discard cmd

2022-11-28 Thread Jaegeuk Kim
Need to run checkpatch?

On 11/23, Yangtao Li wrote:
> This patch adds support for counting the average time of submit discard
> command, and we can see its value in debugfs.
> 
> Signed-off-by: Yangtao Li 
> ---
>  fs/f2fs/debug.c   |  7 +--
>  fs/f2fs/f2fs.h|  5 +
>  fs/f2fs/segment.c | 17 +++--
>  3 files changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
> index a216dcdf6941..ede862cb178d 100644
> --- a/fs/f2fs/debug.c
> +++ b/fs/f2fs/debug.c
> @@ -109,6 +109,9 @@ static void update_general_status(struct f2fs_sb_info 
> *sbi)
>   llist_empty(_I(sbi)->fcc_info->issue_list);
>   }
>   if (SM_I(sbi)->dcc_info) {
> + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
> +
> + si->discard_avg = dcc->discard_time_avg;
>   si->nr_discarded =
>   atomic_read(_I(sbi)->dcc_info->issued_discard);
>   si->nr_discarding =
> @@ -506,11 +509,11 @@ static int stat_show(struct seq_file *s, void *v)
>   seq_printf(s, "  - IO_R (Data: %4d, Node: %4d, Meta: %4d\n",
>  si->nr_rd_data, si->nr_rd_node, si->nr_rd_meta);
>   seq_printf(s, "  - IO_W (CP: %4d, Data: %4d, Flush: (%4d %4d 
> %4d), "
> - "Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n",
> +   "Discard: (%4d %4d avg:%4lldns)) cmd: 
> %4d undiscard:%4u\n",
>  si->nr_wb_cp_data, si->nr_wb_data,
>  si->nr_flushing, si->nr_flushed,
>  si->flush_list_empty,
> -si->nr_discarding, si->nr_discarded,
> +si->nr_discarding, si->nr_discarded, 
> ktime_to_us(si->discard_avg),
>  si->nr_discard_cmd, si->undiscard_blks);
>   seq_printf(s, "  - atomic IO: %4d (Max. %4d)\n",
>  si->aw_cnt, si->max_aw_cnt);
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index f0833638f59e..6891467fdb6a 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -372,6 +372,8 @@ struct discard_cmd {
>   int error;  /* bio error */
>   spinlock_t lock;/* for state/bio_ref updating */
>   unsigned short bio_ref; /* bio reference count */
> + struct discard_cmd_control *dcc; /* global discard cmd control */
> + ktime_t submit_start;   /* submit start time */
>  };
>  
>  enum {
> @@ -415,6 +417,8 @@ struct discard_cmd_control {
>   unsigned int max_ordered_discard;   /* maximum discard granularity 
> issued by lba order */
>   unsigned int undiscard_blks;/* # of undiscard blocks */
>   unsigned int next_pos;  /* next discard position */
> + spinlock_t discard_time_lock;   /* for discard time statistics */
> + ktime_t discard_time_avg;   /* issued discard cmd avg time 
> */
>   atomic_t issued_discard;/* # of issued discard */
>   atomic_t queued_discard;/* # of queued discard */
>   atomic_t discard_cmd_cnt;   /* # of cached cmd count */
> @@ -3883,6 +3887,7 @@ struct f2fs_stat_info {
>   int nr_dio_read, nr_dio_write;
>   unsigned int io_skip_bggc, other_skip_bggc;
>   int nr_flushing, nr_flushed, flush_list_empty;
> + ktime_t discard_avg;
>   int nr_discarding, nr_discarded;
>   int nr_discard_cmd;
>   unsigned int undiscard_blks;
> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
> index 8b0b76550578..dd67e936615a 100644
> --- a/fs/f2fs/segment.c
> +++ b/fs/f2fs/segment.c
> @@ -936,6 +936,7 @@ static struct discard_cmd *__create_discard_cmd(struct 
> f2fs_sb_info *sbi,
>   list_add_tail(>list, pend_list);
>   spin_lock_init(>lock);
>   dc->bio_ref = 0;
> + dc->dcc = dcc;
>   atomic_inc(>discard_cmd_cnt);
>   dcc->undiscard_blks += len;
>  
> @@ -1005,9 +1006,13 @@ static void __remove_discard_cmd(struct f2fs_sb_info 
> *sbi,
>  static void f2fs_submit_discard_endio(struct bio *bio)
>  {
>   struct discard_cmd *dc = (struct discard_cmd *)bio->bi_private;
> + struct discard_cmd_control *dcc = dc->dcc;
>   unsigned long flags;
> + ktime_t submit_time;
> + int nr_discarded;
>  
>   spin_lock_irqsave(>lock, flags);
> + submit_time = ktime_sub(ktime_get(), dc->submit_start);
>   if (!dc->error)
>   dc->error = blk_status_to_errno(bio->bi_status);
>   dc->bio_ref--;
> @@ -1017,6 +1022,13 @@ static void f2fs_submit_discard_endio(struct bio *bio)
>   }
>   spin_unlock_irqrestore(>lock, flags);
>   bio_put(bio);
> +
> + spin_lock_irqsave(>discard_time_lock, flags);
> + nr_discarded = atomic_read(>issued_discard);
> + dcc->discard_time_avg = div_u64(ktime_add(nr_discarded * 
> dcc->discard_time_avg, submit_time),
> + 

Re: [f2fs-dev] [PATCH] f2fs: Add f2fs bug tracker link

2022-11-28 Thread Jaegeuk Kim
If you don't mind, let me merge this patch into Chao's patch, since both
are same topic.

On 11/28, Yangtao Li wrote:
> It's better to use bugzilla.kernel.org for reporting bugs.
> 
> Signed-off-by: Yangtao Li 
> ---
>  Documentation/filesystems/f2fs.rst | 6 +-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/filesystems/f2fs.rst 
> b/Documentation/filesystems/f2fs.rst
> index 6e67c5e6c7c3..67e1f3e86f32 100644
> --- a/Documentation/filesystems/f2fs.rst
> +++ b/Documentation/filesystems/f2fs.rst
> @@ -25,10 +25,14 @@ a consistency checking tool (fsck.f2fs), and a debugging 
> tool (dump.f2fs).
>  
>  - git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
>  
> -For reporting bugs and sending patches, please use the following mailing 
> list:
> +For sending patches, please use the following mailing list:
>  
>  - linux-f2fs-devel@lists.sourceforge.net
>  
> +For reporting bugs, please use the following f2fs bug tracker link:
> +
> +- 
> https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System=f2fs
> +
>  Background and Design issues
>  
>  
> -- 
> 2.25.1


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] segment allocation cleanups

2022-11-28 Thread Jaegeuk Kim
On 11/28, Christoph Hellwig wrote:
> Hi Jaegeuk and Chao,
> 
> this series cleans up the segment allocation code a bit.

Thanks, applied for test.

> 
> Diffstat
>  segment.c |   71 
> ++
>  segment.h |6 -
>  2 files changed, 30 insertions(+), 47 deletions(-)


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


Re: [f2fs-dev] [PATCH v4] fsverity: stop using PG_error to track error status

2022-11-28 Thread Jaegeuk Kim
On 11/25, Eric Biggers wrote:
> From: Eric Biggers 
> 
> As a step towards freeing the PG_error flag for other uses, change ext4
> and f2fs to stop using PG_error to track verity errors.  Instead, if a
> verity error occurs, just mark the whole bio as failed.  The coarser
> granularity isn't really a problem since it isn't any worse than what
> the block layer provides, and errors from a multi-page readahead aren't
> reported to applications unless a single-page read fails too.
> 
> f2fs supports compression, which makes the f2fs changes a bit more
> complicated than desired, but the basic premise still works.
> 
> Note: there are still a few uses of PageError in f2fs, but they are on
> the write path, so they are unrelated and this patch doesn't touch them.
> 
> Reviewed-by: Chao Yu 

Acked-by: Jaegeuk Kim 

Thanks,

> Signed-off-by: Eric Biggers 
> ---
> 
> v4: Added a comment for decompression_attempted, added a paragraph to
> the commit message, and added Chao's Reviewed-by.
> 
> v3: made a small simplification to the f2fs changes.  Also dropped the
> fscrypt patch since it is upstream now.
> 
>  fs/ext4/readpage.c |  8 ++
>  fs/f2fs/compress.c | 64 ++
>  fs/f2fs/data.c | 53 +++---
>  fs/verity/verify.c | 12 -
>  4 files changed, 72 insertions(+), 65 deletions(-)
> 
> diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
> index 3d21eae267fca..e604ea4e102b7 100644
> --- a/fs/ext4/readpage.c
> +++ b/fs/ext4/readpage.c
> @@ -75,14 +75,10 @@ static void __read_end_io(struct bio *bio)
>   bio_for_each_segment_all(bv, bio, iter_all) {
>   page = bv->bv_page;
>  
> - /* PG_error was set if verity failed. */
> - if (bio->bi_status || PageError(page)) {
> + if (bio->bi_status)
>   ClearPageUptodate(page);
> - /* will re-read again later */
> - ClearPageError(page);
> - } else {
> + else
>   SetPageUptodate(page);
> - }
>   unlock_page(page);
>   }
>   if (bio->bi_private)
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index d315c2de136f2..2b7a5cc4ed662 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -1711,50 +1711,27 @@ static void f2fs_put_dic(struct decompress_io_ctx 
> *dic, bool in_task)
>   }
>  }
>  
> -/*
> - * Update and unlock the cluster's pagecache pages, and release the 
> reference to
> - * the decompress_io_ctx that was being held for I/O completion.
> - */
> -static void __f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool 
> failed,
> - bool in_task)
> +static void f2fs_verify_cluster(struct work_struct *work)
>  {
> + struct decompress_io_ctx *dic =
> + container_of(work, struct decompress_io_ctx, verity_work);
>   int i;
>  
> + /* Verify, update, and unlock the decompressed pages. */
>   for (i = 0; i < dic->cluster_size; i++) {
>   struct page *rpage = dic->rpages[i];
>  
>   if (!rpage)
>   continue;
>  
> - /* PG_error was set if verity failed. */
> - if (failed || PageError(rpage)) {
> - ClearPageUptodate(rpage);
> - /* will re-read again later */
> - ClearPageError(rpage);
> - } else {
> + if (fsverity_verify_page(rpage))
>   SetPageUptodate(rpage);
> - }
> + else
> + ClearPageUptodate(rpage);
>   unlock_page(rpage);
>   }
>  
> - f2fs_put_dic(dic, in_task);
> -}
> -
> -static void f2fs_verify_cluster(struct work_struct *work)
> -{
> - struct decompress_io_ctx *dic =
> - container_of(work, struct decompress_io_ctx, verity_work);
> - int i;
> -
> - /* Verify the cluster's decompressed pages with fs-verity. */
> - for (i = 0; i < dic->cluster_size; i++) {
> - struct page *rpage = dic->rpages[i];
> -
> - if (rpage && !fsverity_verify_page(rpage))
> - SetPageError(rpage);
> - }
> -
> - __f2fs_decompress_end_io(dic, false, true);
> + f2fs_put_dic(dic, true);
>  }
>  
>  /*
> @@ -1764,6 +1741,8 @@ static void f2fs_verify_cluster(struct work_struct 
> *work)
>  void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
>   bool in_task)
>  {
> + int i;
> +
>   if (!failed && dic->need_verity) {
>   /*
>* Note that to avoid deadlocks, the verity work can't be done
> @@ -1773,9 +1752,28 @@ void f2fs_decompress_end_io(struct decompress_io_ctx 
> *dic, bool failed,
>*/
>   INIT_WORK(>verity_work, f2fs_verify_cluster);
>   fsverity_enqueue_verify_work(>verity_work);
> - } else {
> -

[f2fs-dev] [syzbot] possible deadlock in f2fs_handle_error

2022-11-28 Thread syzbot
Hello,

syzbot found the following issue on:

HEAD commit:6d464646530f Merge branch 'for-next/core' into for-kernelci
git tree:   git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git 
for-kernelci
console output: https://syzkaller.appspot.com/x/log.txt?x=177fa38188
kernel config:  https://syzkaller.appspot.com/x/.config?x=23eec5c79c22aaf8
dashboard link: https://syzkaller.appspot.com/bug?extid=fbc90a26c932581cfe6b
compiler:   Debian clang version 
13.0.1-++20220126092033+75e33f71c2da-1~exp1~20220126212112.63, GNU ld (GNU 
Binutils for Debian) 2.35.2
userspace arch: arm64

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: 
https://storage.googleapis.com/syzbot-assets/f22d29413625/disk-6d464646.raw.xz
vmlinux: 
https://storage.googleapis.com/syzbot-assets/389f0a5f1a4a/vmlinux-6d464646.xz
kernel image: 
https://storage.googleapis.com/syzbot-assets/48ddb02d82da/Image-6d464646.gz.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+fbc90a26c932581cf...@syzkaller.appspotmail.com

loop3: detected capacity change from 0 to 262144
F2FS-fs (loop3): Mismatch valid blocks 0 vs. 1
==
WARNING: possible circular locking dependency detected
6.1.0-rc6-syzkaller-32662-g6d464646530f #0 Not tainted
--
syz-executor.3/2078 is trying to acquire lock:
00010e914088 (>sb_lock){}-{3:3}, at: f2fs_down_write 
fs/f2fs/f2fs.h:2205 [inline]
00010e914088 (>sb_lock){}-{3:3}, at: f2fs_handle_error+0x9c/0x17c 
fs/f2fs/super.c:3898

but task is already holding lock:
fd2733b8 ([i].journal_rwsem){}-{3:3}, at: 
build_sit_entries+0x568/0x9b8 fs/f2fs/segment.c:4412

which lock already depends on the new lock.


the existing dependency chain (in reverse order) is:

-> #6 ([i].journal_rwsem){}-{3:3}:
   down_read+0x5c/0x78 kernel/locking/rwsem.c:1509
   scan_curseg_cache fs/f2fs/node.c:2401 [inline]
   __f2fs_build_free_nids fs/f2fs/node.c:2513 [inline]
   f2fs_build_free_nids+0x798/0x8f4 fs/f2fs/node.c:2528
   f2fs_build_node_manager+0x624/0x64c fs/f2fs/node.c:3313
   f2fs_fill_super+0x1470/0x1e90 fs/f2fs/super.c:4306
   mount_bdev+0x1b8/0x210 fs/super.c:1401
   f2fs_mount+0x44/0x58 fs/f2fs/super.c:4580
   legacy_get_tree+0x30/0x74 fs/fs_context.c:610
   vfs_get_tree+0x40/0x140 fs/super.c:1531
   do_new_mount+0x1dc/0x4e4 fs/namespace.c:3040
   path_mount+0x358/0x890 fs/namespace.c:3370
   do_mount fs/namespace.c:3383 [inline]
   __do_sys_mount fs/namespace.c:3591 [inline]
   __se_sys_mount fs/namespace.c:3568 [inline]
   __arm64_sys_mount+0x2c4/0x3c4 fs/namespace.c:3568
   __invoke_syscall arch/arm64/kernel/syscall.c:38 [inline]
   invoke_syscall arch/arm64/kernel/syscall.c:52 [inline]
   el0_svc_common+0x138/0x220 arch/arm64/kernel/syscall.c:142
   do_el0_svc+0x48/0x164 arch/arm64/kernel/syscall.c:206
   el0_svc+0x58/0x150 arch/arm64/kernel/entry-common.c:637
   el0t_64_sync_handler+0x84/0xf0 arch/arm64/kernel/entry-common.c:655
   el0t_64_sync+0x190/0x194 arch/arm64/kernel/entry.S:584

-> #5 (_i->nat_tree_lock){}-{3:3}:
   down_read+0x5c/0x78 kernel/locking/rwsem.c:1509
   f2fs_down_read fs/f2fs/f2fs.h:2180 [inline]
   f2fs_get_node_info+0x74/0x458 fs/f2fs/node.c:560
   f2fs_do_write_data_page+0x638/0x1094 fs/f2fs/data.c:2710
   f2fs_write_single_data_page+0x750/0xb24 fs/f2fs/data.c:2845
   f2fs_write_cache_pages+0x498/0xdd0 fs/f2fs/data.c:3097
   __f2fs_write_data_pages+0x3f0/0x47c fs/f2fs/data.c:3247
   f2fs_write_data_pages+0x44/0x54 fs/f2fs/data.c:3274
   do_writepages+0x144/0x27c mm/page-writeback.c:2469
   __writeback_single_inode+0x64/0x2e4 fs/fs-writeback.c:1587
   writeback_sb_inodes+0x3e4/0x85c fs/fs-writeback.c:1870
   wb_writeback+0x198/0x328 fs/fs-writeback.c:2044
   wb_do_writeback+0xc8/0x384 fs/fs-writeback.c:2187
   wb_workfn+0x70/0x15c fs/fs-writeback.c:2227
   process_one_work+0x2d8/0x504 kernel/workqueue.c:2289
   worker_thread+0x340/0x610 kernel/workqueue.c:2436
   kthread+0x12c/0x158 kernel/kthread.c:376
   ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:863

-> #4 (>cp_rwsem){}-{3:3}:
   down_read+0x5c/0x78 kernel/locking/rwsem.c:1509
   f2fs_down_read fs/f2fs/f2fs.h:2180 [inline]
   f2fs_lock_op fs/f2fs/f2fs.h:2223 [inline]
   f2fs_do_truncate_blocks+0x98/0x384 fs/f2fs/file.c:687
   f2fs_truncate_blocks+0x9c/0x1d8 fs/f2fs/file.c:750
   f2fs_truncate+0x1b8/0x2a8 fs/f2fs/file.c:802
   f2fs_setattr+0x5c8/0x788 fs/f2fs/file.c:1009
   notify_change+0x758/0x7f0 fs/attr.c:420
   do_truncate+0x108/0x150 fs/open.c:65
   handle_truncate+0xf4/0x154 fs/namei.c:3216
   do_open fs/namei.c:3561 [inline]
   path_openat+0xee0/0x11c4 fs/namei.c:3713
   

[f2fs-dev] [PATCH 1/3] f2fs: remove struct segment_allocation default_salloc_ops

2022-11-28 Thread Christoph Hellwig
There is only  single instance of these ops, so remove the indirection
and call allocate_segment_by_default directly.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/segment.c | 11 ++-
 fs/f2fs/segment.h |  6 --
 2 files changed, 2 insertions(+), 15 deletions(-)

diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 371d0aa6fc5baf..714f9114d9aac0 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2913,7 +2913,7 @@ static void __allocate_new_segment(struct f2fs_sb_info 
*sbi, int type,
return;
 alloc:
old_segno = curseg->segno;
-   SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
+   allocate_segment_by_default(sbi, type, true);
locate_dirty_segment(sbi, old_segno);
 }
 
@@ -2944,10 +2944,6 @@ void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
f2fs_up_read(_I(sbi)->curseg_lock);
 }
 
-static const struct segment_allocation default_salloc_ops = {
-   .allocate_segment = allocate_segment_by_default,
-};
-
 bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
struct cp_control *cpc)
 {
@@ -3272,7 +3268,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, 
struct page *page,
get_atssr_segment(sbi, type, se->type,
AT_SSR, se->mtime);
else
-   sit_i->s_ops->allocate_segment(sbi, type, false);
+   allocate_segment_by_default(sbi, type, false);
}
/*
 * segment dirty status should be updated after segment allocation,
@@ -4258,9 +4254,6 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
return -ENOMEM;
 #endif
 
-   /* init SIT information */
-   sit_i->s_ops = _salloc_ops;
-
sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
sit_i->written_valid_blocks = 0;
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 95b2b104da395b..d97afd2496a22c 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -222,10 +222,6 @@ struct sec_entry {
unsigned int valid_blocks;  /* # of valid blocks in a section */
 };
 
-struct segment_allocation {
-   void (*allocate_segment)(struct f2fs_sb_info *, int, bool);
-};
-
 #define MAX_SKIP_GC_COUNT  16
 
 struct revoke_entry {
@@ -235,8 +231,6 @@ struct revoke_entry {
 };
 
 struct sit_info {
-   const struct segment_allocation *s_ops;
-
block_t sit_base_addr;  /* start block address of SIT area */
block_t sit_blocks; /* # of blocks used by SIT area */
block_t written_valid_blocks;   /* # of valid blocks in main area */
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 3/3] f2fs: remove the unused flush argument to change_curseg

2022-11-28 Thread Christoph Hellwig
Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/segment.c | 16 +++-
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 2e54df1d3feea5..b3b7ea6559f95e 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2643,7 +2643,7 @@ bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, 
int segno)
  * This function always allocates a used segment(from dirty seglist) by SSR
  * manner, so it should recover the existing segment information of valid 
blocks
  */
-static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)
+static void change_curseg(struct f2fs_sb_info *sbi, int type)
 {
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, type);
@@ -2651,9 +2651,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int 
type, bool flush)
struct f2fs_summary_block *sum_node;
struct page *sum_page;
 
-   if (flush)
-   write_sum_page(sbi, curseg->sum_blk,
-   GET_SUM_BLOCK(sbi, curseg->segno));
+   write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, curseg->segno));
 
__set_test_and_inuse(sbi, new_segno);
 
@@ -2692,7 +2690,7 @@ static void get_atssr_segment(struct f2fs_sb_info *sbi, 
int type,
struct seg_entry *se = get_seg_entry(sbi, curseg->next_segno);
 
curseg->seg_type = se->type;
-   change_curseg(sbi, type, true);
+   change_curseg(sbi, type);
} else {
/* allocate cold segment by default */
curseg->seg_type = CURSEG_COLD_DATA;
@@ -2867,7 +2865,7 @@ void f2fs_allocate_segment_for_resize(struct f2fs_sb_info 
*sbi, int type,
goto unlock;
 
if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0))
-   change_curseg(sbi, type, true);
+   change_curseg(sbi, type);
else
new_curseg(sbi, type, true);
 
@@ -3264,7 +3262,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, 
struct page *page,
if (need_new_seg(sbi, type))
new_curseg(sbi, type, false);
else
-   change_curseg(sbi, type, true);
+   change_curseg(sbi, type);
stat_inc_seg_type(sbi, curseg);
}
}
@@ -3527,7 +3525,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, 
struct f2fs_summary *sum,
/* change the current segment */
if (segno != curseg->segno) {
curseg->next_segno = segno;
-   change_curseg(sbi, type, true);
+   change_curseg(sbi, type);
}
 
curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
@@ -3555,7 +3553,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, 
struct f2fs_summary *sum,
if (recover_curseg) {
if (old_cursegno != curseg->segno) {
curseg->next_segno = old_cursegno;
-   change_curseg(sbi, type, true);
+   change_curseg(sbi, type);
}
curseg->next_blkoff = old_blkoff;
curseg->alloc_type = old_alloc_type;
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 2/3] f2fs: open code allocate_segment_by_default

2022-11-28 Thread Christoph Hellwig
allocate_segment_by_default has just two callers, which use very
different code pathes inside it based on the force paramter.  Just
open code the logic in the two callers using a new helper to decided
if a new segment should be allocated.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/segment.c | 50 +++
 1 file changed, 24 insertions(+), 26 deletions(-)

diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 714f9114d9aac0..2e54df1d3feea5 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2836,31 +2836,20 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, 
int type,
return 0;
 }
 
-/*
- * flush out current segment and replace it with new segment
- * This function should be returned with success, otherwise BUG
- */
-static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
-   int type, bool force)
+static bool need_new_seg(struct f2fs_sb_info *sbi, int type)
 {
struct curseg_info *curseg = CURSEG_I(sbi, type);
 
-   if (force)
-   new_curseg(sbi, type, true);
-   else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&
-   curseg->seg_type == CURSEG_WARM_NODE)
-   new_curseg(sbi, type, false);
-   else if (curseg->alloc_type == LFS &&
-   is_next_segment_free(sbi, curseg, type) &&
-   likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
-   new_curseg(sbi, type, false);
-   else if (f2fs_need_SSR(sbi) &&
-   get_ssr_segment(sbi, type, SSR, 0))
-   change_curseg(sbi, type, true);
-   else
-   new_curseg(sbi, type, false);
-
-   stat_inc_seg_type(sbi, curseg);
+   if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&
+   curseg->seg_type == CURSEG_WARM_NODE)
+   return true;
+   if (curseg->alloc_type == LFS &&
+   is_next_segment_free(sbi, curseg, type) &&
+   likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
+   return true;
+   if (!f2fs_need_SSR(sbi) || !get_ssr_segment(sbi, type, SSR, 0))
+   return true;
+   return false;
 }
 
 void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
@@ -2913,7 +2902,8 @@ static void __allocate_new_segment(struct f2fs_sb_info 
*sbi, int type,
return;
 alloc:
old_segno = curseg->segno;
-   allocate_segment_by_default(sbi, type, true);
+   new_curseg(sbi, type, true);
+   stat_inc_seg_type(sbi, curseg);
locate_dirty_segment(sbi, old_segno);
 }
 
@@ -3264,11 +3254,19 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, 
struct page *page,
update_sit_entry(sbi, old_blkaddr, -1);
 
if (!__has_curseg_space(sbi, curseg)) {
-   if (from_gc)
+   /*
+* Flush out current segment and replace it with new segment.
+*/
+   if (from_gc) {
get_atssr_segment(sbi, type, se->type,
AT_SSR, se->mtime);
-   else
-   allocate_segment_by_default(sbi, type, false);
+   } else {
+   if (need_new_seg(sbi, type))
+   new_curseg(sbi, type, false);
+   else
+   change_curseg(sbi, type, true);
+   stat_inc_seg_type(sbi, curseg);
+   }
}
/*
 * segment dirty status should be updated after segment allocation,
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] segment allocation cleanups

2022-11-28 Thread Christoph Hellwig
Hi Jaegeuk and Chao,

this series cleans up the segment allocation code a bit.

Diffstat
 segment.c |   71 ++
 segment.h |6 -
 2 files changed, 30 insertions(+), 47 deletions(-)


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] a fix and a bunch of cleanups

2022-11-28 Thread Christoph Hellwig
Hi Jaegeuk and Chao,

the first patch in this series fixes a warning and subsequent hang when
testing zoned f2fs.  The other patches are misc cleanups for the I/O path.

Diffstat
 fs/f2fs/compress.c  |2 
 fs/f2fs/data.c  |  544 ++--
 fs/f2fs/extent_cache.c  |   19 -
 fs/f2fs/f2fs.h  |   24 -
 fs/f2fs/file.c  |   16 -
 fs/f2fs/gc.c|4 
 include/trace/events/f2fs.h |   11 
 7 files changed, 309 insertions(+), 311 deletions(-)


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 05/15] f2fs: fold f2fs_lookup_extent_tree into f2fs_lookup_extent_cache

2022-11-28 Thread Christoph Hellwig
No need to keep these two helpers separate.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/extent_cache.c | 16 +---
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index 932c070173b976..538e4b79f83c9b 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -407,14 +407,17 @@ void f2fs_init_extent_tree(struct inode *inode, struct 
page *ipage)
set_inode_flag(inode, FI_NO_EXTENT);
 }
 
-static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
-   struct extent_info *ei)
+bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs,
+   struct extent_info *ei)
 {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct extent_tree *et = F2FS_I(inode)->extent_tree;
struct extent_node *en;
bool ret = false;
 
+   if (!f2fs_may_extent_tree(inode))
+   return false;
+
f2fs_bug_on(sbi, !et);
 
trace_f2fs_lookup_extent_tree_start(inode, pgofs);
@@ -850,15 +853,6 @@ void f2fs_destroy_extent_tree(struct inode *inode)
trace_f2fs_destroy_extent_tree(inode, node_cnt);
 }
 
-bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs,
-   struct extent_info *ei)
-{
-   if (!f2fs_may_extent_tree(inode))
-   return false;
-
-   return f2fs_lookup_extent_tree(inode, pgofs, ei);
-}
-
 void f2fs_update_extent_cache(struct dnode_of_data *dn)
 {
pgoff_t fofs;
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 06/15] f2fs: add a f2fs_lookup_extent_cache_block helper

2022-11-28 Thread Christoph Hellwig
All but three callers of f2fs_lookup_extent_cache just want the block
address.  Add a small helper to simplify them.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 29 +++--
 fs/f2fs/extent_cache.c | 11 +++
 fs/f2fs/f2fs.h |  2 ++
 fs/f2fs/gc.c   |  4 +---
 4 files changed, 21 insertions(+), 25 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 404e1637e31072..a294a589ba1a91 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1199,14 +1199,8 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t 
index)
 
 int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
 {
-   struct extent_info ei = {0, };
-   struct inode *inode = dn->inode;
-
-   if (f2fs_lookup_extent_cache(inode, index, )) {
-   dn->data_blkaddr = ei.blk + index - ei.fofs;
+   if (f2fs_lookup_extent_cache_block(dn->inode, index, >data_blkaddr))
return 0;
-   }
-
return f2fs_reserve_block(dn, index);
 }
 
@@ -1216,15 +1210,13 @@ struct page *f2fs_get_read_data_page(struct inode 
*inode, pgoff_t index,
struct address_space *mapping = inode->i_mapping;
struct dnode_of_data dn;
struct page *page;
-   struct extent_info ei = {0, };
int err;
 
page = f2fs_grab_cache_page(mapping, index, for_write);
if (!page)
return ERR_PTR(-ENOMEM);
 
-   if (f2fs_lookup_extent_cache(inode, index, )) {
-   dn.data_blkaddr = ei.blk + index - ei.fofs;
+   if (f2fs_lookup_extent_cache_block(inode, index, _blkaddr)) {
if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,
DATA_GENERIC_ENHANCE_READ)) {
err = -EFSCORRUPTED;
@@ -2623,7 +2615,6 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
struct page *page = fio->page;
struct inode *inode = page->mapping->host;
struct dnode_of_data dn;
-   struct extent_info ei = {0, };
struct node_info ni;
bool ipu_force = false;
int err = 0;
@@ -2635,9 +2626,8 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
set_new_dnode(, inode, NULL, NULL, 0);
 
if (need_inplace_update(fio) &&
-   f2fs_lookup_extent_cache(inode, page->index, )) {
-   fio->old_blkaddr = ei.blk + page->index - ei.fofs;
-
+   f2fs_lookup_extent_cache_block(inode, page->index,
+  >old_blkaddr)) {
if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
DATA_GENERIC_ENHANCE)) {
f2fs_handle_error(fio->sbi,
@@ -3310,7 +3300,6 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
struct dnode_of_data dn;
struct page *ipage;
bool locked = false;
-   struct extent_info ei = {0, };
int err = 0;
int flag;
 
@@ -3359,9 +3348,8 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
} else if (locked) {
err = f2fs_get_block(, index);
} else {
-   if (f2fs_lookup_extent_cache(inode, index, )) {
-   dn.data_blkaddr = ei.blk + index - ei.fofs;
-   } else {
+   if (!f2fs_lookup_extent_cache_block(inode, index,
+   _blkaddr)) {
/* hole case */
err = f2fs_get_dnode_of_data(, index, LOOKUP_NODE);
if (err || dn.data_blkaddr == NULL_ADDR) {
@@ -3391,7 +3379,6 @@ static int __find_data_block(struct inode *inode, pgoff_t 
index,
 {
struct dnode_of_data dn;
struct page *ipage;
-   struct extent_info ei = {0, };
int err = 0;
 
ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
@@ -3400,9 +3387,7 @@ static int __find_data_block(struct inode *inode, pgoff_t 
index,
 
set_new_dnode(, inode, ipage, ipage, 0);
 
-   if (f2fs_lookup_extent_cache(inode, index, )) {
-   dn.data_blkaddr = ei.blk + index - ei.fofs;
-   } else {
+   if (!f2fs_lookup_extent_cache_block(inode, index, _blkaddr)) {
/* hole case */
err = f2fs_get_dnode_of_data(, index, LOOKUP_NODE);
if (err) {
diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index 538e4b79f83c9b..992a3d6bd6e7c7 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -853,6 +853,17 @@ void f2fs_destroy_extent_tree(struct inode *inode)
trace_f2fs_destroy_extent_tree(inode, node_cnt);
 }
 
+bool f2fs_lookup_extent_cache_block(struct inode *inode, pgoff_t index,
+   block_t *blkaddr)
+{
+   struct extent_info ei = {};
+
+   if (!f2fs_lookup_extent_cache(inode, index, ))
+   return false;
+   *blkaddr = ei.blk + index - ei.fofs;
+   return true;
+}
+
 

[f2fs-dev] [PATCH 08/15] f2fs: f2fs_do_map_lock

2022-11-28 Thread Christoph Hellwig
Split f2fs_do_map_lock into a lock and unlock helper to make the code
using it easier to read.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 46 +++---
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 6df80a30df263c..b7c8e3e0113aff 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1427,19 +1427,20 @@ static int __allocate_data_block(struct dnode_of_data 
*dn, int seg_type)
return 0;
 }
 
-static void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
+static void f2fs_map_lock(struct f2fs_sb_info *sbi, int flag)
 {
-   if (flag == F2FS_GET_BLOCK_PRE_AIO) {
-   if (lock)
-   f2fs_down_read(>node_change);
-   else
-   f2fs_up_read(>node_change);
-   } else {
-   if (lock)
-   f2fs_lock_op(sbi);
-   else
-   f2fs_unlock_op(sbi);
-   }
+   if (flag == F2FS_GET_BLOCK_PRE_AIO)
+   f2fs_down_read(>node_change);
+   else
+   f2fs_lock_op(sbi);
+}
+
+static void f2fs_map_unlock(struct f2fs_sb_info *sbi, int flag)
+{
+   if (flag == F2FS_GET_BLOCK_PRE_AIO)
+   f2fs_up_read(>node_change);
+   else
+   f2fs_unlock_op(sbi);
 }
 
 int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index)
@@ -1447,9 +1448,9 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, 
pgoff_t index)
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
int err;
 
-   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
+   f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
err = f2fs_get_block(dn, index);
-   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
+   f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO);
 
return err;
 }
@@ -1524,7 +1525,7 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
 
 next_dnode:
if (map->m_may_create)
-   f2fs_do_map_lock(sbi, flag, true);
+   f2fs_map_lock(sbi, flag);
 
/* When reading holes, we need its node page */
set_new_dnode(, inode, NULL, NULL, 0);
@@ -1708,7 +1709,7 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
f2fs_put_dnode();
 
if (map->m_may_create) {
-   f2fs_do_map_lock(sbi, flag, false);
+   f2fs_map_unlock(sbi, flag);
f2fs_balance_fs(sbi, dn.node_changed);
}
goto next_dnode;
@@ -1754,7 +1755,7 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
f2fs_put_dnode();
 unlock_out:
if (map->m_may_create) {
-   f2fs_do_map_lock(sbi, flag, false);
+   f2fs_map_unlock(sbi, flag);
f2fs_balance_fs(sbi, dn.node_changed);
}
 out:
@@ -3330,7 +3331,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
 
if (f2fs_has_inline_data(inode) ||
(pos & PAGE_MASK) >= i_size_read(inode)) {
-   f2fs_do_map_lock(sbi, flag, true);
+   f2fs_map_lock(sbi, flag);
locked = true;
}
 
@@ -3366,8 +3367,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
err = f2fs_get_dnode_of_data(, index, LOOKUP_NODE);
if (err || dn.data_blkaddr == NULL_ADDR) {
f2fs_put_dnode();
-   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO,
-   true);
+   f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO);
locked = true;
goto restart;
@@ -3382,7 +3382,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
f2fs_put_dnode();
 unlock_out:
if (locked)
-   f2fs_do_map_lock(sbi, flag, false);
+   f2fs_map_unlock(sbi, flag);
return err;
 }
 
@@ -3420,7 +3420,7 @@ static int __reserve_data_block(struct inode *inode, 
pgoff_t index,
struct page *ipage;
int err = 0;
 
-   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
+   f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
 
ipage = f2fs_get_node_page(sbi, inode->i_ino);
if (IS_ERR(ipage)) {
@@ -3436,7 +3436,7 @@ static int __reserve_data_block(struct inode *inode, 
pgoff_t index,
f2fs_put_dnode();
 
 unlock_out:
-   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
+   f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO);
return err;
 }
 
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 07/15] f2fs: add a f2fs_get_block_locked helper

2022-11-28 Thread Christoph Hellwig
This allows to keep the f2fs_do_map_lock based locking scheme
private to data.c.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 16 ++--
 fs/f2fs/f2fs.h |  3 +--
 fs/f2fs/file.c |  4 +---
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index a294a589ba1a91..6df80a30df263c 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1197,7 +1197,7 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t 
index)
return err;
 }
 
-int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
+static int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
 {
if (f2fs_lookup_extent_cache_block(dn->inode, index, >data_blkaddr))
return 0;
@@ -1427,7 +1427,7 @@ static int __allocate_data_block(struct dnode_of_data 
*dn, int seg_type)
return 0;
 }
 
-void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
+static void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
 {
if (flag == F2FS_GET_BLOCK_PRE_AIO) {
if (lock)
@@ -1442,6 +1442,18 @@ void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int 
flag, bool lock)
}
 }
 
+int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index)
+{
+   struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
+   int err;
+
+   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
+   err = f2fs_get_block(dn, index);
+   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
+
+   return err;
+}
+
 /*
  * f2fs_map_blocks() tries to find or build mapping relationship which
  * maps continuous logical blocks to physical blocks, and return such
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index c0a1a987889167..a3789dab0aade9 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3791,7 +3791,7 @@ void f2fs_set_data_blkaddr(struct dnode_of_data *dn);
 void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
 int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
 int f2fs_reserve_new_block(struct dnode_of_data *dn);
-int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index);
+int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index);
 int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index);
 struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
blk_opf_t op_flags, bool for_write);
@@ -3801,7 +3801,6 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, 
pgoff_t index,
 struct page *f2fs_get_new_data_page(struct inode *inode,
struct page *ipage, pgoff_t index, bool new_i_size);
 int f2fs_do_write_data_page(struct f2fs_io_info *fio);
-void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock);
 int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
int create, int flag);
 int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 82cda12582272a..cbeb7bd880046e 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -113,10 +113,8 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault 
*vmf)
 
if (need_alloc) {
/* block allocation */
-   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
set_new_dnode(, inode, NULL, NULL, 0);
-   err = f2fs_get_block(, page->index);
-   f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
+   err = f2fs_get_block_locked(, page->index);
}
 
 #ifdef CONFIG_F2FS_FS_COMPRESSION
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 01/15] f2fs: don't rely on F2FS_MAP_* in f2fs_iomap_begin

2022-11-28 Thread Christoph Hellwig
When testing with a mixed zoned / convention device combination, there
are regular but not 100% reproducible failures in xfstests generic/113
where the __is_valid_data_blkaddr assert hits due to finding a hole.

This seems to be because f2fs_map_blocks can set this flag on a hole
when it was found in the extent cache.

Rework f2fs_iomap_begin to just check the special block numbers directly.
This has the added benefits of the WARN_ON showing which invalid block
address we found, and being properly error out on delalloc blocks that
are confusingly called unwritten but not actually suitable for direct
I/O.

Fixes: 1517c1a7a445 ("f2fs: implement iomap operations")
Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index a71e818cd67b43..541d625d94be42 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -4134,20 +4134,24 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t 
offset, loff_t length,
 */
map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len);
 
-   if (map.m_flags & (F2FS_MAP_MAPPED | F2FS_MAP_UNWRITTEN)) {
-   iomap->length = blks_to_bytes(inode, map.m_len);
-   if (map.m_flags & F2FS_MAP_MAPPED) {
-   iomap->type = IOMAP_MAPPED;
-   iomap->flags |= IOMAP_F_MERGED;
-   } else {
-   iomap->type = IOMAP_UNWRITTEN;
-   }
-   if (WARN_ON_ONCE(!__is_valid_data_blkaddr(map.m_pblk)))
-   return -EINVAL;
+   /*
+* We should never see delalloc or compressed extents here based on
+* prior flushing and checks.
+*/
+   if (WARN_ON_ONCE(map.m_pblk == NEW_ADDR))
+   return -EINVAL;
+   if (WARN_ON_ONCE(map.m_pblk == COMPRESS_ADDR))
+   return -EINVAL;
 
+   if (map.m_pblk != NULL_ADDR) {
+   iomap->length = blks_to_bytes(inode, map.m_len);
+   iomap->type = IOMAP_MAPPED;
+   iomap->flags |= IOMAP_F_MERGED;
iomap->bdev = map.m_bdev;
iomap->addr = blks_to_bytes(inode, map.m_pblk);
} else {
+   if (flags & IOMAP_WRITE)
+   return -ENOTBLK;
iomap->length = blks_to_bytes(inode, next_pgofs) -
iomap->offset;
iomap->type = IOMAP_HOLE;
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 15/15] f2fs: refactor the hole reporting and allocation logic in f2fs_map_blocks

2022-11-28 Thread Christoph Hellwig
Add a is_hole local variable to figure out if the block number might need
allocation, and untangle to logic to report the hole or fill it with a
block allocation.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 113 -
 1 file changed, 56 insertions(+), 57 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 3c802ce397de52..32e6823e1e9b1a 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1524,6 +1524,7 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map, int flag)
block_t blkaddr;
unsigned int start_pgofs;
int bidx = 0;
+   bool is_hole;
 
if (!maxblocks)
return 0;
@@ -1564,78 +1565,76 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map, int flag)
 
 next_block:
blkaddr = f2fs_data_blkaddr();
-
-   if (__is_valid_data_blkaddr(blkaddr) &&
-   !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
+   is_hole = !__is_valid_data_blkaddr(blkaddr);
+   if (!is_hole &&
+   !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
err = -EFSCORRUPTED;
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
goto sync_out;
}
 
-   if (__is_valid_data_blkaddr(blkaddr)) {
-   /* use out-place-update for driect IO under LFS mode */
-   if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO &&
-   map->m_may_create) {
+   /* use out-place-update for direct IO under LFS mode */
+   if (map->m_may_create &&
+   (is_hole || (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO))) {
+   if (unlikely(f2fs_cp_error(sbi))) {
+   err = -EIO;
+   goto sync_out;
+   }
+
+   switch (flag) {
+   case F2FS_GET_BLOCK_PRE_AIO:
+   if (blkaddr == NULL_ADDR) {
+   prealloc++;
+   last_ofs_in_node = dn.ofs_in_node;
+   }
+   break;
+   case F2FS_GET_BLOCK_PRE_DIO:
+   case F2FS_GET_BLOCK_DIO:
err = __allocate_data_block(, map->m_seg_type);
if (err)
goto sync_out;
-   blkaddr = dn.data_blkaddr;
+   if (flag == F2FS_GET_BLOCK_PRE_DIO)
+   file_need_truncate(inode);
set_inode_flag(inode, FI_APPEND_WRITE);
+   break;
+   default:
+   WARN_ON_ONCE(1);
+   err = -EIO;
+   goto sync_out;
}
-   } else {
-   if (map->m_may_create) {
-   if (unlikely(f2fs_cp_error(sbi))) {
-   err = -EIO;
-   goto sync_out;
-   }
-   if (flag == F2FS_GET_BLOCK_PRE_AIO) {
-   if (blkaddr == NULL_ADDR) {
-   prealloc++;
-   last_ofs_in_node = dn.ofs_in_node;
-   }
-   } else {
-   WARN_ON(flag != F2FS_GET_BLOCK_PRE_DIO &&
-   flag != F2FS_GET_BLOCK_DIO);
-   err = __allocate_data_block(,
-   map->m_seg_type);
-   if (!err) {
-   if (flag == F2FS_GET_BLOCK_PRE_DIO)
-   file_need_truncate(inode);
-   set_inode_flag(inode, FI_APPEND_WRITE);
-   }
-   }
-   if (err)
-   goto sync_out;
+
+   blkaddr = dn.data_blkaddr;
+   if (is_hole)
map->m_flags |= F2FS_MAP_NEW;
-   blkaddr = dn.data_blkaddr;
-   } else {
-   if (f2fs_compressed_file(inode) &&
-   f2fs_sanity_check_cluster() &&
-   (flag != F2FS_GET_BLOCK_FIEMAP ||
-   IS_ENABLED(CONFIG_F2FS_CHECK_FS))) {
-   err = -EFSCORRUPTED;
-   f2fs_handle_error(sbi,
-   ERROR_CORRUPTED_CLUSTER);
-   goto sync_out;
-   }
-   if (flag == F2FS_GET_BLOCK_BMAP) {
-   map->m_pblk = 0;
-   goto sync_out;
-   

[f2fs-dev] [PATCH 04/15] f2fs: split __submit_bio

2022-11-28 Thread Christoph Hellwig
Split __submit_bio into one function each for reads and writes, and a
helper for aligning writes.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/compress.c |   2 +-
 fs/f2fs/data.c | 111 +++--
 fs/f2fs/f2fs.h |   4 +-
 3 files changed, 61 insertions(+), 56 deletions(-)

diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index d315c2de136f26..355200b6dad774 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1073,7 +1073,7 @@ static int prepare_compress_overwrite(struct compress_ctx 
*cc,
if (ret)
goto out;
if (bio)
-   f2fs_submit_bio(sbi, bio, DATA);
+   f2fs_submit_read_bio(sbi, bio, DATA);
 
ret = f2fs_init_compress_ctx(cc);
if (ret)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 444865e0cb6397..404e1637e31072 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -492,65 +492,66 @@ static bool f2fs_crypt_mergeable_bio(struct bio *bio, 
const struct inode *inode,
return fscrypt_mergeable_bio(bio, inode, next_idx);
 }
 
-static inline void __submit_bio(struct f2fs_sb_info *sbi,
-   struct bio *bio, enum page_type type)
+void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio,
+enum page_type type)
 {
-   if (!is_read_io(bio_op(bio))) {
-   unsigned int start;
+   WARN_ON_ONCE(!is_read_io(bio_op(bio)));
+   trace_f2fs_submit_read_bio(sbi->sb, type, bio);
 
-   if (type != DATA && type != NODE)
-   goto submit_io;
+   iostat_update_submit_ctx(bio, type);
+   submit_bio(bio);
+}
 
-   if (f2fs_lfs_mode(sbi) && current->plug)
-   blk_finish_plug(current->plug);
+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 (!F2FS_IO_ALIGNED(sbi))
-   goto submit_io;
+   if (start == 0)
+   return;
 
-   start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
-   start %= F2FS_IO_SIZE(sbi);
+   /* 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);
 
-   if (start == 0)
-   goto submit_io;
+   lock_page(page);
 
-   /* 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);
+   zero_user_segment(page, 0, PAGE_SIZE);
+   set_page_private_dummy(page);
 
-   lock_page(page);
+   if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
+   f2fs_bug_on(sbi, 1);
+   }
+}
 
-   zero_user_segment(page, 0, PAGE_SIZE);
-   set_page_private_dummy(page);
+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 (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
-   f2fs_bug_on(sbi, 1);
+   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);
}
-   /*
-* 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);
}
-submit_io:
-   if (is_read_io(bio_op(bio)))
-   trace_f2fs_submit_read_bio(sbi->sb, type, bio);
-   else
-   trace_f2fs_submit_write_bio(sbi->sb, type, bio);
 
+   trace_f2fs_submit_write_bio(sbi->sb, type, bio);
iostat_update_submit_ctx(bio, type);
submit_bio(bio);
 }
 
-void f2fs_submit_bio(struct f2fs_sb_info *sbi,
-   

[f2fs-dev] [PATCH 02/15] f2fs: decouple F2FS_MAP_ from buffer head flags

2022-11-28 Thread Christoph Hellwig
m_flags is never interchanged with the buffer_heads b_flags directly,
so use separate codepoints from that.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/f2fs.h | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e6355a5683b75c..db2dc3fa73162b 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -643,13 +643,11 @@ struct extent_tree {
 };
 
 /*
- * This structure is taken from ext4_map_blocks.
- *
- * Note that, however, f2fs uses NEW and MAPPED flags for f2fs_map_blocks().
+ * State of block returned by f2fs_map_blocks.
  */
-#define F2FS_MAP_NEW   (1 << BH_New)
-#define F2FS_MAP_MAPPED(1 << BH_Mapped)
-#define F2FS_MAP_UNWRITTEN (1 << BH_Unwritten)
+#define F2FS_MAP_NEW   (1U << 0)
+#define F2FS_MAP_MAPPED(1U << 1)
+#define F2FS_MAP_UNWRITTEN (1U << 2)
 #define F2FS_MAP_FLAGS (F2FS_MAP_NEW | F2FS_MAP_MAPPED |\
F2FS_MAP_UNWRITTEN)
 
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 10/15] f2fs: simplify __allocate_data_block

2022-11-28 Thread Christoph Hellwig
Just use a simple if block for the conditional call to
inc_valid_block_count.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index fc5207859912ce..87c17602a3fdd4 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1407,13 +1407,12 @@ static int __allocate_data_block(struct dnode_of_data 
*dn, int seg_type)
return err;
 
dn->data_blkaddr = f2fs_data_blkaddr(dn);
-   if (dn->data_blkaddr != NULL_ADDR)
-   goto alloc;
-
-   if (unlikely((err = inc_valid_block_count(sbi, dn->inode, 
-   return err;
+   if (dn->data_blkaddr == NULL_ADDR) {
+   err = inc_valid_block_count(sbi, dn->inode, );
+   if (unlikely(err))
+   return err;
+   }
 
-alloc:
set_summary(, dn->nid, dn->ofs_in_node, ni.version);
old_blkaddr = dn->data_blkaddr;
f2fs_allocate_data_block(sbi, NULL, old_blkaddr, >data_blkaddr,
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 11/15] f2fs: remove f2fs_get_block

2022-11-28 Thread Christoph Hellwig
Fold f2fs_get_block into the two remaining callers to simplify the
call chain a bit.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 16 ++--
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 87c17602a3fdd4..2ae8fcf7cf49f4 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1197,13 +1197,6 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t 
index)
return err;
 }
 
-static int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
-{
-   if (f2fs_lookup_extent_cache_block(dn->inode, index, >data_blkaddr))
-   return 0;
-   return f2fs_reserve_block(dn, index);
-}
-
 struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
 blk_opf_t op_flags, bool for_write)
 {
@@ -1445,10 +1438,12 @@ static void f2fs_map_unlock(struct f2fs_sb_info *sbi, 
int flag)
 int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index)
 {
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
-   int err;
+   int err = 0;
 
f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
-   err = f2fs_get_block(dn, index);
+   if (!f2fs_lookup_extent_cache_block(dn->inode, index,
+   >data_blkaddr))
+   err = f2fs_reserve_block(dn, index);
f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO);
 
return err;
@@ -3427,7 +3422,8 @@ static int __reserve_data_block(struct inode *inode, 
pgoff_t index,
}
set_new_dnode(, inode, ipage, ipage, 0);
 
-   err = f2fs_get_block(, index);
+   if (!f2fs_lookup_extent_cache_block(inode, index, _blkaddr))
+   err = f2fs_reserve_block(, index);
 
*blk_addr = dn.data_blkaddr;
*node_changed = dn.node_changed;
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 13/15] f2fs: factor a f2f_map_blocks_cached helper

2022-11-28 Thread Christoph Hellwig
Add a helper to deal with everything needed to return a f2fs_map_blocks
structure based on a lookup in the extent cache.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 62 +++---
 1 file changed, 38 insertions(+), 24 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 730b58ba97c0ae..f6124cedd121a2 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1449,6 +1449,41 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, 
pgoff_t index)
return err;
 }
 
+static bool f2fs_map_blocks_cached(struct inode *inode,
+   struct f2fs_map_blocks *map, int flag)
+{
+   struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+   unsigned int maxblocks = map->m_len;
+   pgoff_t pgoff = (pgoff_t)map->m_lblk;
+   struct extent_info ei = {};
+
+   if (!f2fs_lookup_extent_cache(inode, pgoff, ))
+   return false;
+
+   map->m_pblk = ei.blk + pgoff - ei.fofs;
+   map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgoff);
+   map->m_flags = F2FS_MAP_MAPPED;
+   if (map->m_next_extent)
+   *map->m_next_extent = pgoff + map->m_len;
+
+   /* for hardware encryption, but to avoid potential issue in future */
+   if (flag == F2FS_GET_BLOCK_DIO)
+   f2fs_wait_on_block_writeback_range(inode,
+   map->m_pblk, map->m_len);
+
+   if (f2fs_allow_multi_device_dio(sbi, flag)) {
+   int bidx = f2fs_target_device_index(sbi, map->m_pblk);
+   struct f2fs_dev_info *dev = >devs[bidx];
+
+   map->m_bdev = dev->bdev;
+   map->m_pblk -= dev->start_blk;
+   map->m_len = min(map->m_len, dev->end_blk + 1 - map->m_pblk);
+   } else {
+   map->m_bdev = inode->i_sb->s_bdev;
+   }
+   return true;
+}
+
 /*
  * f2fs_map_blocks() tries to find or build mapping relationship which
  * maps continuous logical blocks to physical blocks, and return such
@@ -1464,7 +1499,6 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map, int flag)
int err = 0, ofs = 1;
unsigned int ofs_in_node, last_ofs_in_node;
blkcnt_t prealloc;
-   struct extent_info ei = {0, };
block_t blkaddr;
unsigned int start_pgofs;
int bidx = 0;
@@ -1472,6 +1506,9 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map, int flag)
if (!maxblocks)
return 0;
 
+   if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag))
+   goto out;
+
map->m_bdev = inode->i_sb->s_bdev;
map->m_multidev_dio =
f2fs_allow_multi_device_dio(F2FS_I_SB(inode), flag);
@@ -1483,29 +1520,6 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map, int flag)
pgofs = (pgoff_t)map->m_lblk;
end = pgofs + maxblocks;
 
-   if (!map->m_may_create && f2fs_lookup_extent_cache(inode, pgofs, )) {
-   map->m_pblk = ei.blk + pgofs - ei.fofs;
-   map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
-   map->m_flags = F2FS_MAP_MAPPED;
-   if (map->m_next_extent)
-   *map->m_next_extent = pgofs + map->m_len;
-
-   /* for hardware encryption, but to avoid potential issue in 
future */
-   if (flag == F2FS_GET_BLOCK_DIO)
-   f2fs_wait_on_block_writeback_range(inode,
-   map->m_pblk, map->m_len);
-
-   if (map->m_multidev_dio) {
-   bidx = f2fs_target_device_index(sbi, map->m_pblk);
-
-   map->m_bdev = FDEV(bidx).bdev;
-   map->m_pblk -= FDEV(bidx).start_blk;
-   map->m_len = min(map->m_len,
-   FDEV(bidx).end_blk + 1 - map->m_pblk);
-   }
-   goto out;
-   }
-
 next_dnode:
if (map->m_may_create)
f2fs_map_lock(sbi, flag);
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 12/15] f2fs: remove the create argument to f2fs_map_blocks

2022-11-28 Thread Christoph Hellwig
The create argument is always identicaly to map->m_may_create, so use
that consistently.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c  | 32 ++--
 fs/f2fs/f2fs.h  |  3 +--
 fs/f2fs/file.c  | 12 ++--
 include/trace/events/f2fs.h | 11 ---
 4 files changed, 21 insertions(+), 37 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 2ae8fcf7cf49f4..730b58ba97c0ae 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1454,8 +1454,7 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, 
pgoff_t index)
  * maps continuous logical blocks to physical blocks, and return such
  * info via f2fs_map_blocks structure.
  */
-int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
-   int create, int flag)
+int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
 {
unsigned int maxblocks = map->m_len;
struct dnode_of_data dn;
@@ -1484,11 +1483,7 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
pgofs = (pgoff_t)map->m_lblk;
end = pgofs + maxblocks;
 
-   if (!create && f2fs_lookup_extent_cache(inode, pgofs, )) {
-   if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO &&
-   map->m_may_create)
-   goto next_dnode;
-
+   if (!map->m_may_create && f2fs_lookup_extent_cache(inode, pgofs, )) {
map->m_pblk = ei.blk + pgofs - ei.fofs;
map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
map->m_flags = F2FS_MAP_MAPPED;
@@ -1501,18 +1496,12 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
map->m_pblk, map->m_len);
 
if (map->m_multidev_dio) {
-   block_t blk_addr = map->m_pblk;
-
bidx = f2fs_target_device_index(sbi, map->m_pblk);
 
map->m_bdev = FDEV(bidx).bdev;
map->m_pblk -= FDEV(bidx).start_blk;
map->m_len = min(map->m_len,
FDEV(bidx).end_blk + 1 - map->m_pblk);
-
-   if (map->m_may_create)
-   f2fs_update_device_state(sbi, inode->i_ino,
-   blk_addr, map->m_len);
}
goto out;
}
@@ -1579,7 +1568,7 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
set_inode_flag(inode, FI_APPEND_WRITE);
}
} else {
-   if (create) {
+   if (map->m_may_create) {
if (unlikely(f2fs_cp_error(sbi))) {
err = -EIO;
goto sync_out;
@@ -1753,7 +1742,7 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
f2fs_balance_fs(sbi, dn.node_changed);
}
 out:
-   trace_f2fs_map_blocks(inode, map, create, flag, err);
+   trace_f2fs_map_blocks(inode, map, flag, err);
return err;
 }
 
@@ -1775,7 +1764,7 @@ bool f2fs_overwrite_io(struct inode *inode, loff_t pos, 
size_t len)
 
while (map.m_lblk < last_lblk) {
map.m_len = last_lblk - map.m_lblk;
-   err = f2fs_map_blocks(inode, , 0, F2FS_GET_BLOCK_DEFAULT);
+   err = f2fs_map_blocks(inode, , F2FS_GET_BLOCK_DEFAULT);
if (err || map.m_len == 0)
return false;
map.m_lblk += map.m_len;
@@ -1949,7 +1938,7 @@ int f2fs_fiemap(struct inode *inode, struct 
fiemap_extent_info *fieinfo,
map.m_len = cluster_size - count_in_cluster;
}
 
-   ret = f2fs_map_blocks(inode, , 0, F2FS_GET_BLOCK_FIEMAP);
+   ret = f2fs_map_blocks(inode, , F2FS_GET_BLOCK_FIEMAP);
if (ret)
goto out;
 
@@ -2082,7 +2071,7 @@ static int f2fs_read_single_page(struct inode *inode, 
struct page *page,
map->m_lblk = block_in_file;
map->m_len = last_block - block_in_file;
 
-   ret = f2fs_map_blocks(inode, map, 0, F2FS_GET_BLOCK_DEFAULT);
+   ret = f2fs_map_blocks(inode, map, F2FS_GET_BLOCK_DEFAULT);
if (ret)
goto out;
 got_it:
@@ -3779,7 +3768,7 @@ static sector_t f2fs_bmap(struct address_space *mapping, 
sector_t block)
map.m_next_pgofs = NULL;
map.m_seg_type = NO_CHECK_TYPE;
 
-   if (!f2fs_map_blocks(inode, , 0, F2FS_GET_BLOCK_BMAP))
+   if (!f2fs_map_blocks(inode, , F2FS_GET_BLOCK_BMAP))
blknr = map.m_pblk;
}
 out:
@@ -3887,7 +3876,7 @@ static int check_swap_activate(struct swap_info_struct 
*sis,
map.m_seg_type = NO_CHECK_TYPE;
map.m_may_create = 

[f2fs-dev] [PATCH 09/15] f2fs: reflow prepare_write_begin

2022-11-28 Thread Christoph Hellwig
Reflow prepare_write_begin so that it reads more straight forward,
and so that there is one place that does an extent cache lookup
instead of three, two of which are hidden in f2fs_get_block calls.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 57 +-
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index b7c8e3e0113aff..fc5207859912ce 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -3313,8 +3313,8 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
struct dnode_of_data dn;
struct page *ipage;
bool locked = false;
+   int flag = F2FS_GET_BLOCK_PRE_AIO;
int err = 0;
-   int flag;
 
/*
 * If a whole page is being written and we already preallocated all the
@@ -3324,13 +3324,12 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
return 0;
 
/* f2fs_lock_op avoids race between write CP and convert_inline_page */
-   if (f2fs_has_inline_data(inode) && pos + len > MAX_INLINE_DATA(inode))
-   flag = F2FS_GET_BLOCK_DEFAULT;
-   else
-   flag = F2FS_GET_BLOCK_PRE_AIO;
-
-   if (f2fs_has_inline_data(inode) ||
-   (pos & PAGE_MASK) >= i_size_read(inode)) {
+   if (f2fs_has_inline_data(inode)) {
+   if (pos + len > MAX_INLINE_DATA(inode))
+   flag = F2FS_GET_BLOCK_DEFAULT;
+   f2fs_map_lock(sbi, flag);
+   locked = true;
+   } else if ((pos & PAGE_MASK) >= i_size_read(inode)) {
f2fs_map_lock(sbi, flag);
locked = true;
}
@@ -3351,34 +3350,34 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
set_inode_flag(inode, FI_DATA_EXIST);
if (inode->i_nlink)
set_page_private_inline(ipage);
-   } else {
-   err = f2fs_convert_inline_page(, page);
-   if (err)
-   goto out;
-   if (dn.data_blkaddr == NULL_ADDR)
-   err = f2fs_get_block(, index);
+   goto out;
}
-   } else if (locked) {
-   err = f2fs_get_block(, index);
-   } else {
-   if (!f2fs_lookup_extent_cache_block(inode, index,
-   _blkaddr)) {
+   err = f2fs_convert_inline_page(, page);
+   if (err || dn.data_blkaddr != NULL_ADDR)
+   goto out;
+   }
+
+   if (!f2fs_lookup_extent_cache_block(inode, index, _blkaddr)) {
+   if (!locked) {
/* hole case */
err = f2fs_get_dnode_of_data(, index, LOOKUP_NODE);
-   if (err || dn.data_blkaddr == NULL_ADDR) {
-   f2fs_put_dnode();
-   f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
-   WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO);
-   locked = true;
-   goto restart;
-   }
+   if (!err && dn.data_blkaddr != NULL_ADDR)
+   goto out;
+   f2fs_put_dnode();
+   f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO);
+   WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO);
+   locked = true;
+   goto restart;
}
+   err = f2fs_reserve_block(, index);
}
 
-   /* convert_inline_page can make node_changed */
-   *blk_addr = dn.data_blkaddr;
-   *node_changed = dn.node_changed;
 out:
+   if (!err) {
+   /* convert_inline_page can make node_changed */
+   *blk_addr = dn.data_blkaddr;
+   *node_changed = dn.node_changed;
+   }
f2fs_put_dnode();
 unlock_out:
if (locked)
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 03/15] f2fs: rename F2FS_MAP_UNWRITTEN to F2FS_MAP_DELALLOC

2022-11-28 Thread Christoph Hellwig
NEW_ADDR blocks are purely in-memory preallocated blocks, and thus
equivalent to what the core FS code calls delayed allocations, and not
unwritten extents which do have on-disk blocks allocated from which
reads always return zeroes until they are converted to written status.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 8 
 fs/f2fs/f2fs.h | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 541d625d94be42..444865e0cb6397 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1638,9 +1638,9 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map,
bidx = f2fs_target_device_index(sbi, blkaddr);
 
if (map->m_len == 0) {
-   /* preallocated unwritten block should be mapped for fiemap. */
+   /* reserved delalloc block should be mapped for fiemap. */
if (blkaddr == NEW_ADDR)
-   map->m_flags |= F2FS_MAP_UNWRITTEN;
+   map->m_flags |= F2FS_MAP_DELALLOC;
map->m_flags |= F2FS_MAP_MAPPED;
 
map->m_pblk = blkaddr;
@@ -1962,7 +1962,7 @@ int f2fs_fiemap(struct inode *inode, struct 
fiemap_extent_info *fieinfo,
 
compr_appended = false;
/* In a case of compressed cluster, append this to the last extent */
-   if (compr_cluster && ((map.m_flags & F2FS_MAP_UNWRITTEN) ||
+   if (compr_cluster && ((map.m_flags & F2FS_MAP_DELALLOC) ||
!(map.m_flags & F2FS_MAP_FLAGS))) {
compr_appended = true;
goto skip_fill;
@@ -2008,7 +2008,7 @@ int f2fs_fiemap(struct inode *inode, struct 
fiemap_extent_info *fieinfo,
compr_cluster = false;
size += blks_to_bytes(inode, 1);
}
-   } else if (map.m_flags & F2FS_MAP_UNWRITTEN) {
+   } else if (map.m_flags & F2FS_MAP_DELALLOC) {
flags = FIEMAP_EXTENT_UNWRITTEN;
}
 
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index db2dc3fa73162b..709bfd1c7c409e 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -647,9 +647,9 @@ struct extent_tree {
  */
 #define F2FS_MAP_NEW   (1U << 0)
 #define F2FS_MAP_MAPPED(1U << 1)
-#define F2FS_MAP_UNWRITTEN (1U << 2)
+#define F2FS_MAP_DELALLOC  (1U << 2)
 #define F2FS_MAP_FLAGS (F2FS_MAP_NEW | F2FS_MAP_MAPPED |\
-   F2FS_MAP_UNWRITTEN)
+   F2FS_MAP_DELALLOC)
 
 struct f2fs_map_blocks {
struct block_device *m_bdev;/* for multi-device dio */
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 14/15] f2fs: factor out a f2fs_map_no_dnode

2022-11-28 Thread Christoph Hellwig
Factor out a helper to return a hole when no dnode was found.

Signed-off-by: Christoph Hellwig 
---
 fs/f2fs/data.c | 47 ---
 1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index f6124cedd121a2..3c802ce397de52 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1449,6 +1449,28 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, 
pgoff_t index)
return err;
 }
 
+static int f2fs_map_no_dnode(struct inode *inode,
+   struct f2fs_map_blocks *map, struct dnode_of_data *dn,
+   pgoff_t pgoff)
+{
+   struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+   /*
+* There is one exceptional case that read_node_page() may return
+* -ENOENT due to filesystem has been shutdown or cp_error, return
+* -EIO in that case.
+*/
+   if (map->m_may_create &&
+   (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) || f2fs_cp_error(sbi)))
+   return -EIO;
+
+   if (map->m_next_pgofs)
+   *map->m_next_pgofs = f2fs_get_next_page_offset(dn, pgoff);
+   if (map->m_next_extent)
+   *map->m_next_extent = f2fs_get_next_page_offset(dn, pgoff);
+   return 0;
+}
+
 static bool f2fs_map_blocks_cached(struct inode *inode,
struct f2fs_map_blocks *map, int flag)
 {
@@ -1530,29 +1552,8 @@ int f2fs_map_blocks(struct inode *inode, struct 
f2fs_map_blocks *map, int flag)
if (err) {
if (flag == F2FS_GET_BLOCK_BMAP)
map->m_pblk = 0;
-
-   if (err == -ENOENT) {
-   /*
-* There is one exceptional case that read_node_page()
-* may return -ENOENT due to filesystem has been
-* shutdown or cp_error, so force to convert error
-* number to EIO for such case.
-*/
-   if (map->m_may_create &&
-   (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) ||
-   f2fs_cp_error(sbi))) {
-   err = -EIO;
-   goto unlock_out;
-   }
-
-   err = 0;
-   if (map->m_next_pgofs)
-   *map->m_next_pgofs =
-   f2fs_get_next_page_offset(, pgofs);
-   if (map->m_next_extent)
-   *map->m_next_extent =
-   f2fs_get_next_page_offset(, pgofs);
-   }
+   if (err == -ENOENT)
+   err = f2fs_map_no_dnode(inode, map, , pgofs);
goto unlock_out;
}
 
-- 
2.30.2



___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 5/5] f2fs: implement data block seperation with block update frequency

2022-11-28 Thread qixiaoyu1
Signed-off-by: qixiaoyu1 
Signed-off-by: xiongping1 
---
 Documentation/ABI/testing/sysfs-fs-f2fs | 14 
 fs/f2fs/block_age.c | 29 +
 fs/f2fs/f2fs.h  |  4 
 fs/f2fs/segment.c   |  9 
 fs/f2fs/sysfs.c | 28 
 include/trace/events/f2fs.h |  2 +-
 6 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs 
b/Documentation/ABI/testing/sysfs-fs-f2fs
index 483639fb727b..34952666b2fe 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -634,3 +634,17 @@ Date:  July 2022
 Contact:   "Daeho Jeong" 
 Description:   Show the accumulated total revoked atomic write block count 
after boot.
If you write "0" here, you can initialize to "0".
+
+What:  /sys/fs/f2fs//hot_data_age_threshold
+Date:  November 2022
+Contact:   "Ping Xiong" 
+Description:   When DATA SEPARATION is on, it controls the age threshold to 
indicate
+   the data blocks as hot. By default it was initialized as 262144 
blocks
+   (equals to 1GB).
+
+What:  /sys/fs/f2fs//warm_data_age_threshold
+Date:  November 2022
+Contact:   "Ping Xiong" 
+Description:   When DATA SEPARATION is on, it controls the age threshold to 
indicate
+   the data blocks as warm. By default it was initialized as 
2621440 blocks
+   (equals to 10GB).
diff --git a/fs/f2fs/block_age.c b/fs/f2fs/block_age.c
index 488461b3f4bf..d0b578544df7 100644
--- a/fs/f2fs/block_age.c
+++ b/fs/f2fs/block_age.c
@@ -17,6 +17,13 @@
 #define LAST_AGE_WEIGHT30
 #define SAME_AGE_REGION1024
 
+/*
+ * Define data block with age less than 1GB as hot data
+ * define data block with age less than 10GB but more than 1GB as warm data
+ */
+#define DEF_HOT_DATA_AGE_THRESHOLD 262144
+#define DEF_WARM_DATA_AGE_THRESHOLD2621440
+
 static struct kmem_cache *age_extent_tree_slab;
 static struct kmem_cache *age_extent_node_slab;
 
@@ -29,6 +36,9 @@ static inline void f2fs_inc_data_block_alloc(struct 
f2fs_sb_info *sbi)
 static void f2fs_init_block_age_info(struct f2fs_sb_info *sbi)
 {
atomic64_set(>total_data_alloc, 0);
+
+   sbi->hot_data_age_threshold = DEF_HOT_DATA_AGE_THRESHOLD;
+   sbi->warm_data_age_threshold = DEF_WARM_DATA_AGE_THRESHOLD;
 }
 
 static inline bool f2fs_may_age_extent_tree(struct inode *inode)
@@ -697,6 +707,25 @@ unsigned long f2fs_count_age_extent_cache(struct 
f2fs_sb_info *sbi)
atomic_read(>total_age_ext_node);
 }
 
+int f2fs_get_data_segment_type(struct inode *inode, pgoff_t pgofs)
+{
+   struct age_extent_info ei;
+   struct f2fs_sb_info *sbi =  F2FS_I_SB(inode);
+
+   if (f2fs_lookup_age_extent_cache(inode, pgofs, )) {
+   if (ei.age != 0) {
+   if (ei.age <= sbi->hot_data_age_threshold)
+   return CURSEG_HOT_DATA;
+   else if (ei.age <= sbi->warm_data_age_threshold)
+   return CURSEG_WARM_DATA;
+   else
+   return CURSEG_COLD_DATA;
+   }
+   }
+
+   return NO_CHECK_TYPE;
+}
+
 void f2fs_destroy_age_extent_cache(void)
 {
kmem_cache_destroy(age_extent_node_slab);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 23516498b6d0..50f6f21b23bf 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1854,6 +1854,9 @@ struct f2fs_sb_info {
 
 #ifdef CONFIG_F2FS_FS_DATA_SEPARATION
atomic64_t total_data_alloc;
+   /* The threshold used for hot and warm data seperation*/
+   unsigned int hot_data_age_threshold;
+   unsigned int warm_data_age_threshold;
 #endif
 
/* Reference to checksum algorithm driver via cryptoapi */
@@ -4241,6 +4244,7 @@ void f2fs_update_age_extent_cache(struct inode *inode, 
pgoff_t fofs,
 void f2fs_update_data_block_age(struct dnode_of_data *dn);
 void f2fs_truncate_age_extent_cache(struct inode *inode, pgoff_t fofs,
unsigned int len);
+int f2fs_get_data_segment_type(struct inode *inode, pgoff_t pgofs);
 int __init f2fs_create_age_extent_cache(void);
 void f2fs_destroy_age_extent_cache(void);
 #endif
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index d4c338f332fa..2fa5b22119ac 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -3163,6 +3163,9 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
if (fio->type == DATA) {
struct inode *inode = fio->page->mapping->host;
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   int type;
+#endif
if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
return CURSEG_COLD_DATA_PINNED;
 
@@ -3176,6 +3179,12 @@ static int 

[f2fs-dev] [PATCH 2/5] f2fs: implement cache to manager block update frequency per inode

2022-11-28 Thread qixiaoyu1
From: xiongping1 

Signed-off-by: xiongping1 
Signed-off-by: qixiaoyu1 
---
 fs/f2fs/block_age.c | 590 +++-
 fs/f2fs/debug.c |  13 +
 fs/f2fs/f2fs.h  |  64 +++-
 fs/f2fs/file.c  |  10 +
 fs/f2fs/inode.c |   8 +
 fs/f2fs/namei.c |   4 +
 fs/f2fs/node.c  |   7 +-
 fs/f2fs/node.h  |   3 +
 fs/f2fs/segment.c   |   6 +
 fs/f2fs/shrinker.c  |   3 +
 fs/f2fs/super.c |  22 +-
 include/trace/events/f2fs.h | 239 +++
 12 files changed, 965 insertions(+), 4 deletions(-)

diff --git a/fs/f2fs/block_age.c b/fs/f2fs/block_age.c
index 1e8711a03959..c8e8fbe51d8e 100644
--- a/fs/f2fs/block_age.c
+++ b/fs/f2fs/block_age.c
@@ -10,19 +10,607 @@
 
 #include "f2fs.h"
 #include "segment.h"
+#include 
+
+static struct kmem_cache *age_extent_tree_slab;
+static struct kmem_cache *age_extent_node_slab;
+
 
 static inline void f2fs_inc_data_block_alloc(struct f2fs_sb_info *sbi)
 {
atomic64_inc(>total_data_alloc);
 }
 
-void f2fs_init_block_age_info(struct f2fs_sb_info *sbi)
+static void f2fs_init_block_age_info(struct f2fs_sb_info *sbi)
 {
atomic64_set(>total_data_alloc, 0);
 }
 
+static inline bool f2fs_may_age_extent_tree(struct inode *inode)
+{
+   struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+   /*
+* for recovered files during mount do not create extents
+* if shrinker is not registered.
+*/
+   if (list_empty(>s_list))
+   return false;
+
+   /* don't cache block age info for cold file */
+   if (is_inode_flag_set(inode, FI_COMPRESSED_FILE) ||
+   file_is_cold(inode))
+   return false;
+
+   return S_ISREG(inode->i_mode)
+   || S_ISDIR(inode->i_mode);
+}
+
+static void f2fs_init_age_cache_info(struct f2fs_sb_info *sbi)
+{
+   INIT_RADIX_TREE(>age_extent_tree_root, GFP_NOIO);
+   mutex_init(>age_extent_tree_lock);
+   INIT_LIST_HEAD(>age_extent_list);
+   spin_lock_init(>age_extent_lock);
+   atomic_set(>total_age_ext_tree, 0);
+   INIT_LIST_HEAD(>zombie_age_list);
+   atomic_set(>total_zombie_age_tree, 0);
+   atomic_set(>total_age_ext_node, 0);
+}
+
+#ifdef CONFIG_QUOTA
+static void f2fs_init_quota_age_extent_cache(struct f2fs_sb_info *sbi)
+{
+   struct quota_info *dqopt = sb_dqopt(sbi->sb);
+   struct inode *qinode;
+   int cnt;
+
+   for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+   if (!sb_has_quota_active(sbi->sb, cnt))
+   continue;
+
+   qinode = dqopt->files[cnt];
+   f2fs_init_age_extent_tree(qinode);
+   }
+}
+#endif
+
+static void __detach_age_extent_node(struct f2fs_sb_info *sbi,
+   struct age_extent_tree *et, struct 
age_extent_node *en)
+{
+   rb_erase_cached(>rb_node, >root);
+   atomic_dec(>node_cnt);
+   atomic_dec(>total_age_ext_node);
+
+   if (et->cached_en == en)
+   et->cached_en = NULL;
+
+   trace_f2fs_detach_age_extent_node(sbi, et, >ei);
+   kmem_cache_free(age_extent_node_slab, en);
+}
+
+/*
+ * Flow to release an age_extent_node:
+ * 1. list_del_init
+ * 2. __detach_age_extent_node
+ * 3. kmem_cache_free.
+ */
+static void __release_age_extent_node(struct f2fs_sb_info *sbi,
+   struct age_extent_tree *et, struct age_extent_node *en)
+{
+   spin_lock(>age_extent_lock);
+   f2fs_bug_on(sbi, list_empty(>list));
+   list_del_init(>list);
+   spin_unlock(>age_extent_lock);
+
+   __detach_age_extent_node(sbi, et, en);
+}
+
+static unsigned int __free_age_extent_tree(struct f2fs_sb_info *sbi,
+   struct age_extent_tree *et)
+{
+   struct rb_node *node, *next;
+   struct age_extent_node *en;
+   unsigned int count = atomic_read(>node_cnt);
+
+   node = rb_first_cached(>root);
+   while (node) {
+   next = rb_next(node);
+   en = rb_entry(node, struct age_extent_node, rb_node);
+   __release_age_extent_node(sbi, et, en);
+   node = next;
+   }
+
+   return count - atomic_read(>node_cnt);
+}
+
+unsigned int f2fs_drop_age_extent_node(struct inode *inode)
+{
+   struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+   struct age_extent_tree *et = F2FS_I(inode)->age_extent_tree;
+   unsigned int node_cnt = 0;
+
+   if (!et || !atomic_read(>node_cnt))
+   return 0;
+
+   write_lock(>lock);
+   node_cnt = __free_age_extent_tree(sbi, et);
+   write_unlock(>lock);
+
+   return node_cnt;
+}
+
+unsigned int f2fs_shrink_age_extent_tree(struct f2fs_sb_info *sbi, int 
nr_shrink)
+{
+   struct age_extent_tree *et, *next;
+   struct age_extent_node *en;
+   unsigned int node_cnt = 0, tree_cnt = 0;
+   int remained;
+
+   if (!atomic_read(>total_zombie_age_tree))
+

[f2fs-dev] [PATCH 4/5] f2fs: update block age info during out of place update

2022-11-28 Thread qixiaoyu1
Signed-off-by: qixiaoyu1 
Signed-off-by: xiongping1 
---
 fs/f2fs/block_age.c | 89 -
 fs/f2fs/f2fs.h  |  1 +
 fs/f2fs/segment.c   |  4 ++
 3 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/block_age.c b/fs/f2fs/block_age.c
index bc009616adfb..488461b3f4bf 100644
--- a/fs/f2fs/block_age.c
+++ b/fs/f2fs/block_age.c
@@ -9,9 +9,14 @@
 #include 
 
 #include "f2fs.h"
+#include "node.h"
 #include "segment.h"
 #include 
 
+
+#define LAST_AGE_WEIGHT30
+#define SAME_AGE_REGION1024
+
 static struct kmem_cache *age_extent_tree_slab;
 static struct kmem_cache *age_extent_node_slab;
 
@@ -264,8 +269,8 @@ static inline bool __is_age_extent_mergeable(struct 
age_extent_info *back,
struct age_extent_info *front)
 {
return (back->fofs + back->len == front->fofs &&
-   back->age == front->age &&
-   back->last_blocks == front->last_blocks);
+   abs(back->age - front->age) <= SAME_AGE_REGION &&
+   abs(back->last_blocks - front->last_blocks) <= 
SAME_AGE_REGION);
 }
 
 static inline bool __is_back_age_ext_mergeable(struct age_extent_info *cur,
@@ -497,6 +502,86 @@ void f2fs_truncate_age_extent_cache(struct inode *inode, 
pgoff_t fofs, unsigned
f2fs_update_age_extent_cache(inode, fofs, len, 0, 0);
 }
 
+unsigned long long f2fs_get_cur_dblock_allocated(struct f2fs_sb_info *sbi)
+{
+   return atomic64_read(>total_data_alloc);
+}
+
+static unsigned long long calculate_block_age(unsigned long long new,
+   unsigned long long old)
+{
+   if (new >= old)
+   return new - (new - old) * LAST_AGE_WEIGHT / 100;
+   else
+   return new + (old - new) * LAST_AGE_WEIGHT / 100;
+}
+
+void f2fs_update_data_block_age(struct dnode_of_data *dn)
+{
+   struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
+   unsigned long long cur_total_blk_alloced = 
f2fs_get_cur_dblock_allocated(sbi);
+   pgoff_t fofs;
+   unsigned long long cur_age, new_age;
+   struct age_extent_info ei;
+   bool find;
+   loff_t f_size = i_size_read(dn->inode);
+
+   if (!f2fs_may_age_extent_tree(dn->inode))
+   return;
+
+   fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
+   dn->ofs_in_node;
+
+
+   /* When I/O is not aligned to a PAGE_SIZE, update will happen to the 
last
+* file block even in seq write. So don't record age for newly last file
+* block here.
+*/
+   if ((f_size >> PAGE_SHIFT) == fofs && f_size & (PAGE_SIZE - 1) &&
+   dn->data_blkaddr == NEW_ADDR)
+   return;
+
+   find = f2fs_lookup_age_extent_cache(dn->inode, fofs, );
+   if (find) {
+   if (cur_total_blk_alloced >= ei.last_blocks)
+   cur_age = cur_total_blk_alloced - ei.last_blocks;
+   else
+   /* total_data_alloc overflow */
+   cur_age = ULLONG_MAX - ei.last_blocks + 
cur_total_blk_alloced;
+
+   if (ei.age)
+   new_age = calculate_block_age(cur_age, ei.age);
+   else
+   new_age = cur_age;
+
+   WARN(new_age > cur_total_blk_alloced,
+   "inode block(%lu: %lu) age changed from: %llu 
to %llu",
+   dn->inode->i_ino, fofs, ei.age, new_age);
+   } else {
+   f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR);
+
+   if (dn->data_blkaddr == NEW_ADDR)
+   /* the data block was allocated for the first time */
+   new_age = 0;
+   else {
+   if (__is_valid_data_blkaddr(dn->data_blkaddr) &&
+   !f2fs_is_valid_blkaddr(sbi, 
dn->data_blkaddr,
+   
DATA_GENERIC_ENHANCE)) {
+   f2fs_bug_on(sbi, 1);
+   return;
+   }
+
+   /*
+* init block age with zero, this can happen when the 
block age extent
+* was reclaimed due to memory constraint or system 
reboot
+*/
+   new_age = 0;
+   }
+   }
+
+   f2fs_update_age_extent_cache(dn->inode, fofs, 1, new_age, 
cur_total_blk_alloced);
+}
+
 void f2fs_destroy_age_extent_tree(struct inode *inode)
 {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 428cc560b721..23516498b6d0 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -4238,6 +4238,7 @@ bool f2fs_lookup_age_extent_cache(struct inode 

[f2fs-dev] [PATCH 3/5] f2fs: add age_extent_cache mount option

2022-11-28 Thread qixiaoyu1
From: xiongping1 

enable data block seperation feature only when
age_extent_cache mount option is on

Signed-off-by: xiongping1 
Signed-off-by: qixiaoyu1 
---
 Documentation/filesystems/f2fs.rst |  4 
 fs/f2fs/block_age.c|  3 +++
 fs/f2fs/f2fs.h |  1 +
 fs/f2fs/super.c| 27 +++
 4 files changed, 35 insertions(+)

diff --git a/Documentation/filesystems/f2fs.rst 
b/Documentation/filesystems/f2fs.rst
index 17df9a02ccff..f4e8943f649d 100644
--- a/Documentation/filesystems/f2fs.rst
+++ b/Documentation/filesystems/f2fs.rst
@@ -340,6 +340,10 @@ memory=%s   Control memory mode. This supports 
"normal" and "low" modes.
 Because of the nature of low memory devices, in this 
mode, f2fs
 will try to save memory sometimes by sacrificing 
performance.
 "normal" mode is the default mode and same as before.
+age_extent_cacheEnable an age extent cache based on rb-tree, it can 
record
+data block update frequency of the extent per inode, in
+order to indicate better temperature info for data 
block
+allocation.
  

 
 Debugfs Entries
diff --git a/fs/f2fs/block_age.c b/fs/f2fs/block_age.c
index c8e8fbe51d8e..bc009616adfb 100644
--- a/fs/f2fs/block_age.c
+++ b/fs/f2fs/block_age.c
@@ -37,6 +37,9 @@ static inline bool f2fs_may_age_extent_tree(struct inode 
*inode)
if (list_empty(>s_list))
return false;
 
+   if (!test_opt(sbi, AGE_EXTENT_CACHE))
+   return false;
+
/* don't cache block age info for cold file */
if (is_inode_flag_set(inode, FI_COMPRESSED_FILE) ||
file_is_cold(inode))
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 5cc516228407..428cc560b721 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -106,6 +106,7 @@ extern const char *f2fs_fault_name[FAULT_MAX];
 #define F2FS_MOUNT_MERGE_CHECKPOINT0x1000
 #defineF2FS_MOUNT_GC_MERGE 0x2000
 #define F2FS_MOUNT_COMPRESS_CACHE  0x4000
+#define F2FS_MOUNT_AGE_EXTENT_CACHE0x8000
 
 #define F2FS_OPTION(sbi)   ((sbi)->mount_opt)
 #define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option)
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 91d3c9d0425d..dcb5905c7264 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -161,6 +161,9 @@ enum {
Opt_nogc_merge,
Opt_discard_unit,
Opt_memory_mode,
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   Opt_age_extent_cache,
+#endif
Opt_err,
 };
 
@@ -238,6 +241,9 @@ static match_table_t f2fs_tokens = {
{Opt_nogc_merge, "nogc_merge"},
{Opt_discard_unit, "discard_unit=%s"},
{Opt_memory_mode, "memory=%s"},
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   {Opt_age_extent_cache, "age_extent_cache"},
+#endif
{Opt_err, NULL},
 };
 
@@ -1253,6 +1259,11 @@ static int parse_options(struct super_block *sb, char 
*options, bool is_remount)
}
kfree(name);
break;
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   case Opt_age_extent_cache:
+   set_opt(sbi, AGE_EXTENT_CACHE);
+   break;
+#endif
default:
f2fs_err(sbi, "Unrecognized mount option \"%s\" or 
missing value",
 p);
@@ -2035,6 +2046,10 @@ static int f2fs_show_options(struct seq_file *seq, 
struct dentry *root)
else if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW)
seq_printf(seq, ",memory=%s", "low");
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   if (test_opt(sbi, AGE_EXTENT_CACHE))
+   seq_puts(seq, ",age_extent_cache");
+#endif
return 0;
 }
 
@@ -2206,6 +2221,9 @@ static int f2fs_remount(struct super_block *sb, int 
*flags, char *data)
bool need_restart_discard = false, need_stop_discard = false;
bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
bool enable_checkpoint = !test_opt(sbi, DISABLE_CHECKPOINT);
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   bool no_age_extent_cache = !test_opt(sbi, AGE_EXTENT_CACHE);
+#endif
bool no_io_align = !F2FS_IO_ALIGNED(sbi);
bool no_atgc = !test_opt(sbi, ATGC);
bool no_discard = !test_opt(sbi, DISCARD);
@@ -2300,6 +2318,15 @@ static int f2fs_remount(struct super_block *sb, int 
*flags, char *data)
goto restore_opts;
}
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   /* disallow enable/disable age extent_cache dynamically */
+   if (no_age_extent_cache == !!test_opt(sbi, AGE_EXTENT_CACHE)) {
+   err = -EINVAL;
+   f2fs_warn(sbi, "switch age_extent_cache option is not allowed");
+  

[f2fs-dev] [PATCH 0/5] Support enhanced hot/cold data separation for f2fs

2022-11-28 Thread qixiaoyu1
This patch series introduce a runtime hot/cold data separation
method for f2fs, in order to improve the accuracy for data
temperature classification, reduce the garbage collection overhead
after long-term data updates.

Enhanced hot/cold data separation can record data block update
frequency as "age" of the extent per inode, and take use of the age
info to indicate better temperature type for data block allocation:
 - It record total data blocks allocated since mount;
 - When file extent has been updated, it calculate the count of data
blocks allocated since last update as the age of the extent;
 - Before the data block allocated, it search for the age info and
choose the suitable segment for allocation.

Patch 1 records total data blocks allocated since mount.

Patch 2 implements cache to manager block update frequency per inode.

Patch 3 adds age_extent_cache mount option to enable this feature only
when age_extent_cache mount option is on.

Patch 4 updates block age info during out of place update.

Patch 5 implements data block seperation with block update frequency.

Test and result:
 - Prepare: create about 3 files
  * 3% for cold files (with cold file extension like .apk, from 3M to 10M)
  * 50% for warm files (with random file extension like .FcDxq, from 1K
to 4M)
  * 47% for hot files (with hot file extension like .db, from 1K to 256K)
 - create(5%)/random update(90%)/delete(5%) the files
  * total write amount is about 70G
  * fsync will be called for .db files, and buffered write will be used
for other files

The storage of test device is large enough(128G) so that it will not
switch to SSR mode during the test.

Benefit: dirty segment count increment reduce about 14%
 - before: Dirty +21110
 - after:  Dirty +18286

qixiaoyu1 (2):
  f2fs: update block age info during out of place update
  f2fs: implement data block seperation with block update frequency

xiongping1 (3):
  f2fs: record total data blocks allocated since mount
  f2fs: implement cache to manager block update frequency per inode
  f2fs: add age_extent_cache mount option

 Documentation/ABI/testing/sysfs-fs-f2fs |  14 +
 Documentation/filesystems/f2fs.rst  |   4 +
 fs/f2fs/Kconfig |   7 +
 fs/f2fs/Makefile|   1 +
 fs/f2fs/block_age.c | 733 
 fs/f2fs/debug.c |  20 +
 fs/f2fs/f2fs.h  |  83 +++
 fs/f2fs/file.c  |  10 +
 fs/f2fs/inode.c |   8 +
 fs/f2fs/namei.c |   4 +
 fs/f2fs/node.c  |   7 +-
 fs/f2fs/node.h  |   3 +
 fs/f2fs/segment.c   |  23 +
 fs/f2fs/shrinker.c  |   3 +
 fs/f2fs/super.c |  51 ++
 fs/f2fs/sysfs.c |  28 +
 include/trace/events/f2fs.h | 239 
 17 files changed, 1237 insertions(+), 1 deletion(-)
 create mode 100644 fs/f2fs/block_age.c

-- 
2.36.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/5] f2fs: record total data blocks allocated since mount

2022-11-28 Thread qixiaoyu1
From: xiongping1 

Signed-off-by: xiongping1 
Signed-off-by: qixiaoyu1 
---
 fs/f2fs/Kconfig |  7 +++
 fs/f2fs/Makefile|  1 +
 fs/f2fs/block_age.c | 28 
 fs/f2fs/debug.c |  7 +++
 fs/f2fs/f2fs.h  | 15 +++
 fs/f2fs/segment.c   |  4 
 fs/f2fs/super.c |  4 
 7 files changed, 66 insertions(+)
 create mode 100644 fs/f2fs/block_age.c

diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig
index 03ef087537c7..84915f9c6bc8 100644
--- a/fs/f2fs/Kconfig
+++ b/fs/f2fs/Kconfig
@@ -150,3 +150,10 @@ config F2FS_UNFAIR_RWSEM
help
  Use unfair rw_semaphore, if system configured IO priority by block
  cgroup.
+
+config F2FS_FS_DATA_SEPARATION
+   bool "F2FS hot/cold data separation feature"
+   depends on F2FS_FS
+   help
+ Enable data blocks separation according to block update frequency.
+
diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile
index 8a7322d229e4..70d8f0e23b46 100644
--- a/fs/f2fs/Makefile
+++ b/fs/f2fs/Makefile
@@ -10,3 +10,4 @@ f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o
 f2fs-$(CONFIG_FS_VERITY) += verity.o
 f2fs-$(CONFIG_F2FS_FS_COMPRESSION) += compress.o
 f2fs-$(CONFIG_F2FS_IOSTAT) += iostat.o
+f2fs-$(CONFIG_F2FS_FS_DATA_SEPARATION) += block_age.o
diff --git a/fs/f2fs/block_age.c b/fs/f2fs/block_age.c
new file mode 100644
index ..1e8711a03959
--- /dev/null
+++ b/fs/f2fs/block_age.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fs/f2fs/block_age.c
+ *
+ * Copyright (c) 2022 xiaomi Co., Ltd.
+ * http://www.xiaomi.com/
+ */
+#include 
+#include 
+
+#include "f2fs.h"
+#include "segment.h"
+
+static inline void f2fs_inc_data_block_alloc(struct f2fs_sb_info *sbi)
+{
+   atomic64_inc(>total_data_alloc);
+}
+
+void f2fs_init_block_age_info(struct f2fs_sb_info *sbi)
+{
+   atomic64_set(>total_data_alloc, 0);
+}
+
+void f2fs_inc_block_alloc_count(struct f2fs_sb_info *sbi, int type)
+{
+   if (IS_DATASEG(type))
+   f2fs_inc_data_block_alloc(sbi);
+}
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index a216dcdf6941..d24abdac20bb 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -81,6 +81,9 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->ext_tree = atomic_read(>total_ext_tree);
si->zombie_tree = atomic_read(>total_zombie_tree);
si->ext_node = atomic_read(>total_ext_node);
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   si->total_data_blocks_alloc = atomic64_read(>total_data_alloc);
+#endif
si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
@@ -373,6 +376,10 @@ static int stat_show(struct seq_file *s, void *v)
seq_printf(s, "Utilization: %u%% (%u valid blocks)\n",
si->utilization, si->valid_count);
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   seq_printf(s, "  - Data Block Allocated: %llu\n",
+  si->total_data_blocks_alloc);
+#endif
seq_printf(s, "  - Node: %u (Inode: %u, ",
   si->valid_node_count, si->valid_inode_count);
seq_printf(s, "Other: %u)\n  - Data: %u\n",
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e6355a5683b7..686f09846de4 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1807,6 +1807,10 @@ struct f2fs_sb_info {
u64 sectors_written_start;
u64 kbytes_written;
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   atomic64_t total_data_alloc;
+#endif
+
/* Reference to checksum algorithm driver via cryptoapi */
struct crypto_shash *s_chksum_driver;
 
@@ -3858,6 +3862,9 @@ struct f2fs_stat_info {
int main_area_segs, main_area_sections, main_area_zones;
unsigned long long hit_largest, hit_cached, hit_rbtree;
unsigned long long hit_total, total_ext;
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+   unsigned long long total_data_blocks_alloc;
+#endif
int ext_tree, zombie_tree, ext_node;
int ndirty_node, ndirty_dent, ndirty_meta, ndirty_imeta;
int ndirty_data, ndirty_qdata;
@@ -4166,6 +4173,14 @@ void f2fs_init_extent_cache_info(struct f2fs_sb_info 
*sbi);
 int __init f2fs_create_extent_cache(void);
 void f2fs_destroy_extent_cache(void);
 
+#ifdef CONFIG_F2FS_FS_DATA_SEPARATION
+/*
+ * block_age.c
+ */
+void f2fs_init_block_age_info(struct f2fs_sb_info *sbi);
+void f2fs_inc_block_alloc_count(struct f2fs_sb_info *sbi, int type);
+#endif
+
 /*
  * sysfs.c
  */
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index acf3d3fa4363..0cf022fd3560 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -3280,6 +3280,10 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, 
struct page *page,
locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr));
 
+#ifdef