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