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 < 0) { 435 total = ret; 436 break; 437 } 438 if (ret == remain) { 439 /* snprintf() didn't fit */ 440 total = -E2BIG; 441 break; 442 } 443 total += ret; 444 remain -= ret; 445 } 446 spin_unlock(&ent->fs_fcheck->fc_lock); 447 448 exit: 449 ocfs2_filecheck_sysfs_put(ent); 450 return total; 451 } 452 453 static int 454 ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent) 455 { 456 struct ocfs2_filecheck_entry *p; 457 458 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 459 if (p->fe_done) { 460 list_del(&p->fe_list); 461 kfree(p); 462 ent->fs_fcheck->fc_size--; 463 ent->fs_fcheck->fc_done--; 464 return 1; 465 } 466 } 467 468 return 0; 469 } 470 471 static int 472 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 473 unsigned int count) 474 { 475 unsigned int i = 0; 476 unsigned int ret = 0; 477 478 while (i++ < count) { 479 if (ocfs2_filecheck_erase_entry(ent)) 480 ret++; 481 else 482 break; 483 } 484 485 return (ret == count ? 1 : 0); 486 } 487 488 static void 489 ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent, 490 struct ocfs2_filecheck_entry *entry) 491 { 492 entry->fe_done = 1; 493 spin_lock(&ent->fs_fcheck->fc_lock); 494 ent->fs_fcheck->fc_done++; 495 spin_unlock(&ent->fs_fcheck->fc_lock); 496 } 497 498 static unsigned int 499 ocfs2_filecheck_handle(struct super_block *sb, 500 unsigned long ino, unsigned int flags) 501 { 502 unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS; 503 struct inode *inode = NULL; 504 int rc; 505 506 inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0); 507 if (IS_ERR(inode)) { 508 rc = (int)(-(long)inode); 509 if (rc >= OCFS2_FILECHECK_ERR_START && 510 rc < OCFS2_FILECHECK_ERR_END) 511 ret = rc; 512 else 513 ret = OCFS2_FILECHECK_ERR_FAILED; 514 } else 515 iput(inode); 516 517 return ret; 518 } 519 520 static void 521 ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent, 522 struct ocfs2_filecheck_entry *entry) 523 { 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); 530 else 531 entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED; 532 533 ocfs2_filecheck_done_entry(ent, entry); 534 } 535 536 static ssize_t ocfs2_filecheck_store(struct kobject *kobj, 537 struct kobj_attribute *attr, 538 const char *buf, size_t count) 539 { 540 struct ocfs2_filecheck_args args; 541 struct ocfs2_filecheck_entry *entry; 542 struct ocfs2_filecheck_sysfs_entry *ent; 543 ssize_t ret = 0; 544 545 if (count == 0) 546 return count; 547 548 if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) { 549 mlog(ML_ERROR, "Invalid arguments for online file check\n"); 550 return -EINVAL; 551 } 552 553 ent = ocfs2_filecheck_sysfs_get(kobj->parent->name); 554 if (!ent) { 555 mlog(ML_ERROR, 556 "Cannot get the corresponding entry via device basename %s\n", 557 kobj->parent->name); 558 return -ENODEV; 559 } 560 561 if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) { 562 ret = ocfs2_filecheck_adjust_max(ent, args.fa_len); 563 goto exit; 564 } 565 566 entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS); 567 if (!entry) { 568 ret = -ENOMEM; 569 goto exit; 570 } 571 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)) { 575 mlog(ML_ERROR, 576 "Cannot do more file check " 577 "since file check queue(%u) is full now\n", 578 ent->fs_fcheck->fc_max); 579 ret = -EBUSY; 580 kfree(entry); 581 } else { 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 587 */ 588 BUG_ON(!ocfs2_filecheck_erase_entry(ent)); 589 } 590 591 entry->fe_ino = args.fa_ino; 592 entry->fe_type = args.fa_type; 593 entry->fe_done = 0; 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++; 597 } 598 spin_unlock(&ent->fs_fcheck->fc_lock); 599 600 if (!ret) 601 ocfs2_filecheck_handle_entry(ent, entry); 602 603 exit: 604 ocfs2_filecheck_sysfs_put(ent); 605 return (!ret ? count : ret); 606 } 607