It makes the discard process run faster on a more powerful CPU, or not.
And if bind it to a specific cpu, it is possible to have more cache
locality.

Signed-off-by: Yangtao Li <frank...@vivo.com>
---
v2:
-fix kernel test robot warn
 Documentation/filesystems/f2fs.rst |  2 ++
 fs/f2fs/f2fs.h                     |  1 +
 fs/f2fs/segment.c                  |  8 ++++++-
 fs/f2fs/super.c                    | 36 ++++++++++++++++++++++++++++++
 kernel/kthread.c                   |  1 +
 5 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/Documentation/filesystems/f2fs.rst 
b/Documentation/filesystems/f2fs.rst
index 2055e72871fe..dc005f3b784a 100644
--- a/Documentation/filesystems/f2fs.rst
+++ b/Documentation/filesystems/f2fs.rst
@@ -351,6 +351,8 @@ age_extent_cache     Enable an age extent cache based on 
rb-tree. It records
                         data block update frequency of the extent per inode, in
                         order to provide better temperature hints for data 
block
                         allocation.
+discard_cpuset=%u               Set the cpumask of dicard thread, it makes the 
discard
+                        process run faster on a more powerful CPU, or not.
 ======================== 
============================================================
 
 Debugfs Entries
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index b0ab2062038a..62ce02a87d33 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -183,6 +183,7 @@ struct f2fs_mount_info {
        int compress_mode;                      /* compression mode */
        unsigned char extensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* 
extensions */
        unsigned char noextensions[COMPRESS_EXT_NUM][F2FS_EXTENSION_LEN]; /* 
extensions */
+       struct cpumask discard_cpumask; /* discard thread cpumask */
 };
 
 #define F2FS_FEATURE_ENCRYPT           0x0001
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 227e25836173..2648c564833e 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2054,11 +2054,17 @@ int f2fs_start_discard_thread(struct f2fs_sb_info *sbi)
        if (!f2fs_realtime_discard_enable(sbi))
                return 0;
 
-       dcc->f2fs_issue_discard = kthread_run(issue_discard_thread, sbi,
+       dcc->f2fs_issue_discard = kthread_create(issue_discard_thread, sbi,
                                "f2fs_discard-%u:%u", MAJOR(dev), MINOR(dev));
        if (IS_ERR(dcc->f2fs_issue_discard)) {
                err = PTR_ERR(dcc->f2fs_issue_discard);
                dcc->f2fs_issue_discard = NULL;
+       } else {
+               if (!cpumask_empty(&F2FS_OPTION(sbi).discard_cpumask)) {
+                       kthread_bind_mask(dcc->f2fs_issue_discard,
+                                       &F2FS_OPTION(sbi).discard_cpumask);
+               }
+               wake_up_process(dcc->f2fs_issue_discard);
        }
 
        return err;
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index fbaaabbcd6de..8ecbe3595f34 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -164,6 +164,7 @@ enum {
        Opt_discard_unit,
        Opt_memory_mode,
        Opt_age_extent_cache,
+       Opt_discard_cpuset,
        Opt_err,
 };
 
@@ -243,6 +244,7 @@ static match_table_t f2fs_tokens = {
        {Opt_discard_unit, "discard_unit=%s"},
        {Opt_memory_mode, "memory=%s"},
        {Opt_age_extent_cache, "age_extent_cache"},
+       {Opt_discard_cpuset, "discard_cpuset=%u"},
        {Opt_err, NULL},
 };
 
@@ -1256,6 +1258,22 @@ static int parse_options(struct super_block *sb, char 
*options, bool is_remount)
                case Opt_age_extent_cache:
                        set_opt(sbi, AGE_EXTENT_CACHE);
                        break;
+               case Opt_discard_cpuset:
+                       if (!f2fs_hw_support_discard(sbi)) {
+                               f2fs_warn(sbi, "device does not support 
discard");
+                               break;
+                       }
+
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+
+                       if (!cpu_possible(arg)) {
+                               f2fs_err(sbi, "invalid cpu%d for 
discard_cpuset", arg);
+                               return -EINVAL;
+                       }
+
+                       cpumask_set_cpu(arg, &F2FS_OPTION(sbi).discard_cpumask);
+                       break;
                default:
                        f2fs_err(sbi, "Unrecognized mount option \"%s\" or 
missing value",
                                 p);
@@ -1358,6 +1376,14 @@ static int parse_options(struct super_block *sb, char 
*options, bool is_remount)
                f2fs_err(sbi, "Allow to mount readonly mode only");
                return -EROFS;
        }
+
+       if (!cpumask_empty(&F2FS_OPTION(sbi).discard_cpumask) &&
+                       !cpumask_intersects(cpu_online_mask,
+                               &F2FS_OPTION(sbi).discard_cpumask)) {
+               f2fs_err(sbi, "Must include one online CPU for discard_cpuset");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -1884,6 +1910,7 @@ static inline void f2fs_show_compress_options(struct 
seq_file *seq,
 static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
+       unsigned int cpu;
 
        if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC)
                seq_printf(seq, ",background_gc=%s", "sync");
@@ -1909,6 +1936,8 @@ static int f2fs_show_options(struct seq_file *seq, struct 
dentry *root)
                        seq_printf(seq, ",discard_unit=%s", "segment");
                else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
                        seq_printf(seq, ",discard_unit=%s", "section");
+               for_each_cpu(cpu, &F2FS_OPTION(sbi).discard_cpumask)
+                       seq_printf(seq, ",discard_cpuset=%u", cpu);
        } else {
                seq_puts(seq, ",nodiscard");
        }
@@ -2340,6 +2369,13 @@ static int f2fs_remount(struct super_block *sb, int 
*flags, char *data)
                goto restore_opts;
        }
 
+       if (!cpumask_equal(&org_mount_opt.discard_cpumask,
+                       &F2FS_OPTION(sbi).discard_cpumask)) {
+               err = -EINVAL;
+               f2fs_warn(sbi, "switch discard_cpuset option is not allowed");
+               goto restore_opts;
+       }
+
        if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) {
                err = -EINVAL;
                f2fs_warn(sbi, "disabling checkpoint not compatible with 
read-only");
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 7e6751b29101..8ddc2cd1b27e 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -541,6 +541,7 @@ void kthread_bind_mask(struct task_struct *p, const struct 
cpumask *mask)
 {
        __kthread_bind_mask(p, mask, TASK_UNINTERRUPTIBLE);
 }
+EXPORT_SYMBOL_GPL(kthread_bind_mask);
 
 /**
  * kthread_bind - bind a just-created kthread to a cpu.
-- 
2.25.1



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

Reply via email to