filecheck.c 12 KB

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