filecheck.c 12 KB

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