Merge tag 'net-5.16-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / fs / f2fs / segment.c
index a135d22..df9ed75 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/timer.h>
 #include <linux/freezer.h>
 #include <linux/sched/signal.h>
+#include <linux/random.h>
 
 #include "f2fs.h"
 #include "segment.h"
@@ -529,6 +530,25 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
        }
 }
 
+static inline bool excess_dirty_threshold(struct f2fs_sb_info *sbi)
+{
+       int factor = rwsem_is_locked(&sbi->cp_rwsem) ? 3 : 2;
+       unsigned int dents = get_pages(sbi, F2FS_DIRTY_DENTS);
+       unsigned int qdata = get_pages(sbi, F2FS_DIRTY_QDATA);
+       unsigned int nodes = get_pages(sbi, F2FS_DIRTY_NODES);
+       unsigned int meta = get_pages(sbi, F2FS_DIRTY_META);
+       unsigned int imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
+       unsigned int threshold = sbi->blocks_per_seg * factor *
+                                       DEFAULT_DIRTY_THRESHOLD;
+       unsigned int global_threshold = threshold * 3 / 2;
+
+       if (dents >= threshold || qdata >= threshold ||
+               nodes >= threshold || meta >= threshold ||
+               imeta >= threshold)
+               return true;
+       return dents + qdata + nodes + meta + imeta >  global_threshold;
+}
+
 void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
 {
        if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
@@ -547,8 +567,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
        else
                f2fs_build_free_nids(sbi, false, false);
 
-       if (excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) ||
-               excess_prefree_segs(sbi))
+       if (excess_dirty_nats(sbi) || excess_dirty_threshold(sbi) ||
+               excess_prefree_segs(sbi) || !f2fs_space_for_roll_forward(sbi))
                goto do_sync;
 
        /* there is background inflight IO or foreground operation recently */
@@ -561,7 +581,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
                goto do_sync;
 
        /* checkpoint is the only way to shrink partial cached entries */
-       if (f2fs_available_free_memory(sbi, NAT_ENTRIES) ||
+       if (f2fs_available_free_memory(sbi, NAT_ENTRIES) &&
                f2fs_available_free_memory(sbi, INO_ENTRIES))
                return;
 
@@ -2630,6 +2650,8 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
        unsigned short seg_type = curseg->seg_type;
 
        sanity_check_seg_type(sbi, seg_type);
+       if (f2fs_need_rand_seg(sbi))
+               return prandom_u32() % (MAIN_SECS(sbi) * sbi->segs_per_sec);
 
        /* if segs_per_sec is large than 1, we need to keep original policy. */
        if (__is_large_section(sbi))
@@ -2681,6 +2703,9 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
        curseg->next_segno = segno;
        reset_curseg(sbi, type, 1);
        curseg->alloc_type = LFS;
+       if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
+               curseg->fragment_remained_chunk =
+                               prandom_u32() % sbi->max_fragment_chunk + 1;
 }
 
 static int __next_free_blkoff(struct f2fs_sb_info *sbi,
@@ -2707,12 +2732,22 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi,
 static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
                                struct curseg_info *seg)
 {
-       if (seg->alloc_type == SSR)
+       if (seg->alloc_type == SSR) {
                seg->next_blkoff =
                        __next_free_blkoff(sbi, seg->segno,
                                                seg->next_blkoff + 1);
-       else
+       } else {
                seg->next_blkoff++;
+               if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) {
+                       /* To allocate block chunks in different sizes, use random number */
+                       if (--seg->fragment_remained_chunk <= 0) {
+                               seg->fragment_remained_chunk =
+                                  prandom_u32() % sbi->max_fragment_chunk + 1;
+                               seg->next_blkoff +=
+                                  prandom_u32() % sbi->max_fragment_hole + 1;
+                       }
+               }
+       }
 }
 
 bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
@@ -3485,24 +3520,30 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
        up_read(&SM_I(sbi)->curseg_lock);
 }
 
-static void update_device_state(struct f2fs_io_info *fio)
+void f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino,
+                                       block_t blkaddr, unsigned int blkcnt)
 {
-       struct f2fs_sb_info *sbi = fio->sbi;
-       unsigned int devidx;
-
        if (!f2fs_is_multi_device(sbi))
                return;
 
-       devidx = f2fs_target_device_index(sbi, fio->new_blkaddr);
+       while (1) {
+               unsigned int devidx = f2fs_target_device_index(sbi, blkaddr);
+               unsigned int blks = FDEV(devidx).end_blk - blkaddr + 1;
 
-       /* update device state for fsync */
-       f2fs_set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO);
+               /* update device state for fsync */
+               f2fs_set_dirty_device(sbi, ino, devidx, FLUSH_INO);
 
-       /* update device state for checkpoint */
-       if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
-               spin_lock(&sbi->dev_lock);
-               f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
-               spin_unlock(&sbi->dev_lock);
+               /* update device state for checkpoint */
+               if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
+                       spin_lock(&sbi->dev_lock);
+                       f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
+                       spin_unlock(&sbi->dev_lock);
+               }
+
+               if (blkcnt <= blks)
+                       break;
+               blkcnt -= blks;
+               blkaddr += blks;
        }
 }
 
@@ -3529,7 +3570,7 @@ reallocate:
                goto reallocate;
        }
 
-       update_device_state(fio);
+       f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1);
 
        if (keep_order)
                up_read(&fio->sbi->io_order_lock);
@@ -3611,6 +3652,9 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
                goto drop_bio;
        }
 
+       invalidate_mapping_pages(META_MAPPING(sbi),
+                               fio->new_blkaddr, fio->new_blkaddr);
+
        stat_inc_inplace_blocks(fio->sbi);
 
        if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE)))
@@ -3618,7 +3662,8 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
        else
                err = f2fs_submit_page_bio(fio);
        if (!err) {
-               update_device_state(fio);
+               f2fs_update_device_state(fio->sbi, fio->ino,
+                                               fio->new_blkaddr, 1);
                f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
        }