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