Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: refactor sysfs support code

Make the code more easily extensible as well as taking up less
compiled space.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>

+131 -136
+131 -136
fs/ext4/sysfs.c
··· 15 15 #include "ext4.h" 16 16 #include "ext4_jbd2.h" 17 17 18 + typedef enum { 19 + attr_noop, 20 + attr_delayed_allocation_blocks, 21 + attr_session_write_kbytes, 22 + attr_lifetime_write_kbytes, 23 + attr_reserved_clusters, 24 + attr_inode_readahead, 25 + attr_trigger_test_error, 26 + attr_feature, 27 + attr_pointer_ui, 28 + attr_pointer_atomic, 29 + } attr_id_t; 30 + 31 + typedef enum { 32 + ptr_explicit, 33 + ptr_ext4_sb_info_offset, 34 + ptr_ext4_super_block_offset, 35 + } attr_ptr_t; 36 + 18 37 struct ext4_attr { 19 38 struct attribute attr; 20 - ssize_t (*show)(struct ext4_attr *, struct ext4_sb_info *, char *); 21 - ssize_t (*store)(struct ext4_attr *, struct ext4_sb_info *, 22 - const char *, size_t); 39 + short attr_id; 40 + short attr_ptr; 23 41 union { 24 42 int offset; 25 - int deprecated_val; 43 + void *explicit_ptr; 26 44 } u; 27 45 }; 28 - 29 - static int parse_strtoull(const char *buf, 30 - unsigned long long max, unsigned long long *value) 31 - { 32 - int ret; 33 - 34 - ret = kstrtoull(skip_spaces(buf), 0, value); 35 - if (!ret && *value > max) 36 - ret = -EINVAL; 37 - return ret; 38 - } 39 - 40 - static ssize_t delayed_allocation_blocks_show(struct ext4_attr *a, 41 - struct ext4_sb_info *sbi, 42 - char *buf) 43 - { 44 - return snprintf(buf, PAGE_SIZE, "%llu\n", 45 - (s64) EXT4_C2B(sbi, 46 - percpu_counter_sum(&sbi->s_dirtyclusters_counter))); 47 - } 48 46 49 47 static ssize_t session_write_kbytes_show(struct ext4_attr *a, 50 48 struct ext4_sb_info *sbi, char *buf) ··· 87 89 return count; 88 90 } 89 91 90 - static ssize_t sbi_ui_show(struct ext4_attr *a, 91 - struct ext4_sb_info *sbi, char *buf) 92 - { 93 - unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset); 94 - 95 - return snprintf(buf, PAGE_SIZE, "%u\n", *ui); 96 - } 97 - 98 - static ssize_t sbi_ui_store(struct ext4_attr *a, 99 - struct ext4_sb_info *sbi, 100 - const char *buf, size_t count) 101 - { 102 - unsigned int *ui = (unsigned int *) (((char *) sbi) + a->u.offset); 103 - unsigned long t; 104 - int ret; 105 - 106 - ret = kstrtoul(skip_spaces(buf), 0, &t); 107 - if (ret) 108 - return ret; 109 - *ui = t; 110 - return count; 111 - } 112 - 113 - static ssize_t es_ui_show(struct ext4_attr *a, 114 - struct ext4_sb_info *sbi, char *buf) 115 - { 116 - 117 - unsigned int *ui = (unsigned int *) (((char *) sbi->s_es) + 118 - a->u.offset); 119 - 120 - return snprintf(buf, PAGE_SIZE, "%u\n", *ui); 121 - } 122 - 123 - static ssize_t reserved_clusters_show(struct ext4_attr *a, 124 - struct ext4_sb_info *sbi, char *buf) 125 - { 126 - return snprintf(buf, PAGE_SIZE, "%llu\n", 127 - (unsigned long long) atomic64_read(&sbi->s_resv_clusters)); 128 - } 129 - 130 92 static ssize_t reserved_clusters_store(struct ext4_attr *a, 131 93 struct ext4_sb_info *sbi, 132 94 const char *buf, size_t count) ··· 94 136 unsigned long long val; 95 137 ext4_fsblk_t clusters = (ext4_blocks_count(sbi->s_es) >> 96 138 sbi->s_cluster_bits); 139 + int ret; 97 140 98 - if (parse_strtoull(buf, -1ULL, &val)) 99 - return -EINVAL; 100 - 101 - if (val >= clusters) 141 + ret = kstrtoull(skip_spaces(buf), 0, &val); 142 + if (!ret || val >= clusters) 102 143 return -EINVAL; 103 144 104 145 atomic64_set(&sbi->s_resv_clusters, val); ··· 121 164 return count; 122 165 } 123 166 124 - static ssize_t sbi_deprecated_show(struct ext4_attr *a, 125 - struct ext4_sb_info *sbi, char *buf) 126 - { 127 - return snprintf(buf, PAGE_SIZE, "%d\n", a->u.deprecated_val); 128 - } 129 - 130 - #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ 131 - static struct ext4_attr ext4_attr_##_name = { \ 132 - .attr = {.name = __stringify(_name), .mode = _mode }, \ 133 - .show = _show, \ 134 - .store = _store, \ 135 - .u = { \ 136 - .offset = offsetof(struct ext4_sb_info, _elname),\ 137 - }, \ 138 - } 139 - 140 - #define EXT4_ATTR_OFFSET_ES(_name,_mode,_show,_store,_elname) \ 167 + #define EXT4_ATTR(_name,_mode,_id) \ 141 168 static struct ext4_attr ext4_attr_##_name = { \ 142 169 .attr = {.name = __stringify(_name), .mode = _mode }, \ 143 - .show = _show, \ 144 - .store = _store, \ 145 - .u = { \ 146 - .offset = offsetof(struct ext4_super_block, _elname), \ 147 - }, \ 170 + .attr_id = attr_##_id, \ 148 171 } 149 172 150 - #define EXT4_ATTR(name, mode, show, store) \ 151 - static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store) 173 + #define EXT4_ATTR_FUNC(_name,_mode) EXT4_ATTR(_name,_mode,_name) 152 174 153 - #define EXT4_INFO_ATTR(name) EXT4_ATTR(name, 0444, NULL, NULL) 154 - #define EXT4_RO_ATTR(name) EXT4_ATTR(name, 0444, name##_show, NULL) 155 - #define EXT4_RW_ATTR(name) EXT4_ATTR(name, 0644, name##_show, name##_store) 175 + #define EXT4_ATTR_FEATURE(_name) EXT4_ATTR(_name, 0444, feature) 156 176 157 - #define EXT4_RO_ATTR_ES_UI(name, elname) \ 158 - EXT4_ATTR_OFFSET_ES(name, 0444, es_ui_show, NULL, elname) 159 - #define EXT4_RW_ATTR_SBI_UI(name, elname) \ 160 - EXT4_ATTR_OFFSET(name, 0644, sbi_ui_show, sbi_ui_store, elname) 161 - 162 - #define ATTR_LIST(name) &ext4_attr_##name.attr 163 - #define EXT4_DEPRECATED_ATTR(_name, _val) \ 177 + #define EXT4_ATTR_OFFSET(_name,_mode,_id,_struct,_elname) \ 164 178 static struct ext4_attr ext4_attr_##_name = { \ 165 - .attr = {.name = __stringify(_name), .mode = 0444 }, \ 166 - .show = sbi_deprecated_show, \ 179 + .attr = {.name = __stringify(_name), .mode = _mode }, \ 180 + .attr_id = attr_##_id, \ 181 + .attr_ptr = ptr_##_struct##_offset, \ 167 182 .u = { \ 168 - .deprecated_val = _val, \ 183 + .offset = offsetof(struct _struct, _elname),\ 169 184 }, \ 170 185 } 171 186 172 - EXT4_RO_ATTR(delayed_allocation_blocks); 173 - EXT4_RO_ATTR(session_write_kbytes); 174 - EXT4_RO_ATTR(lifetime_write_kbytes); 175 - EXT4_RW_ATTR(reserved_clusters); 176 - EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, 177 - inode_readahead_blks_store, s_inode_readahead_blks); 187 + #define EXT4_RO_ATTR_ES_UI(_name,_elname) \ 188 + EXT4_ATTR_OFFSET(_name, 0444, pointer_ui, ext4_super_block, _elname) 189 + 190 + #define EXT4_RW_ATTR_SBI_UI(_name,_elname) \ 191 + EXT4_ATTR_OFFSET(_name, 0644, pointer_ui, ext4_sb_info, _elname) 192 + 193 + #define EXT4_ATTR_PTR(_name,_mode,_id,_ptr) \ 194 + static struct ext4_attr ext4_attr_##_name = { \ 195 + .attr = {.name = __stringify(_name), .mode = _mode }, \ 196 + .attr_id = attr_##_id, \ 197 + .attr_ptr = ptr_explicit, \ 198 + .u = { \ 199 + .explicit_ptr = _ptr, \ 200 + }, \ 201 + } 202 + 203 + #define ATTR_LIST(name) &ext4_attr_##name.attr 204 + 205 + EXT4_ATTR_FUNC(delayed_allocation_blocks, 0444); 206 + EXT4_ATTR_FUNC(session_write_kbytes, 0444); 207 + EXT4_ATTR_FUNC(lifetime_write_kbytes, 0444); 208 + EXT4_ATTR_FUNC(reserved_clusters, 0644); 209 + 210 + EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, inode_readahead, 211 + ext4_sb_info, s_inode_readahead_blks); 178 212 EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); 179 213 EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); 180 214 EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); ··· 173 225 EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); 174 226 EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); 175 227 EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); 176 - EXT4_DEPRECATED_ATTR(max_writeback_mb_bump, 128); 177 228 EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb); 178 - EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error); 229 + EXT4_ATTR(trigger_fs_error, 0200, trigger_test_error); 179 230 EXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval); 180 231 EXT4_RW_ATTR_SBI_UI(err_ratelimit_burst, s_err_ratelimit_state.burst); 181 232 EXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.interval); ··· 184 237 EXT4_RO_ATTR_ES_UI(errors_count, s_error_count); 185 238 EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time); 186 239 EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time); 240 + 241 + static unsigned int old_bump_val = 128; 242 + EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val); 187 243 188 244 static struct attribute *ext4_attrs[] = { 189 245 ATTR_LIST(delayed_allocation_blocks), ··· 217 267 }; 218 268 219 269 /* Features this copy of ext4 supports */ 220 - EXT4_INFO_ATTR(lazy_itable_init); 221 - EXT4_INFO_ATTR(batched_discard); 222 - EXT4_INFO_ATTR(meta_bg_resize); 223 - EXT4_INFO_ATTR(encryption); 270 + EXT4_ATTR_FEATURE(lazy_itable_init); 271 + EXT4_ATTR_FEATURE(batched_discard); 272 + EXT4_ATTR_FEATURE(meta_bg_resize); 273 + EXT4_ATTR_FEATURE(encryption); 224 274 225 275 static struct attribute *ext4_feat_attrs[] = { 226 276 ATTR_LIST(lazy_itable_init), ··· 230 280 NULL, 231 281 }; 232 282 283 + static void *calc_ptr(struct ext4_attr *a, struct ext4_sb_info *sbi) 284 + { 285 + switch (a->attr_ptr) { 286 + case ptr_explicit: 287 + return a->u.explicit_ptr; 288 + case ptr_ext4_sb_info_offset: 289 + return (void *) (((char *) sbi) + a->u.offset); 290 + case ptr_ext4_super_block_offset: 291 + return (void *) (((char *) sbi->s_es) + a->u.offset); 292 + } 293 + return NULL; 294 + } 295 + 233 296 static ssize_t ext4_attr_show(struct kobject *kobj, 234 297 struct attribute *attr, char *buf) 235 298 { 236 299 struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, 237 300 s_kobj); 238 301 struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); 302 + void *ptr = calc_ptr(a, sbi); 239 303 240 - return a->show ? a->show(a, sbi, buf) : 0; 304 + switch (a->attr_id) { 305 + case attr_delayed_allocation_blocks: 306 + return snprintf(buf, PAGE_SIZE, "%llu\n", 307 + (s64) EXT4_C2B(sbi, 308 + percpu_counter_sum(&sbi->s_dirtyclusters_counter))); 309 + case attr_session_write_kbytes: 310 + return session_write_kbytes_show(a, sbi, buf); 311 + case attr_lifetime_write_kbytes: 312 + return lifetime_write_kbytes_show(a, sbi, buf); 313 + case attr_reserved_clusters: 314 + return snprintf(buf, PAGE_SIZE, "%llu\n", 315 + (unsigned long long) 316 + atomic64_read(&sbi->s_resv_clusters)); 317 + case attr_inode_readahead: 318 + case attr_pointer_ui: 319 + if (!ptr) 320 + return 0; 321 + return snprintf(buf, PAGE_SIZE, "%u\n", 322 + *((unsigned int *) ptr)); 323 + case attr_pointer_atomic: 324 + if (!ptr) 325 + return 0; 326 + return snprintf(buf, PAGE_SIZE, "%d\n", 327 + atomic_read((atomic_t *) ptr)); 328 + case attr_feature: 329 + return snprintf(buf, PAGE_SIZE, "supported\n"); 330 + } 331 + 332 + return 0; 241 333 } 242 334 243 335 static ssize_t ext4_attr_store(struct kobject *kobj, ··· 289 297 struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, 290 298 s_kobj); 291 299 struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); 300 + void *ptr = calc_ptr(a, sbi); 301 + unsigned long t; 302 + int ret; 292 303 293 - return a->store ? a->store(a, sbi, buf, len) : 0; 304 + switch (a->attr_id) { 305 + case attr_reserved_clusters: 306 + return reserved_clusters_store(a, sbi, buf, len); 307 + case attr_pointer_ui: 308 + if (!ptr) 309 + return 0; 310 + ret = kstrtoul(skip_spaces(buf), 0, &t); 311 + if (ret) 312 + return ret; 313 + *((unsigned int *) ptr) = t; 314 + return len; 315 + case attr_inode_readahead: 316 + return inode_readahead_blks_store(a, sbi, buf, len); 317 + case attr_trigger_test_error: 318 + return trigger_test_error(a, sbi, buf, len); 319 + } 320 + return 0; 294 321 } 295 322 296 323 static void ext4_sb_release(struct kobject *kobj) ··· 338 327 .kobj = {.ktype = &ext4_ktype}, 339 328 }; 340 329 341 - static ssize_t ext4_feat_show(struct kobject *kobj, 342 - struct attribute *attr, char *buf) 343 - { 344 - return snprintf(buf, PAGE_SIZE, "supported\n"); 345 - } 346 - 347 - /* 348 - * We can not use ext4_attr_show/store because it relies on the kobject 349 - * being embedded in the ext4_sb_info structure which is definitely not 350 - * true in this case. 351 - */ 352 - static const struct sysfs_ops ext4_feat_ops = { 353 - .show = ext4_feat_show, 354 - .store = NULL, 355 - }; 356 - 357 330 static struct kobj_type ext4_feat_ktype = { 358 331 .default_attrs = ext4_feat_attrs, 359 - .sysfs_ops = &ext4_feat_ops, 332 + .sysfs_ops = &ext4_attr_ops, 360 333 }; 361 334 362 335 static struct kobject ext4_feat = {