File Index
Files and directories
Sign in
FILE

xfs_sysfs.c

File preview with syntax highlighting.

linux-6.19.14/fs/xfs/xfs_sysfs.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2014 Red Hat, Inc.
  4 * All Rights Reserved.
  5 */
  6
  7#include "xfs.h"
  8#include "xfs_shared.h"
  9#include "xfs_format.h"
 10#include "xfs_log_format.h"
 11#include "xfs_trans_resv.h"
 12#include "xfs_sysfs.h"
 13#include "xfs_log.h"
 14#include "xfs_log_priv.h"
 15#include "xfs_mount.h"
 16#include "xfs_zones.h"
 17
 18struct xfs_sysfs_attr {
 19	struct attribute attr;
 20	ssize_t (*show)(struct kobject *kobject, char *buf);
 21	ssize_t (*store)(struct kobject *kobject, const char *buf,
 22			 size_t count);
 23};
 24
 25static inline struct xfs_sysfs_attr *
 26to_attr(struct attribute *attr)
 27{
 28	return container_of(attr, struct xfs_sysfs_attr, attr);
 29}
 30
 31#define XFS_SYSFS_ATTR_RW(name) \
 32	static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RW(name)
 33#define XFS_SYSFS_ATTR_RO(name) \
 34	static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RO(name)
 35#define XFS_SYSFS_ATTR_WO(name) \
 36	static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_WO(name)
 37
 38#define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr
 39
 40STATIC ssize_t
 41xfs_sysfs_object_show(
 42	struct kobject		*kobject,
 43	struct attribute	*attr,
 44	char			*buf)
 45{
 46	struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
 47
 48	return xfs_attr->show ? xfs_attr->show(kobject, buf) : 0;
 49}
 50
 51STATIC ssize_t
 52xfs_sysfs_object_store(
 53	struct kobject		*kobject,
 54	struct attribute	*attr,
 55	const char		*buf,
 56	size_t			count)
 57{
 58	struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
 59
 60	return xfs_attr->store ? xfs_attr->store(kobject, buf, count) : 0;
 61}
 62
 63static const struct sysfs_ops xfs_sysfs_ops = {
 64	.show = xfs_sysfs_object_show,
 65	.store = xfs_sysfs_object_store,
 66};
 67
 68static struct attribute *xfs_mp_attrs[] = {
 69	NULL,
 70};
 71ATTRIBUTE_GROUPS(xfs_mp);
 72
 73static const struct kobj_type xfs_mp_ktype = {
 74	.release = xfs_sysfs_release,
 75	.sysfs_ops = &xfs_sysfs_ops,
 76	.default_groups = xfs_mp_groups,
 77};
 78
 79#ifdef DEBUG
 80/* debug */
 81
 82STATIC ssize_t
 83bug_on_assert_store(
 84	struct kobject		*kobject,
 85	const char		*buf,
 86	size_t			count)
 87{
 88	int			ret;
 89	int			val;
 90
 91	ret = kstrtoint(buf, 0, &val);
 92	if (ret)
 93		return ret;
 94
 95	if (val == 1)
 96		xfs_globals.bug_on_assert = true;
 97	else if (val == 0)
 98		xfs_globals.bug_on_assert = false;
 99	else
100		return -EINVAL;
101
102	return count;
103}
104
105STATIC ssize_t
106bug_on_assert_show(
107	struct kobject		*kobject,
108	char			*buf)
109{
110	return sysfs_emit(buf, "%d\n", xfs_globals.bug_on_assert);
111}
112XFS_SYSFS_ATTR_RW(bug_on_assert);
113
114STATIC ssize_t
115log_recovery_delay_store(
116	struct kobject	*kobject,
117	const char	*buf,
118	size_t		count)
119{
120	int		ret;
121	int		val;
122
123	ret = kstrtoint(buf, 0, &val);
124	if (ret)
125		return ret;
126
127	if (val < 0 || val > 60)
128		return -EINVAL;
129
130	xfs_globals.log_recovery_delay = val;
131
132	return count;
133}
134
135STATIC ssize_t
136log_recovery_delay_show(
137	struct kobject	*kobject,
138	char		*buf)
139{
140	return sysfs_emit(buf, "%d\n", xfs_globals.log_recovery_delay);
141}
142XFS_SYSFS_ATTR_RW(log_recovery_delay);
143
144STATIC ssize_t
145mount_delay_store(
146	struct kobject	*kobject,
147	const char	*buf,
148	size_t		count)
149{
150	int		ret;
151	int		val;
152
153	ret = kstrtoint(buf, 0, &val);
154	if (ret)
155		return ret;
156
157	if (val < 0 || val > 60)
158		return -EINVAL;
159
160	xfs_globals.mount_delay = val;
161
162	return count;
163}
164
165STATIC ssize_t
166mount_delay_show(
167	struct kobject	*kobject,
168	char		*buf)
169{
170	return sysfs_emit(buf, "%d\n", xfs_globals.mount_delay);
171}
172XFS_SYSFS_ATTR_RW(mount_delay);
173
174static ssize_t
175always_cow_store(
176	struct kobject	*kobject,
177	const char	*buf,
178	size_t		count)
179{
180	ssize_t		ret;
181
182	ret = kstrtobool(buf, &xfs_globals.always_cow);
183	if (ret < 0)
184		return ret;
185	return count;
186}
187
188static ssize_t
189always_cow_show(
190	struct kobject	*kobject,
191	char		*buf)
192{
193	return sysfs_emit(buf, "%d\n", xfs_globals.always_cow);
194}
195XFS_SYSFS_ATTR_RW(always_cow);
196
197/*
198 * Override how many threads the parallel work queue is allowed to create.
199 * This has to be a debug-only global (instead of an errortag) because one of
200 * the main users of parallel workqueues is mount time quotacheck.
201 */
202STATIC ssize_t
203pwork_threads_store(
204	struct kobject	*kobject,
205	const char	*buf,
206	size_t		count)
207{
208	int		ret;
209	int		val;
210
211	ret = kstrtoint(buf, 0, &val);
212	if (ret)
213		return ret;
214
215	if (val < -1 || val > num_possible_cpus())
216		return -EINVAL;
217
218	xfs_globals.pwork_threads = val;
219
220	return count;
221}
222
223STATIC ssize_t
224pwork_threads_show(
225	struct kobject	*kobject,
226	char		*buf)
227{
228	return sysfs_emit(buf, "%d\n", xfs_globals.pwork_threads);
229}
230XFS_SYSFS_ATTR_RW(pwork_threads);
231
232/*
233 * The "LARP" (Logged extended Attribute Recovery Persistence) debugging knob
234 * sets the XFS_DA_OP_LOGGED flag on all xfs_attr_set operations performed on
235 * V5 filesystems.  As a result, the intermediate progress of all setxattr and
236 * removexattr operations are tracked via the log and can be restarted during
237 * recovery.  This is useful for testing xattr recovery prior to merging of the
238 * parent pointer feature which requires it to maintain consistency, and may be
239 * enabled for userspace xattrs in the future.
240 */
241static ssize_t
242larp_store(
243	struct kobject	*kobject,
244	const char	*buf,
245	size_t		count)
246{
247	ssize_t		ret;
248
249	ret = kstrtobool(buf, &xfs_globals.larp);
250	if (ret < 0)
251		return ret;
252	return count;
253}
254
255STATIC ssize_t
256larp_show(
257	struct kobject	*kobject,
258	char		*buf)
259{
260	return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.larp);
261}
262XFS_SYSFS_ATTR_RW(larp);
263
264STATIC ssize_t
265bload_leaf_slack_store(
266	struct kobject	*kobject,
267	const char	*buf,
268	size_t		count)
269{
270	int		ret;
271	int		val;
272
273	ret = kstrtoint(buf, 0, &val);
274	if (ret)
275		return ret;
276
277	xfs_globals.bload_leaf_slack = val;
278	return count;
279}
280
281STATIC ssize_t
282bload_leaf_slack_show(
283	struct kobject	*kobject,
284	char		*buf)
285{
286	return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.bload_leaf_slack);
287}
288XFS_SYSFS_ATTR_RW(bload_leaf_slack);
289
290STATIC ssize_t
291bload_node_slack_store(
292	struct kobject	*kobject,
293	const char	*buf,
294	size_t		count)
295{
296	int		ret;
297	int		val;
298
299	ret = kstrtoint(buf, 0, &val);
300	if (ret)
301		return ret;
302
303	xfs_globals.bload_node_slack = val;
304	return count;
305}
306
307STATIC ssize_t
308bload_node_slack_show(
309	struct kobject	*kobject,
310	char		*buf)
311{
312	return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.bload_node_slack);
313}
314XFS_SYSFS_ATTR_RW(bload_node_slack);
315
316static struct attribute *xfs_dbg_attrs[] = {
317	ATTR_LIST(bug_on_assert),
318	ATTR_LIST(log_recovery_delay),
319	ATTR_LIST(mount_delay),
320	ATTR_LIST(always_cow),
321	ATTR_LIST(pwork_threads),
322	ATTR_LIST(larp),
323	ATTR_LIST(bload_leaf_slack),
324	ATTR_LIST(bload_node_slack),
325	NULL,
326};
327ATTRIBUTE_GROUPS(xfs_dbg);
328
329const struct kobj_type xfs_dbg_ktype = {
330	.release = xfs_sysfs_release,
331	.sysfs_ops = &xfs_sysfs_ops,
332	.default_groups = xfs_dbg_groups,
333};
334
335#endif /* DEBUG */
336
337/* stats */
338
339static inline struct xstats *
340to_xstats(struct kobject *kobject)
341{
342	struct xfs_kobj *kobj = to_kobj(kobject);
343
344	return container_of(kobj, struct xstats, xs_kobj);
345}
346
347STATIC ssize_t
348stats_show(
349	struct kobject	*kobject,
350	char		*buf)
351{
352	struct xstats	*stats = to_xstats(kobject);
353
354	return xfs_stats_format(stats->xs_stats, buf);
355}
356XFS_SYSFS_ATTR_RO(stats);
357
358STATIC ssize_t
359stats_clear_store(
360	struct kobject	*kobject,
361	const char	*buf,
362	size_t		count)
363{
364	int		ret;
365	int		val;
366	struct xstats	*stats = to_xstats(kobject);
367
368	ret = kstrtoint(buf, 0, &val);
369	if (ret)
370		return ret;
371
372	if (val != 1)
373		return -EINVAL;
374
375	xfs_stats_clearall(stats->xs_stats);
376	return count;
377}
378XFS_SYSFS_ATTR_WO(stats_clear);
379
380static struct attribute *xfs_stats_attrs[] = {
381	ATTR_LIST(stats),
382	ATTR_LIST(stats_clear),
383	NULL,
384};
385ATTRIBUTE_GROUPS(xfs_stats);
386
387const struct kobj_type xfs_stats_ktype = {
388	.release = xfs_sysfs_release,
389	.sysfs_ops = &xfs_sysfs_ops,
390	.default_groups = xfs_stats_groups,
391};
392
393/* xlog */
394
395static inline struct xlog *
396to_xlog(struct kobject *kobject)
397{
398	struct xfs_kobj *kobj = to_kobj(kobject);
399
400	return container_of(kobj, struct xlog, l_kobj);
401}
402
403STATIC ssize_t
404log_head_lsn_show(
405	struct kobject	*kobject,
406	char		*buf)
407{
408	int cycle;
409	int block;
410	struct xlog *log = to_xlog(kobject);
411
412	spin_lock(&log->l_icloglock);
413	cycle = log->l_curr_cycle;
414	block = log->l_curr_block;
415	spin_unlock(&log->l_icloglock);
416
417	return sysfs_emit(buf, "%d:%d\n", cycle, block);
418}
419XFS_SYSFS_ATTR_RO(log_head_lsn);
420
421STATIC ssize_t
422log_tail_lsn_show(
423	struct kobject	*kobject,
424	char		*buf)
425{
426	int cycle;
427	int block;
428	struct xlog *log = to_xlog(kobject);
429
430	xlog_crack_atomic_lsn(&log->l_tail_lsn, &cycle, &block);
431	return sysfs_emit(buf, "%d:%d\n", cycle, block);
432}
433XFS_SYSFS_ATTR_RO(log_tail_lsn);
434
435STATIC ssize_t
436reserve_grant_head_bytes_show(
437	struct kobject	*kobject,
438	char		*buf)
439{
440	return sysfs_emit(buf, "%lld\n",
441			atomic64_read(&to_xlog(kobject)->l_reserve_head.grant));
442}
443XFS_SYSFS_ATTR_RO(reserve_grant_head_bytes);
444
445STATIC ssize_t
446write_grant_head_bytes_show(
447	struct kobject	*kobject,
448	char		*buf)
449{
450	return sysfs_emit(buf, "%lld\n",
451			atomic64_read(&to_xlog(kobject)->l_write_head.grant));
452}
453XFS_SYSFS_ATTR_RO(write_grant_head_bytes);
454
455static struct attribute *xfs_log_attrs[] = {
456	ATTR_LIST(log_head_lsn),
457	ATTR_LIST(log_tail_lsn),
458	ATTR_LIST(reserve_grant_head_bytes),
459	ATTR_LIST(write_grant_head_bytes),
460	NULL,
461};
462ATTRIBUTE_GROUPS(xfs_log);
463
464const struct kobj_type xfs_log_ktype = {
465	.release = xfs_sysfs_release,
466	.sysfs_ops = &xfs_sysfs_ops,
467	.default_groups = xfs_log_groups,
468};
469
470/*
471 * Metadata IO error configuration
472 *
473 * The sysfs structure here is:
474 *	...xfs/<dev>/error/<class>/<errno>/<error_attrs>
475 *
476 * where <class> allows us to discriminate between data IO and metadata IO,
477 * and any other future type of IO (e.g. special inode or directory error
478 * handling) we care to support.
479 */
480static inline struct xfs_error_cfg *
481to_error_cfg(struct kobject *kobject)
482{
483	struct xfs_kobj *kobj = to_kobj(kobject);
484	return container_of(kobj, struct xfs_error_cfg, kobj);
485}
486
487static inline struct xfs_mount *
488err_to_mp(struct kobject *kobject)
489{
490	struct xfs_kobj *kobj = to_kobj(kobject);
491	return container_of(kobj, struct xfs_mount, m_error_kobj);
492}
493
494static ssize_t
495max_retries_show(
496	struct kobject	*kobject,
497	char		*buf)
498{
499	int		retries;
500	struct xfs_error_cfg *cfg = to_error_cfg(kobject);
501
502	if (cfg->max_retries == XFS_ERR_RETRY_FOREVER)
503		retries = -1;
504	else
505		retries = cfg->max_retries;
506
507	return sysfs_emit(buf, "%d\n", retries);
508}
509
510static ssize_t
511max_retries_store(
512	struct kobject	*kobject,
513	const char	*buf,
514	size_t		count)
515{
516	struct xfs_error_cfg *cfg = to_error_cfg(kobject);
517	int		ret;
518	int		val;
519
520	ret = kstrtoint(buf, 0, &val);
521	if (ret)
522		return ret;
523
524	if (val < -1)
525		return -EINVAL;
526
527	if (val == -1)
528		cfg->max_retries = XFS_ERR_RETRY_FOREVER;
529	else
530		cfg->max_retries = val;
531	return count;
532}
533XFS_SYSFS_ATTR_RW(max_retries);
534
535static ssize_t
536retry_timeout_seconds_show(
537	struct kobject	*kobject,
538	char		*buf)
539{
540	int		timeout;
541	struct xfs_error_cfg *cfg = to_error_cfg(kobject);
542
543	if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER)
544		timeout = -1;
545	else
546		timeout = jiffies_to_msecs(cfg->retry_timeout) / MSEC_PER_SEC;
547
548	return sysfs_emit(buf, "%d\n", timeout);
549}
550
551static ssize_t
552retry_timeout_seconds_store(
553	struct kobject	*kobject,
554	const char	*buf,
555	size_t		count)
556{
557	struct xfs_error_cfg *cfg = to_error_cfg(kobject);
558	int		ret;
559	int		val;
560
561	ret = kstrtoint(buf, 0, &val);
562	if (ret)
563		return ret;
564
565	/* 1 day timeout maximum, -1 means infinite */
566	if (val < -1 || val > 86400)
567		return -EINVAL;
568
569	if (val == -1)
570		cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
571	else {
572		cfg->retry_timeout = secs_to_jiffies(val);
573		ASSERT(secs_to_jiffies(val) < LONG_MAX);
574	}
575	return count;
576}
577XFS_SYSFS_ATTR_RW(retry_timeout_seconds);
578
579static ssize_t
580fail_at_unmount_show(
581	struct kobject	*kobject,
582	char		*buf)
583{
584	struct xfs_mount	*mp = err_to_mp(kobject);
585
586	return sysfs_emit(buf, "%d\n", mp->m_fail_unmount);
587}
588
589static ssize_t
590fail_at_unmount_store(
591	struct kobject	*kobject,
592	const char	*buf,
593	size_t		count)
594{
595	struct xfs_mount	*mp = err_to_mp(kobject);
596	int		ret;
597	int		val;
598
599	ret = kstrtoint(buf, 0, &val);
600	if (ret)
601		return ret;
602
603	if (val < 0 || val > 1)
604		return -EINVAL;
605
606	mp->m_fail_unmount = val;
607	return count;
608}
609XFS_SYSFS_ATTR_RW(fail_at_unmount);
610
611static struct attribute *xfs_error_attrs[] = {
612	ATTR_LIST(max_retries),
613	ATTR_LIST(retry_timeout_seconds),
614	NULL,
615};
616ATTRIBUTE_GROUPS(xfs_error);
617
618static const struct kobj_type xfs_error_cfg_ktype = {
619	.release = xfs_sysfs_release,
620	.sysfs_ops = &xfs_sysfs_ops,
621	.default_groups = xfs_error_groups,
622};
623
624static const struct kobj_type xfs_error_ktype = {
625	.release = xfs_sysfs_release,
626	.sysfs_ops = &xfs_sysfs_ops,
627};
628
629/*
630 * Error initialization tables. These need to be ordered in the same
631 * order as the enums used to index the array. All class init tables need to
632 * define a "default" behaviour as the first entry, all other entries can be
633 * empty.
634 */
635struct xfs_error_init {
636	char		*name;
637	int		max_retries;
638	int		retry_timeout;	/* in seconds */
639};
640
641static const struct xfs_error_init xfs_error_meta_init[XFS_ERR_ERRNO_MAX] = {
642	{ .name = "default",
643	  .max_retries = XFS_ERR_RETRY_FOREVER,
644	  .retry_timeout = XFS_ERR_RETRY_FOREVER,
645	},
646	{ .name = "EIO",
647	  .max_retries = XFS_ERR_RETRY_FOREVER,
648	  .retry_timeout = XFS_ERR_RETRY_FOREVER,
649	},
650	{ .name = "ENOSPC",
651	  .max_retries = XFS_ERR_RETRY_FOREVER,
652	  .retry_timeout = XFS_ERR_RETRY_FOREVER,
653	},
654	{ .name = "ENODEV",
655	  .max_retries = 0,	/* We can't recover from devices disappearing */
656	  .retry_timeout = 0,
657	},
658};
659
660static int
661xfs_error_sysfs_init_class(
662	struct xfs_mount	*mp,
663	int			class,
664	const char		*parent_name,
665	struct xfs_kobj		*parent_kobj,
666	const struct xfs_error_init init[])
667{
668	struct xfs_error_cfg	*cfg;
669	int			error;
670	int			i;
671
672	ASSERT(class < XFS_ERR_CLASS_MAX);
673
674	error = xfs_sysfs_init(parent_kobj, &xfs_error_ktype,
675				&mp->m_error_kobj, parent_name);
676	if (error)
677		return error;
678
679	for (i = 0; i < XFS_ERR_ERRNO_MAX; i++) {
680		cfg = &mp->m_error_cfg[class][i];
681		error = xfs_sysfs_init(&cfg->kobj, &xfs_error_cfg_ktype,
682					parent_kobj, init[i].name);
683		if (error)
684			goto out_error;
685
686		cfg->max_retries = init[i].max_retries;
687		if (init[i].retry_timeout == XFS_ERR_RETRY_FOREVER)
688			cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
689		else
690			cfg->retry_timeout =
691					secs_to_jiffies(init[i].retry_timeout);
692	}
693	return 0;
694
695out_error:
696	/* unwind the entries that succeeded */
697	for (i--; i >= 0; i--) {
698		cfg = &mp->m_error_cfg[class][i];
699		xfs_sysfs_del(&cfg->kobj);
700	}
701	xfs_sysfs_del(parent_kobj);
702	return error;
703}
704
705static inline struct xfs_mount *zoned_to_mp(struct kobject *kobj)
706{
707	return container_of(to_kobj(kobj), struct xfs_mount, m_zoned_kobj);
708}
709
710static ssize_t
711max_open_zones_show(
712	struct kobject		*kobj,
713	char			*buf)
714{
715	/* only report the open zones available for user data */
716	return sysfs_emit(buf, "%u\n",
717		zoned_to_mp(kobj)->m_max_open_zones - XFS_OPEN_GC_ZONES);
718}
719XFS_SYSFS_ATTR_RO(max_open_zones);
720
721static ssize_t
722zonegc_low_space_store(
723	struct kobject		*kobj,
724	const char		*buf,
725	size_t			count)
726{
727	int			ret;
728	unsigned int		val;
729
730	ret = kstrtouint(buf, 0, &val);
731	if (ret)
732		return ret;
733
734	if (val > 100)
735		return -EINVAL;
736
737	zoned_to_mp(kobj)->m_zonegc_low_space = val;
738
739	return count;
740}
741
742static ssize_t
743zonegc_low_space_show(
744	struct kobject		*kobj,
745	char			*buf)
746{
747	return sysfs_emit(buf, "%u\n",
748			zoned_to_mp(kobj)->m_zonegc_low_space);
749}
750XFS_SYSFS_ATTR_RW(zonegc_low_space);
751
752static struct attribute *xfs_zoned_attrs[] = {
753	ATTR_LIST(max_open_zones),
754	ATTR_LIST(zonegc_low_space),
755	NULL,
756};
757ATTRIBUTE_GROUPS(xfs_zoned);
758
759static const struct kobj_type xfs_zoned_ktype = {
760	.release = xfs_sysfs_release,
761	.sysfs_ops = &xfs_sysfs_ops,
762	.default_groups = xfs_zoned_groups,
763};
764
765int
766xfs_mount_sysfs_init(
767	struct xfs_mount	*mp)
768{
769	int			error;
770
771	super_set_sysfs_name_id(mp->m_super);
772
773	/* .../xfs/<dev>/ */
774	error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype,
775			       NULL, mp->m_super->s_id);
776	if (error)
777		return error;
778
779	/* .../xfs/<dev>/stats/ */
780	error = xfs_sysfs_init(&mp->m_stats.xs_kobj, &xfs_stats_ktype,
781			       &mp->m_kobj, "stats");
782	if (error)
783		goto out_remove_fsdir;
784
785	/* .../xfs/<dev>/error/ */
786	error = xfs_sysfs_init(&mp->m_error_kobj, &xfs_error_ktype,
787				&mp->m_kobj, "error");
788	if (error)
789		goto out_remove_stats_dir;
790
791	/* .../xfs/<dev>/error/fail_at_unmount */
792	error = sysfs_create_file(&mp->m_error_kobj.kobject,
793				  ATTR_LIST(fail_at_unmount));
794
795	if (error)
796		goto out_remove_error_dir;
797
798	/* .../xfs/<dev>/error/metadata/ */
799	error = xfs_error_sysfs_init_class(mp, XFS_ERR_METADATA,
800				"metadata", &mp->m_error_meta_kobj,
801				xfs_error_meta_init);
802	if (error)
803		goto out_remove_error_dir;
804
805	if (IS_ENABLED(CONFIG_XFS_RT) && xfs_has_zoned(mp)) {
806		/* .../xfs/<dev>/zoned/ */
807		error = xfs_sysfs_init(&mp->m_zoned_kobj, &xfs_zoned_ktype,
808					&mp->m_kobj, "zoned");
809		if (error)
810			goto out_remove_error_dir;
811	}
812
813	return 0;
814
815out_remove_error_dir:
816	xfs_sysfs_del(&mp->m_error_kobj);
817out_remove_stats_dir:
818	xfs_sysfs_del(&mp->m_stats.xs_kobj);
819out_remove_fsdir:
820	xfs_sysfs_del(&mp->m_kobj);
821	return error;
822}
823
824void
825xfs_mount_sysfs_del(
826	struct xfs_mount	*mp)
827{
828	struct xfs_error_cfg	*cfg;
829	int			i, j;
830
831	if (IS_ENABLED(CONFIG_XFS_RT) && xfs_has_zoned(mp))
832		xfs_sysfs_del(&mp->m_zoned_kobj);
833
834	for (i = 0; i < XFS_ERR_CLASS_MAX; i++) {
835		for (j = 0; j < XFS_ERR_ERRNO_MAX; j++) {
836			cfg = &mp->m_error_cfg[i][j];
837
838			xfs_sysfs_del(&cfg->kobj);
839		}
840	}
841	xfs_sysfs_del(&mp->m_error_meta_kobj);
842	xfs_sysfs_del(&mp->m_error_kobj);
843	xfs_sysfs_del(&mp->m_stats.xs_kobj);
844	xfs_sysfs_del(&mp->m_kobj);
845}
846
847struct xfs_error_cfg *
848xfs_error_get_cfg(
849	struct xfs_mount	*mp,
850	int			error_class,
851	int			error)
852{
853	struct xfs_error_cfg	*cfg;
854
855	if (error < 0)
856		error = -error;
857
858	switch (error) {
859	case EIO:
860		cfg = &mp->m_error_cfg[error_class][XFS_ERR_EIO];
861		break;
862	case ENOSPC:
863		cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENOSPC];
864		break;
865	case ENODEV:
866		cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENODEV];
867		break;
868	default:
869		cfg = &mp->m_error_cfg[error_class][XFS_ERR_DEFAULT];
870		break;
871	}
872
873	return cfg;
874}
~/ Read-only file preview.