f2fs: expose extension_list sysfs entry
authorChao Yu <yuchao0@huawei.com>
Mon, 26 Feb 2018 14:04:13 +0000 (22:04 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 12 Mar 2018 23:05:48 +0000 (08:05 +0900)
This patch adds a sysfs entry 'extension_list' to support
query/add/del item in extension list.

Query:
cat /sys/fs/f2fs/<device>/extension_list

Add:
echo 'extension' > /sys/fs/f2fs/<device>/extension_list

Del:
echo '!extension' > /sys/fs/f2fs/<device>/extension_list

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Documentation/ABI/testing/sysfs-fs-f2fs
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/namei.c
fs/f2fs/super.c
fs/f2fs/sysfs.c
include/linux/f2fs_fs.h

index d870b55..7fa84e3 100644 (file)
@@ -192,3 +192,12 @@ Date:              November 2017
 Contact:       "Sheng Yong" <shengyong1@huawei.com>
 Description:
                 Controls readahead inode block in readdir.
+
+What:          /sys/fs/f2fs/<disk>/extension_list
+Date:          Feburary 2018
+Contact:       "Chao Yu" <yuchao0@huawei.com>
+Description:
+                Used to control configure extension list:
+                - Query: cat /sys/fs/f2fs/<disk>/extension_list
+                - Add: echo 'extension' > /sys/fs/f2fs/<disk>/extension_list
+                - Del: echo '!extension' > /sys/fs/f2fs/<disk>/extension_list
index 6d0e7b1..3bb4e94 100644 (file)
@@ -1047,7 +1047,7 @@ struct f2fs_sb_info {
        struct super_block *sb;                 /* pointer to VFS super block */
        struct proc_dir_entry *s_proc;          /* proc entry */
        struct f2fs_super_block *raw_super;     /* raw super block pointer */
-       struct mutex sb_lock;                   /* lock for raw super block */
+       struct rw_semaphore sb_lock;            /* lock for raw super block */
        int valid_super_block;                  /* valid super block no */
        unsigned long s_flag;                           /* flags for sbi */
 
@@ -2605,6 +2605,8 @@ void handle_failed_inode(struct inode *inode);
 /*
  * namei.c
  */
+int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
+                                                               bool set);
 struct dentry *f2fs_get_parent(struct dentry *child);
 
 /*
index db9dc9e..c0a8098 100644 (file)
@@ -1970,7 +1970,7 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
        if (err)
                return err;
 
-       mutex_lock(&sbi->sb_lock);
+       down_write(&sbi->sb_lock);
 
        if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
                goto got_it;
@@ -1989,7 +1989,7 @@ got_it:
                                                                        16))
                err = -EFAULT;
 out_err:
-       mutex_unlock(&sbi->sb_lock);
+       up_write(&sbi->sb_lock);
        mnt_drop_write_file(filp);
        return err;
 }
index 2ebf3d0..2bd6e9f 100644 (file)
@@ -171,16 +171,52 @@ static int is_multimedia_file(const unsigned char *s, const char *sub)
 static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode,
                const unsigned char *name)
 {
-       int i;
-       __u8 (*extlist)[8] = sbi->raw_super->extension_list;
+       __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
+       int i, count;
+
+       down_read(&sbi->sb_lock);
+
+       count = le32_to_cpu(sbi->raw_super->extension_count);
 
-       int count = le32_to_cpu(sbi->raw_super->extension_count);
        for (i = 0; i < count; i++) {
                if (is_multimedia_file(name, extlist[i])) {
                        file_set_cold(inode);
                        break;
                }
        }
+
+       up_read(&sbi->sb_lock);
+}
+
+int update_extension_list(struct f2fs_sb_info *sbi, const char *name, bool set)
+{
+       __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
+       int count = le32_to_cpu(sbi->raw_super->extension_count);
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if (strcmp(name, extlist[i]))
+                       continue;
+
+               if (set)
+                       return -EINVAL;
+
+               memcpy(extlist[i], extlist[i + 1],
+                               F2FS_EXTENSION_LEN * (count - i - 1));
+               memset(extlist[count - 1], 0, F2FS_EXTENSION_LEN);
+               sbi->raw_super->extension_count = cpu_to_le32(count - 1);
+               return 0;
+       }
+
+       if (!set)
+               return -EINVAL;
+
+       if (count == F2FS_MAX_EXTENSION)
+               return -EINVAL;
+
+       strncpy(extlist[count], name, strlen(name));
+       sbi->raw_super->extension_count = cpu_to_le32(count + 1);
+       return 0;
 }
 
 static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
index d2833a2..06da158 100644 (file)
@@ -2222,7 +2222,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
        sbi->dirty_device = 0;
        spin_lock_init(&sbi->dev_lock);
 
-       mutex_init(&sbi->sb_lock);
+       init_rwsem(&sbi->sb_lock);
 }
 
 static int init_percpu_info(struct f2fs_sb_info *sbi)
index 374ee5c..d27b28e 100644 (file)
@@ -136,6 +136,18 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
        if (!ptr)
                return -EINVAL;
 
+       if (!strcmp(a->attr.name, "extension_list")) {
+               __u8 (*extlist)[F2FS_EXTENSION_LEN] =
+                                       sbi->raw_super->extension_list;
+               int count = le32_to_cpu(sbi->raw_super->extension_count);
+               int len = 0, i;
+
+               for (i = 0; i < count; i++)
+                       len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
+                                                               extlist[i]);
+               return len;
+       }
+
        ui = (unsigned int *)(ptr + a->offset);
 
        return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
@@ -154,6 +166,32 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
        if (!ptr)
                return -EINVAL;
 
+       if (!strcmp(a->attr.name, "extension_list")) {
+               const char *name = strim((char *)buf);
+               bool set = true;
+
+               if (name[0] == '!') {
+                       name++;
+                       set = false;
+               }
+
+               if (strlen(name) >= F2FS_EXTENSION_LEN)
+                       return -EINVAL;
+
+               down_write(&sbi->sb_lock);
+
+               ret = update_extension_list(sbi, name, set);
+               if (ret)
+                       goto out;
+
+               ret = f2fs_commit_super(sbi, false);
+               if (ret)
+                       update_extension_list(sbi, name, !set);
+out:
+               up_write(&sbi->sb_lock);
+               return ret ? ret : count;
+       }
+
        ui = (unsigned int *)(ptr + a->offset);
 
        ret = kstrtoul(skip_spaces(buf), 0, &t);
@@ -307,6 +345,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list);
 #ifdef CONFIG_F2FS_FAULT_INJECTION
 F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
 F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
@@ -357,6 +396,7 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(iostat_enable),
        ATTR_LIST(readdir_ra),
        ATTR_LIST(gc_pin_file_thresh),
+       ATTR_LIST(extension_list),
 #ifdef CONFIG_F2FS_FAULT_INJECTION
        ATTR_LIST(inject_rate),
        ATTR_LIST(inject_type),
index 96c9bdb..d8c2414 100644 (file)
@@ -21,6 +21,7 @@
 #define F2FS_BLKSIZE                   4096    /* support only 4KB block */
 #define F2FS_BLKSIZE_BITS              12      /* bits for F2FS_BLKSIZE */
 #define F2FS_MAX_EXTENSION             64      /* # of extension entries */
+#define F2FS_EXTENSION_LEN             8       /* max size of extension */
 #define F2FS_BLK_ALIGN(x)      (((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS)
 
 #define NULL_ADDR              ((block_t)0)    /* used as block_t addresses */
@@ -101,7 +102,7 @@ struct f2fs_super_block {
        __u8 uuid[16];                  /* 128-bit uuid for volume */
        __le16 volume_name[MAX_VOLUME_NAME];    /* volume name */
        __le32 extension_count;         /* # of extensions below */
-       __u8 extension_list[F2FS_MAX_EXTENSION][8];     /* extension array */
+       __u8 extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */
        __le32 cp_payload;
        __u8 version[VERSION_LEN];      /* the kernel version */
        __u8 init_version[VERSION_LEN]; /* the initial kernel version */