// SPDX-License-Identifier: GPL-2.0/* * f2fs sysfs interface * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * Copyright (c) 2017 Chao Yu <chao@kernel.org> */#include <linux/compiler.h>#include <linux/proc_fs.h>#include <linux/f2fs_fs.h>#include <linux/seq_file.h>#include <linux/unicode.h>#include <linux/ioprio.h>#include <linux/sysfs.h> #include "f2fs.h"#include "segment.h"#include "gc.h"#include "iostat.h"#include <trace/events/f2fs.h> static struct proc_dir_entry *f2fs_proc_root; /* Sysfs support for f2fs */enum { GC_THREAD, /* struct f2fs_gc_thread */ SM_INFO, /* struct f2fs_sm_info */ DCC_INFO, /* struct discard_cmd_control */ NM_INFO, /* struct f2fs_nm_info */ F2FS_SBI, /* struct f2fs_sb_info */#ifdef CONFIG_F2FS_STAT_FS STAT_INFO, /* struct f2fs_stat_info */#endif#ifdef CONFIG_F2FS_FAULT_INJECTION FAULT_INFO_RATE, /* struct f2fs_fault_info */ FAULT_INFO_TYPE, /* struct f2fs_fault_info */ FAULT_INFO_TIMEOUT, /* struct f2fs_fault_info */#endif RESERVED_BLOCKS, /* struct f2fs_sb_info */ CPRC_INFO, /* struct ckpt_req_control */ ATGC_INFO, /* struct atgc_management */}; static const char *gc_mode_names[MAX_GC_MODE] = { "GC_NORMAL", "GC_IDLE_CB", "GC_IDLE_GREEDY", "GC_IDLE_AT", "GC_URGENT_HIGH", "GC_URGENT_LOW", "GC_URGENT_MID"}; struct f2fs_attr { struct attribute attr; ssize_t (*show)(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf); ssize_t (*store)(struct f2fs_attr *a, struct f2fs_sb_info *sbi, const char *buf, size_t len); int struct_type; int offset; int size; int id;}; struct f2fs_base_attr { struct attribute attr; ssize_t (*show)(struct f2fs_base_attr *a, char *buf); ssize_t (*store)(struct f2fs_base_attr *a, const char *buf, size_t len);}; static ssize_t f2fs_sbi_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf); static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type){ if (struct_type == GC_THREAD) return (unsigned char *)&sbi->gc_thread; else if (struct_type == SM_INFO) return (unsigned char *)SM_I(sbi); else if (struct_type == DCC_INFO) return (unsigned char *)SM_I(sbi)->dcc_info; else if (struct_type == NM_INFO) return (unsigned char *)NM_I(sbi); else if (struct_type == F2FS_SBI || struct_type == RESERVED_BLOCKS) return (unsigned char *)sbi;#ifdef CONFIG_F2FS_FAULT_INJECTION else if (struct_type == FAULT_INFO_RATE || struct_type == FAULT_INFO_TYPE || struct_type == FAULT_INFO_TIMEOUT) return (unsigned char *)&F2FS_OPTION(sbi).fault_info;#endif#ifdef CONFIG_F2FS_STAT_FS else if (struct_type == STAT_INFO) return (unsigned char *)F2FS_STAT(sbi);#endif else if (struct_type == CPRC_INFO) return (unsigned char *)&sbi->cprc_info; else if (struct_type == ATGC_INFO) return (unsigned char *)&sbi->am; return NULL;} static ssize_t dirty_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%llu\n", (unsigned long long)(dirty_segments(sbi)));} static ssize_t free_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%llu\n", (unsigned long long)(free_segments(sbi)));} static ssize_t ovp_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%llu\n", (unsigned long long)(overprovision_segments(sbi)));} static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%llu\n", (unsigned long long)(sbi->kbytes_written + ((f2fs_get_sectors_written(sbi) - sbi->sectors_written_start) >> 1)));} static ssize_t sb_status_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%lx\n", sbi->s_flag);} static ssize_t cp_status_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%x\n", le32_to_cpu(F2FS_CKPT(sbi)->ckpt_flags));} static ssize_t pending_discard_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read( &SM_I(sbi)->dcc_info->discard_cmd_cnt));} static ssize_t issued_discard_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read( &SM_I(sbi)->dcc_info->issued_discard));} static ssize_t queued_discard_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read( &SM_I(sbi)->dcc_info->queued_discard));} static ssize_t undiscard_blks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%u\n", SM_I(sbi)->dcc_info->undiscard_blks);} static ssize_t atgc_enabled_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%d\n", sbi->am.atgc_enabled ? 1 : 0);} static ssize_t gc_mode_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%s\n", gc_mode_names[sbi->gc_mode]);} static ssize_t features_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ int len = 0; if (f2fs_sb_has_encrypt(sbi)) len += sysfs_emit_at(buf, len, "%s", "encryption"); if (f2fs_sb_has_blkzoned(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "blkzoned"); if (f2fs_sb_has_extra_attr(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "extra_attr"); if (f2fs_sb_has_project_quota(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "projquota"); if (f2fs_sb_has_inode_chksum(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "inode_checksum"); if (f2fs_sb_has_flexible_inline_xattr(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "flexible_inline_xattr"); if (f2fs_sb_has_quota_ino(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "quota_ino"); if (f2fs_sb_has_inode_crtime(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "inode_crtime"); if (f2fs_sb_has_lost_found(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "lost_found"); if (f2fs_sb_has_verity(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "verity"); if (f2fs_sb_has_sb_chksum(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "sb_checksum"); if (f2fs_sb_has_casefold(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "casefold"); if (f2fs_sb_has_readonly(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "readonly"); if (f2fs_sb_has_compression(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "compression"); if (f2fs_sb_has_packed_ssa(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "packed_ssa"); len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "pin_file"); len += sysfs_emit_at(buf, len, "\n"); return len;} static ssize_t current_reserved_blocks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%u\n", sbi->current_reserved_blocks);} static ssize_t unusable_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ block_t unusable; if (test_opt(sbi, DISABLE_CHECKPOINT)) unusable = sbi->unusable_block_count; else unusable = f2fs_get_unusable_blocks(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)unusable);} static ssize_t encoding_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){#if IS_ENABLED(CONFIG_UNICODE) struct super_block *sb = sbi->sb; if (f2fs_sb_has_casefold(sbi)) return sysfs_emit(buf, "UTF-8 (%d.%d.%d)\n", (sb->s_encoding->version >> 16) & 0xff, (sb->s_encoding->version >> 8) & 0xff, sb->s_encoding->version & 0xff);#endif return sysfs_emit(buf, "(none)\n");} static ssize_t encoding_flags_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%x\n", le16_to_cpu(F2FS_RAW_SUPER(sbi)->s_encoding_flags));} static ssize_t effective_lookup_mode_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ switch (F2FS_OPTION(sbi).lookup_mode) { case LOOKUP_PERF: return sysfs_emit(buf, "perf\n"); case LOOKUP_COMPAT: return sysfs_emit(buf, "compat\n"); case LOOKUP_AUTO: if (sb_no_casefold_compat_fallback(sbi->sb)) return sysfs_emit(buf, "auto:perf\n"); return sysfs_emit(buf, "auto:compat\n"); } return 0;} static ssize_t mounted_time_sec_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%llu\n", SIT_I(sbi)->mounted_time);} #ifdef CONFIG_F2FS_STAT_FSstatic ssize_t moved_blocks_foreground_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ struct f2fs_stat_info *si = F2FS_STAT(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->tot_blks - (si->bg_data_blks + si->bg_node_blks)));} static ssize_t moved_blocks_background_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ struct f2fs_stat_info *si = F2FS_STAT(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->bg_data_blks + si->bg_node_blks));} static ssize_t avg_vblocks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ struct f2fs_stat_info *si = F2FS_STAT(sbi); si->dirty_count = dirty_segments(sbi); f2fs_update_sit_info(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->avg_vblocks));} static ssize_t defrag_blocks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ struct f2fs_stat_info *si = F2FS_STAT(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->defrag_blks));}#endif static ssize_t main_blkaddr_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ return sysfs_emit(buf, "%llu\n", (unsigned long long)MAIN_BLKADDR(sbi));} static ssize_t __sbi_show_value(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf, unsigned char *value){ switch (a->size) { case 1: return sysfs_emit(buf, "%u\n", *(u8 *)value); case 2: return sysfs_emit(buf, "%u\n", *(u16 *)value); case 4: return sysfs_emit(buf, "%u\n", *(u32 *)value); case 8: return sysfs_emit(buf, "%llu\n", *(u64 *)value); default: f2fs_bug_on(sbi, 1); return sysfs_emit(buf, "show sysfs node value with wrong type\n"); }} static ssize_t f2fs_sbi_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf){ unsigned char *ptr = NULL; ptr = __struct_ptr(sbi, a->struct_type); if (!ptr) return -EINVAL; if (!strcmp(a->attr.name, "extension_list")) { __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; int cold_count, hot_count; int len = 0, i; f2fs_down_read(&sbi->sb_lock); cold_count = le32_to_cpu(sbi->raw_super->extension_count); hot_count = sbi->raw_super->hot_ext_count; len += sysfs_emit_at(buf, len, "cold file extension:\n"); for (i = 0; i < cold_count; i++) len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); len += sysfs_emit_at(buf, len, "hot file extension:\n"); for (i = cold_count; i < cold_count + hot_count; i++) len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); f2fs_up_read(&sbi->sb_lock); return len; } if (!strcmp(a->attr.name, "ckpt_thread_ioprio")) { struct ckpt_req_control *cprc = &sbi->cprc_info; int class = IOPRIO_PRIO_CLASS(cprc->ckpt_thread_ioprio); int level = IOPRIO_PRIO_LEVEL(cprc->ckpt_thread_ioprio); if (class != IOPRIO_CLASS_RT && class != IOPRIO_CLASS_BE) return -EINVAL; return sysfs_emit(buf, "%s,%d\n", class == IOPRIO_CLASS_RT ? "rt" : "be", level); } #ifdef CONFIG_F2FS_FS_COMPRESSION if (!strcmp(a->attr.name, "compr_written_block")) return sysfs_emit(buf, "%llu\n", sbi->compr_written_block); if (!strcmp(a->attr.name, "compr_saved_block")) return sysfs_emit(buf, "%llu\n", sbi->compr_saved_block); if (!strcmp(a->attr.name, "compr_new_inode")) return sysfs_emit(buf, "%u\n", sbi->compr_new_inode);#endif if (!strcmp(a->attr.name, "gc_segment_mode")) return sysfs_emit(buf, "%u\n", sbi->gc_segment_mode); if (!strcmp(a->attr.name, "gc_reclaimed_segments")) { return sysfs_emit(buf, "%u\n", sbi->gc_reclaimed_segs[sbi->gc_segment_mode]); } if (!strcmp(a->attr.name, "current_atomic_write")) { s64 current_write = atomic64_read(&sbi->current_atomic_write); return sysfs_emit(buf, "%lld\n", current_write); } if (!strcmp(a->attr.name, "peak_atomic_write")) return sysfs_emit(buf, "%lld\n", sbi->peak_atomic_write); if (!strcmp(a->attr.name, "committed_atomic_block")) return sysfs_emit(buf, "%llu\n", sbi->committed_atomic_block); if (!strcmp(a->attr.name, "revoked_atomic_block")) return sysfs_emit(buf, "%llu\n", sbi->revoked_atomic_block); #ifdef CONFIG_F2FS_STAT_FS if (!strcmp(a->attr.name, "cp_foreground_calls")) return sysfs_emit(buf, "%d\n", atomic_read(&sbi->cp_call_count[TOTAL_CALL]) - atomic_read(&sbi->cp_call_count[BACKGROUND])); if (!strcmp(a->attr.name, "cp_background_calls")) return sysfs_emit(buf, "%d\n", atomic_read(&sbi->cp_call_count[BACKGROUND]));#endif return __sbi_show_value(a, sbi, buf, ptr + a->offset);} static void __sbi_store_value(struct f2fs_attr *a, struct f2fs_sb_info *sbi, unsigned char *ui, unsigned long value){ switch (a->size) { case 1: *(u8 *)ui = value; break; case 2: *(u16 *)ui = value; break; case 4: *(u32 *)ui = value; break; case 8: *(u64 *)ui = value; break; default: f2fs_bug_on(sbi, 1); f2fs_err(sbi, "store sysfs node value with wrong type"); }} static ssize_t __sbi_store(struct f2fs_attr *a, struct f2fs_sb_info *sbi, const char *buf, size_t count){ unsigned char *ptr; unsigned long t; unsigned int *ui; ssize_t ret; ptr = __struct_ptr(sbi, a->struct_type); if (!ptr)Lines 1–500 of 2118. Load more
// SPDX-License-Identifier: GPL-2.0 /* * f2fs sysfs interface * * Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * Copyright (c) 2017 Chao Yu <chao@kernel.org> */ #include <linux/compiler.h> #include <linux/proc_fs.h> #include <linux/f2fs_fs.h> #include <linux/seq_file.h> #include <linux/unicode.h> #include <linux/ioprio.h> #include <linux/sysfs.h> #include "f2fs.h" #include "segment.h" #include "gc.h" #include "iostat.h" #include <trace/events/f2fs.h> static struct proc_dir_entry *f2fs_proc_root; /* Sysfs support for f2fs */ enum { GC_THREAD, /* struct f2fs_gc_thread */ SM_INFO, /* struct f2fs_sm_info */ DCC_INFO, /* struct discard_cmd_control */ NM_INFO, /* struct f2fs_nm_info */ F2FS_SBI, /* struct f2fs_sb_info */ #ifdef CONFIG_F2FS_STAT_FS STAT_INFO, /* struct f2fs_stat_info */ #endif #ifdef CONFIG_F2FS_FAULT_INJECTION FAULT_INFO_RATE, /* struct f2fs_fault_info */ FAULT_INFO_TYPE, /* struct f2fs_fault_info */ FAULT_INFO_TIMEOUT, /* struct f2fs_fault_info */ #endif RESERVED_BLOCKS, /* struct f2fs_sb_info */ CPRC_INFO, /* struct ckpt_req_control */ ATGC_INFO, /* struct atgc_management */ }; static const char *gc_mode_names[MAX_GC_MODE] = { "GC_NORMAL", "GC_IDLE_CB", "GC_IDLE_GREEDY", "GC_IDLE_AT", "GC_URGENT_HIGH", "GC_URGENT_LOW", "GC_URGENT_MID" }; struct f2fs_attr { struct attribute attr; ssize_t (*show)(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf); ssize_t (*store)(struct f2fs_attr *a, struct f2fs_sb_info *sbi, const char *buf, size_t len); int struct_type; int offset; int size; int id; }; struct f2fs_base_attr { struct attribute attr; ssize_t (*show)(struct f2fs_base_attr *a, char *buf); ssize_t (*store)(struct f2fs_base_attr *a, const char *buf, size_t len); }; static ssize_t f2fs_sbi_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf); static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) { if (struct_type == GC_THREAD) return (unsigned char *)&sbi->gc_thread; else if (struct_type == SM_INFO) return (unsigned char *)SM_I(sbi); else if (struct_type == DCC_INFO) return (unsigned char *)SM_I(sbi)->dcc_info; else if (struct_type == NM_INFO) return (unsigned char *)NM_I(sbi); else if (struct_type == F2FS_SBI || struct_type == RESERVED_BLOCKS) return (unsigned char *)sbi; #ifdef CONFIG_F2FS_FAULT_INJECTION else if (struct_type == FAULT_INFO_RATE || struct_type == FAULT_INFO_TYPE || struct_type == FAULT_INFO_TIMEOUT) return (unsigned char *)&F2FS_OPTION(sbi).fault_info; #endif #ifdef CONFIG_F2FS_STAT_FS else if (struct_type == STAT_INFO) return (unsigned char *)F2FS_STAT(sbi); #endif else if (struct_type == CPRC_INFO) return (unsigned char *)&sbi->cprc_info; else if (struct_type == ATGC_INFO) return (unsigned char *)&sbi->am; return NULL; } static ssize_t dirty_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%llu\n", (unsigned long long)(dirty_segments(sbi))); } static ssize_t free_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%llu\n", (unsigned long long)(free_segments(sbi))); } static ssize_t ovp_segments_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%llu\n", (unsigned long long)(overprovision_segments(sbi))); } static ssize_t lifetime_write_kbytes_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%llu\n", (unsigned long long)(sbi->kbytes_written + ((f2fs_get_sectors_written(sbi) - sbi->sectors_written_start) >> 1))); } static ssize_t sb_status_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%lx\n", sbi->s_flag); } static ssize_t cp_status_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%x\n", le32_to_cpu(F2FS_CKPT(sbi)->ckpt_flags)); } static ssize_t pending_discard_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read( &SM_I(sbi)->dcc_info->discard_cmd_cnt)); } static ssize_t issued_discard_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read( &SM_I(sbi)->dcc_info->issued_discard)); } static ssize_t queued_discard_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%llu\n", (unsigned long long)atomic_read( &SM_I(sbi)->dcc_info->queued_discard)); } static ssize_t undiscard_blks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { if (!SM_I(sbi)->dcc_info) return -EINVAL; return sysfs_emit(buf, "%u\n", SM_I(sbi)->dcc_info->undiscard_blks); } static ssize_t atgc_enabled_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%d\n", sbi->am.atgc_enabled ? 1 : 0); } static ssize_t gc_mode_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%s\n", gc_mode_names[sbi->gc_mode]); } static ssize_t features_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { int len = 0; if (f2fs_sb_has_encrypt(sbi)) len += sysfs_emit_at(buf, len, "%s", "encryption"); if (f2fs_sb_has_blkzoned(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "blkzoned"); if (f2fs_sb_has_extra_attr(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "extra_attr"); if (f2fs_sb_has_project_quota(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "projquota"); if (f2fs_sb_has_inode_chksum(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "inode_checksum"); if (f2fs_sb_has_flexible_inline_xattr(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "flexible_inline_xattr"); if (f2fs_sb_has_quota_ino(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "quota_ino"); if (f2fs_sb_has_inode_crtime(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "inode_crtime"); if (f2fs_sb_has_lost_found(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "lost_found"); if (f2fs_sb_has_verity(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "verity"); if (f2fs_sb_has_sb_chksum(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "sb_checksum"); if (f2fs_sb_has_casefold(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "casefold"); if (f2fs_sb_has_readonly(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "readonly"); if (f2fs_sb_has_compression(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "compression"); if (f2fs_sb_has_packed_ssa(sbi)) len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "packed_ssa"); len += sysfs_emit_at(buf, len, "%s%s", len ? ", " : "", "pin_file"); len += sysfs_emit_at(buf, len, "\n"); return len; } static ssize_t current_reserved_blocks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%u\n", sbi->current_reserved_blocks); } static ssize_t unusable_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { block_t unusable; if (test_opt(sbi, DISABLE_CHECKPOINT)) unusable = sbi->unusable_block_count; else unusable = f2fs_get_unusable_blocks(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)unusable); } static ssize_t encoding_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { #if IS_ENABLED(CONFIG_UNICODE) struct super_block *sb = sbi->sb; if (f2fs_sb_has_casefold(sbi)) return sysfs_emit(buf, "UTF-8 (%d.%d.%d)\n", (sb->s_encoding->version >> 16) & 0xff, (sb->s_encoding->version >> 8) & 0xff, sb->s_encoding->version & 0xff); #endif return sysfs_emit(buf, "(none)\n"); } static ssize_t encoding_flags_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%x\n", le16_to_cpu(F2FS_RAW_SUPER(sbi)->s_encoding_flags)); } static ssize_t effective_lookup_mode_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { switch (F2FS_OPTION(sbi).lookup_mode) { case LOOKUP_PERF: return sysfs_emit(buf, "perf\n"); case LOOKUP_COMPAT: return sysfs_emit(buf, "compat\n"); case LOOKUP_AUTO: if (sb_no_casefold_compat_fallback(sbi->sb)) return sysfs_emit(buf, "auto:perf\n"); return sysfs_emit(buf, "auto:compat\n"); } return 0; } static ssize_t mounted_time_sec_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%llu\n", SIT_I(sbi)->mounted_time); } #ifdef CONFIG_F2FS_STAT_FS static ssize_t moved_blocks_foreground_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { struct f2fs_stat_info *si = F2FS_STAT(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->tot_blks - (si->bg_data_blks + si->bg_node_blks))); } static ssize_t moved_blocks_background_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { struct f2fs_stat_info *si = F2FS_STAT(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->bg_data_blks + si->bg_node_blks)); } static ssize_t avg_vblocks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { struct f2fs_stat_info *si = F2FS_STAT(sbi); si->dirty_count = dirty_segments(sbi); f2fs_update_sit_info(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->avg_vblocks)); } static ssize_t defrag_blocks_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { struct f2fs_stat_info *si = F2FS_STAT(sbi); return sysfs_emit(buf, "%llu\n", (unsigned long long)(si->defrag_blks)); } #endif static ssize_t main_blkaddr_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { return sysfs_emit(buf, "%llu\n", (unsigned long long)MAIN_BLKADDR(sbi)); } static ssize_t __sbi_show_value(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf, unsigned char *value) { switch (a->size) { case 1: return sysfs_emit(buf, "%u\n", *(u8 *)value); case 2: return sysfs_emit(buf, "%u\n", *(u16 *)value); case 4: return sysfs_emit(buf, "%u\n", *(u32 *)value); case 8: return sysfs_emit(buf, "%llu\n", *(u64 *)value); default: f2fs_bug_on(sbi, 1); return sysfs_emit(buf, "show sysfs node value with wrong type\n"); } } static ssize_t f2fs_sbi_show(struct f2fs_attr *a, struct f2fs_sb_info *sbi, char *buf) { unsigned char *ptr = NULL; ptr = __struct_ptr(sbi, a->struct_type); if (!ptr) return -EINVAL; if (!strcmp(a->attr.name, "extension_list")) { __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; int cold_count, hot_count; int len = 0, i; f2fs_down_read(&sbi->sb_lock); cold_count = le32_to_cpu(sbi->raw_super->extension_count); hot_count = sbi->raw_super->hot_ext_count; len += sysfs_emit_at(buf, len, "cold file extension:\n"); for (i = 0; i < cold_count; i++) len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); len += sysfs_emit_at(buf, len, "hot file extension:\n"); for (i = cold_count; i < cold_count + hot_count; i++) len += sysfs_emit_at(buf, len, "%s\n", extlist[i]); f2fs_up_read(&sbi->sb_lock); return len; } if (!strcmp(a->attr.name, "ckpt_thread_ioprio")) { struct ckpt_req_control *cprc = &sbi->cprc_info; int class = IOPRIO_PRIO_CLASS(cprc->ckpt_thread_ioprio); int level = IOPRIO_PRIO_LEVEL(cprc->ckpt_thread_ioprio); if (class != IOPRIO_CLASS_RT && class != IOPRIO_CLASS_BE) return -EINVAL; return sysfs_emit(buf, "%s,%d\n", class == IOPRIO_CLASS_RT ? "rt" : "be", level); } #ifdef CONFIG_F2FS_FS_COMPRESSION if (!strcmp(a->attr.name, "compr_written_block")) return sysfs_emit(buf, "%llu\n", sbi->compr_written_block); if (!strcmp(a->attr.name, "compr_saved_block")) return sysfs_emit(buf, "%llu\n", sbi->compr_saved_block); if (!strcmp(a->attr.name, "compr_new_inode")) return sysfs_emit(buf, "%u\n", sbi->compr_new_inode); #endif if (!strcmp(a->attr.name, "gc_segment_mode")) return sysfs_emit(buf, "%u\n", sbi->gc_segment_mode); if (!strcmp(a->attr.name, "gc_reclaimed_segments")) { return sysfs_emit(buf, "%u\n", sbi->gc_reclaimed_segs[sbi->gc_segment_mode]); } if (!strcmp(a->attr.name, "current_atomic_write")) { s64 current_write = atomic64_read(&sbi->current_atomic_write); return sysfs_emit(buf, "%lld\n", current_write); } if (!strcmp(a->attr.name, "peak_atomic_write")) return sysfs_emit(buf, "%lld\n", sbi->peak_atomic_write); if (!strcmp(a->attr.name, "committed_atomic_block")) return sysfs_emit(buf, "%llu\n", sbi->committed_atomic_block); if (!strcmp(a->attr.name, "revoked_atomic_block")) return sysfs_emit(buf, "%llu\n", sbi->revoked_atomic_block); #ifdef CONFIG_F2FS_STAT_FS if (!strcmp(a->attr.name, "cp_foreground_calls")) return sysfs_emit(buf, "%d\n", atomic_read(&sbi->cp_call_count[TOTAL_CALL]) - atomic_read(&sbi->cp_call_count[BACKGROUND])); if (!strcmp(a->attr.name, "cp_background_calls")) return sysfs_emit(buf, "%d\n", atomic_read(&sbi->cp_call_count[BACKGROUND])); #endif return __sbi_show_value(a, sbi, buf, ptr + a->offset); } static void __sbi_store_value(struct f2fs_attr *a, struct f2fs_sb_info *sbi, unsigned char *ui, unsigned long value) { switch (a->size) { case 1: *(u8 *)ui = value; break; case 2: *(u16 *)ui = value; break; case 4: *(u32 *)ui = value; break; case 8: *(u64 *)ui = value; break; default: f2fs_bug_on(sbi, 1); f2fs_err(sbi, "store sysfs node value with wrong type"); } } static ssize_t __sbi_store(struct f2fs_attr *a, struct f2fs_sb_info *sbi, const char *buf, size_t count) { unsigned char *ptr; unsigned long t; unsigned int *ui; ssize_t ret; ptr = __struct_ptr(sbi, a->struct_type); if (!ptr)