1 /* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
6 * Code which implements online file check.
8 * Copyright (C) 2016 SuSE. All rights reserved.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public
12 * License as published by the Free Software Foundation, version 2.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
20 #include <linux/list.h>
21 #include <linux/spinlock.h>
22 #include <linux/module.h>
23 #include <linux/slab.h>
24 #include <linux/kmod.h>
26 #include <linux/kobject.h>
27 #include <linux/sysfs.h>
28 #include <linux/sysctl.h>
29 #include <cluster/masklog.h>
33 #include "stackglue.h"
36 #include "filecheck.h"
39 /* File check error strings,
40 * must correspond with error number in header file.
42 static const char * const ocfs2_filecheck_errs
[] = {
56 static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock
);
57 static LIST_HEAD(ocfs2_filecheck_sysfs_list
);
59 struct ocfs2_filecheck
{
60 struct list_head fc_head
; /* File check entry list head */
62 unsigned int fc_max
; /* Maximum number of entry in list */
63 unsigned int fc_size
; /* Current entry count in list */
64 unsigned int fc_done
; /* Finished entry count in list */
67 struct ocfs2_filecheck_sysfs_entry
{ /* sysfs entry per mounting */
68 struct list_head fs_list
;
70 struct super_block
*fs_sb
;
71 struct kset
*fs_devicekset
;
72 struct kset
*fs_fcheckkset
;
73 struct ocfs2_filecheck
*fs_fcheck
;
76 #define OCFS2_FILECHECK_MAXSIZE 100
77 #define OCFS2_FILECHECK_MINSIZE 10
79 /* File check operation type */
81 OCFS2_FILECHECK_TYPE_CHK
= 0, /* Check a file(inode) */
82 OCFS2_FILECHECK_TYPE_FIX
, /* Fix a file(inode) */
83 OCFS2_FILECHECK_TYPE_SET
= 100 /* Set entry list maximum size */
86 struct ocfs2_filecheck_entry
{
87 struct list_head fe_list
;
90 unsigned int fe_done
:1;
91 unsigned int fe_status
:31;
94 struct ocfs2_filecheck_args
{
103 ocfs2_filecheck_error(int errno
)
106 return ocfs2_filecheck_errs
[errno
];
108 BUG_ON(errno
< OCFS2_FILECHECK_ERR_START
||
109 errno
> OCFS2_FILECHECK_ERR_END
);
110 return ocfs2_filecheck_errs
[errno
- OCFS2_FILECHECK_ERR_START
+ 1];
113 static ssize_t
ocfs2_filecheck_show(struct kobject
*kobj
,
114 struct kobj_attribute
*attr
,
116 static ssize_t
ocfs2_filecheck_store(struct kobject
*kobj
,
117 struct kobj_attribute
*attr
,
118 const char *buf
, size_t count
);
119 static struct kobj_attribute ocfs2_attr_filecheck_chk
=
120 __ATTR(check
, S_IRUSR
| S_IWUSR
,
121 ocfs2_filecheck_show
,
122 ocfs2_filecheck_store
);
123 static struct kobj_attribute ocfs2_attr_filecheck_fix
=
124 __ATTR(fix
, S_IRUSR
| S_IWUSR
,
125 ocfs2_filecheck_show
,
126 ocfs2_filecheck_store
);
127 static struct kobj_attribute ocfs2_attr_filecheck_set
=
128 __ATTR(set
, S_IRUSR
| S_IWUSR
,
129 ocfs2_filecheck_show
,
130 ocfs2_filecheck_store
);
132 static int ocfs2_filecheck_sysfs_wait(atomic_t
*p
)
139 ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry
*entry
)
141 struct ocfs2_filecheck_entry
*p
;
143 if (!atomic_dec_and_test(&entry
->fs_count
))
144 wait_on_atomic_t(&entry
->fs_count
, ocfs2_filecheck_sysfs_wait
,
145 TASK_UNINTERRUPTIBLE
);
147 spin_lock(&entry
->fs_fcheck
->fc_lock
);
148 while (!list_empty(&entry
->fs_fcheck
->fc_head
)) {
149 p
= list_first_entry(&entry
->fs_fcheck
->fc_head
,
150 struct ocfs2_filecheck_entry
, fe_list
);
151 list_del(&p
->fe_list
);
152 BUG_ON(!p
->fe_done
); /* To free a undone file check entry */
155 spin_unlock(&entry
->fs_fcheck
->fc_lock
);
157 kset_unregister(entry
->fs_fcheckkset
);
158 kset_unregister(entry
->fs_devicekset
);
159 kfree(entry
->fs_fcheck
);
164 ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry
*entry
)
166 spin_lock(&ocfs2_filecheck_sysfs_lock
);
167 list_add_tail(&entry
->fs_list
, &ocfs2_filecheck_sysfs_list
);
168 spin_unlock(&ocfs2_filecheck_sysfs_lock
);
171 static int ocfs2_filecheck_sysfs_del(const char *devname
)
173 struct ocfs2_filecheck_sysfs_entry
*p
;
175 spin_lock(&ocfs2_filecheck_sysfs_lock
);
176 list_for_each_entry(p
, &ocfs2_filecheck_sysfs_list
, fs_list
) {
177 if (!strcmp(p
->fs_sb
->s_id
, devname
)) {
178 list_del(&p
->fs_list
);
179 spin_unlock(&ocfs2_filecheck_sysfs_lock
);
180 ocfs2_filecheck_sysfs_free(p
);
184 spin_unlock(&ocfs2_filecheck_sysfs_lock
);
189 ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry
*entry
)
191 if (atomic_dec_and_test(&entry
->fs_count
))
192 wake_up_atomic_t(&entry
->fs_count
);
195 static struct ocfs2_filecheck_sysfs_entry
*
196 ocfs2_filecheck_sysfs_get(const char *devname
)
198 struct ocfs2_filecheck_sysfs_entry
*p
= NULL
;
200 spin_lock(&ocfs2_filecheck_sysfs_lock
);
201 list_for_each_entry(p
, &ocfs2_filecheck_sysfs_list
, fs_list
) {
202 if (!strcmp(p
->fs_sb
->s_id
, devname
)) {
203 atomic_inc(&p
->fs_count
);
204 spin_unlock(&ocfs2_filecheck_sysfs_lock
);
208 spin_unlock(&ocfs2_filecheck_sysfs_lock
);
212 int ocfs2_filecheck_create_sysfs(struct super_block
*sb
)
215 struct kset
*device_kset
= NULL
;
216 struct kset
*fcheck_kset
= NULL
;
217 struct ocfs2_filecheck
*fcheck
= NULL
;
218 struct ocfs2_filecheck_sysfs_entry
*entry
= NULL
;
219 struct attribute
**attrs
= NULL
;
220 struct attribute_group attrgp
;
225 attrs
= kmalloc(sizeof(struct attribute
*) * 4, GFP_NOFS
);
230 attrs
[0] = &ocfs2_attr_filecheck_chk
.attr
;
231 attrs
[1] = &ocfs2_attr_filecheck_fix
.attr
;
232 attrs
[2] = &ocfs2_attr_filecheck_set
.attr
;
234 memset(&attrgp
, 0, sizeof(attrgp
));
235 attrgp
.attrs
= attrs
;
238 fcheck
= kmalloc(sizeof(struct ocfs2_filecheck
), GFP_NOFS
);
243 INIT_LIST_HEAD(&fcheck
->fc_head
);
244 spin_lock_init(&fcheck
->fc_lock
);
245 fcheck
->fc_max
= OCFS2_FILECHECK_MINSIZE
;
250 if (strlen(sb
->s_id
) <= 0) {
252 "Cannot get device basename when create filecheck sysfs\n");
257 device_kset
= kset_create_and_add(sb
->s_id
, NULL
, &ocfs2_kset
->kobj
);
263 fcheck_kset
= kset_create_and_add("filecheck", NULL
,
270 ret
= sysfs_create_group(&fcheck_kset
->kobj
, &attrgp
);
274 entry
= kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry
), GFP_NOFS
);
279 atomic_set(&entry
->fs_count
, 1);
281 entry
->fs_devicekset
= device_kset
;
282 entry
->fs_fcheckkset
= fcheck_kset
;
283 entry
->fs_fcheck
= fcheck
;
284 ocfs2_filecheck_sysfs_add(entry
);
294 kset_unregister(fcheck_kset
);
295 kset_unregister(device_kset
);
299 int ocfs2_filecheck_remove_sysfs(struct super_block
*sb
)
301 return ocfs2_filecheck_sysfs_del(sb
->s_id
);
305 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry
*ent
,
308 ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry
*ent
,
313 if ((len
< OCFS2_FILECHECK_MINSIZE
) || (len
> OCFS2_FILECHECK_MAXSIZE
))
316 spin_lock(&ent
->fs_fcheck
->fc_lock
);
317 if (len
< (ent
->fs_fcheck
->fc_size
- ent
->fs_fcheck
->fc_done
)) {
319 "Cannot set online file check maximum entry number "
320 "to %u due to too many pending entries(%u)\n",
321 len
, ent
->fs_fcheck
->fc_size
- ent
->fs_fcheck
->fc_done
);
324 if (len
< ent
->fs_fcheck
->fc_size
)
325 BUG_ON(!ocfs2_filecheck_erase_entries(ent
,
326 ent
->fs_fcheck
->fc_size
- len
));
328 ent
->fs_fcheck
->fc_max
= len
;
331 spin_unlock(&ent
->fs_fcheck
->fc_lock
);
336 #define OCFS2_FILECHECK_ARGS_LEN 24
338 ocfs2_filecheck_args_get_long(const char *buf
, size_t count
,
341 char buffer
[OCFS2_FILECHECK_ARGS_LEN
];
343 memcpy(buffer
, buf
, count
);
344 buffer
[count
] = '\0';
346 if (kstrtoul(buffer
, 0, val
))
353 ocfs2_filecheck_type_parse(const char *name
, unsigned int *type
)
355 if (!strncmp(name
, "fix", 4))
356 *type
= OCFS2_FILECHECK_TYPE_FIX
;
357 else if (!strncmp(name
, "check", 6))
358 *type
= OCFS2_FILECHECK_TYPE_CHK
;
359 else if (!strncmp(name
, "set", 4))
360 *type
= OCFS2_FILECHECK_TYPE_SET
;
368 ocfs2_filecheck_args_parse(const char *name
, const char *buf
, size_t count
,
369 struct ocfs2_filecheck_args
*args
)
371 unsigned long val
= 0;
374 /* too short/long args length */
375 if ((count
< 1) || (count
>= OCFS2_FILECHECK_ARGS_LEN
))
378 if (ocfs2_filecheck_type_parse(name
, &type
))
380 if (ocfs2_filecheck_args_get_long(buf
, count
, &val
))
386 args
->fa_type
= type
;
387 if (type
== OCFS2_FILECHECK_TYPE_SET
)
388 args
->fa_len
= (unsigned int)val
;
395 static ssize_t
ocfs2_filecheck_show(struct kobject
*kobj
,
396 struct kobj_attribute
*attr
,
400 ssize_t ret
= 0, total
= 0, remain
= PAGE_SIZE
;
402 struct ocfs2_filecheck_entry
*p
;
403 struct ocfs2_filecheck_sysfs_entry
*ent
;
405 if (ocfs2_filecheck_type_parse(attr
->attr
.name
, &type
))
408 ent
= ocfs2_filecheck_sysfs_get(kobj
->parent
->name
);
411 "Cannot get the corresponding entry via device basename %s\n",
416 if (type
== OCFS2_FILECHECK_TYPE_SET
) {
417 spin_lock(&ent
->fs_fcheck
->fc_lock
);
418 total
= snprintf(buf
, remain
, "%u\n", ent
->fs_fcheck
->fc_max
);
419 spin_unlock(&ent
->fs_fcheck
->fc_lock
);
423 ret
= snprintf(buf
, remain
, "INO\t\tDONE\tERROR\n");
426 spin_lock(&ent
->fs_fcheck
->fc_lock
);
427 list_for_each_entry(p
, &ent
->fs_fcheck
->fc_head
, fe_list
) {
428 if (p
->fe_type
!= type
)
431 ret
= snprintf(buf
+ total
, remain
, "%lu\t\t%u\t%s\n",
432 p
->fe_ino
, p
->fe_done
,
433 ocfs2_filecheck_error(p
->fe_status
));
439 /* snprintf() didn't fit */
446 spin_unlock(&ent
->fs_fcheck
->fc_lock
);
449 ocfs2_filecheck_sysfs_put(ent
);
454 ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry
*ent
)
456 struct ocfs2_filecheck_entry
*p
;
458 list_for_each_entry(p
, &ent
->fs_fcheck
->fc_head
, fe_list
) {
460 list_del(&p
->fe_list
);
462 ent
->fs_fcheck
->fc_size
--;
463 ent
->fs_fcheck
->fc_done
--;
472 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry
*ent
,
476 unsigned int ret
= 0;
478 while (i
++ < count
) {
479 if (ocfs2_filecheck_erase_entry(ent
))
485 return (ret
== count
? 1 : 0);
489 ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry
*ent
,
490 struct ocfs2_filecheck_entry
*entry
)
493 spin_lock(&ent
->fs_fcheck
->fc_lock
);
494 ent
->fs_fcheck
->fc_done
++;
495 spin_unlock(&ent
->fs_fcheck
->fc_lock
);
499 ocfs2_filecheck_handle(struct super_block
*sb
,
500 unsigned long ino
, unsigned int flags
)
502 unsigned int ret
= OCFS2_FILECHECK_ERR_SUCCESS
;
503 struct inode
*inode
= NULL
;
506 inode
= ocfs2_iget(OCFS2_SB(sb
), ino
, flags
, 0);
508 rc
= (int)(-(long)inode
);
509 if (rc
>= OCFS2_FILECHECK_ERR_START
&&
510 rc
< OCFS2_FILECHECK_ERR_END
)
513 ret
= OCFS2_FILECHECK_ERR_FAILED
;
521 ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry
*ent
,
522 struct ocfs2_filecheck_entry
*entry
)
524 if (entry
->fe_type
== OCFS2_FILECHECK_TYPE_CHK
)
525 entry
->fe_status
= ocfs2_filecheck_handle(ent
->fs_sb
,
526 entry
->fe_ino
, OCFS2_FI_FLAG_FILECHECK_CHK
);
527 else if (entry
->fe_type
== OCFS2_FILECHECK_TYPE_FIX
)
528 entry
->fe_status
= ocfs2_filecheck_handle(ent
->fs_sb
,
529 entry
->fe_ino
, OCFS2_FI_FLAG_FILECHECK_FIX
);
531 entry
->fe_status
= OCFS2_FILECHECK_ERR_UNSUPPORTED
;
533 ocfs2_filecheck_done_entry(ent
, entry
);
536 static ssize_t
ocfs2_filecheck_store(struct kobject
*kobj
,
537 struct kobj_attribute
*attr
,
538 const char *buf
, size_t count
)
540 struct ocfs2_filecheck_args args
;
541 struct ocfs2_filecheck_entry
*entry
;
542 struct ocfs2_filecheck_sysfs_entry
*ent
;
548 if (ocfs2_filecheck_args_parse(attr
->attr
.name
, buf
, count
, &args
)) {
549 mlog(ML_ERROR
, "Invalid arguments for online file check\n");
553 ent
= ocfs2_filecheck_sysfs_get(kobj
->parent
->name
);
556 "Cannot get the corresponding entry via device basename %s\n",
561 if (args
.fa_type
== OCFS2_FILECHECK_TYPE_SET
) {
562 ret
= ocfs2_filecheck_adjust_max(ent
, args
.fa_len
);
566 entry
= kmalloc(sizeof(struct ocfs2_filecheck_entry
), GFP_NOFS
);
572 spin_lock(&ent
->fs_fcheck
->fc_lock
);
573 if ((ent
->fs_fcheck
->fc_size
>= ent
->fs_fcheck
->fc_max
) &&
574 (ent
->fs_fcheck
->fc_done
== 0)) {
576 "Cannot do more file check "
577 "since file check queue(%u) is full now\n",
578 ent
->fs_fcheck
->fc_max
);
582 if ((ent
->fs_fcheck
->fc_size
>= ent
->fs_fcheck
->fc_max
) &&
583 (ent
->fs_fcheck
->fc_done
> 0)) {
584 /* Delete the oldest entry which was done,
585 * make sure the entry size in list does
586 * not exceed maximum value
588 BUG_ON(!ocfs2_filecheck_erase_entry(ent
));
591 entry
->fe_ino
= args
.fa_ino
;
592 entry
->fe_type
= args
.fa_type
;
594 entry
->fe_status
= OCFS2_FILECHECK_ERR_INPROGRESS
;
595 list_add_tail(&entry
->fe_list
, &ent
->fs_fcheck
->fc_head
);
596 ent
->fs_fcheck
->fc_size
++;
598 spin_unlock(&ent
->fs_fcheck
->fc_lock
);
601 ocfs2_filecheck_handle_entry(ent
, entry
);
604 ocfs2_filecheck_sysfs_put(ent
);
605 return (!ret
? count
: ret
);