filecheck.c 14 KB

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