root/fs/ocfs2/filecheck.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ocfs2_filecheck_error
  2. ocfs2_filecheck_release
  3. ocfs2_filecheck_show
  4. ocfs2_filecheck_store
  5. ocfs2_filecheck_sysfs_free
  6. ocfs2_filecheck_create_sysfs
  7. ocfs2_filecheck_remove_sysfs
  8. ocfs2_filecheck_adjust_max
  9. ocfs2_filecheck_args_get_long
  10. ocfs2_filecheck_type_parse
  11. ocfs2_filecheck_args_parse
  12. ocfs2_filecheck_attr_show
  13. ocfs2_filecheck_is_dup_entry
  14. ocfs2_filecheck_erase_entry
  15. ocfs2_filecheck_erase_entries
  16. ocfs2_filecheck_done_entry
  17. ocfs2_filecheck_handle
  18. ocfs2_filecheck_handle_entry
  19. ocfs2_filecheck_attr_store

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* -*- mode: c; c-basic-offset: 8; -*-
   3  * vim: noexpandtab sw=8 ts=8 sts=0:
   4  *
   5  * filecheck.c
   6  *
   7  * Code which implements online file check.
   8  *
   9  * Copyright (C) 2016 SuSE.  All rights reserved.
  10  */
  11 
  12 #include <linux/list.h>
  13 #include <linux/spinlock.h>
  14 #include <linux/module.h>
  15 #include <linux/slab.h>
  16 #include <linux/kmod.h>
  17 #include <linux/fs.h>
  18 #include <linux/kobject.h>
  19 #include <linux/sysfs.h>
  20 #include <linux/sysctl.h>
  21 #include <cluster/masklog.h>
  22 
  23 #include "ocfs2.h"
  24 #include "ocfs2_fs.h"
  25 #include "stackglue.h"
  26 #include "inode.h"
  27 
  28 #include "filecheck.h"
  29 
  30 
  31 /* File check error strings,
  32  * must correspond with error number in header file.
  33  */
  34 static const char * const ocfs2_filecheck_errs[] = {
  35         "SUCCESS",
  36         "FAILED",
  37         "INPROGRESS",
  38         "READONLY",
  39         "INJBD",
  40         "INVALIDINO",
  41         "BLOCKECC",
  42         "BLOCKNO",
  43         "VALIDFLAG",
  44         "GENERATION",
  45         "UNSUPPORTED"
  46 };
  47 
  48 struct ocfs2_filecheck_entry {
  49         struct list_head fe_list;
  50         unsigned long fe_ino;
  51         unsigned int fe_type;
  52         unsigned int fe_done:1;
  53         unsigned int fe_status:31;
  54 };
  55 
  56 struct ocfs2_filecheck_args {
  57         unsigned int fa_type;
  58         union {
  59                 unsigned long fa_ino;
  60                 unsigned int fa_len;
  61         };
  62 };
  63 
  64 static const char *
  65 ocfs2_filecheck_error(int errno)
  66 {
  67         if (!errno)
  68                 return ocfs2_filecheck_errs[errno];
  69 
  70         BUG_ON(errno < OCFS2_FILECHECK_ERR_START ||
  71                errno > OCFS2_FILECHECK_ERR_END);
  72         return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
  73 }
  74 
  75 static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
  76                                         struct kobj_attribute *attr,
  77                                         char *buf);
  78 static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
  79                                         struct kobj_attribute *attr,
  80                                         const char *buf, size_t count);
  81 static struct kobj_attribute ocfs2_filecheck_attr_chk =
  82                                         __ATTR(check, S_IRUSR | S_IWUSR,
  83                                         ocfs2_filecheck_attr_show,
  84                                         ocfs2_filecheck_attr_store);
  85 static struct kobj_attribute ocfs2_filecheck_attr_fix =
  86                                         __ATTR(fix, S_IRUSR | S_IWUSR,
  87                                         ocfs2_filecheck_attr_show,
  88                                         ocfs2_filecheck_attr_store);
  89 static struct kobj_attribute ocfs2_filecheck_attr_set =
  90                                         __ATTR(set, S_IRUSR | S_IWUSR,
  91                                         ocfs2_filecheck_attr_show,
  92                                         ocfs2_filecheck_attr_store);
  93 static struct attribute *ocfs2_filecheck_attrs[] = {
  94         &ocfs2_filecheck_attr_chk.attr,
  95         &ocfs2_filecheck_attr_fix.attr,
  96         &ocfs2_filecheck_attr_set.attr,
  97         NULL
  98 };
  99 
 100 static void ocfs2_filecheck_release(struct kobject *kobj)
 101 {
 102         struct ocfs2_filecheck_sysfs_entry *entry = container_of(kobj,
 103                                 struct ocfs2_filecheck_sysfs_entry, fs_kobj);
 104 
 105         complete(&entry->fs_kobj_unregister);
 106 }
 107 
 108 static ssize_t
 109 ocfs2_filecheck_show(struct kobject *kobj, struct attribute *attr, char *buf)
 110 {
 111         ssize_t ret = -EIO;
 112         struct kobj_attribute *kattr = container_of(attr,
 113                                         struct kobj_attribute, attr);
 114 
 115         kobject_get(kobj);
 116         if (kattr->show)
 117                 ret = kattr->show(kobj, kattr, buf);
 118         kobject_put(kobj);
 119         return ret;
 120 }
 121 
 122 static ssize_t
 123 ocfs2_filecheck_store(struct kobject *kobj, struct attribute *attr,
 124                         const char *buf, size_t count)
 125 {
 126         ssize_t ret = -EIO;
 127         struct kobj_attribute *kattr = container_of(attr,
 128                                         struct kobj_attribute, attr);
 129 
 130         kobject_get(kobj);
 131         if (kattr->store)
 132                 ret = kattr->store(kobj, kattr, buf, count);
 133         kobject_put(kobj);
 134         return ret;
 135 }
 136 
 137 static const struct sysfs_ops ocfs2_filecheck_ops = {
 138         .show = ocfs2_filecheck_show,
 139         .store = ocfs2_filecheck_store,
 140 };
 141 
 142 static struct kobj_type ocfs2_ktype_filecheck = {
 143         .default_attrs = ocfs2_filecheck_attrs,
 144         .sysfs_ops = &ocfs2_filecheck_ops,
 145         .release = ocfs2_filecheck_release,
 146 };
 147 
 148 static void
 149 ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
 150 {
 151         struct ocfs2_filecheck_entry *p;
 152 
 153         spin_lock(&entry->fs_fcheck->fc_lock);
 154         while (!list_empty(&entry->fs_fcheck->fc_head)) {
 155                 p = list_first_entry(&entry->fs_fcheck->fc_head,
 156                                      struct ocfs2_filecheck_entry, fe_list);
 157                 list_del(&p->fe_list);
 158                 BUG_ON(!p->fe_done); /* To free a undone file check entry */
 159                 kfree(p);
 160         }
 161         spin_unlock(&entry->fs_fcheck->fc_lock);
 162 
 163         kfree(entry->fs_fcheck);
 164         entry->fs_fcheck = NULL;
 165 }
 166 
 167 int ocfs2_filecheck_create_sysfs(struct ocfs2_super *osb)
 168 {
 169         int ret;
 170         struct ocfs2_filecheck *fcheck;
 171         struct ocfs2_filecheck_sysfs_entry *entry = &osb->osb_fc_ent;
 172 
 173         fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
 174         if (!fcheck)
 175                 return -ENOMEM;
 176 
 177         INIT_LIST_HEAD(&fcheck->fc_head);
 178         spin_lock_init(&fcheck->fc_lock);
 179         fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
 180         fcheck->fc_size = 0;
 181         fcheck->fc_done = 0;
 182 
 183         entry->fs_kobj.kset = osb->osb_dev_kset;
 184         init_completion(&entry->fs_kobj_unregister);
 185         ret = kobject_init_and_add(&entry->fs_kobj, &ocfs2_ktype_filecheck,
 186                                         NULL, "filecheck");
 187         if (ret) {
 188                 kobject_put(&entry->fs_kobj);
 189                 kfree(fcheck);
 190                 return ret;
 191         }
 192 
 193         entry->fs_fcheck = fcheck;
 194         return 0;
 195 }
 196 
 197 void ocfs2_filecheck_remove_sysfs(struct ocfs2_super *osb)
 198 {
 199         if (!osb->osb_fc_ent.fs_fcheck)
 200                 return;
 201 
 202         kobject_del(&osb->osb_fc_ent.fs_kobj);
 203         kobject_put(&osb->osb_fc_ent.fs_kobj);
 204         wait_for_completion(&osb->osb_fc_ent.fs_kobj_unregister);
 205         ocfs2_filecheck_sysfs_free(&osb->osb_fc_ent);
 206 }
 207 
 208 static int
 209 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
 210                               unsigned int count);
 211 static int
 212 ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
 213                            unsigned int len)
 214 {
 215         int ret;
 216 
 217         if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
 218                 return -EINVAL;
 219 
 220         spin_lock(&ent->fs_fcheck->fc_lock);
 221         if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
 222                 mlog(ML_NOTICE,
 223                 "Cannot set online file check maximum entry number "
 224                 "to %u due to too many pending entries(%u)\n",
 225                 len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
 226                 ret = -EBUSY;
 227         } else {
 228                 if (len < ent->fs_fcheck->fc_size)
 229                         BUG_ON(!ocfs2_filecheck_erase_entries(ent,
 230                                 ent->fs_fcheck->fc_size - len));
 231 
 232                 ent->fs_fcheck->fc_max = len;
 233                 ret = 0;
 234         }
 235         spin_unlock(&ent->fs_fcheck->fc_lock);
 236 
 237         return ret;
 238 }
 239 
 240 #define OCFS2_FILECHECK_ARGS_LEN        24
 241 static int
 242 ocfs2_filecheck_args_get_long(const char *buf, size_t count,
 243                               unsigned long *val)
 244 {
 245         char buffer[OCFS2_FILECHECK_ARGS_LEN];
 246 
 247         memcpy(buffer, buf, count);
 248         buffer[count] = '\0';
 249 
 250         if (kstrtoul(buffer, 0, val))
 251                 return 1;
 252 
 253         return 0;
 254 }
 255 
 256 static int
 257 ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
 258 {
 259         if (!strncmp(name, "fix", 4))
 260                 *type = OCFS2_FILECHECK_TYPE_FIX;
 261         else if (!strncmp(name, "check", 6))
 262                 *type = OCFS2_FILECHECK_TYPE_CHK;
 263         else if (!strncmp(name, "set", 4))
 264                 *type = OCFS2_FILECHECK_TYPE_SET;
 265         else
 266                 return 1;
 267 
 268         return 0;
 269 }
 270 
 271 static int
 272 ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
 273                            struct ocfs2_filecheck_args *args)
 274 {
 275         unsigned long val = 0;
 276         unsigned int type;
 277 
 278         /* too short/long args length */
 279         if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
 280                 return 1;
 281 
 282         if (ocfs2_filecheck_type_parse(name, &type))
 283                 return 1;
 284         if (ocfs2_filecheck_args_get_long(buf, count, &val))
 285                 return 1;
 286 
 287         if (val <= 0)
 288                 return 1;
 289 
 290         args->fa_type = type;
 291         if (type == OCFS2_FILECHECK_TYPE_SET)
 292                 args->fa_len = (unsigned int)val;
 293         else
 294                 args->fa_ino = val;
 295 
 296         return 0;
 297 }
 298 
 299 static ssize_t ocfs2_filecheck_attr_show(struct kobject *kobj,
 300                                     struct kobj_attribute *attr,
 301                                     char *buf)
 302 {
 303 
 304         ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
 305         unsigned int type;
 306         struct ocfs2_filecheck_entry *p;
 307         struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
 308                                 struct ocfs2_filecheck_sysfs_entry, fs_kobj);
 309 
 310         if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
 311                 return -EINVAL;
 312 
 313         if (type == OCFS2_FILECHECK_TYPE_SET) {
 314                 spin_lock(&ent->fs_fcheck->fc_lock);
 315                 total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
 316                 spin_unlock(&ent->fs_fcheck->fc_lock);
 317                 goto exit;
 318         }
 319 
 320         ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
 321         total += ret;
 322         remain -= ret;
 323         spin_lock(&ent->fs_fcheck->fc_lock);
 324         list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
 325                 if (p->fe_type != type)
 326                         continue;
 327 
 328                 ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n",
 329                                p->fe_ino, p->fe_done,
 330                                ocfs2_filecheck_error(p->fe_status));
 331                 if (ret < 0) {
 332                         total = ret;
 333                         break;
 334                 }
 335                 if (ret == remain) {
 336                         /* snprintf() didn't fit */
 337                         total = -E2BIG;
 338                         break;
 339                 }
 340                 total += ret;
 341                 remain -= ret;
 342         }
 343         spin_unlock(&ent->fs_fcheck->fc_lock);
 344 
 345 exit:
 346         return total;
 347 }
 348 
 349 static inline int
 350 ocfs2_filecheck_is_dup_entry(struct ocfs2_filecheck_sysfs_entry *ent,
 351                                 unsigned long ino)
 352 {
 353         struct ocfs2_filecheck_entry *p;
 354 
 355         list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
 356                 if (!p->fe_done) {
 357                         if (p->fe_ino == ino)
 358                                 return 1;
 359                 }
 360         }
 361 
 362         return 0;
 363 }
 364 
 365 static inline int
 366 ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
 367 {
 368         struct ocfs2_filecheck_entry *p;
 369 
 370         list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
 371                 if (p->fe_done) {
 372                         list_del(&p->fe_list);
 373                         kfree(p);
 374                         ent->fs_fcheck->fc_size--;
 375                         ent->fs_fcheck->fc_done--;
 376                         return 1;
 377                 }
 378         }
 379 
 380         return 0;
 381 }
 382 
 383 static int
 384 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
 385                               unsigned int count)
 386 {
 387         unsigned int i = 0;
 388         unsigned int ret = 0;
 389 
 390         while (i++ < count) {
 391                 if (ocfs2_filecheck_erase_entry(ent))
 392                         ret++;
 393                 else
 394                         break;
 395         }
 396 
 397         return (ret == count ? 1 : 0);
 398 }
 399 
 400 static void
 401 ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
 402                            struct ocfs2_filecheck_entry *entry)
 403 {
 404         spin_lock(&ent->fs_fcheck->fc_lock);
 405         entry->fe_done = 1;
 406         ent->fs_fcheck->fc_done++;
 407         spin_unlock(&ent->fs_fcheck->fc_lock);
 408 }
 409 
 410 static unsigned int
 411 ocfs2_filecheck_handle(struct ocfs2_super *osb,
 412                        unsigned long ino, unsigned int flags)
 413 {
 414         unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
 415         struct inode *inode = NULL;
 416         int rc;
 417 
 418         inode = ocfs2_iget(osb, ino, flags, 0);
 419         if (IS_ERR(inode)) {
 420                 rc = (int)(-(long)inode);
 421                 if (rc >= OCFS2_FILECHECK_ERR_START &&
 422                     rc < OCFS2_FILECHECK_ERR_END)
 423                         ret = rc;
 424                 else
 425                         ret = OCFS2_FILECHECK_ERR_FAILED;
 426         } else
 427                 iput(inode);
 428 
 429         return ret;
 430 }
 431 
 432 static void
 433 ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
 434                              struct ocfs2_filecheck_entry *entry)
 435 {
 436         struct ocfs2_super *osb = container_of(ent, struct ocfs2_super,
 437                                                 osb_fc_ent);
 438 
 439         if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
 440                 entry->fe_status = ocfs2_filecheck_handle(osb,
 441                                 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
 442         else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
 443                 entry->fe_status = ocfs2_filecheck_handle(osb,
 444                                 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
 445         else
 446                 entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
 447 
 448         ocfs2_filecheck_done_entry(ent, entry);
 449 }
 450 
 451 static ssize_t ocfs2_filecheck_attr_store(struct kobject *kobj,
 452                                      struct kobj_attribute *attr,
 453                                      const char *buf, size_t count)
 454 {
 455         ssize_t ret = 0;
 456         struct ocfs2_filecheck_args args;
 457         struct ocfs2_filecheck_entry *entry;
 458         struct ocfs2_filecheck_sysfs_entry *ent = container_of(kobj,
 459                                 struct ocfs2_filecheck_sysfs_entry, fs_kobj);
 460 
 461         if (count == 0)
 462                 return count;
 463 
 464         if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args))
 465                 return -EINVAL;
 466 
 467         if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
 468                 ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
 469                 goto exit;
 470         }
 471 
 472         entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
 473         if (!entry) {
 474                 ret = -ENOMEM;
 475                 goto exit;
 476         }
 477 
 478         spin_lock(&ent->fs_fcheck->fc_lock);
 479         if (ocfs2_filecheck_is_dup_entry(ent, args.fa_ino)) {
 480                 ret = -EEXIST;
 481                 kfree(entry);
 482         } else if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
 483                 (ent->fs_fcheck->fc_done == 0)) {
 484                 mlog(ML_NOTICE,
 485                 "Cannot do more file check "
 486                 "since file check queue(%u) is full now\n",
 487                 ent->fs_fcheck->fc_max);
 488                 ret = -EAGAIN;
 489                 kfree(entry);
 490         } else {
 491                 if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
 492                     (ent->fs_fcheck->fc_done > 0)) {
 493                         /* Delete the oldest entry which was done,
 494                          * make sure the entry size in list does
 495                          * not exceed maximum value
 496                          */
 497                         BUG_ON(!ocfs2_filecheck_erase_entry(ent));
 498                 }
 499 
 500                 entry->fe_ino = args.fa_ino;
 501                 entry->fe_type = args.fa_type;
 502                 entry->fe_done = 0;
 503                 entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
 504                 list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
 505                 ent->fs_fcheck->fc_size++;
 506         }
 507         spin_unlock(&ent->fs_fcheck->fc_lock);
 508 
 509         if (!ret)
 510                 ocfs2_filecheck_handle_entry(ent, entry);
 511 
 512 exit:
 513         return (!ret ? count : ret);
 514 }

/* [<][>][^][v][top][bottom][index][help] */