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 void 133 ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry) 134 { 135 struct ocfs2_filecheck_entry *p; 136 137 if (!atomic_dec_and_test(&entry->fs_count)) { 138 wait_var_event(&entry->fs_count, 139 !atomic_read(&entry->fs_count)); 140 } 141 142 spin_lock(&entry->fs_fcheck->fc_lock); 143 while (!list_empty(&entry->fs_fcheck->fc_head)) { 144 p = list_first_entry(&entry->fs_fcheck->fc_head, 145 struct ocfs2_filecheck_entry, fe_list); 146 list_del(&p->fe_list); 147 BUG_ON(!p->fe_done); /* To free a undone file check entry */ 148 kfree(p); 149 } 150 spin_unlock(&entry->fs_fcheck->fc_lock); 151 152 kset_unregister(entry->fs_fcheckkset); 153 kset_unregister(entry->fs_devicekset); 154 kfree(entry->fs_fcheck); 155 kfree(entry); 156 } 157 158 static void 159 ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry) 160 { 161 spin_lock(&ocfs2_filecheck_sysfs_lock); 162 list_add_tail(&entry->fs_list, &ocfs2_filecheck_sysfs_list); 163 spin_unlock(&ocfs2_filecheck_sysfs_lock); 164 } 165 166 static int ocfs2_filecheck_sysfs_del(const char *devname) 167 { 168 struct ocfs2_filecheck_sysfs_entry *p; 169 170 spin_lock(&ocfs2_filecheck_sysfs_lock); 171 list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) { 172 if (!strcmp(p->fs_sb->s_id, devname)) { 173 list_del(&p->fs_list); 174 spin_unlock(&ocfs2_filecheck_sysfs_lock); 175 ocfs2_filecheck_sysfs_free(p); 176 return 0; 177 } 178 } 179 spin_unlock(&ocfs2_filecheck_sysfs_lock); 180 return 1; 181 } 182 183 static void 184 ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry) 185 { 186 if (atomic_dec_and_test(&entry->fs_count)) 187 wake_up_var(&entry->fs_count); 188 } 189 190 static struct ocfs2_filecheck_sysfs_entry * 191 ocfs2_filecheck_sysfs_get(const char *devname) 192 { 193 struct ocfs2_filecheck_sysfs_entry *p = NULL; 194 195 spin_lock(&ocfs2_filecheck_sysfs_lock); 196 list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) { 197 if (!strcmp(p->fs_sb->s_id, devname)) { 198 atomic_inc(&p->fs_count); 199 spin_unlock(&ocfs2_filecheck_sysfs_lock); 200 return p; 201 } 202 } 203 spin_unlock(&ocfs2_filecheck_sysfs_lock); 204 return NULL; 205 } 206 207 int ocfs2_filecheck_create_sysfs(struct super_block *sb) 208 { 209 int ret = 0; 210 struct kset *device_kset = NULL; 211 struct kset *fcheck_kset = NULL; 212 struct ocfs2_filecheck *fcheck = NULL; 213 struct ocfs2_filecheck_sysfs_entry *entry = NULL; 214 struct attribute **attrs = NULL; 215 struct attribute_group attrgp; 216 217 if (!ocfs2_kset) 218 return -ENOMEM; 219 220 attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS); 221 if (!attrs) { 222 ret = -ENOMEM; 223 goto error; 224 } else { 225 attrs[0] = &ocfs2_attr_filecheck_chk.attr; 226 attrs[1] = &ocfs2_attr_filecheck_fix.attr; 227 attrs[2] = &ocfs2_attr_filecheck_set.attr; 228 attrs[3] = NULL; 229 memset(&attrgp, 0, sizeof(attrgp)); 230 attrgp.attrs = attrs; 231 } 232 233 fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS); 234 if (!fcheck) { 235 ret = -ENOMEM; 236 goto error; 237 } else { 238 INIT_LIST_HEAD(&fcheck->fc_head); 239 spin_lock_init(&fcheck->fc_lock); 240 fcheck->fc_max = OCFS2_FILECHECK_MINSIZE; 241 fcheck->fc_size = 0; 242 fcheck->fc_done = 0; 243 } 244 245 if (strlen(sb->s_id) <= 0) { 246 mlog(ML_ERROR, 247 "Cannot get device basename when create filecheck sysfs\n"); 248 ret = -ENODEV; 249 goto error; 250 } 251 252 device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj); 253 if (!device_kset) { 254 ret = -ENOMEM; 255 goto error; 256 } 257 258 fcheck_kset = kset_create_and_add("filecheck", NULL, 259 &device_kset->kobj); 260 if (!fcheck_kset) { 261 ret = -ENOMEM; 262 goto error; 263 } 264 265 ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp); 266 if (ret) 267 goto error; 268 269 entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS); 270 if (!entry) { 271 ret = -ENOMEM; 272 goto error; 273 } else { 274 atomic_set(&entry->fs_count, 1); 275 entry->fs_sb = sb; 276 entry->fs_devicekset = device_kset; 277 entry->fs_fcheckkset = fcheck_kset; 278 entry->fs_fcheck = fcheck; 279 ocfs2_filecheck_sysfs_add(entry); 280 } 281 282 kfree(attrs); 283 return 0; 284 285 error: 286 kfree(attrs); 287 kfree(entry); 288 kfree(fcheck); 289 kset_unregister(fcheck_kset); 290 kset_unregister(device_kset); 291 return ret; 292 } 293 294 int ocfs2_filecheck_remove_sysfs(struct super_block *sb) 295 { 296 return ocfs2_filecheck_sysfs_del(sb->s_id); 297 } 298 299 static int 300 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 301 unsigned int count); 302 static int 303 ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent, 304 unsigned int len) 305 { 306 int ret; 307 308 if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE)) 309 return -EINVAL; 310 311 spin_lock(&ent->fs_fcheck->fc_lock); 312 if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) { 313 mlog(ML_ERROR, 314 "Cannot set online file check maximum entry number " 315 "to %u due to too many pending entries(%u)\n", 316 len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done); 317 ret = -EBUSY; 318 } else { 319 if (len < ent->fs_fcheck->fc_size) 320 BUG_ON(!ocfs2_filecheck_erase_entries(ent, 321 ent->fs_fcheck->fc_size - len)); 322 323 ent->fs_fcheck->fc_max = len; 324 ret = 0; 325 } 326 spin_unlock(&ent->fs_fcheck->fc_lock); 327 328 return ret; 329 } 330 331 #define OCFS2_FILECHECK_ARGS_LEN 24 332 static int 333 ocfs2_filecheck_args_get_long(const char *buf, size_t count, 334 unsigned long *val) 335 { 336 char buffer[OCFS2_FILECHECK_ARGS_LEN]; 337 338 memcpy(buffer, buf, count); 339 buffer[count] = '\0'; 340 341 if (kstrtoul(buffer, 0, val)) 342 return 1; 343 344 return 0; 345 } 346 347 static int 348 ocfs2_filecheck_type_parse(const char *name, unsigned int *type) 349 { 350 if (!strncmp(name, "fix", 4)) 351 *type = OCFS2_FILECHECK_TYPE_FIX; 352 else if (!strncmp(name, "check", 6)) 353 *type = OCFS2_FILECHECK_TYPE_CHK; 354 else if (!strncmp(name, "set", 4)) 355 *type = OCFS2_FILECHECK_TYPE_SET; 356 else 357 return 1; 358 359 return 0; 360 } 361 362 static int 363 ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count, 364 struct ocfs2_filecheck_args *args) 365 { 366 unsigned long val = 0; 367 unsigned int type; 368 369 /* too short/long args length */ 370 if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN)) 371 return 1; 372 373 if (ocfs2_filecheck_type_parse(name, &type)) 374 return 1; 375 if (ocfs2_filecheck_args_get_long(buf, count, &val)) 376 return 1; 377 378 if (val <= 0) 379 return 1; 380 381 args->fa_type = type; 382 if (type == OCFS2_FILECHECK_TYPE_SET) 383 args->fa_len = (unsigned int)val; 384 else 385 args->fa_ino = val; 386 387 return 0; 388 } 389 390 static ssize_t ocfs2_filecheck_show(struct kobject *kobj, 391 struct kobj_attribute *attr, 392 char *buf) 393 { 394 395 ssize_t ret = 0, total = 0, remain = PAGE_SIZE; 396 unsigned int type; 397 struct ocfs2_filecheck_entry *p; 398 struct ocfs2_filecheck_sysfs_entry *ent; 399 400 if (ocfs2_filecheck_type_parse(attr->attr.name, &type)) 401 return -EINVAL; 402 403 ent = ocfs2_filecheck_sysfs_get(kobj->parent->name); 404 if (!ent) { 405 mlog(ML_ERROR, 406 "Cannot get the corresponding entry via device basename %s\n", 407 kobj->name); 408 return -ENODEV; 409 } 410 411 if (type == OCFS2_FILECHECK_TYPE_SET) { 412 spin_lock(&ent->fs_fcheck->fc_lock); 413 total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max); 414 spin_unlock(&ent->fs_fcheck->fc_lock); 415 goto exit; 416 } 417 418 ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n"); 419 total += ret; 420 remain -= ret; 421 spin_lock(&ent->fs_fcheck->fc_lock); 422 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 423 if (p->fe_type != type) 424 continue; 425 426 ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n", 427 p->fe_ino, p->fe_done, 428 ocfs2_filecheck_error(p->fe_status)); 429 if (ret < 0) { 430 total = ret; 431 break; 432 } 433 if (ret == remain) { 434 /* snprintf() didn't fit */ 435 total = -E2BIG; 436 break; 437 } 438 total += ret; 439 remain -= ret; 440 } 441 spin_unlock(&ent->fs_fcheck->fc_lock); 442 443 exit: 444 ocfs2_filecheck_sysfs_put(ent); 445 return total; 446 } 447 448 static int 449 ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent) 450 { 451 struct ocfs2_filecheck_entry *p; 452 453 list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) { 454 if (p->fe_done) { 455 list_del(&p->fe_list); 456 kfree(p); 457 ent->fs_fcheck->fc_size--; 458 ent->fs_fcheck->fc_done--; 459 return 1; 460 } 461 } 462 463 return 0; 464 } 465 466 static int 467 ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent, 468 unsigned int count) 469 { 470 unsigned int i = 0; 471 unsigned int ret = 0; 472 473 while (i++ < count) { 474 if (ocfs2_filecheck_erase_entry(ent)) 475 ret++; 476 else 477 break; 478 } 479 480 return (ret == count ? 1 : 0); 481 } 482 483 static void 484 ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent, 485 struct ocfs2_filecheck_entry *entry) 486 { 487 entry->fe_done = 1; 488 spin_lock(&ent->fs_fcheck->fc_lock); 489 ent->fs_fcheck->fc_done++; 490 spin_unlock(&ent->fs_fcheck->fc_lock); 491 } 492 493 static unsigned int 494 ocfs2_filecheck_handle(struct super_block *sb, 495 unsigned long ino, unsigned int flags) 496 { 497 unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS; 498 struct inode *inode = NULL; 499 int rc; 500 501 inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0); 502 if (IS_ERR(inode)) { 503 rc = (int)(-(long)inode); 504 if (rc >= OCFS2_FILECHECK_ERR_START && 505 rc < OCFS2_FILECHECK_ERR_END) 506 ret = rc; 507 else 508 ret = OCFS2_FILECHECK_ERR_FAILED; 509 } else 510 iput(inode); 511 512 return ret; 513 } 514 515 static void 516 ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent, 517 struct ocfs2_filecheck_entry *entry) 518 { 519 if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK) 520 entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb, 521 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK); 522 else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX) 523 entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb, 524 entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX); 525 else 526 entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED; 527 528 ocfs2_filecheck_done_entry(ent, entry); 529 } 530 531 static ssize_t ocfs2_filecheck_store(struct kobject *kobj, 532 struct kobj_attribute *attr, 533 const char *buf, size_t count) 534 { 535 struct ocfs2_filecheck_args args; 536 struct ocfs2_filecheck_entry *entry; 537 struct ocfs2_filecheck_sysfs_entry *ent; 538 ssize_t ret = 0; 539 540 if (count == 0) 541 return count; 542 543 if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) { 544 mlog(ML_ERROR, "Invalid arguments for online file check\n"); 545 return -EINVAL; 546 } 547 548 ent = ocfs2_filecheck_sysfs_get(kobj->parent->name); 549 if (!ent) { 550 mlog(ML_ERROR, 551 "Cannot get the corresponding entry via device basename %s\n", 552 kobj->parent->name); 553 return -ENODEV; 554 } 555 556 if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) { 557 ret = ocfs2_filecheck_adjust_max(ent, args.fa_len); 558 goto exit; 559 } 560 561 entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS); 562 if (!entry) { 563 ret = -ENOMEM; 564 goto exit; 565 } 566 567 spin_lock(&ent->fs_fcheck->fc_lock); 568 if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 569 (ent->fs_fcheck->fc_done == 0)) { 570 mlog(ML_ERROR, 571 "Cannot do more file check " 572 "since file check queue(%u) is full now\n", 573 ent->fs_fcheck->fc_max); 574 ret = -EBUSY; 575 kfree(entry); 576 } else { 577 if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) && 578 (ent->fs_fcheck->fc_done > 0)) { 579 /* Delete the oldest entry which was done, 580 * make sure the entry size in list does 581 * not exceed maximum value 582 */ 583 BUG_ON(!ocfs2_filecheck_erase_entry(ent)); 584 } 585 586 entry->fe_ino = args.fa_ino; 587 entry->fe_type = args.fa_type; 588 entry->fe_done = 0; 589 entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS; 590 list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head); 591 ent->fs_fcheck->fc_size++; 592 } 593 spin_unlock(&ent->fs_fcheck->fc_lock); 594 595 if (!ret) 596 ocfs2_filecheck_handle_entry(ent, entry); 597 598 exit: 599 ocfs2_filecheck_sysfs_put(ent); 600 return (!ret ? count : ret); 601 } 602