| 1 | |
| 2 | |
| 3 | * Simple file system for zoned block devices exposing zones as files.
|
| 4 | *
|
| 5 | * Copyright (C) 2022 Western Digital Corporation or its affiliates.
|
| 6 |
|
| 7 | #include <linux/fs.h>
|
| 8 | #include <linux/seq_file.h>
|
| 9 | #include <linux/blkdev.h>
|
| 10 |
|
| 11 | #include "zonefs.h"
|
| 12 |
|
| 13 | struct zonefs_sysfs_attr {
|
| 14 | struct attribute attr;
|
| 15 | ssize_t (*show)(struct zonefs_sb_info *sbi, char *buf);
|
| 16 | };
|
| 17 |
|
| 18 | #define ZONEFS_SYSFS_ATTR_RO(name) \
|
| 19 | static struct zonefs_sysfs_attr zonefs_sysfs_attr_##name = __ATTR_RO(name)
|
| 20 |
|
| 21 | #define ATTR_LIST(name) &zonefs_sysfs_attr_##name.attr
|
| 22 |
|
| 23 | static ssize_t zonefs_sysfs_attr_show(struct kobject *kobj,
|
| 24 | struct attribute *attr, char *buf)
|
| 25 | {
|
| 26 | struct zonefs_sb_info *sbi =
|
| 27 | container_of(kobj, struct zonefs_sb_info, s_kobj);
|
| 28 | struct zonefs_sysfs_attr *zonefs_attr =
|
| 29 | container_of(attr, struct zonefs_sysfs_attr, attr);
|
| 30 |
|
| 31 | if (!zonefs_attr->show)
|
| 32 | return 0;
|
| 33 |
|
| 34 | return zonefs_attr->show(sbi, buf);
|
| 35 | }
|
| 36 |
|
| 37 | static ssize_t max_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
| 38 | {
|
| 39 | return sysfs_emit(buf, "%u\n", sbi->s_max_wro_seq_files);
|
| 40 | }
|
| 41 | ZONEFS_SYSFS_ATTR_RO(max_wro_seq_files);
|
| 42 |
|
| 43 | static ssize_t nr_wro_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
| 44 | {
|
| 45 | return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_wro_seq_files));
|
| 46 | }
|
| 47 | ZONEFS_SYSFS_ATTR_RO(nr_wro_seq_files);
|
| 48 |
|
| 49 | static ssize_t max_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
| 50 | {
|
| 51 | return sysfs_emit(buf, "%u\n", sbi->s_max_active_seq_files);
|
| 52 | }
|
| 53 | ZONEFS_SYSFS_ATTR_RO(max_active_seq_files);
|
| 54 |
|
| 55 | static ssize_t nr_active_seq_files_show(struct zonefs_sb_info *sbi, char *buf)
|
| 56 | {
|
| 57 | return sysfs_emit(buf, "%d\n", atomic_read(&sbi->s_active_seq_files));
|
| 58 | }
|
| 59 | ZONEFS_SYSFS_ATTR_RO(nr_active_seq_files);
|
| 60 |
|
| 61 | static struct attribute *zonefs_sysfs_attrs[] = {
|
| 62 | ATTR_LIST(max_wro_seq_files),
|
| 63 | ATTR_LIST(nr_wro_seq_files),
|
| 64 | ATTR_LIST(max_active_seq_files),
|
| 65 | ATTR_LIST(nr_active_seq_files),
|
| 66 | NULL,
|
| 67 | };
|
| 68 | ATTRIBUTE_GROUPS(zonefs_sysfs);
|
| 69 |
|
| 70 | static void zonefs_sysfs_sb_release(struct kobject *kobj)
|
| 71 | {
|
| 72 | struct zonefs_sb_info *sbi =
|
| 73 | container_of(kobj, struct zonefs_sb_info, s_kobj);
|
| 74 |
|
| 75 | complete(&sbi->s_kobj_unregister);
|
| 76 | }
|
| 77 |
|
| 78 | static const struct sysfs_ops zonefs_sysfs_attr_ops = {
|
| 79 | .show = zonefs_sysfs_attr_show,
|
| 80 | };
|
| 81 |
|
| 82 | static const struct kobj_type zonefs_sb_ktype = {
|
| 83 | .default_groups = zonefs_sysfs_groups,
|
| 84 | .sysfs_ops = &zonefs_sysfs_attr_ops,
|
| 85 | .release = zonefs_sysfs_sb_release,
|
| 86 | };
|
| 87 |
|
| 88 | static struct kobject *zonefs_sysfs_root;
|
| 89 |
|
| 90 | int zonefs_sysfs_register(struct super_block *sb)
|
| 91 | {
|
| 92 | struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
|
| 93 | int ret;
|
| 94 |
|
| 95 | super_set_sysfs_name_id(sb);
|
| 96 | init_completion(&sbi->s_kobj_unregister);
|
| 97 | ret = kobject_init_and_add(&sbi->s_kobj, &zonefs_sb_ktype,
|
| 98 | zonefs_sysfs_root, "%s", sb->s_id);
|
| 99 | if (ret) {
|
| 100 | kobject_put(&sbi->s_kobj);
|
| 101 | wait_for_completion(&sbi->s_kobj_unregister);
|
| 102 | return ret;
|
| 103 | }
|
| 104 |
|
| 105 | sbi->s_sysfs_registered = true;
|
| 106 |
|
| 107 | return 0;
|
| 108 | }
|
| 109 |
|
| 110 | void zonefs_sysfs_unregister(struct super_block *sb)
|
| 111 | {
|
| 112 | struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
|
| 113 |
|
| 114 | if (!sbi || !sbi->s_sysfs_registered)
|
| 115 | return;
|
| 116 |
|
| 117 | kobject_del(&sbi->s_kobj);
|
| 118 | kobject_put(&sbi->s_kobj);
|
| 119 | wait_for_completion(&sbi->s_kobj_unregister);
|
| 120 | }
|
| 121 |
|
| 122 | int __init zonefs_sysfs_init(void)
|
| 123 | {
|
| 124 | zonefs_sysfs_root = kobject_create_and_add("zonefs", fs_kobj);
|
| 125 | if (!zonefs_sysfs_root)
|
| 126 | return -ENOMEM;
|
| 127 |
|
| 128 | return 0;
|
| 129 | }
|
| 130 |
|
| 131 | void zonefs_sysfs_exit(void)
|
| 132 | {
|
| 133 | kobject_put(zonefs_sysfs_root);
|
| 134 | zonefs_sysfs_root = NULL;
|
| 135 | }
|