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