162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ext4/sysfs.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 662306a36Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 762306a36Sopenharmony_ci * Theodore Ts'o (tytso@mit.edu) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/time.h> 1262306a36Sopenharmony_ci#include <linux/fs.h> 1362306a36Sopenharmony_ci#include <linux/seq_file.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/proc_fs.h> 1662306a36Sopenharmony_ci#include <linux/part_stat.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "ext4.h" 1962306a36Sopenharmony_ci#include "ext4_jbd2.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_citypedef enum { 2262306a36Sopenharmony_ci attr_noop, 2362306a36Sopenharmony_ci attr_delayed_allocation_blocks, 2462306a36Sopenharmony_ci attr_session_write_kbytes, 2562306a36Sopenharmony_ci attr_lifetime_write_kbytes, 2662306a36Sopenharmony_ci attr_reserved_clusters, 2762306a36Sopenharmony_ci attr_sra_exceeded_retry_limit, 2862306a36Sopenharmony_ci attr_inode_readahead, 2962306a36Sopenharmony_ci attr_trigger_test_error, 3062306a36Sopenharmony_ci attr_first_error_time, 3162306a36Sopenharmony_ci attr_last_error_time, 3262306a36Sopenharmony_ci attr_feature, 3362306a36Sopenharmony_ci attr_pointer_ui, 3462306a36Sopenharmony_ci attr_pointer_ul, 3562306a36Sopenharmony_ci attr_pointer_u64, 3662306a36Sopenharmony_ci attr_pointer_u8, 3762306a36Sopenharmony_ci attr_pointer_string, 3862306a36Sopenharmony_ci attr_pointer_atomic, 3962306a36Sopenharmony_ci attr_journal_task, 4062306a36Sopenharmony_ci} attr_id_t; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_citypedef enum { 4362306a36Sopenharmony_ci ptr_explicit, 4462306a36Sopenharmony_ci ptr_ext4_sb_info_offset, 4562306a36Sopenharmony_ci ptr_ext4_super_block_offset, 4662306a36Sopenharmony_ci} attr_ptr_t; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const char proc_dirname[] = "fs/ext4"; 4962306a36Sopenharmony_cistatic struct proc_dir_entry *ext4_proc_root; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct ext4_attr { 5262306a36Sopenharmony_ci struct attribute attr; 5362306a36Sopenharmony_ci short attr_id; 5462306a36Sopenharmony_ci short attr_ptr; 5562306a36Sopenharmony_ci unsigned short attr_size; 5662306a36Sopenharmony_ci union { 5762306a36Sopenharmony_ci int offset; 5862306a36Sopenharmony_ci void *explicit_ptr; 5962306a36Sopenharmony_ci } u; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic ssize_t session_write_kbytes_show(struct ext4_sb_info *sbi, char *buf) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct super_block *sb = sbi->s_buddy_cache->i_sb; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", 6762306a36Sopenharmony_ci (part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) - 6862306a36Sopenharmony_ci sbi->s_sectors_written_start) >> 1); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic ssize_t lifetime_write_kbytes_show(struct ext4_sb_info *sbi, char *buf) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct super_block *sb = sbi->s_buddy_cache->i_sb; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 7662306a36Sopenharmony_ci (unsigned long long)(sbi->s_kbytes_written + 7762306a36Sopenharmony_ci ((part_stat_read(sb->s_bdev, sectors[STAT_WRITE]) - 7862306a36Sopenharmony_ci EXT4_SB(sb)->s_sectors_written_start) >> 1))); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic ssize_t inode_readahead_blks_store(struct ext4_sb_info *sbi, 8262306a36Sopenharmony_ci const char *buf, size_t count) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci unsigned long t; 8562306a36Sopenharmony_ci int ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci ret = kstrtoul(skip_spaces(buf), 0, &t); 8862306a36Sopenharmony_ci if (ret) 8962306a36Sopenharmony_ci return ret; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (t && (!is_power_of_2(t) || t > 0x40000000)) 9262306a36Sopenharmony_ci return -EINVAL; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci sbi->s_inode_readahead_blks = t; 9562306a36Sopenharmony_ci return count; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic ssize_t reserved_clusters_store(struct ext4_sb_info *sbi, 9962306a36Sopenharmony_ci const char *buf, size_t count) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci unsigned long long val; 10262306a36Sopenharmony_ci ext4_fsblk_t clusters = (ext4_blocks_count(sbi->s_es) >> 10362306a36Sopenharmony_ci sbi->s_cluster_bits); 10462306a36Sopenharmony_ci int ret; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ret = kstrtoull(skip_spaces(buf), 0, &val); 10762306a36Sopenharmony_ci if (ret || val >= clusters) 10862306a36Sopenharmony_ci return -EINVAL; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci atomic64_set(&sbi->s_resv_clusters, val); 11162306a36Sopenharmony_ci return count; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic ssize_t trigger_test_error(struct ext4_sb_info *sbi, 11562306a36Sopenharmony_ci const char *buf, size_t count) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int len = count; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 12062306a36Sopenharmony_ci return -EPERM; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (len && buf[len-1] == '\n') 12362306a36Sopenharmony_ci len--; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (len) 12662306a36Sopenharmony_ci ext4_error(sbi->s_sb, "%.*s", len, buf); 12762306a36Sopenharmony_ci return count; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic ssize_t journal_task_show(struct ext4_sb_info *sbi, char *buf) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci if (!sbi->s_journal) 13362306a36Sopenharmony_ci return sysfs_emit(buf, "<none>\n"); 13462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", 13562306a36Sopenharmony_ci task_pid_vnr(sbi->s_journal->j_task)); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#define EXT4_ATTR(_name,_mode,_id) \ 13962306a36Sopenharmony_cistatic struct ext4_attr ext4_attr_##_name = { \ 14062306a36Sopenharmony_ci .attr = {.name = __stringify(_name), .mode = _mode }, \ 14162306a36Sopenharmony_ci .attr_id = attr_##_id, \ 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#define EXT4_ATTR_FUNC(_name,_mode) EXT4_ATTR(_name,_mode,_name) 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci#define EXT4_ATTR_FEATURE(_name) EXT4_ATTR(_name, 0444, feature) 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define EXT4_ATTR_OFFSET(_name,_mode,_id,_struct,_elname) \ 14962306a36Sopenharmony_cistatic struct ext4_attr ext4_attr_##_name = { \ 15062306a36Sopenharmony_ci .attr = {.name = __stringify(_name), .mode = _mode }, \ 15162306a36Sopenharmony_ci .attr_id = attr_##_id, \ 15262306a36Sopenharmony_ci .attr_ptr = ptr_##_struct##_offset, \ 15362306a36Sopenharmony_ci .u = { \ 15462306a36Sopenharmony_ci .offset = offsetof(struct _struct, _elname),\ 15562306a36Sopenharmony_ci }, \ 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define EXT4_ATTR_STRING(_name,_mode,_size,_struct,_elname) \ 15962306a36Sopenharmony_cistatic struct ext4_attr ext4_attr_##_name = { \ 16062306a36Sopenharmony_ci .attr = {.name = __stringify(_name), .mode = _mode }, \ 16162306a36Sopenharmony_ci .attr_id = attr_pointer_string, \ 16262306a36Sopenharmony_ci .attr_size = _size, \ 16362306a36Sopenharmony_ci .attr_ptr = ptr_##_struct##_offset, \ 16462306a36Sopenharmony_ci .u = { \ 16562306a36Sopenharmony_ci .offset = offsetof(struct _struct, _elname),\ 16662306a36Sopenharmony_ci }, \ 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#define EXT4_RO_ATTR_ES_UI(_name,_elname) \ 17062306a36Sopenharmony_ci EXT4_ATTR_OFFSET(_name, 0444, pointer_ui, ext4_super_block, _elname) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define EXT4_RO_ATTR_ES_U8(_name,_elname) \ 17362306a36Sopenharmony_ci EXT4_ATTR_OFFSET(_name, 0444, pointer_u8, ext4_super_block, _elname) 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#define EXT4_RO_ATTR_ES_U64(_name,_elname) \ 17662306a36Sopenharmony_ci EXT4_ATTR_OFFSET(_name, 0444, pointer_u64, ext4_super_block, _elname) 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#define EXT4_RO_ATTR_ES_STRING(_name,_elname,_size) \ 17962306a36Sopenharmony_ci EXT4_ATTR_STRING(_name, 0444, _size, ext4_super_block, _elname) 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#define EXT4_RW_ATTR_SBI_UI(_name,_elname) \ 18262306a36Sopenharmony_ci EXT4_ATTR_OFFSET(_name, 0644, pointer_ui, ext4_sb_info, _elname) 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#define EXT4_RW_ATTR_SBI_UL(_name,_elname) \ 18562306a36Sopenharmony_ci EXT4_ATTR_OFFSET(_name, 0644, pointer_ul, ext4_sb_info, _elname) 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci#define EXT4_RO_ATTR_SBI_ATOMIC(_name,_elname) \ 18862306a36Sopenharmony_ci EXT4_ATTR_OFFSET(_name, 0444, pointer_atomic, ext4_sb_info, _elname) 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci#define EXT4_ATTR_PTR(_name,_mode,_id,_ptr) \ 19162306a36Sopenharmony_cistatic struct ext4_attr ext4_attr_##_name = { \ 19262306a36Sopenharmony_ci .attr = {.name = __stringify(_name), .mode = _mode }, \ 19362306a36Sopenharmony_ci .attr_id = attr_##_id, \ 19462306a36Sopenharmony_ci .attr_ptr = ptr_explicit, \ 19562306a36Sopenharmony_ci .u = { \ 19662306a36Sopenharmony_ci .explicit_ptr = _ptr, \ 19762306a36Sopenharmony_ci }, \ 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#define ATTR_LIST(name) &ext4_attr_##name.attr 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ciEXT4_ATTR_FUNC(delayed_allocation_blocks, 0444); 20362306a36Sopenharmony_ciEXT4_ATTR_FUNC(session_write_kbytes, 0444); 20462306a36Sopenharmony_ciEXT4_ATTR_FUNC(lifetime_write_kbytes, 0444); 20562306a36Sopenharmony_ciEXT4_ATTR_FUNC(reserved_clusters, 0644); 20662306a36Sopenharmony_ciEXT4_ATTR_FUNC(sra_exceeded_retry_limit, 0444); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciEXT4_ATTR_OFFSET(inode_readahead_blks, 0644, inode_readahead, 20962306a36Sopenharmony_ci ext4_sb_info, s_inode_readahead_blks); 21062306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); 21162306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); 21262306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); 21362306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); 21462306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); 21562306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); 21662306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); 21762306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_max_linear_groups, s_mb_max_linear_groups); 21862306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb); 21962306a36Sopenharmony_ciEXT4_ATTR(trigger_fs_error, 0200, trigger_test_error); 22062306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval); 22162306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(err_ratelimit_burst, s_err_ratelimit_state.burst); 22262306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.interval); 22362306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst); 22462306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval); 22562306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst); 22662306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_best_avail_max_trim_order, s_mb_best_avail_max_trim_order); 22762306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG 22862306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UL(simulate_fail, s_simulate_fail); 22962306a36Sopenharmony_ci#endif 23062306a36Sopenharmony_ciEXT4_RO_ATTR_SBI_ATOMIC(warning_count, s_warning_count); 23162306a36Sopenharmony_ciEXT4_RO_ATTR_SBI_ATOMIC(msg_count, s_msg_count); 23262306a36Sopenharmony_ciEXT4_RO_ATTR_ES_UI(errors_count, s_error_count); 23362306a36Sopenharmony_ciEXT4_RO_ATTR_ES_U8(first_error_errcode, s_first_error_errcode); 23462306a36Sopenharmony_ciEXT4_RO_ATTR_ES_U8(last_error_errcode, s_last_error_errcode); 23562306a36Sopenharmony_ciEXT4_RO_ATTR_ES_UI(first_error_ino, s_first_error_ino); 23662306a36Sopenharmony_ciEXT4_RO_ATTR_ES_UI(last_error_ino, s_last_error_ino); 23762306a36Sopenharmony_ciEXT4_RO_ATTR_ES_U64(first_error_block, s_first_error_block); 23862306a36Sopenharmony_ciEXT4_RO_ATTR_ES_U64(last_error_block, s_last_error_block); 23962306a36Sopenharmony_ciEXT4_RO_ATTR_ES_UI(first_error_line, s_first_error_line); 24062306a36Sopenharmony_ciEXT4_RO_ATTR_ES_UI(last_error_line, s_last_error_line); 24162306a36Sopenharmony_ciEXT4_RO_ATTR_ES_STRING(first_error_func, s_first_error_func, 32); 24262306a36Sopenharmony_ciEXT4_RO_ATTR_ES_STRING(last_error_func, s_last_error_func, 32); 24362306a36Sopenharmony_ciEXT4_ATTR(first_error_time, 0444, first_error_time); 24462306a36Sopenharmony_ciEXT4_ATTR(last_error_time, 0444, last_error_time); 24562306a36Sopenharmony_ciEXT4_ATTR(journal_task, 0444, journal_task); 24662306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_prefetch, s_mb_prefetch); 24762306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UI(mb_prefetch_limit, s_mb_prefetch_limit); 24862306a36Sopenharmony_ciEXT4_RW_ATTR_SBI_UL(last_trim_minblks, s_last_trim_minblks); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic unsigned int old_bump_val = 128; 25162306a36Sopenharmony_ciEXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic struct attribute *ext4_attrs[] = { 25462306a36Sopenharmony_ci ATTR_LIST(delayed_allocation_blocks), 25562306a36Sopenharmony_ci ATTR_LIST(session_write_kbytes), 25662306a36Sopenharmony_ci ATTR_LIST(lifetime_write_kbytes), 25762306a36Sopenharmony_ci ATTR_LIST(reserved_clusters), 25862306a36Sopenharmony_ci ATTR_LIST(sra_exceeded_retry_limit), 25962306a36Sopenharmony_ci ATTR_LIST(inode_readahead_blks), 26062306a36Sopenharmony_ci ATTR_LIST(inode_goal), 26162306a36Sopenharmony_ci ATTR_LIST(mb_stats), 26262306a36Sopenharmony_ci ATTR_LIST(mb_max_to_scan), 26362306a36Sopenharmony_ci ATTR_LIST(mb_min_to_scan), 26462306a36Sopenharmony_ci ATTR_LIST(mb_order2_req), 26562306a36Sopenharmony_ci ATTR_LIST(mb_stream_req), 26662306a36Sopenharmony_ci ATTR_LIST(mb_group_prealloc), 26762306a36Sopenharmony_ci ATTR_LIST(mb_max_linear_groups), 26862306a36Sopenharmony_ci ATTR_LIST(max_writeback_mb_bump), 26962306a36Sopenharmony_ci ATTR_LIST(extent_max_zeroout_kb), 27062306a36Sopenharmony_ci ATTR_LIST(trigger_fs_error), 27162306a36Sopenharmony_ci ATTR_LIST(err_ratelimit_interval_ms), 27262306a36Sopenharmony_ci ATTR_LIST(err_ratelimit_burst), 27362306a36Sopenharmony_ci ATTR_LIST(warning_ratelimit_interval_ms), 27462306a36Sopenharmony_ci ATTR_LIST(warning_ratelimit_burst), 27562306a36Sopenharmony_ci ATTR_LIST(msg_ratelimit_interval_ms), 27662306a36Sopenharmony_ci ATTR_LIST(msg_ratelimit_burst), 27762306a36Sopenharmony_ci ATTR_LIST(mb_best_avail_max_trim_order), 27862306a36Sopenharmony_ci ATTR_LIST(errors_count), 27962306a36Sopenharmony_ci ATTR_LIST(warning_count), 28062306a36Sopenharmony_ci ATTR_LIST(msg_count), 28162306a36Sopenharmony_ci ATTR_LIST(first_error_ino), 28262306a36Sopenharmony_ci ATTR_LIST(last_error_ino), 28362306a36Sopenharmony_ci ATTR_LIST(first_error_block), 28462306a36Sopenharmony_ci ATTR_LIST(last_error_block), 28562306a36Sopenharmony_ci ATTR_LIST(first_error_line), 28662306a36Sopenharmony_ci ATTR_LIST(last_error_line), 28762306a36Sopenharmony_ci ATTR_LIST(first_error_func), 28862306a36Sopenharmony_ci ATTR_LIST(last_error_func), 28962306a36Sopenharmony_ci ATTR_LIST(first_error_errcode), 29062306a36Sopenharmony_ci ATTR_LIST(last_error_errcode), 29162306a36Sopenharmony_ci ATTR_LIST(first_error_time), 29262306a36Sopenharmony_ci ATTR_LIST(last_error_time), 29362306a36Sopenharmony_ci ATTR_LIST(journal_task), 29462306a36Sopenharmony_ci#ifdef CONFIG_EXT4_DEBUG 29562306a36Sopenharmony_ci ATTR_LIST(simulate_fail), 29662306a36Sopenharmony_ci#endif 29762306a36Sopenharmony_ci ATTR_LIST(mb_prefetch), 29862306a36Sopenharmony_ci ATTR_LIST(mb_prefetch_limit), 29962306a36Sopenharmony_ci ATTR_LIST(last_trim_minblks), 30062306a36Sopenharmony_ci NULL, 30162306a36Sopenharmony_ci}; 30262306a36Sopenharmony_ciATTRIBUTE_GROUPS(ext4); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci/* Features this copy of ext4 supports */ 30562306a36Sopenharmony_ciEXT4_ATTR_FEATURE(lazy_itable_init); 30662306a36Sopenharmony_ciEXT4_ATTR_FEATURE(batched_discard); 30762306a36Sopenharmony_ciEXT4_ATTR_FEATURE(meta_bg_resize); 30862306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 30962306a36Sopenharmony_ciEXT4_ATTR_FEATURE(encryption); 31062306a36Sopenharmony_ciEXT4_ATTR_FEATURE(test_dummy_encryption_v2); 31162306a36Sopenharmony_ci#endif 31262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 31362306a36Sopenharmony_ciEXT4_ATTR_FEATURE(casefold); 31462306a36Sopenharmony_ci#endif 31562306a36Sopenharmony_ci#ifdef CONFIG_FS_VERITY 31662306a36Sopenharmony_ciEXT4_ATTR_FEATURE(verity); 31762306a36Sopenharmony_ci#endif 31862306a36Sopenharmony_ciEXT4_ATTR_FEATURE(metadata_csum_seed); 31962306a36Sopenharmony_ciEXT4_ATTR_FEATURE(fast_commit); 32062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION) 32162306a36Sopenharmony_ciEXT4_ATTR_FEATURE(encrypted_casefold); 32262306a36Sopenharmony_ci#endif 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic struct attribute *ext4_feat_attrs[] = { 32562306a36Sopenharmony_ci ATTR_LIST(lazy_itable_init), 32662306a36Sopenharmony_ci ATTR_LIST(batched_discard), 32762306a36Sopenharmony_ci ATTR_LIST(meta_bg_resize), 32862306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 32962306a36Sopenharmony_ci ATTR_LIST(encryption), 33062306a36Sopenharmony_ci ATTR_LIST(test_dummy_encryption_v2), 33162306a36Sopenharmony_ci#endif 33262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 33362306a36Sopenharmony_ci ATTR_LIST(casefold), 33462306a36Sopenharmony_ci#endif 33562306a36Sopenharmony_ci#ifdef CONFIG_FS_VERITY 33662306a36Sopenharmony_ci ATTR_LIST(verity), 33762306a36Sopenharmony_ci#endif 33862306a36Sopenharmony_ci ATTR_LIST(metadata_csum_seed), 33962306a36Sopenharmony_ci ATTR_LIST(fast_commit), 34062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) && defined(CONFIG_FS_ENCRYPTION) 34162306a36Sopenharmony_ci ATTR_LIST(encrypted_casefold), 34262306a36Sopenharmony_ci#endif 34362306a36Sopenharmony_ci NULL, 34462306a36Sopenharmony_ci}; 34562306a36Sopenharmony_ciATTRIBUTE_GROUPS(ext4_feat); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void *calc_ptr(struct ext4_attr *a, struct ext4_sb_info *sbi) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci switch (a->attr_ptr) { 35062306a36Sopenharmony_ci case ptr_explicit: 35162306a36Sopenharmony_ci return a->u.explicit_ptr; 35262306a36Sopenharmony_ci case ptr_ext4_sb_info_offset: 35362306a36Sopenharmony_ci return (void *) (((char *) sbi) + a->u.offset); 35462306a36Sopenharmony_ci case ptr_ext4_super_block_offset: 35562306a36Sopenharmony_ci return (void *) (((char *) sbi->s_es) + a->u.offset); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci return NULL; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic ssize_t __print_tstamp(char *buf, __le32 lo, __u8 hi) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci return sysfs_emit(buf, "%lld\n", 36362306a36Sopenharmony_ci ((time64_t)hi << 32) + le32_to_cpu(lo)); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci#define print_tstamp(buf, es, tstamp) \ 36762306a36Sopenharmony_ci __print_tstamp(buf, (es)->tstamp, (es)->tstamp ## _hi) 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic ssize_t ext4_attr_show(struct kobject *kobj, 37062306a36Sopenharmony_ci struct attribute *attr, char *buf) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, 37362306a36Sopenharmony_ci s_kobj); 37462306a36Sopenharmony_ci struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); 37562306a36Sopenharmony_ci void *ptr = calc_ptr(a, sbi); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci switch (a->attr_id) { 37862306a36Sopenharmony_ci case attr_delayed_allocation_blocks: 37962306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 38062306a36Sopenharmony_ci (s64) EXT4_C2B(sbi, 38162306a36Sopenharmony_ci percpu_counter_sum(&sbi->s_dirtyclusters_counter))); 38262306a36Sopenharmony_ci case attr_session_write_kbytes: 38362306a36Sopenharmony_ci return session_write_kbytes_show(sbi, buf); 38462306a36Sopenharmony_ci case attr_lifetime_write_kbytes: 38562306a36Sopenharmony_ci return lifetime_write_kbytes_show(sbi, buf); 38662306a36Sopenharmony_ci case attr_reserved_clusters: 38762306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 38862306a36Sopenharmony_ci (unsigned long long) 38962306a36Sopenharmony_ci atomic64_read(&sbi->s_resv_clusters)); 39062306a36Sopenharmony_ci case attr_sra_exceeded_retry_limit: 39162306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 39262306a36Sopenharmony_ci (unsigned long long) 39362306a36Sopenharmony_ci percpu_counter_sum(&sbi->s_sra_exceeded_retry_limit)); 39462306a36Sopenharmony_ci case attr_inode_readahead: 39562306a36Sopenharmony_ci case attr_pointer_ui: 39662306a36Sopenharmony_ci if (!ptr) 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci if (a->attr_ptr == ptr_ext4_super_block_offset) 39962306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", 40062306a36Sopenharmony_ci le32_to_cpup(ptr)); 40162306a36Sopenharmony_ci else 40262306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", 40362306a36Sopenharmony_ci *((unsigned int *) ptr)); 40462306a36Sopenharmony_ci case attr_pointer_ul: 40562306a36Sopenharmony_ci if (!ptr) 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", 40862306a36Sopenharmony_ci *((unsigned long *) ptr)); 40962306a36Sopenharmony_ci case attr_pointer_u8: 41062306a36Sopenharmony_ci if (!ptr) 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", 41362306a36Sopenharmony_ci *((unsigned char *) ptr)); 41462306a36Sopenharmony_ci case attr_pointer_u64: 41562306a36Sopenharmony_ci if (!ptr) 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci if (a->attr_ptr == ptr_ext4_super_block_offset) 41862306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 41962306a36Sopenharmony_ci le64_to_cpup(ptr)); 42062306a36Sopenharmony_ci else 42162306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 42262306a36Sopenharmony_ci *((unsigned long long *) ptr)); 42362306a36Sopenharmony_ci case attr_pointer_string: 42462306a36Sopenharmony_ci if (!ptr) 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci return sysfs_emit(buf, "%.*s\n", a->attr_size, 42762306a36Sopenharmony_ci (char *) ptr); 42862306a36Sopenharmony_ci case attr_pointer_atomic: 42962306a36Sopenharmony_ci if (!ptr) 43062306a36Sopenharmony_ci return 0; 43162306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", 43262306a36Sopenharmony_ci atomic_read((atomic_t *) ptr)); 43362306a36Sopenharmony_ci case attr_feature: 43462306a36Sopenharmony_ci return sysfs_emit(buf, "supported\n"); 43562306a36Sopenharmony_ci case attr_first_error_time: 43662306a36Sopenharmony_ci return print_tstamp(buf, sbi->s_es, s_first_error_time); 43762306a36Sopenharmony_ci case attr_last_error_time: 43862306a36Sopenharmony_ci return print_tstamp(buf, sbi->s_es, s_last_error_time); 43962306a36Sopenharmony_ci case attr_journal_task: 44062306a36Sopenharmony_ci return journal_task_show(sbi, buf); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic ssize_t ext4_attr_store(struct kobject *kobj, 44762306a36Sopenharmony_ci struct attribute *attr, 44862306a36Sopenharmony_ci const char *buf, size_t len) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, 45162306a36Sopenharmony_ci s_kobj); 45262306a36Sopenharmony_ci struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); 45362306a36Sopenharmony_ci void *ptr = calc_ptr(a, sbi); 45462306a36Sopenharmony_ci unsigned long t; 45562306a36Sopenharmony_ci int ret; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci switch (a->attr_id) { 45862306a36Sopenharmony_ci case attr_reserved_clusters: 45962306a36Sopenharmony_ci return reserved_clusters_store(sbi, buf, len); 46062306a36Sopenharmony_ci case attr_pointer_ui: 46162306a36Sopenharmony_ci if (!ptr) 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci ret = kstrtoul(skip_spaces(buf), 0, &t); 46462306a36Sopenharmony_ci if (ret) 46562306a36Sopenharmony_ci return ret; 46662306a36Sopenharmony_ci if (a->attr_ptr == ptr_ext4_super_block_offset) 46762306a36Sopenharmony_ci *((__le32 *) ptr) = cpu_to_le32(t); 46862306a36Sopenharmony_ci else 46962306a36Sopenharmony_ci *((unsigned int *) ptr) = t; 47062306a36Sopenharmony_ci return len; 47162306a36Sopenharmony_ci case attr_pointer_ul: 47262306a36Sopenharmony_ci if (!ptr) 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci ret = kstrtoul(skip_spaces(buf), 0, &t); 47562306a36Sopenharmony_ci if (ret) 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci *((unsigned long *) ptr) = t; 47862306a36Sopenharmony_ci return len; 47962306a36Sopenharmony_ci case attr_inode_readahead: 48062306a36Sopenharmony_ci return inode_readahead_blks_store(sbi, buf, len); 48162306a36Sopenharmony_ci case attr_trigger_test_error: 48262306a36Sopenharmony_ci return trigger_test_error(sbi, buf, len); 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void ext4_sb_release(struct kobject *kobj) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, 49062306a36Sopenharmony_ci s_kobj); 49162306a36Sopenharmony_ci complete(&sbi->s_kobj_unregister); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic void ext4_feat_release(struct kobject *kobj) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci kfree(kobj); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic const struct sysfs_ops ext4_attr_ops = { 50062306a36Sopenharmony_ci .show = ext4_attr_show, 50162306a36Sopenharmony_ci .store = ext4_attr_store, 50262306a36Sopenharmony_ci}; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic const struct kobj_type ext4_sb_ktype = { 50562306a36Sopenharmony_ci .default_groups = ext4_groups, 50662306a36Sopenharmony_ci .sysfs_ops = &ext4_attr_ops, 50762306a36Sopenharmony_ci .release = ext4_sb_release, 50862306a36Sopenharmony_ci}; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic const struct kobj_type ext4_feat_ktype = { 51162306a36Sopenharmony_ci .default_groups = ext4_feat_groups, 51262306a36Sopenharmony_ci .sysfs_ops = &ext4_attr_ops, 51362306a36Sopenharmony_ci .release = ext4_feat_release, 51462306a36Sopenharmony_ci}; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_civoid ext4_notify_error_sysfs(struct ext4_sb_info *sbi) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci sysfs_notify(&sbi->s_kobj, NULL, "errors_count"); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic struct kobject *ext4_root; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic struct kobject *ext4_feat; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ciint ext4_register_sysfs(struct super_block *sb) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 52862306a36Sopenharmony_ci int err; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci init_completion(&sbi->s_kobj_unregister); 53162306a36Sopenharmony_ci err = kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, ext4_root, 53262306a36Sopenharmony_ci "%s", sb->s_id); 53362306a36Sopenharmony_ci if (err) { 53462306a36Sopenharmony_ci kobject_put(&sbi->s_kobj); 53562306a36Sopenharmony_ci wait_for_completion(&sbi->s_kobj_unregister); 53662306a36Sopenharmony_ci return err; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (ext4_proc_root) 54062306a36Sopenharmony_ci sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); 54162306a36Sopenharmony_ci if (sbi->s_proc) { 54262306a36Sopenharmony_ci proc_create_single_data("options", S_IRUGO, sbi->s_proc, 54362306a36Sopenharmony_ci ext4_seq_options_show, sb); 54462306a36Sopenharmony_ci proc_create_single_data("es_shrinker_info", S_IRUGO, 54562306a36Sopenharmony_ci sbi->s_proc, ext4_seq_es_shrinker_info_show, 54662306a36Sopenharmony_ci sb); 54762306a36Sopenharmony_ci proc_create_single_data("fc_info", 0444, sbi->s_proc, 54862306a36Sopenharmony_ci ext4_fc_info_show, sb); 54962306a36Sopenharmony_ci proc_create_seq_data("mb_groups", S_IRUGO, sbi->s_proc, 55062306a36Sopenharmony_ci &ext4_mb_seq_groups_ops, sb); 55162306a36Sopenharmony_ci proc_create_single_data("mb_stats", 0444, sbi->s_proc, 55262306a36Sopenharmony_ci ext4_seq_mb_stats_show, sb); 55362306a36Sopenharmony_ci proc_create_seq_data("mb_structs_summary", 0444, sbi->s_proc, 55462306a36Sopenharmony_ci &ext4_mb_seq_structs_summary_ops, sb); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_civoid ext4_unregister_sysfs(struct super_block *sb) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (sbi->s_proc) 56462306a36Sopenharmony_ci remove_proc_subtree(sb->s_id, ext4_proc_root); 56562306a36Sopenharmony_ci kobject_del(&sbi->s_kobj); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ciint __init ext4_init_sysfs(void) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci int ret; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci ext4_root = kobject_create_and_add("ext4", fs_kobj); 57362306a36Sopenharmony_ci if (!ext4_root) 57462306a36Sopenharmony_ci return -ENOMEM; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci ext4_feat = kzalloc(sizeof(*ext4_feat), GFP_KERNEL); 57762306a36Sopenharmony_ci if (!ext4_feat) { 57862306a36Sopenharmony_ci ret = -ENOMEM; 57962306a36Sopenharmony_ci goto root_err; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci ret = kobject_init_and_add(ext4_feat, &ext4_feat_ktype, 58362306a36Sopenharmony_ci ext4_root, "features"); 58462306a36Sopenharmony_ci if (ret) 58562306a36Sopenharmony_ci goto feat_err; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci ext4_proc_root = proc_mkdir(proc_dirname, NULL); 58862306a36Sopenharmony_ci return ret; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cifeat_err: 59162306a36Sopenharmony_ci kobject_put(ext4_feat); 59262306a36Sopenharmony_ci ext4_feat = NULL; 59362306a36Sopenharmony_ciroot_err: 59462306a36Sopenharmony_ci kobject_put(ext4_root); 59562306a36Sopenharmony_ci ext4_root = NULL; 59662306a36Sopenharmony_ci return ret; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_civoid ext4_exit_sysfs(void) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci kobject_put(ext4_feat); 60262306a36Sopenharmony_ci ext4_feat = NULL; 60362306a36Sopenharmony_ci kobject_put(ext4_root); 60462306a36Sopenharmony_ci ext4_root = NULL; 60562306a36Sopenharmony_ci remove_proc_entry(proc_dirname, NULL); 60662306a36Sopenharmony_ci ext4_proc_root = NULL; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 609