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