162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014 Red Hat, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "xfs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_log_format.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_sysfs.h" 1362306a36Sopenharmony_ci#include "xfs_log.h" 1462306a36Sopenharmony_ci#include "xfs_log_priv.h" 1562306a36Sopenharmony_ci#include "xfs_mount.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct xfs_sysfs_attr { 1862306a36Sopenharmony_ci struct attribute attr; 1962306a36Sopenharmony_ci ssize_t (*show)(struct kobject *kobject, char *buf); 2062306a36Sopenharmony_ci ssize_t (*store)(struct kobject *kobject, const char *buf, 2162306a36Sopenharmony_ci size_t count); 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic inline struct xfs_sysfs_attr * 2562306a36Sopenharmony_cito_attr(struct attribute *attr) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci return container_of(attr, struct xfs_sysfs_attr, attr); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define XFS_SYSFS_ATTR_RW(name) \ 3162306a36Sopenharmony_ci static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RW(name) 3262306a36Sopenharmony_ci#define XFS_SYSFS_ATTR_RO(name) \ 3362306a36Sopenharmony_ci static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RO(name) 3462306a36Sopenharmony_ci#define XFS_SYSFS_ATTR_WO(name) \ 3562306a36Sopenharmony_ci static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_WO(name) 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciSTATIC ssize_t 4062306a36Sopenharmony_cixfs_sysfs_object_show( 4162306a36Sopenharmony_ci struct kobject *kobject, 4262306a36Sopenharmony_ci struct attribute *attr, 4362306a36Sopenharmony_ci char *buf) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct xfs_sysfs_attr *xfs_attr = to_attr(attr); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return xfs_attr->show ? xfs_attr->show(kobject, buf) : 0; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciSTATIC ssize_t 5162306a36Sopenharmony_cixfs_sysfs_object_store( 5262306a36Sopenharmony_ci struct kobject *kobject, 5362306a36Sopenharmony_ci struct attribute *attr, 5462306a36Sopenharmony_ci const char *buf, 5562306a36Sopenharmony_ci size_t count) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct xfs_sysfs_attr *xfs_attr = to_attr(attr); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return xfs_attr->store ? xfs_attr->store(kobject, buf, count) : 0; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const struct sysfs_ops xfs_sysfs_ops = { 6362306a36Sopenharmony_ci .show = xfs_sysfs_object_show, 6462306a36Sopenharmony_ci .store = xfs_sysfs_object_store, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic struct attribute *xfs_mp_attrs[] = { 6862306a36Sopenharmony_ci NULL, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ciATTRIBUTE_GROUPS(xfs_mp); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciconst struct kobj_type xfs_mp_ktype = { 7362306a36Sopenharmony_ci .release = xfs_sysfs_release, 7462306a36Sopenharmony_ci .sysfs_ops = &xfs_sysfs_ops, 7562306a36Sopenharmony_ci .default_groups = xfs_mp_groups, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#ifdef DEBUG 7962306a36Sopenharmony_ci/* debug */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ciSTATIC ssize_t 8262306a36Sopenharmony_cibug_on_assert_store( 8362306a36Sopenharmony_ci struct kobject *kobject, 8462306a36Sopenharmony_ci const char *buf, 8562306a36Sopenharmony_ci size_t count) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci int ret; 8862306a36Sopenharmony_ci int val; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 9162306a36Sopenharmony_ci if (ret) 9262306a36Sopenharmony_ci return ret; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (val == 1) 9562306a36Sopenharmony_ci xfs_globals.bug_on_assert = true; 9662306a36Sopenharmony_ci else if (val == 0) 9762306a36Sopenharmony_ci xfs_globals.bug_on_assert = false; 9862306a36Sopenharmony_ci else 9962306a36Sopenharmony_ci return -EINVAL; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return count; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciSTATIC ssize_t 10562306a36Sopenharmony_cibug_on_assert_show( 10662306a36Sopenharmony_ci struct kobject *kobject, 10762306a36Sopenharmony_ci char *buf) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", xfs_globals.bug_on_assert); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(bug_on_assert); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciSTATIC ssize_t 11462306a36Sopenharmony_cilog_recovery_delay_store( 11562306a36Sopenharmony_ci struct kobject *kobject, 11662306a36Sopenharmony_ci const char *buf, 11762306a36Sopenharmony_ci size_t count) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci int ret; 12062306a36Sopenharmony_ci int val; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 12362306a36Sopenharmony_ci if (ret) 12462306a36Sopenharmony_ci return ret; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (val < 0 || val > 60) 12762306a36Sopenharmony_ci return -EINVAL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci xfs_globals.log_recovery_delay = val; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return count; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciSTATIC ssize_t 13562306a36Sopenharmony_cilog_recovery_delay_show( 13662306a36Sopenharmony_ci struct kobject *kobject, 13762306a36Sopenharmony_ci char *buf) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", xfs_globals.log_recovery_delay); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(log_recovery_delay); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciSTATIC ssize_t 14462306a36Sopenharmony_cimount_delay_store( 14562306a36Sopenharmony_ci struct kobject *kobject, 14662306a36Sopenharmony_ci const char *buf, 14762306a36Sopenharmony_ci size_t count) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci int ret; 15062306a36Sopenharmony_ci int val; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 15362306a36Sopenharmony_ci if (ret) 15462306a36Sopenharmony_ci return ret; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (val < 0 || val > 60) 15762306a36Sopenharmony_ci return -EINVAL; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci xfs_globals.mount_delay = val; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return count; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ciSTATIC ssize_t 16562306a36Sopenharmony_cimount_delay_show( 16662306a36Sopenharmony_ci struct kobject *kobject, 16762306a36Sopenharmony_ci char *buf) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", xfs_globals.mount_delay); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(mount_delay); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic ssize_t 17462306a36Sopenharmony_cialways_cow_store( 17562306a36Sopenharmony_ci struct kobject *kobject, 17662306a36Sopenharmony_ci const char *buf, 17762306a36Sopenharmony_ci size_t count) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci ssize_t ret; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ret = kstrtobool(buf, &xfs_globals.always_cow); 18262306a36Sopenharmony_ci if (ret < 0) 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci return count; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic ssize_t 18862306a36Sopenharmony_cialways_cow_show( 18962306a36Sopenharmony_ci struct kobject *kobject, 19062306a36Sopenharmony_ci char *buf) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", xfs_globals.always_cow); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(always_cow); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#ifdef DEBUG 19762306a36Sopenharmony_ci/* 19862306a36Sopenharmony_ci * Override how many threads the parallel work queue is allowed to create. 19962306a36Sopenharmony_ci * This has to be a debug-only global (instead of an errortag) because one of 20062306a36Sopenharmony_ci * the main users of parallel workqueues is mount time quotacheck. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ciSTATIC ssize_t 20362306a36Sopenharmony_cipwork_threads_store( 20462306a36Sopenharmony_ci struct kobject *kobject, 20562306a36Sopenharmony_ci const char *buf, 20662306a36Sopenharmony_ci size_t count) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci int ret; 20962306a36Sopenharmony_ci int val; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 21262306a36Sopenharmony_ci if (ret) 21362306a36Sopenharmony_ci return ret; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (val < -1 || val > num_possible_cpus()) 21662306a36Sopenharmony_ci return -EINVAL; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci xfs_globals.pwork_threads = val; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return count; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciSTATIC ssize_t 22462306a36Sopenharmony_cipwork_threads_show( 22562306a36Sopenharmony_ci struct kobject *kobject, 22662306a36Sopenharmony_ci char *buf) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", xfs_globals.pwork_threads); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(pwork_threads); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic ssize_t 23362306a36Sopenharmony_cilarp_store( 23462306a36Sopenharmony_ci struct kobject *kobject, 23562306a36Sopenharmony_ci const char *buf, 23662306a36Sopenharmony_ci size_t count) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci ssize_t ret; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci ret = kstrtobool(buf, &xfs_globals.larp); 24162306a36Sopenharmony_ci if (ret < 0) 24262306a36Sopenharmony_ci return ret; 24362306a36Sopenharmony_ci return count; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciSTATIC ssize_t 24762306a36Sopenharmony_cilarp_show( 24862306a36Sopenharmony_ci struct kobject *kobject, 24962306a36Sopenharmony_ci char *buf) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.larp); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(larp); 25462306a36Sopenharmony_ci#endif /* DEBUG */ 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic struct attribute *xfs_dbg_attrs[] = { 25762306a36Sopenharmony_ci ATTR_LIST(bug_on_assert), 25862306a36Sopenharmony_ci ATTR_LIST(log_recovery_delay), 25962306a36Sopenharmony_ci ATTR_LIST(mount_delay), 26062306a36Sopenharmony_ci ATTR_LIST(always_cow), 26162306a36Sopenharmony_ci#ifdef DEBUG 26262306a36Sopenharmony_ci ATTR_LIST(pwork_threads), 26362306a36Sopenharmony_ci ATTR_LIST(larp), 26462306a36Sopenharmony_ci#endif 26562306a36Sopenharmony_ci NULL, 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ciATTRIBUTE_GROUPS(xfs_dbg); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ciconst struct kobj_type xfs_dbg_ktype = { 27062306a36Sopenharmony_ci .release = xfs_sysfs_release, 27162306a36Sopenharmony_ci .sysfs_ops = &xfs_sysfs_ops, 27262306a36Sopenharmony_ci .default_groups = xfs_dbg_groups, 27362306a36Sopenharmony_ci}; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci#endif /* DEBUG */ 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/* stats */ 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic inline struct xstats * 28062306a36Sopenharmony_cito_xstats(struct kobject *kobject) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci struct xfs_kobj *kobj = to_kobj(kobject); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return container_of(kobj, struct xstats, xs_kobj); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ciSTATIC ssize_t 28862306a36Sopenharmony_cistats_show( 28962306a36Sopenharmony_ci struct kobject *kobject, 29062306a36Sopenharmony_ci char *buf) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct xstats *stats = to_xstats(kobject); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return xfs_stats_format(stats->xs_stats, buf); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ciXFS_SYSFS_ATTR_RO(stats); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciSTATIC ssize_t 29962306a36Sopenharmony_cistats_clear_store( 30062306a36Sopenharmony_ci struct kobject *kobject, 30162306a36Sopenharmony_ci const char *buf, 30262306a36Sopenharmony_ci size_t count) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci int ret; 30562306a36Sopenharmony_ci int val; 30662306a36Sopenharmony_ci struct xstats *stats = to_xstats(kobject); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 30962306a36Sopenharmony_ci if (ret) 31062306a36Sopenharmony_ci return ret; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (val != 1) 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci xfs_stats_clearall(stats->xs_stats); 31662306a36Sopenharmony_ci return count; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ciXFS_SYSFS_ATTR_WO(stats_clear); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic struct attribute *xfs_stats_attrs[] = { 32162306a36Sopenharmony_ci ATTR_LIST(stats), 32262306a36Sopenharmony_ci ATTR_LIST(stats_clear), 32362306a36Sopenharmony_ci NULL, 32462306a36Sopenharmony_ci}; 32562306a36Sopenharmony_ciATTRIBUTE_GROUPS(xfs_stats); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ciconst struct kobj_type xfs_stats_ktype = { 32862306a36Sopenharmony_ci .release = xfs_sysfs_release, 32962306a36Sopenharmony_ci .sysfs_ops = &xfs_sysfs_ops, 33062306a36Sopenharmony_ci .default_groups = xfs_stats_groups, 33162306a36Sopenharmony_ci}; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci/* xlog */ 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic inline struct xlog * 33662306a36Sopenharmony_cito_xlog(struct kobject *kobject) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct xfs_kobj *kobj = to_kobj(kobject); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return container_of(kobj, struct xlog, l_kobj); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciSTATIC ssize_t 34462306a36Sopenharmony_cilog_head_lsn_show( 34562306a36Sopenharmony_ci struct kobject *kobject, 34662306a36Sopenharmony_ci char *buf) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci int cycle; 34962306a36Sopenharmony_ci int block; 35062306a36Sopenharmony_ci struct xlog *log = to_xlog(kobject); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci spin_lock(&log->l_icloglock); 35362306a36Sopenharmony_ci cycle = log->l_curr_cycle; 35462306a36Sopenharmony_ci block = log->l_curr_block; 35562306a36Sopenharmony_ci spin_unlock(&log->l_icloglock); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return sysfs_emit(buf, "%d:%d\n", cycle, block); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ciXFS_SYSFS_ATTR_RO(log_head_lsn); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ciSTATIC ssize_t 36262306a36Sopenharmony_cilog_tail_lsn_show( 36362306a36Sopenharmony_ci struct kobject *kobject, 36462306a36Sopenharmony_ci char *buf) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci int cycle; 36762306a36Sopenharmony_ci int block; 36862306a36Sopenharmony_ci struct xlog *log = to_xlog(kobject); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci xlog_crack_atomic_lsn(&log->l_tail_lsn, &cycle, &block); 37162306a36Sopenharmony_ci return sysfs_emit(buf, "%d:%d\n", cycle, block); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ciXFS_SYSFS_ATTR_RO(log_tail_lsn); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ciSTATIC ssize_t 37662306a36Sopenharmony_cireserve_grant_head_show( 37762306a36Sopenharmony_ci struct kobject *kobject, 37862306a36Sopenharmony_ci char *buf) 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci int cycle; 38262306a36Sopenharmony_ci int bytes; 38362306a36Sopenharmony_ci struct xlog *log = to_xlog(kobject); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci xlog_crack_grant_head(&log->l_reserve_head.grant, &cycle, &bytes); 38662306a36Sopenharmony_ci return sysfs_emit(buf, "%d:%d\n", cycle, bytes); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ciXFS_SYSFS_ATTR_RO(reserve_grant_head); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ciSTATIC ssize_t 39162306a36Sopenharmony_ciwrite_grant_head_show( 39262306a36Sopenharmony_ci struct kobject *kobject, 39362306a36Sopenharmony_ci char *buf) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci int cycle; 39662306a36Sopenharmony_ci int bytes; 39762306a36Sopenharmony_ci struct xlog *log = to_xlog(kobject); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &bytes); 40062306a36Sopenharmony_ci return sysfs_emit(buf, "%d:%d\n", cycle, bytes); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ciXFS_SYSFS_ATTR_RO(write_grant_head); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic struct attribute *xfs_log_attrs[] = { 40562306a36Sopenharmony_ci ATTR_LIST(log_head_lsn), 40662306a36Sopenharmony_ci ATTR_LIST(log_tail_lsn), 40762306a36Sopenharmony_ci ATTR_LIST(reserve_grant_head), 40862306a36Sopenharmony_ci ATTR_LIST(write_grant_head), 40962306a36Sopenharmony_ci NULL, 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ciATTRIBUTE_GROUPS(xfs_log); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ciconst struct kobj_type xfs_log_ktype = { 41462306a36Sopenharmony_ci .release = xfs_sysfs_release, 41562306a36Sopenharmony_ci .sysfs_ops = &xfs_sysfs_ops, 41662306a36Sopenharmony_ci .default_groups = xfs_log_groups, 41762306a36Sopenharmony_ci}; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/* 42062306a36Sopenharmony_ci * Metadata IO error configuration 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * The sysfs structure here is: 42362306a36Sopenharmony_ci * ...xfs/<dev>/error/<class>/<errno>/<error_attrs> 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * where <class> allows us to discriminate between data IO and metadata IO, 42662306a36Sopenharmony_ci * and any other future type of IO (e.g. special inode or directory error 42762306a36Sopenharmony_ci * handling) we care to support. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_cistatic inline struct xfs_error_cfg * 43062306a36Sopenharmony_cito_error_cfg(struct kobject *kobject) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct xfs_kobj *kobj = to_kobj(kobject); 43362306a36Sopenharmony_ci return container_of(kobj, struct xfs_error_cfg, kobj); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic inline struct xfs_mount * 43762306a36Sopenharmony_cierr_to_mp(struct kobject *kobject) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct xfs_kobj *kobj = to_kobj(kobject); 44062306a36Sopenharmony_ci return container_of(kobj, struct xfs_mount, m_error_kobj); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic ssize_t 44462306a36Sopenharmony_cimax_retries_show( 44562306a36Sopenharmony_ci struct kobject *kobject, 44662306a36Sopenharmony_ci char *buf) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci int retries; 44962306a36Sopenharmony_ci struct xfs_error_cfg *cfg = to_error_cfg(kobject); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (cfg->max_retries == XFS_ERR_RETRY_FOREVER) 45262306a36Sopenharmony_ci retries = -1; 45362306a36Sopenharmony_ci else 45462306a36Sopenharmony_ci retries = cfg->max_retries; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", retries); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic ssize_t 46062306a36Sopenharmony_cimax_retries_store( 46162306a36Sopenharmony_ci struct kobject *kobject, 46262306a36Sopenharmony_ci const char *buf, 46362306a36Sopenharmony_ci size_t count) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct xfs_error_cfg *cfg = to_error_cfg(kobject); 46662306a36Sopenharmony_ci int ret; 46762306a36Sopenharmony_ci int val; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 47062306a36Sopenharmony_ci if (ret) 47162306a36Sopenharmony_ci return ret; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (val < -1) 47462306a36Sopenharmony_ci return -EINVAL; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (val == -1) 47762306a36Sopenharmony_ci cfg->max_retries = XFS_ERR_RETRY_FOREVER; 47862306a36Sopenharmony_ci else 47962306a36Sopenharmony_ci cfg->max_retries = val; 48062306a36Sopenharmony_ci return count; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(max_retries); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic ssize_t 48562306a36Sopenharmony_ciretry_timeout_seconds_show( 48662306a36Sopenharmony_ci struct kobject *kobject, 48762306a36Sopenharmony_ci char *buf) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci int timeout; 49062306a36Sopenharmony_ci struct xfs_error_cfg *cfg = to_error_cfg(kobject); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER) 49362306a36Sopenharmony_ci timeout = -1; 49462306a36Sopenharmony_ci else 49562306a36Sopenharmony_ci timeout = jiffies_to_msecs(cfg->retry_timeout) / MSEC_PER_SEC; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", timeout); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic ssize_t 50162306a36Sopenharmony_ciretry_timeout_seconds_store( 50262306a36Sopenharmony_ci struct kobject *kobject, 50362306a36Sopenharmony_ci const char *buf, 50462306a36Sopenharmony_ci size_t count) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct xfs_error_cfg *cfg = to_error_cfg(kobject); 50762306a36Sopenharmony_ci int ret; 50862306a36Sopenharmony_ci int val; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 51162306a36Sopenharmony_ci if (ret) 51262306a36Sopenharmony_ci return ret; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* 1 day timeout maximum, -1 means infinite */ 51562306a36Sopenharmony_ci if (val < -1 || val > 86400) 51662306a36Sopenharmony_ci return -EINVAL; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (val == -1) 51962306a36Sopenharmony_ci cfg->retry_timeout = XFS_ERR_RETRY_FOREVER; 52062306a36Sopenharmony_ci else { 52162306a36Sopenharmony_ci cfg->retry_timeout = msecs_to_jiffies(val * MSEC_PER_SEC); 52262306a36Sopenharmony_ci ASSERT(msecs_to_jiffies(val * MSEC_PER_SEC) < LONG_MAX); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci return count; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(retry_timeout_seconds); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic ssize_t 52962306a36Sopenharmony_cifail_at_unmount_show( 53062306a36Sopenharmony_ci struct kobject *kobject, 53162306a36Sopenharmony_ci char *buf) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct xfs_mount *mp = err_to_mp(kobject); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", mp->m_fail_unmount); 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic ssize_t 53962306a36Sopenharmony_cifail_at_unmount_store( 54062306a36Sopenharmony_ci struct kobject *kobject, 54162306a36Sopenharmony_ci const char *buf, 54262306a36Sopenharmony_ci size_t count) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct xfs_mount *mp = err_to_mp(kobject); 54562306a36Sopenharmony_ci int ret; 54662306a36Sopenharmony_ci int val; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ret = kstrtoint(buf, 0, &val); 54962306a36Sopenharmony_ci if (ret) 55062306a36Sopenharmony_ci return ret; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (val < 0 || val > 1) 55362306a36Sopenharmony_ci return -EINVAL; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci mp->m_fail_unmount = val; 55662306a36Sopenharmony_ci return count; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ciXFS_SYSFS_ATTR_RW(fail_at_unmount); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic struct attribute *xfs_error_attrs[] = { 56162306a36Sopenharmony_ci ATTR_LIST(max_retries), 56262306a36Sopenharmony_ci ATTR_LIST(retry_timeout_seconds), 56362306a36Sopenharmony_ci NULL, 56462306a36Sopenharmony_ci}; 56562306a36Sopenharmony_ciATTRIBUTE_GROUPS(xfs_error); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic const struct kobj_type xfs_error_cfg_ktype = { 56862306a36Sopenharmony_ci .release = xfs_sysfs_release, 56962306a36Sopenharmony_ci .sysfs_ops = &xfs_sysfs_ops, 57062306a36Sopenharmony_ci .default_groups = xfs_error_groups, 57162306a36Sopenharmony_ci}; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic const struct kobj_type xfs_error_ktype = { 57462306a36Sopenharmony_ci .release = xfs_sysfs_release, 57562306a36Sopenharmony_ci .sysfs_ops = &xfs_sysfs_ops, 57662306a36Sopenharmony_ci}; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/* 57962306a36Sopenharmony_ci * Error initialization tables. These need to be ordered in the same 58062306a36Sopenharmony_ci * order as the enums used to index the array. All class init tables need to 58162306a36Sopenharmony_ci * define a "default" behaviour as the first entry, all other entries can be 58262306a36Sopenharmony_ci * empty. 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_cistruct xfs_error_init { 58562306a36Sopenharmony_ci char *name; 58662306a36Sopenharmony_ci int max_retries; 58762306a36Sopenharmony_ci int retry_timeout; /* in seconds */ 58862306a36Sopenharmony_ci}; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic const struct xfs_error_init xfs_error_meta_init[XFS_ERR_ERRNO_MAX] = { 59162306a36Sopenharmony_ci { .name = "default", 59262306a36Sopenharmony_ci .max_retries = XFS_ERR_RETRY_FOREVER, 59362306a36Sopenharmony_ci .retry_timeout = XFS_ERR_RETRY_FOREVER, 59462306a36Sopenharmony_ci }, 59562306a36Sopenharmony_ci { .name = "EIO", 59662306a36Sopenharmony_ci .max_retries = XFS_ERR_RETRY_FOREVER, 59762306a36Sopenharmony_ci .retry_timeout = XFS_ERR_RETRY_FOREVER, 59862306a36Sopenharmony_ci }, 59962306a36Sopenharmony_ci { .name = "ENOSPC", 60062306a36Sopenharmony_ci .max_retries = XFS_ERR_RETRY_FOREVER, 60162306a36Sopenharmony_ci .retry_timeout = XFS_ERR_RETRY_FOREVER, 60262306a36Sopenharmony_ci }, 60362306a36Sopenharmony_ci { .name = "ENODEV", 60462306a36Sopenharmony_ci .max_retries = 0, /* We can't recover from devices disappearing */ 60562306a36Sopenharmony_ci .retry_timeout = 0, 60662306a36Sopenharmony_ci }, 60762306a36Sopenharmony_ci}; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int 61062306a36Sopenharmony_cixfs_error_sysfs_init_class( 61162306a36Sopenharmony_ci struct xfs_mount *mp, 61262306a36Sopenharmony_ci int class, 61362306a36Sopenharmony_ci const char *parent_name, 61462306a36Sopenharmony_ci struct xfs_kobj *parent_kobj, 61562306a36Sopenharmony_ci const struct xfs_error_init init[]) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct xfs_error_cfg *cfg; 61862306a36Sopenharmony_ci int error; 61962306a36Sopenharmony_ci int i; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ASSERT(class < XFS_ERR_CLASS_MAX); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci error = xfs_sysfs_init(parent_kobj, &xfs_error_ktype, 62462306a36Sopenharmony_ci &mp->m_error_kobj, parent_name); 62562306a36Sopenharmony_ci if (error) 62662306a36Sopenharmony_ci return error; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci for (i = 0; i < XFS_ERR_ERRNO_MAX; i++) { 62962306a36Sopenharmony_ci cfg = &mp->m_error_cfg[class][i]; 63062306a36Sopenharmony_ci error = xfs_sysfs_init(&cfg->kobj, &xfs_error_cfg_ktype, 63162306a36Sopenharmony_ci parent_kobj, init[i].name); 63262306a36Sopenharmony_ci if (error) 63362306a36Sopenharmony_ci goto out_error; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci cfg->max_retries = init[i].max_retries; 63662306a36Sopenharmony_ci if (init[i].retry_timeout == XFS_ERR_RETRY_FOREVER) 63762306a36Sopenharmony_ci cfg->retry_timeout = XFS_ERR_RETRY_FOREVER; 63862306a36Sopenharmony_ci else 63962306a36Sopenharmony_ci cfg->retry_timeout = msecs_to_jiffies( 64062306a36Sopenharmony_ci init[i].retry_timeout * MSEC_PER_SEC); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciout_error: 64562306a36Sopenharmony_ci /* unwind the entries that succeeded */ 64662306a36Sopenharmony_ci for (i--; i >= 0; i--) { 64762306a36Sopenharmony_ci cfg = &mp->m_error_cfg[class][i]; 64862306a36Sopenharmony_ci xfs_sysfs_del(&cfg->kobj); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci xfs_sysfs_del(parent_kobj); 65162306a36Sopenharmony_ci return error; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ciint 65562306a36Sopenharmony_cixfs_error_sysfs_init( 65662306a36Sopenharmony_ci struct xfs_mount *mp) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci int error; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* .../xfs/<dev>/error/ */ 66162306a36Sopenharmony_ci error = xfs_sysfs_init(&mp->m_error_kobj, &xfs_error_ktype, 66262306a36Sopenharmony_ci &mp->m_kobj, "error"); 66362306a36Sopenharmony_ci if (error) 66462306a36Sopenharmony_ci return error; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci error = sysfs_create_file(&mp->m_error_kobj.kobject, 66762306a36Sopenharmony_ci ATTR_LIST(fail_at_unmount)); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (error) 67062306a36Sopenharmony_ci goto out_error; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* .../xfs/<dev>/error/metadata/ */ 67362306a36Sopenharmony_ci error = xfs_error_sysfs_init_class(mp, XFS_ERR_METADATA, 67462306a36Sopenharmony_ci "metadata", &mp->m_error_meta_kobj, 67562306a36Sopenharmony_ci xfs_error_meta_init); 67662306a36Sopenharmony_ci if (error) 67762306a36Sopenharmony_ci goto out_error; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ciout_error: 68262306a36Sopenharmony_ci xfs_sysfs_del(&mp->m_error_kobj); 68362306a36Sopenharmony_ci return error; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_civoid 68762306a36Sopenharmony_cixfs_error_sysfs_del( 68862306a36Sopenharmony_ci struct xfs_mount *mp) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct xfs_error_cfg *cfg; 69162306a36Sopenharmony_ci int i, j; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci for (i = 0; i < XFS_ERR_CLASS_MAX; i++) { 69462306a36Sopenharmony_ci for (j = 0; j < XFS_ERR_ERRNO_MAX; j++) { 69562306a36Sopenharmony_ci cfg = &mp->m_error_cfg[i][j]; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci xfs_sysfs_del(&cfg->kobj); 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci xfs_sysfs_del(&mp->m_error_meta_kobj); 70162306a36Sopenharmony_ci xfs_sysfs_del(&mp->m_error_kobj); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistruct xfs_error_cfg * 70562306a36Sopenharmony_cixfs_error_get_cfg( 70662306a36Sopenharmony_ci struct xfs_mount *mp, 70762306a36Sopenharmony_ci int error_class, 70862306a36Sopenharmony_ci int error) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct xfs_error_cfg *cfg; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (error < 0) 71362306a36Sopenharmony_ci error = -error; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci switch (error) { 71662306a36Sopenharmony_ci case EIO: 71762306a36Sopenharmony_ci cfg = &mp->m_error_cfg[error_class][XFS_ERR_EIO]; 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci case ENOSPC: 72062306a36Sopenharmony_ci cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENOSPC]; 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci case ENODEV: 72362306a36Sopenharmony_ci cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENODEV]; 72462306a36Sopenharmony_ci break; 72562306a36Sopenharmony_ci default: 72662306a36Sopenharmony_ci cfg = &mp->m_error_cfg[error_class][XFS_ERR_DEFAULT]; 72762306a36Sopenharmony_ci break; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci return cfg; 73162306a36Sopenharmony_ci} 732