GNU Linux-libre 4.14.262-gnu1
[releases.git] / fs / ocfs2 / filecheck.c
1 /* -*- mode: c; c-basic-offset: 8; -*-
2  * vim: noexpandtab sw=8 ts=8 sts=0:
3  *
4  * filecheck.c
5  *
6  * Code which implements online file check.
7  *
8  * Copyright (C) 2016 SuSE.  All rights reserved.
9  *
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.
13  *
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.
18  */
19
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>
25 #include <linux/fs.h>
26 #include <linux/kobject.h>
27 #include <linux/sysfs.h>
28 #include <linux/sysctl.h>
29 #include <cluster/masklog.h>
30
31 #include "ocfs2.h"
32 #include "ocfs2_fs.h"
33 #include "stackglue.h"
34 #include "inode.h"
35
36 #include "filecheck.h"
37
38
39 /* File check error strings,
40  * must correspond with error number in header file.
41  */
42 static const char * const ocfs2_filecheck_errs[] = {
43         "SUCCESS",
44         "FAILED",
45         "INPROGRESS",
46         "READONLY",
47         "INJBD",
48         "INVALIDINO",
49         "BLOCKECC",
50         "BLOCKNO",
51         "VALIDFLAG",
52         "GENERATION",
53         "UNSUPPORTED"
54 };
55
56 static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
57 static LIST_HEAD(ocfs2_filecheck_sysfs_list);
58
59 struct ocfs2_filecheck {
60         struct list_head fc_head;       /* File check entry list head */
61         spinlock_t fc_lock;
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 */
65 };
66
67 struct ocfs2_filecheck_sysfs_entry {    /* sysfs entry per mounting */
68         struct list_head fs_list;
69         atomic_t fs_count;
70         struct super_block *fs_sb;
71         struct kset *fs_devicekset;
72         struct kset *fs_fcheckkset;
73         struct ocfs2_filecheck *fs_fcheck;
74 };
75
76 #define OCFS2_FILECHECK_MAXSIZE         100
77 #define OCFS2_FILECHECK_MINSIZE         10
78
79 /* File check operation type */
80 enum {
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 */
84 };
85
86 struct ocfs2_filecheck_entry {
87         struct list_head fe_list;
88         unsigned long fe_ino;
89         unsigned int fe_type;
90         unsigned int fe_done:1;
91         unsigned int fe_status:31;
92 };
93
94 struct ocfs2_filecheck_args {
95         unsigned int fa_type;
96         union {
97                 unsigned long fa_ino;
98                 unsigned int fa_len;
99         };
100 };
101
102 static const char *
103 ocfs2_filecheck_error(int errno)
104 {
105         if (!errno)
106                 return ocfs2_filecheck_errs[errno];
107
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];
111 }
112
113 static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
114                                     struct kobj_attribute *attr,
115                                     char *buf);
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);
131
132 static int ocfs2_filecheck_sysfs_wait(atomic_t *p)
133 {
134         schedule();
135         return 0;
136 }
137
138 static void
139 ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
140 {
141         struct ocfs2_filecheck_entry *p;
142
143         if (!atomic_dec_and_test(&entry->fs_count))
144                 wait_on_atomic_t(&entry->fs_count, ocfs2_filecheck_sysfs_wait,
145                                  TASK_UNINTERRUPTIBLE);
146
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 */
153                 kfree(p);
154         }
155         spin_unlock(&entry->fs_fcheck->fc_lock);
156
157         kset_unregister(entry->fs_fcheckkset);
158         kset_unregister(entry->fs_devicekset);
159         kfree(entry->fs_fcheck);
160         kfree(entry);
161 }
162
163 static void
164 ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry)
165 {
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);
169 }
170
171 static int ocfs2_filecheck_sysfs_del(const char *devname)
172 {
173         struct ocfs2_filecheck_sysfs_entry *p;
174
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);
181                         return 0;
182                 }
183         }
184         spin_unlock(&ocfs2_filecheck_sysfs_lock);
185         return 1;
186 }
187
188 static void
189 ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry)
190 {
191         if (atomic_dec_and_test(&entry->fs_count))
192                 wake_up_atomic_t(&entry->fs_count);
193 }
194
195 static struct ocfs2_filecheck_sysfs_entry *
196 ocfs2_filecheck_sysfs_get(const char *devname)
197 {
198         struct ocfs2_filecheck_sysfs_entry *p = NULL;
199
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);
205                         return p;
206                 }
207         }
208         spin_unlock(&ocfs2_filecheck_sysfs_lock);
209         return NULL;
210 }
211
212 int ocfs2_filecheck_create_sysfs(struct super_block *sb)
213 {
214         int ret = 0;
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;
221
222         if (!ocfs2_kset)
223                 return -ENOMEM;
224
225         attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS);
226         if (!attrs) {
227                 ret = -ENOMEM;
228                 goto error;
229         } else {
230                 attrs[0] = &ocfs2_attr_filecheck_chk.attr;
231                 attrs[1] = &ocfs2_attr_filecheck_fix.attr;
232                 attrs[2] = &ocfs2_attr_filecheck_set.attr;
233                 attrs[3] = NULL;
234                 memset(&attrgp, 0, sizeof(attrgp));
235                 attrgp.attrs = attrs;
236         }
237
238         fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
239         if (!fcheck) {
240                 ret = -ENOMEM;
241                 goto error;
242         } else {
243                 INIT_LIST_HEAD(&fcheck->fc_head);
244                 spin_lock_init(&fcheck->fc_lock);
245                 fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
246                 fcheck->fc_size = 0;
247                 fcheck->fc_done = 0;
248         }
249
250         if (strlen(sb->s_id) <= 0) {
251                 mlog(ML_ERROR,
252                 "Cannot get device basename when create filecheck sysfs\n");
253                 ret = -ENODEV;
254                 goto error;
255         }
256
257         device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj);
258         if (!device_kset) {
259                 ret = -ENOMEM;
260                 goto error;
261         }
262
263         fcheck_kset = kset_create_and_add("filecheck", NULL,
264                                           &device_kset->kobj);
265         if (!fcheck_kset) {
266                 ret = -ENOMEM;
267                 goto error;
268         }
269
270         ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp);
271         if (ret)
272                 goto error;
273
274         entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS);
275         if (!entry) {
276                 ret = -ENOMEM;
277                 goto error;
278         } else {
279                 atomic_set(&entry->fs_count, 1);
280                 entry->fs_sb = sb;
281                 entry->fs_devicekset = device_kset;
282                 entry->fs_fcheckkset = fcheck_kset;
283                 entry->fs_fcheck = fcheck;
284                 ocfs2_filecheck_sysfs_add(entry);
285         }
286
287         kfree(attrs);
288         return 0;
289
290 error:
291         kfree(attrs);
292         kfree(entry);
293         kfree(fcheck);
294         kset_unregister(fcheck_kset);
295         kset_unregister(device_kset);
296         return ret;
297 }
298
299 int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
300 {
301         return ocfs2_filecheck_sysfs_del(sb->s_id);
302 }
303
304 static int
305 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
306                               unsigned int count);
307 static int
308 ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
309                            unsigned int len)
310 {
311         int ret;
312
313         if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
314                 return -EINVAL;
315
316         spin_lock(&ent->fs_fcheck->fc_lock);
317         if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
318                 mlog(ML_ERROR,
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);
322                 ret = -EBUSY;
323         } else {
324                 if (len < ent->fs_fcheck->fc_size)
325                         BUG_ON(!ocfs2_filecheck_erase_entries(ent,
326                                 ent->fs_fcheck->fc_size - len));
327
328                 ent->fs_fcheck->fc_max = len;
329                 ret = 0;
330         }
331         spin_unlock(&ent->fs_fcheck->fc_lock);
332
333         return ret;
334 }
335
336 #define OCFS2_FILECHECK_ARGS_LEN        24
337 static int
338 ocfs2_filecheck_args_get_long(const char *buf, size_t count,
339                               unsigned long *val)
340 {
341         char buffer[OCFS2_FILECHECK_ARGS_LEN];
342
343         memcpy(buffer, buf, count);
344         buffer[count] = '\0';
345
346         if (kstrtoul(buffer, 0, val))
347                 return 1;
348
349         return 0;
350 }
351
352 static int
353 ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
354 {
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;
361         else
362                 return 1;
363
364         return 0;
365 }
366
367 static int
368 ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
369                            struct ocfs2_filecheck_args *args)
370 {
371         unsigned long val = 0;
372         unsigned int type;
373
374         /* too short/long args length */
375         if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
376                 return 1;
377
378         if (ocfs2_filecheck_type_parse(name, &type))
379                 return 1;
380         if (ocfs2_filecheck_args_get_long(buf, count, &val))
381                 return 1;
382
383         if (val <= 0)
384                 return 1;
385
386         args->fa_type = type;
387         if (type == OCFS2_FILECHECK_TYPE_SET)
388                 args->fa_len = (unsigned int)val;
389         else
390                 args->fa_ino = val;
391
392         return 0;
393 }
394
395 static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
396                                     struct kobj_attribute *attr,
397                                     char *buf)
398 {
399
400         ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
401         unsigned int type;
402         struct ocfs2_filecheck_entry *p;
403         struct ocfs2_filecheck_sysfs_entry *ent;
404
405         if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
406                 return -EINVAL;
407
408         ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
409         if (!ent) {
410                 mlog(ML_ERROR,
411                 "Cannot get the corresponding entry via device basename %s\n",
412                 kobj->name);
413                 return -ENODEV;
414         }
415
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);
420                 goto exit;
421         }
422
423         ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
424         total += ret;
425         remain -= ret;
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)
429                         continue;
430
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));
434                 if (ret >= remain) {
435                         /* snprintf() didn't fit */
436                         total = -E2BIG;
437                         break;
438                 }
439                 total += ret;
440                 remain -= ret;
441         }
442         spin_unlock(&ent->fs_fcheck->fc_lock);
443
444 exit:
445         ocfs2_filecheck_sysfs_put(ent);
446         return total;
447 }
448
449 static int
450 ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
451 {
452         struct ocfs2_filecheck_entry *p;
453
454         list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
455                 if (p->fe_done) {
456                         list_del(&p->fe_list);
457                         kfree(p);
458                         ent->fs_fcheck->fc_size--;
459                         ent->fs_fcheck->fc_done--;
460                         return 1;
461                 }
462         }
463
464         return 0;
465 }
466
467 static int
468 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
469                               unsigned int count)
470 {
471         unsigned int i = 0;
472         unsigned int ret = 0;
473
474         while (i++ < count) {
475                 if (ocfs2_filecheck_erase_entry(ent))
476                         ret++;
477                 else
478                         break;
479         }
480
481         return (ret == count ? 1 : 0);
482 }
483
484 static void
485 ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
486                            struct ocfs2_filecheck_entry *entry)
487 {
488         entry->fe_done = 1;
489         spin_lock(&ent->fs_fcheck->fc_lock);
490         ent->fs_fcheck->fc_done++;
491         spin_unlock(&ent->fs_fcheck->fc_lock);
492 }
493
494 static unsigned int
495 ocfs2_filecheck_handle(struct super_block *sb,
496                        unsigned long ino, unsigned int flags)
497 {
498         unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
499         struct inode *inode = NULL;
500         int rc;
501
502         inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0);
503         if (IS_ERR(inode)) {
504                 rc = (int)(-(long)inode);
505                 if (rc >= OCFS2_FILECHECK_ERR_START &&
506                     rc < OCFS2_FILECHECK_ERR_END)
507                         ret = rc;
508                 else
509                         ret = OCFS2_FILECHECK_ERR_FAILED;
510         } else
511                 iput(inode);
512
513         return ret;
514 }
515
516 static void
517 ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
518                              struct ocfs2_filecheck_entry *entry)
519 {
520         if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
521                 entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
522                                 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
523         else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
524                 entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
525                                 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
526         else
527                 entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
528
529         ocfs2_filecheck_done_entry(ent, entry);
530 }
531
532 static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
533                                      struct kobj_attribute *attr,
534                                      const char *buf, size_t count)
535 {
536         struct ocfs2_filecheck_args args;
537         struct ocfs2_filecheck_entry *entry;
538         struct ocfs2_filecheck_sysfs_entry *ent;
539         ssize_t ret = 0;
540
541         if (count == 0)
542                 return count;
543
544         if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) {
545                 mlog(ML_ERROR, "Invalid arguments for online file check\n");
546                 return -EINVAL;
547         }
548
549         ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
550         if (!ent) {
551                 mlog(ML_ERROR,
552                 "Cannot get the corresponding entry via device basename %s\n",
553                 kobj->parent->name);
554                 return -ENODEV;
555         }
556
557         if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
558                 ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
559                 goto exit;
560         }
561
562         entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
563         if (!entry) {
564                 ret = -ENOMEM;
565                 goto exit;
566         }
567
568         spin_lock(&ent->fs_fcheck->fc_lock);
569         if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
570             (ent->fs_fcheck->fc_done == 0)) {
571                 mlog(ML_ERROR,
572                 "Cannot do more file check "
573                 "since file check queue(%u) is full now\n",
574                 ent->fs_fcheck->fc_max);
575                 ret = -EBUSY;
576                 kfree(entry);
577         } else {
578                 if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
579                     (ent->fs_fcheck->fc_done > 0)) {
580                         /* Delete the oldest entry which was done,
581                          * make sure the entry size in list does
582                          * not exceed maximum value
583                          */
584                         BUG_ON(!ocfs2_filecheck_erase_entry(ent));
585                 }
586
587                 entry->fe_ino = args.fa_ino;
588                 entry->fe_type = args.fa_type;
589                 entry->fe_done = 0;
590                 entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
591                 list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
592                 ent->fs_fcheck->fc_size++;
593         }
594         spin_unlock(&ent->fs_fcheck->fc_lock);
595
596         if (!ret)
597                 ocfs2_filecheck_handle_entry(ent, entry);
598
599 exit:
600         ocfs2_filecheck_sysfs_put(ent);
601         return (!ret ? count : ret);
602 }