1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2014 Red Hat, Inc.
4*4882a593Smuzhiyun * All Rights Reserved.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include "xfs.h"
8*4882a593Smuzhiyun #include "xfs_shared.h"
9*4882a593Smuzhiyun #include "xfs_format.h"
10*4882a593Smuzhiyun #include "xfs_log_format.h"
11*4882a593Smuzhiyun #include "xfs_trans_resv.h"
12*4882a593Smuzhiyun #include "xfs_sysfs.h"
13*4882a593Smuzhiyun #include "xfs_log_priv.h"
14*4882a593Smuzhiyun #include "xfs_mount.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun struct xfs_sysfs_attr {
17*4882a593Smuzhiyun struct attribute attr;
18*4882a593Smuzhiyun ssize_t (*show)(struct kobject *kobject, char *buf);
19*4882a593Smuzhiyun ssize_t (*store)(struct kobject *kobject, const char *buf,
20*4882a593Smuzhiyun size_t count);
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun static inline struct xfs_sysfs_attr *
to_attr(struct attribute * attr)24*4882a593Smuzhiyun to_attr(struct attribute *attr)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun return container_of(attr, struct xfs_sysfs_attr, attr);
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define XFS_SYSFS_ATTR_RW(name) \
30*4882a593Smuzhiyun static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RW(name)
31*4882a593Smuzhiyun #define XFS_SYSFS_ATTR_RO(name) \
32*4882a593Smuzhiyun static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RO(name)
33*4882a593Smuzhiyun #define XFS_SYSFS_ATTR_WO(name) \
34*4882a593Smuzhiyun static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_WO(name)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun STATIC ssize_t
xfs_sysfs_object_show(struct kobject * kobject,struct attribute * attr,char * buf)39*4882a593Smuzhiyun xfs_sysfs_object_show(
40*4882a593Smuzhiyun struct kobject *kobject,
41*4882a593Smuzhiyun struct attribute *attr,
42*4882a593Smuzhiyun char *buf)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun return xfs_attr->show ? xfs_attr->show(kobject, buf) : 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun STATIC ssize_t
xfs_sysfs_object_store(struct kobject * kobject,struct attribute * attr,const char * buf,size_t count)50*4882a593Smuzhiyun xfs_sysfs_object_store(
51*4882a593Smuzhiyun struct kobject *kobject,
52*4882a593Smuzhiyun struct attribute *attr,
53*4882a593Smuzhiyun const char *buf,
54*4882a593Smuzhiyun size_t count)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun return xfs_attr->store ? xfs_attr->store(kobject, buf, count) : 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static const struct sysfs_ops xfs_sysfs_ops = {
62*4882a593Smuzhiyun .show = xfs_sysfs_object_show,
63*4882a593Smuzhiyun .store = xfs_sysfs_object_store,
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static struct attribute *xfs_mp_attrs[] = {
67*4882a593Smuzhiyun NULL,
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun struct kobj_type xfs_mp_ktype = {
71*4882a593Smuzhiyun .release = xfs_sysfs_release,
72*4882a593Smuzhiyun .sysfs_ops = &xfs_sysfs_ops,
73*4882a593Smuzhiyun .default_attrs = xfs_mp_attrs,
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #ifdef DEBUG
77*4882a593Smuzhiyun /* debug */
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun STATIC ssize_t
bug_on_assert_store(struct kobject * kobject,const char * buf,size_t count)80*4882a593Smuzhiyun bug_on_assert_store(
81*4882a593Smuzhiyun struct kobject *kobject,
82*4882a593Smuzhiyun const char *buf,
83*4882a593Smuzhiyun size_t count)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun int ret;
86*4882a593Smuzhiyun int val;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
89*4882a593Smuzhiyun if (ret)
90*4882a593Smuzhiyun return ret;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun if (val == 1)
93*4882a593Smuzhiyun xfs_globals.bug_on_assert = true;
94*4882a593Smuzhiyun else if (val == 0)
95*4882a593Smuzhiyun xfs_globals.bug_on_assert = false;
96*4882a593Smuzhiyun else
97*4882a593Smuzhiyun return -EINVAL;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun return count;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun STATIC ssize_t
bug_on_assert_show(struct kobject * kobject,char * buf)103*4882a593Smuzhiyun bug_on_assert_show(
104*4882a593Smuzhiyun struct kobject *kobject,
105*4882a593Smuzhiyun char *buf)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.bug_on_assert ? 1 : 0);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(bug_on_assert);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun STATIC ssize_t
log_recovery_delay_store(struct kobject * kobject,const char * buf,size_t count)112*4882a593Smuzhiyun log_recovery_delay_store(
113*4882a593Smuzhiyun struct kobject *kobject,
114*4882a593Smuzhiyun const char *buf,
115*4882a593Smuzhiyun size_t count)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun int ret;
118*4882a593Smuzhiyun int val;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
121*4882a593Smuzhiyun if (ret)
122*4882a593Smuzhiyun return ret;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (val < 0 || val > 60)
125*4882a593Smuzhiyun return -EINVAL;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun xfs_globals.log_recovery_delay = val;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun return count;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun STATIC ssize_t
log_recovery_delay_show(struct kobject * kobject,char * buf)133*4882a593Smuzhiyun log_recovery_delay_show(
134*4882a593Smuzhiyun struct kobject *kobject,
135*4882a593Smuzhiyun char *buf)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.log_recovery_delay);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(log_recovery_delay);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun STATIC ssize_t
mount_delay_store(struct kobject * kobject,const char * buf,size_t count)142*4882a593Smuzhiyun mount_delay_store(
143*4882a593Smuzhiyun struct kobject *kobject,
144*4882a593Smuzhiyun const char *buf,
145*4882a593Smuzhiyun size_t count)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun int ret;
148*4882a593Smuzhiyun int val;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
151*4882a593Smuzhiyun if (ret)
152*4882a593Smuzhiyun return ret;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (val < 0 || val > 60)
155*4882a593Smuzhiyun return -EINVAL;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun xfs_globals.mount_delay = val;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun return count;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun STATIC ssize_t
mount_delay_show(struct kobject * kobject,char * buf)163*4882a593Smuzhiyun mount_delay_show(
164*4882a593Smuzhiyun struct kobject *kobject,
165*4882a593Smuzhiyun char *buf)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.mount_delay);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(mount_delay);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun static ssize_t
always_cow_store(struct kobject * kobject,const char * buf,size_t count)172*4882a593Smuzhiyun always_cow_store(
173*4882a593Smuzhiyun struct kobject *kobject,
174*4882a593Smuzhiyun const char *buf,
175*4882a593Smuzhiyun size_t count)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun ssize_t ret;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun ret = kstrtobool(buf, &xfs_globals.always_cow);
180*4882a593Smuzhiyun if (ret < 0)
181*4882a593Smuzhiyun return ret;
182*4882a593Smuzhiyun return count;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun static ssize_t
always_cow_show(struct kobject * kobject,char * buf)186*4882a593Smuzhiyun always_cow_show(
187*4882a593Smuzhiyun struct kobject *kobject,
188*4882a593Smuzhiyun char *buf)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.always_cow);
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(always_cow);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun #ifdef DEBUG
195*4882a593Smuzhiyun /*
196*4882a593Smuzhiyun * Override how many threads the parallel work queue is allowed to create.
197*4882a593Smuzhiyun * This has to be a debug-only global (instead of an errortag) because one of
198*4882a593Smuzhiyun * the main users of parallel workqueues is mount time quotacheck.
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun STATIC ssize_t
pwork_threads_store(struct kobject * kobject,const char * buf,size_t count)201*4882a593Smuzhiyun pwork_threads_store(
202*4882a593Smuzhiyun struct kobject *kobject,
203*4882a593Smuzhiyun const char *buf,
204*4882a593Smuzhiyun size_t count)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun int ret;
207*4882a593Smuzhiyun int val;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
210*4882a593Smuzhiyun if (ret)
211*4882a593Smuzhiyun return ret;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (val < -1 || val > num_possible_cpus())
214*4882a593Smuzhiyun return -EINVAL;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun xfs_globals.pwork_threads = val;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun return count;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun STATIC ssize_t
pwork_threads_show(struct kobject * kobject,char * buf)222*4882a593Smuzhiyun pwork_threads_show(
223*4882a593Smuzhiyun struct kobject *kobject,
224*4882a593Smuzhiyun char *buf)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.pwork_threads);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(pwork_threads);
229*4882a593Smuzhiyun #endif /* DEBUG */
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun static struct attribute *xfs_dbg_attrs[] = {
232*4882a593Smuzhiyun ATTR_LIST(bug_on_assert),
233*4882a593Smuzhiyun ATTR_LIST(log_recovery_delay),
234*4882a593Smuzhiyun ATTR_LIST(mount_delay),
235*4882a593Smuzhiyun ATTR_LIST(always_cow),
236*4882a593Smuzhiyun #ifdef DEBUG
237*4882a593Smuzhiyun ATTR_LIST(pwork_threads),
238*4882a593Smuzhiyun #endif
239*4882a593Smuzhiyun NULL,
240*4882a593Smuzhiyun };
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun struct kobj_type xfs_dbg_ktype = {
243*4882a593Smuzhiyun .release = xfs_sysfs_release,
244*4882a593Smuzhiyun .sysfs_ops = &xfs_sysfs_ops,
245*4882a593Smuzhiyun .default_attrs = xfs_dbg_attrs,
246*4882a593Smuzhiyun };
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun #endif /* DEBUG */
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* stats */
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun static inline struct xstats *
to_xstats(struct kobject * kobject)253*4882a593Smuzhiyun to_xstats(struct kobject *kobject)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun struct xfs_kobj *kobj = to_kobj(kobject);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun return container_of(kobj, struct xstats, xs_kobj);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun STATIC ssize_t
stats_show(struct kobject * kobject,char * buf)261*4882a593Smuzhiyun stats_show(
262*4882a593Smuzhiyun struct kobject *kobject,
263*4882a593Smuzhiyun char *buf)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun struct xstats *stats = to_xstats(kobject);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return xfs_stats_format(stats->xs_stats, buf);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun XFS_SYSFS_ATTR_RO(stats);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun STATIC ssize_t
stats_clear_store(struct kobject * kobject,const char * buf,size_t count)272*4882a593Smuzhiyun stats_clear_store(
273*4882a593Smuzhiyun struct kobject *kobject,
274*4882a593Smuzhiyun const char *buf,
275*4882a593Smuzhiyun size_t count)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun int ret;
278*4882a593Smuzhiyun int val;
279*4882a593Smuzhiyun struct xstats *stats = to_xstats(kobject);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
282*4882a593Smuzhiyun if (ret)
283*4882a593Smuzhiyun return ret;
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (val != 1)
286*4882a593Smuzhiyun return -EINVAL;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun xfs_stats_clearall(stats->xs_stats);
289*4882a593Smuzhiyun return count;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun XFS_SYSFS_ATTR_WO(stats_clear);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun static struct attribute *xfs_stats_attrs[] = {
294*4882a593Smuzhiyun ATTR_LIST(stats),
295*4882a593Smuzhiyun ATTR_LIST(stats_clear),
296*4882a593Smuzhiyun NULL,
297*4882a593Smuzhiyun };
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun struct kobj_type xfs_stats_ktype = {
300*4882a593Smuzhiyun .release = xfs_sysfs_release,
301*4882a593Smuzhiyun .sysfs_ops = &xfs_sysfs_ops,
302*4882a593Smuzhiyun .default_attrs = xfs_stats_attrs,
303*4882a593Smuzhiyun };
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun /* xlog */
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun static inline struct xlog *
to_xlog(struct kobject * kobject)308*4882a593Smuzhiyun to_xlog(struct kobject *kobject)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun struct xfs_kobj *kobj = to_kobj(kobject);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun return container_of(kobj, struct xlog, l_kobj);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun STATIC ssize_t
log_head_lsn_show(struct kobject * kobject,char * buf)316*4882a593Smuzhiyun log_head_lsn_show(
317*4882a593Smuzhiyun struct kobject *kobject,
318*4882a593Smuzhiyun char *buf)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun int cycle;
321*4882a593Smuzhiyun int block;
322*4882a593Smuzhiyun struct xlog *log = to_xlog(kobject);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun spin_lock(&log->l_icloglock);
325*4882a593Smuzhiyun cycle = log->l_curr_cycle;
326*4882a593Smuzhiyun block = log->l_curr_block;
327*4882a593Smuzhiyun spin_unlock(&log->l_icloglock);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, block);
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun XFS_SYSFS_ATTR_RO(log_head_lsn);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun STATIC ssize_t
log_tail_lsn_show(struct kobject * kobject,char * buf)334*4882a593Smuzhiyun log_tail_lsn_show(
335*4882a593Smuzhiyun struct kobject *kobject,
336*4882a593Smuzhiyun char *buf)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun int cycle;
339*4882a593Smuzhiyun int block;
340*4882a593Smuzhiyun struct xlog *log = to_xlog(kobject);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun xlog_crack_atomic_lsn(&log->l_tail_lsn, &cycle, &block);
343*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, block);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun XFS_SYSFS_ATTR_RO(log_tail_lsn);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun STATIC ssize_t
reserve_grant_head_show(struct kobject * kobject,char * buf)348*4882a593Smuzhiyun reserve_grant_head_show(
349*4882a593Smuzhiyun struct kobject *kobject,
350*4882a593Smuzhiyun char *buf)
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun int cycle;
354*4882a593Smuzhiyun int bytes;
355*4882a593Smuzhiyun struct xlog *log = to_xlog(kobject);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun xlog_crack_grant_head(&log->l_reserve_head.grant, &cycle, &bytes);
358*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, bytes);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun XFS_SYSFS_ATTR_RO(reserve_grant_head);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun STATIC ssize_t
write_grant_head_show(struct kobject * kobject,char * buf)363*4882a593Smuzhiyun write_grant_head_show(
364*4882a593Smuzhiyun struct kobject *kobject,
365*4882a593Smuzhiyun char *buf)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun int cycle;
368*4882a593Smuzhiyun int bytes;
369*4882a593Smuzhiyun struct xlog *log = to_xlog(kobject);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &bytes);
372*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, bytes);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun XFS_SYSFS_ATTR_RO(write_grant_head);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun static struct attribute *xfs_log_attrs[] = {
377*4882a593Smuzhiyun ATTR_LIST(log_head_lsn),
378*4882a593Smuzhiyun ATTR_LIST(log_tail_lsn),
379*4882a593Smuzhiyun ATTR_LIST(reserve_grant_head),
380*4882a593Smuzhiyun ATTR_LIST(write_grant_head),
381*4882a593Smuzhiyun NULL,
382*4882a593Smuzhiyun };
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun struct kobj_type xfs_log_ktype = {
385*4882a593Smuzhiyun .release = xfs_sysfs_release,
386*4882a593Smuzhiyun .sysfs_ops = &xfs_sysfs_ops,
387*4882a593Smuzhiyun .default_attrs = xfs_log_attrs,
388*4882a593Smuzhiyun };
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /*
391*4882a593Smuzhiyun * Metadata IO error configuration
392*4882a593Smuzhiyun *
393*4882a593Smuzhiyun * The sysfs structure here is:
394*4882a593Smuzhiyun * ...xfs/<dev>/error/<class>/<errno>/<error_attrs>
395*4882a593Smuzhiyun *
396*4882a593Smuzhiyun * where <class> allows us to discriminate between data IO and metadata IO,
397*4882a593Smuzhiyun * and any other future type of IO (e.g. special inode or directory error
398*4882a593Smuzhiyun * handling) we care to support.
399*4882a593Smuzhiyun */
400*4882a593Smuzhiyun static inline struct xfs_error_cfg *
to_error_cfg(struct kobject * kobject)401*4882a593Smuzhiyun to_error_cfg(struct kobject *kobject)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun struct xfs_kobj *kobj = to_kobj(kobject);
404*4882a593Smuzhiyun return container_of(kobj, struct xfs_error_cfg, kobj);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun static inline struct xfs_mount *
err_to_mp(struct kobject * kobject)408*4882a593Smuzhiyun err_to_mp(struct kobject *kobject)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun struct xfs_kobj *kobj = to_kobj(kobject);
411*4882a593Smuzhiyun return container_of(kobj, struct xfs_mount, m_error_kobj);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun static ssize_t
max_retries_show(struct kobject * kobject,char * buf)415*4882a593Smuzhiyun max_retries_show(
416*4882a593Smuzhiyun struct kobject *kobject,
417*4882a593Smuzhiyun char *buf)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun int retries;
420*4882a593Smuzhiyun struct xfs_error_cfg *cfg = to_error_cfg(kobject);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun if (cfg->max_retries == XFS_ERR_RETRY_FOREVER)
423*4882a593Smuzhiyun retries = -1;
424*4882a593Smuzhiyun else
425*4882a593Smuzhiyun retries = cfg->max_retries;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", retries);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun static ssize_t
max_retries_store(struct kobject * kobject,const char * buf,size_t count)431*4882a593Smuzhiyun max_retries_store(
432*4882a593Smuzhiyun struct kobject *kobject,
433*4882a593Smuzhiyun const char *buf,
434*4882a593Smuzhiyun size_t count)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun struct xfs_error_cfg *cfg = to_error_cfg(kobject);
437*4882a593Smuzhiyun int ret;
438*4882a593Smuzhiyun int val;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
441*4882a593Smuzhiyun if (ret)
442*4882a593Smuzhiyun return ret;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (val < -1)
445*4882a593Smuzhiyun return -EINVAL;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun if (val == -1)
448*4882a593Smuzhiyun cfg->max_retries = XFS_ERR_RETRY_FOREVER;
449*4882a593Smuzhiyun else
450*4882a593Smuzhiyun cfg->max_retries = val;
451*4882a593Smuzhiyun return count;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(max_retries);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun static ssize_t
retry_timeout_seconds_show(struct kobject * kobject,char * buf)456*4882a593Smuzhiyun retry_timeout_seconds_show(
457*4882a593Smuzhiyun struct kobject *kobject,
458*4882a593Smuzhiyun char *buf)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun int timeout;
461*4882a593Smuzhiyun struct xfs_error_cfg *cfg = to_error_cfg(kobject);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER)
464*4882a593Smuzhiyun timeout = -1;
465*4882a593Smuzhiyun else
466*4882a593Smuzhiyun timeout = jiffies_to_msecs(cfg->retry_timeout) / MSEC_PER_SEC;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", timeout);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun static ssize_t
retry_timeout_seconds_store(struct kobject * kobject,const char * buf,size_t count)472*4882a593Smuzhiyun retry_timeout_seconds_store(
473*4882a593Smuzhiyun struct kobject *kobject,
474*4882a593Smuzhiyun const char *buf,
475*4882a593Smuzhiyun size_t count)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun struct xfs_error_cfg *cfg = to_error_cfg(kobject);
478*4882a593Smuzhiyun int ret;
479*4882a593Smuzhiyun int val;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
482*4882a593Smuzhiyun if (ret)
483*4882a593Smuzhiyun return ret;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /* 1 day timeout maximum, -1 means infinite */
486*4882a593Smuzhiyun if (val < -1 || val > 86400)
487*4882a593Smuzhiyun return -EINVAL;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun if (val == -1)
490*4882a593Smuzhiyun cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
491*4882a593Smuzhiyun else {
492*4882a593Smuzhiyun cfg->retry_timeout = msecs_to_jiffies(val * MSEC_PER_SEC);
493*4882a593Smuzhiyun ASSERT(msecs_to_jiffies(val * MSEC_PER_SEC) < LONG_MAX);
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun return count;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(retry_timeout_seconds);
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun static ssize_t
fail_at_unmount_show(struct kobject * kobject,char * buf)500*4882a593Smuzhiyun fail_at_unmount_show(
501*4882a593Smuzhiyun struct kobject *kobject,
502*4882a593Smuzhiyun char *buf)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun struct xfs_mount *mp = err_to_mp(kobject);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%d\n", mp->m_fail_unmount);
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun static ssize_t
fail_at_unmount_store(struct kobject * kobject,const char * buf,size_t count)510*4882a593Smuzhiyun fail_at_unmount_store(
511*4882a593Smuzhiyun struct kobject *kobject,
512*4882a593Smuzhiyun const char *buf,
513*4882a593Smuzhiyun size_t count)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun struct xfs_mount *mp = err_to_mp(kobject);
516*4882a593Smuzhiyun int ret;
517*4882a593Smuzhiyun int val;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun ret = kstrtoint(buf, 0, &val);
520*4882a593Smuzhiyun if (ret)
521*4882a593Smuzhiyun return ret;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun if (val < 0 || val > 1)
524*4882a593Smuzhiyun return -EINVAL;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun mp->m_fail_unmount = val;
527*4882a593Smuzhiyun return count;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun XFS_SYSFS_ATTR_RW(fail_at_unmount);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun static struct attribute *xfs_error_attrs[] = {
532*4882a593Smuzhiyun ATTR_LIST(max_retries),
533*4882a593Smuzhiyun ATTR_LIST(retry_timeout_seconds),
534*4882a593Smuzhiyun NULL,
535*4882a593Smuzhiyun };
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun static struct kobj_type xfs_error_cfg_ktype = {
539*4882a593Smuzhiyun .release = xfs_sysfs_release,
540*4882a593Smuzhiyun .sysfs_ops = &xfs_sysfs_ops,
541*4882a593Smuzhiyun .default_attrs = xfs_error_attrs,
542*4882a593Smuzhiyun };
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun static struct kobj_type xfs_error_ktype = {
545*4882a593Smuzhiyun .release = xfs_sysfs_release,
546*4882a593Smuzhiyun .sysfs_ops = &xfs_sysfs_ops,
547*4882a593Smuzhiyun };
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun /*
550*4882a593Smuzhiyun * Error initialization tables. These need to be ordered in the same
551*4882a593Smuzhiyun * order as the enums used to index the array. All class init tables need to
552*4882a593Smuzhiyun * define a "default" behaviour as the first entry, all other entries can be
553*4882a593Smuzhiyun * empty.
554*4882a593Smuzhiyun */
555*4882a593Smuzhiyun struct xfs_error_init {
556*4882a593Smuzhiyun char *name;
557*4882a593Smuzhiyun int max_retries;
558*4882a593Smuzhiyun int retry_timeout; /* in seconds */
559*4882a593Smuzhiyun };
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun static const struct xfs_error_init xfs_error_meta_init[XFS_ERR_ERRNO_MAX] = {
562*4882a593Smuzhiyun { .name = "default",
563*4882a593Smuzhiyun .max_retries = XFS_ERR_RETRY_FOREVER,
564*4882a593Smuzhiyun .retry_timeout = XFS_ERR_RETRY_FOREVER,
565*4882a593Smuzhiyun },
566*4882a593Smuzhiyun { .name = "EIO",
567*4882a593Smuzhiyun .max_retries = XFS_ERR_RETRY_FOREVER,
568*4882a593Smuzhiyun .retry_timeout = XFS_ERR_RETRY_FOREVER,
569*4882a593Smuzhiyun },
570*4882a593Smuzhiyun { .name = "ENOSPC",
571*4882a593Smuzhiyun .max_retries = XFS_ERR_RETRY_FOREVER,
572*4882a593Smuzhiyun .retry_timeout = XFS_ERR_RETRY_FOREVER,
573*4882a593Smuzhiyun },
574*4882a593Smuzhiyun { .name = "ENODEV",
575*4882a593Smuzhiyun .max_retries = 0, /* We can't recover from devices disappearing */
576*4882a593Smuzhiyun .retry_timeout = 0,
577*4882a593Smuzhiyun },
578*4882a593Smuzhiyun };
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun static int
xfs_error_sysfs_init_class(struct xfs_mount * mp,int class,const char * parent_name,struct xfs_kobj * parent_kobj,const struct xfs_error_init init[])581*4882a593Smuzhiyun xfs_error_sysfs_init_class(
582*4882a593Smuzhiyun struct xfs_mount *mp,
583*4882a593Smuzhiyun int class,
584*4882a593Smuzhiyun const char *parent_name,
585*4882a593Smuzhiyun struct xfs_kobj *parent_kobj,
586*4882a593Smuzhiyun const struct xfs_error_init init[])
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun struct xfs_error_cfg *cfg;
589*4882a593Smuzhiyun int error;
590*4882a593Smuzhiyun int i;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun ASSERT(class < XFS_ERR_CLASS_MAX);
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun error = xfs_sysfs_init(parent_kobj, &xfs_error_ktype,
595*4882a593Smuzhiyun &mp->m_error_kobj, parent_name);
596*4882a593Smuzhiyun if (error)
597*4882a593Smuzhiyun return error;
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun for (i = 0; i < XFS_ERR_ERRNO_MAX; i++) {
600*4882a593Smuzhiyun cfg = &mp->m_error_cfg[class][i];
601*4882a593Smuzhiyun error = xfs_sysfs_init(&cfg->kobj, &xfs_error_cfg_ktype,
602*4882a593Smuzhiyun parent_kobj, init[i].name);
603*4882a593Smuzhiyun if (error)
604*4882a593Smuzhiyun goto out_error;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun cfg->max_retries = init[i].max_retries;
607*4882a593Smuzhiyun if (init[i].retry_timeout == XFS_ERR_RETRY_FOREVER)
608*4882a593Smuzhiyun cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
609*4882a593Smuzhiyun else
610*4882a593Smuzhiyun cfg->retry_timeout = msecs_to_jiffies(
611*4882a593Smuzhiyun init[i].retry_timeout * MSEC_PER_SEC);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun return 0;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun out_error:
616*4882a593Smuzhiyun /* unwind the entries that succeeded */
617*4882a593Smuzhiyun for (i--; i >= 0; i--) {
618*4882a593Smuzhiyun cfg = &mp->m_error_cfg[class][i];
619*4882a593Smuzhiyun xfs_sysfs_del(&cfg->kobj);
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun xfs_sysfs_del(parent_kobj);
622*4882a593Smuzhiyun return error;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun int
xfs_error_sysfs_init(struct xfs_mount * mp)626*4882a593Smuzhiyun xfs_error_sysfs_init(
627*4882a593Smuzhiyun struct xfs_mount *mp)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun int error;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun /* .../xfs/<dev>/error/ */
632*4882a593Smuzhiyun error = xfs_sysfs_init(&mp->m_error_kobj, &xfs_error_ktype,
633*4882a593Smuzhiyun &mp->m_kobj, "error");
634*4882a593Smuzhiyun if (error)
635*4882a593Smuzhiyun return error;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun error = sysfs_create_file(&mp->m_error_kobj.kobject,
638*4882a593Smuzhiyun ATTR_LIST(fail_at_unmount));
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun if (error)
641*4882a593Smuzhiyun goto out_error;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun /* .../xfs/<dev>/error/metadata/ */
644*4882a593Smuzhiyun error = xfs_error_sysfs_init_class(mp, XFS_ERR_METADATA,
645*4882a593Smuzhiyun "metadata", &mp->m_error_meta_kobj,
646*4882a593Smuzhiyun xfs_error_meta_init);
647*4882a593Smuzhiyun if (error)
648*4882a593Smuzhiyun goto out_error;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun return 0;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun out_error:
653*4882a593Smuzhiyun xfs_sysfs_del(&mp->m_error_kobj);
654*4882a593Smuzhiyun return error;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun void
xfs_error_sysfs_del(struct xfs_mount * mp)658*4882a593Smuzhiyun xfs_error_sysfs_del(
659*4882a593Smuzhiyun struct xfs_mount *mp)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun struct xfs_error_cfg *cfg;
662*4882a593Smuzhiyun int i, j;
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun for (i = 0; i < XFS_ERR_CLASS_MAX; i++) {
665*4882a593Smuzhiyun for (j = 0; j < XFS_ERR_ERRNO_MAX; j++) {
666*4882a593Smuzhiyun cfg = &mp->m_error_cfg[i][j];
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun xfs_sysfs_del(&cfg->kobj);
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun xfs_sysfs_del(&mp->m_error_meta_kobj);
672*4882a593Smuzhiyun xfs_sysfs_del(&mp->m_error_kobj);
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun struct xfs_error_cfg *
xfs_error_get_cfg(struct xfs_mount * mp,int error_class,int error)676*4882a593Smuzhiyun xfs_error_get_cfg(
677*4882a593Smuzhiyun struct xfs_mount *mp,
678*4882a593Smuzhiyun int error_class,
679*4882a593Smuzhiyun int error)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun struct xfs_error_cfg *cfg;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun if (error < 0)
684*4882a593Smuzhiyun error = -error;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun switch (error) {
687*4882a593Smuzhiyun case EIO:
688*4882a593Smuzhiyun cfg = &mp->m_error_cfg[error_class][XFS_ERR_EIO];
689*4882a593Smuzhiyun break;
690*4882a593Smuzhiyun case ENOSPC:
691*4882a593Smuzhiyun cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENOSPC];
692*4882a593Smuzhiyun break;
693*4882a593Smuzhiyun case ENODEV:
694*4882a593Smuzhiyun cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENODEV];
695*4882a593Smuzhiyun break;
696*4882a593Smuzhiyun default:
697*4882a593Smuzhiyun cfg = &mp->m_error_cfg[error_class][XFS_ERR_DEFAULT];
698*4882a593Smuzhiyun break;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun return cfg;
702*4882a593Smuzhiyun }
703