debug.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. /*
  2. * Copyright (c) International Business Machines Corp., 2006
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  12. * the GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. * Author: Artem Bityutskiy (Битюцкий Артём)
  19. */
  20. #include "ubi.h"
  21. #include <linux/debugfs.h>
  22. #include <linux/uaccess.h>
  23. #include <linux/module.h>
  24. #include <linux/seq_file.h>
  25. /**
  26. * ubi_dump_flash - dump a region of flash.
  27. * @ubi: UBI device description object
  28. * @pnum: the physical eraseblock number to dump
  29. * @offset: the starting offset within the physical eraseblock to dump
  30. * @len: the length of the region to dump
  31. */
  32. void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
  33. {
  34. int err;
  35. size_t read;
  36. void *buf;
  37. loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
  38. buf = vmalloc(len);
  39. if (!buf)
  40. return;
  41. err = mtd_read(ubi->mtd, addr, len, &read, buf);
  42. if (err && err != -EUCLEAN) {
  43. ubi_err(ubi, "err %d while reading %d bytes from PEB %d:%d, read %zd bytes",
  44. err, len, pnum, offset, read);
  45. goto out;
  46. }
  47. ubi_msg(ubi, "dumping %d bytes of data from PEB %d, offset %d",
  48. len, pnum, offset);
  49. print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
  50. out:
  51. vfree(buf);
  52. return;
  53. }
  54. /**
  55. * ubi_dump_ec_hdr - dump an erase counter header.
  56. * @ec_hdr: the erase counter header to dump
  57. */
  58. void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
  59. {
  60. pr_err("Erase counter header dump:\n");
  61. pr_err("\tmagic %#08x\n", be32_to_cpu(ec_hdr->magic));
  62. pr_err("\tversion %d\n", (int)ec_hdr->version);
  63. pr_err("\tec %llu\n", (long long)be64_to_cpu(ec_hdr->ec));
  64. pr_err("\tvid_hdr_offset %d\n", be32_to_cpu(ec_hdr->vid_hdr_offset));
  65. pr_err("\tdata_offset %d\n", be32_to_cpu(ec_hdr->data_offset));
  66. pr_err("\timage_seq %d\n", be32_to_cpu(ec_hdr->image_seq));
  67. pr_err("\thdr_crc %#08x\n", be32_to_cpu(ec_hdr->hdr_crc));
  68. pr_err("erase counter header hexdump:\n");
  69. print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
  70. ec_hdr, UBI_EC_HDR_SIZE, 1);
  71. }
  72. /**
  73. * ubi_dump_vid_hdr - dump a volume identifier header.
  74. * @vid_hdr: the volume identifier header to dump
  75. */
  76. void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
  77. {
  78. pr_err("Volume identifier header dump:\n");
  79. pr_err("\tmagic %08x\n", be32_to_cpu(vid_hdr->magic));
  80. pr_err("\tversion %d\n", (int)vid_hdr->version);
  81. pr_err("\tvol_type %d\n", (int)vid_hdr->vol_type);
  82. pr_err("\tcopy_flag %d\n", (int)vid_hdr->copy_flag);
  83. pr_err("\tcompat %d\n", (int)vid_hdr->compat);
  84. pr_err("\tvol_id %d\n", be32_to_cpu(vid_hdr->vol_id));
  85. pr_err("\tlnum %d\n", be32_to_cpu(vid_hdr->lnum));
  86. pr_err("\tdata_size %d\n", be32_to_cpu(vid_hdr->data_size));
  87. pr_err("\tused_ebs %d\n", be32_to_cpu(vid_hdr->used_ebs));
  88. pr_err("\tdata_pad %d\n", be32_to_cpu(vid_hdr->data_pad));
  89. pr_err("\tsqnum %llu\n",
  90. (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
  91. pr_err("\thdr_crc %08x\n", be32_to_cpu(vid_hdr->hdr_crc));
  92. pr_err("Volume identifier header hexdump:\n");
  93. print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
  94. vid_hdr, UBI_VID_HDR_SIZE, 1);
  95. }
  96. /**
  97. * ubi_dump_vol_info - dump volume information.
  98. * @vol: UBI volume description object
  99. */
  100. void ubi_dump_vol_info(const struct ubi_volume *vol)
  101. {
  102. pr_err("Volume information dump:\n");
  103. pr_err("\tvol_id %d\n", vol->vol_id);
  104. pr_err("\treserved_pebs %d\n", vol->reserved_pebs);
  105. pr_err("\talignment %d\n", vol->alignment);
  106. pr_err("\tdata_pad %d\n", vol->data_pad);
  107. pr_err("\tvol_type %d\n", vol->vol_type);
  108. pr_err("\tname_len %d\n", vol->name_len);
  109. pr_err("\tusable_leb_size %d\n", vol->usable_leb_size);
  110. pr_err("\tused_ebs %d\n", vol->used_ebs);
  111. pr_err("\tused_bytes %lld\n", vol->used_bytes);
  112. pr_err("\tlast_eb_bytes %d\n", vol->last_eb_bytes);
  113. pr_err("\tcorrupted %d\n", vol->corrupted);
  114. pr_err("\tupd_marker %d\n", vol->upd_marker);
  115. if (vol->name_len <= UBI_VOL_NAME_MAX &&
  116. strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
  117. pr_err("\tname %s\n", vol->name);
  118. } else {
  119. pr_err("\t1st 5 characters of name: %c%c%c%c%c\n",
  120. vol->name[0], vol->name[1], vol->name[2],
  121. vol->name[3], vol->name[4]);
  122. }
  123. }
  124. /**
  125. * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
  126. * @r: the object to dump
  127. * @idx: volume table index
  128. */
  129. void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
  130. {
  131. int name_len = be16_to_cpu(r->name_len);
  132. pr_err("Volume table record %d dump:\n", idx);
  133. pr_err("\treserved_pebs %d\n", be32_to_cpu(r->reserved_pebs));
  134. pr_err("\talignment %d\n", be32_to_cpu(r->alignment));
  135. pr_err("\tdata_pad %d\n", be32_to_cpu(r->data_pad));
  136. pr_err("\tvol_type %d\n", (int)r->vol_type);
  137. pr_err("\tupd_marker %d\n", (int)r->upd_marker);
  138. pr_err("\tname_len %d\n", name_len);
  139. if (r->name[0] == '\0') {
  140. pr_err("\tname NULL\n");
  141. return;
  142. }
  143. if (name_len <= UBI_VOL_NAME_MAX &&
  144. strnlen(&r->name[0], name_len + 1) == name_len) {
  145. pr_err("\tname %s\n", &r->name[0]);
  146. } else {
  147. pr_err("\t1st 5 characters of name: %c%c%c%c%c\n",
  148. r->name[0], r->name[1], r->name[2], r->name[3],
  149. r->name[4]);
  150. }
  151. pr_err("\tcrc %#08x\n", be32_to_cpu(r->crc));
  152. }
  153. /**
  154. * ubi_dump_av - dump a &struct ubi_ainf_volume object.
  155. * @av: the object to dump
  156. */
  157. void ubi_dump_av(const struct ubi_ainf_volume *av)
  158. {
  159. pr_err("Volume attaching information dump:\n");
  160. pr_err("\tvol_id %d\n", av->vol_id);
  161. pr_err("\thighest_lnum %d\n", av->highest_lnum);
  162. pr_err("\tleb_count %d\n", av->leb_count);
  163. pr_err("\tcompat %d\n", av->compat);
  164. pr_err("\tvol_type %d\n", av->vol_type);
  165. pr_err("\tused_ebs %d\n", av->used_ebs);
  166. pr_err("\tlast_data_size %d\n", av->last_data_size);
  167. pr_err("\tdata_pad %d\n", av->data_pad);
  168. }
  169. /**
  170. * ubi_dump_aeb - dump a &struct ubi_ainf_peb object.
  171. * @aeb: the object to dump
  172. * @type: object type: 0 - not corrupted, 1 - corrupted
  173. */
  174. void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type)
  175. {
  176. pr_err("eraseblock attaching information dump:\n");
  177. pr_err("\tec %d\n", aeb->ec);
  178. pr_err("\tpnum %d\n", aeb->pnum);
  179. if (type == 0) {
  180. pr_err("\tlnum %d\n", aeb->lnum);
  181. pr_err("\tscrub %d\n", aeb->scrub);
  182. pr_err("\tsqnum %llu\n", aeb->sqnum);
  183. }
  184. }
  185. /**
  186. * ubi_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
  187. * @req: the object to dump
  188. */
  189. void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
  190. {
  191. char nm[17];
  192. pr_err("Volume creation request dump:\n");
  193. pr_err("\tvol_id %d\n", req->vol_id);
  194. pr_err("\talignment %d\n", req->alignment);
  195. pr_err("\tbytes %lld\n", (long long)req->bytes);
  196. pr_err("\tvol_type %d\n", req->vol_type);
  197. pr_err("\tname_len %d\n", req->name_len);
  198. memcpy(nm, req->name, 16);
  199. nm[16] = 0;
  200. pr_err("\t1st 16 characters of name: %s\n", nm);
  201. }
  202. /*
  203. * Root directory for UBI stuff in debugfs. Contains sub-directories which
  204. * contain the stuff specific to particular UBI devices.
  205. */
  206. static struct dentry *dfs_rootdir;
  207. /**
  208. * ubi_debugfs_init - create UBI debugfs directory.
  209. *
  210. * Create UBI debugfs directory. Returns zero in case of success and a negative
  211. * error code in case of failure.
  212. */
  213. int ubi_debugfs_init(void)
  214. {
  215. if (!IS_ENABLED(CONFIG_DEBUG_FS))
  216. return 0;
  217. dfs_rootdir = debugfs_create_dir("ubi", NULL);
  218. if (IS_ERR_OR_NULL(dfs_rootdir)) {
  219. int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV;
  220. pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n",
  221. err);
  222. return err;
  223. }
  224. return 0;
  225. }
  226. /**
  227. * ubi_debugfs_exit - remove UBI debugfs directory.
  228. */
  229. void ubi_debugfs_exit(void)
  230. {
  231. if (IS_ENABLED(CONFIG_DEBUG_FS))
  232. debugfs_remove(dfs_rootdir);
  233. }
  234. /* Read an UBI debugfs file */
  235. static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
  236. size_t count, loff_t *ppos)
  237. {
  238. unsigned long ubi_num = (unsigned long)file->private_data;
  239. struct dentry *dent = file->f_path.dentry;
  240. struct ubi_device *ubi;
  241. struct ubi_debug_info *d;
  242. char buf[8];
  243. int val;
  244. ubi = ubi_get_device(ubi_num);
  245. if (!ubi)
  246. return -ENODEV;
  247. d = &ubi->dbg;
  248. if (dent == d->dfs_chk_gen)
  249. val = d->chk_gen;
  250. else if (dent == d->dfs_chk_io)
  251. val = d->chk_io;
  252. else if (dent == d->dfs_chk_fastmap)
  253. val = d->chk_fastmap;
  254. else if (dent == d->dfs_disable_bgt)
  255. val = d->disable_bgt;
  256. else if (dent == d->dfs_emulate_bitflips)
  257. val = d->emulate_bitflips;
  258. else if (dent == d->dfs_emulate_io_failures)
  259. val = d->emulate_io_failures;
  260. else if (dent == d->dfs_emulate_power_cut) {
  261. snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
  262. count = simple_read_from_buffer(user_buf, count, ppos,
  263. buf, strlen(buf));
  264. goto out;
  265. } else if (dent == d->dfs_power_cut_min) {
  266. snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min);
  267. count = simple_read_from_buffer(user_buf, count, ppos,
  268. buf, strlen(buf));
  269. goto out;
  270. } else if (dent == d->dfs_power_cut_max) {
  271. snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max);
  272. count = simple_read_from_buffer(user_buf, count, ppos,
  273. buf, strlen(buf));
  274. goto out;
  275. }
  276. else {
  277. count = -EINVAL;
  278. goto out;
  279. }
  280. if (val)
  281. buf[0] = '1';
  282. else
  283. buf[0] = '0';
  284. buf[1] = '\n';
  285. buf[2] = 0x00;
  286. count = simple_read_from_buffer(user_buf, count, ppos, buf, 2);
  287. out:
  288. ubi_put_device(ubi);
  289. return count;
  290. }
  291. /* Write an UBI debugfs file */
  292. static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
  293. size_t count, loff_t *ppos)
  294. {
  295. unsigned long ubi_num = (unsigned long)file->private_data;
  296. struct dentry *dent = file->f_path.dentry;
  297. struct ubi_device *ubi;
  298. struct ubi_debug_info *d;
  299. size_t buf_size;
  300. char buf[8] = {0};
  301. int val;
  302. ubi = ubi_get_device(ubi_num);
  303. if (!ubi)
  304. return -ENODEV;
  305. d = &ubi->dbg;
  306. buf_size = min_t(size_t, count, (sizeof(buf) - 1));
  307. if (copy_from_user(buf, user_buf, buf_size)) {
  308. count = -EFAULT;
  309. goto out;
  310. }
  311. if (dent == d->dfs_power_cut_min) {
  312. if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
  313. count = -EINVAL;
  314. goto out;
  315. } else if (dent == d->dfs_power_cut_max) {
  316. if (kstrtouint(buf, 0, &d->power_cut_max) != 0)
  317. count = -EINVAL;
  318. goto out;
  319. } else if (dent == d->dfs_emulate_power_cut) {
  320. if (kstrtoint(buf, 0, &val) != 0)
  321. count = -EINVAL;
  322. else
  323. d->emulate_power_cut = val;
  324. goto out;
  325. }
  326. if (buf[0] == '1')
  327. val = 1;
  328. else if (buf[0] == '0')
  329. val = 0;
  330. else {
  331. count = -EINVAL;
  332. goto out;
  333. }
  334. if (dent == d->dfs_chk_gen)
  335. d->chk_gen = val;
  336. else if (dent == d->dfs_chk_io)
  337. d->chk_io = val;
  338. else if (dent == d->dfs_chk_fastmap)
  339. d->chk_fastmap = val;
  340. else if (dent == d->dfs_disable_bgt)
  341. d->disable_bgt = val;
  342. else if (dent == d->dfs_emulate_bitflips)
  343. d->emulate_bitflips = val;
  344. else if (dent == d->dfs_emulate_io_failures)
  345. d->emulate_io_failures = val;
  346. else
  347. count = -EINVAL;
  348. out:
  349. ubi_put_device(ubi);
  350. return count;
  351. }
  352. /* File operations for all UBI debugfs files except
  353. * detailed_erase_block_info
  354. */
  355. static const struct file_operations dfs_fops = {
  356. .read = dfs_file_read,
  357. .write = dfs_file_write,
  358. .open = simple_open,
  359. .llseek = no_llseek,
  360. .owner = THIS_MODULE,
  361. };
  362. /* As long as the position is less then that total number of erase blocks,
  363. * we still have more to print.
  364. */
  365. static void *eraseblk_count_seq_start(struct seq_file *s, loff_t *pos)
  366. {
  367. struct ubi_device *ubi = s->private;
  368. if (*pos < ubi->peb_count)
  369. return pos;
  370. return NULL;
  371. }
  372. /* Since we are using the position as the iterator, we just need to check if we
  373. * are done and increment the position.
  374. */
  375. static void *eraseblk_count_seq_next(struct seq_file *s, void *v, loff_t *pos)
  376. {
  377. struct ubi_device *ubi = s->private;
  378. (*pos)++;
  379. if (*pos < ubi->peb_count)
  380. return pos;
  381. return NULL;
  382. }
  383. static void eraseblk_count_seq_stop(struct seq_file *s, void *v)
  384. {
  385. }
  386. static int eraseblk_count_seq_show(struct seq_file *s, void *iter)
  387. {
  388. struct ubi_device *ubi = s->private;
  389. struct ubi_wl_entry *wl;
  390. int *block_number = iter;
  391. int erase_count = -1;
  392. int err;
  393. /* If this is the start, print a header */
  394. if (*block_number == 0)
  395. seq_puts(s, "physical_block_number\terase_count\n");
  396. err = ubi_io_is_bad(ubi, *block_number);
  397. if (err)
  398. return err;
  399. spin_lock(&ubi->wl_lock);
  400. wl = ubi->lookuptbl[*block_number];
  401. if (wl)
  402. erase_count = wl->ec;
  403. spin_unlock(&ubi->wl_lock);
  404. if (erase_count < 0)
  405. return 0;
  406. seq_printf(s, "%-22d\t%-11d\n", *block_number, erase_count);
  407. return 0;
  408. }
  409. static const struct seq_operations eraseblk_count_seq_ops = {
  410. .start = eraseblk_count_seq_start,
  411. .next = eraseblk_count_seq_next,
  412. .stop = eraseblk_count_seq_stop,
  413. .show = eraseblk_count_seq_show
  414. };
  415. static int eraseblk_count_open(struct inode *inode, struct file *f)
  416. {
  417. struct seq_file *s;
  418. int err;
  419. err = seq_open(f, &eraseblk_count_seq_ops);
  420. if (err)
  421. return err;
  422. s = f->private_data;
  423. s->private = ubi_get_device((unsigned long)inode->i_private);
  424. if (!s->private)
  425. return -ENODEV;
  426. else
  427. return 0;
  428. }
  429. static int eraseblk_count_release(struct inode *inode, struct file *f)
  430. {
  431. struct seq_file *s = f->private_data;
  432. struct ubi_device *ubi = s->private;
  433. ubi_put_device(ubi);
  434. return seq_release(inode, f);
  435. }
  436. static const struct file_operations eraseblk_count_fops = {
  437. .owner = THIS_MODULE,
  438. .open = eraseblk_count_open,
  439. .read = seq_read,
  440. .llseek = seq_lseek,
  441. .release = eraseblk_count_release,
  442. };
  443. /**
  444. * ubi_debugfs_init_dev - initialize debugfs for an UBI device.
  445. * @ubi: UBI device description object
  446. *
  447. * This function creates all debugfs files for UBI device @ubi. Returns zero in
  448. * case of success and a negative error code in case of failure.
  449. */
  450. int ubi_debugfs_init_dev(struct ubi_device *ubi)
  451. {
  452. int err, n;
  453. unsigned long ubi_num = ubi->ubi_num;
  454. const char *fname;
  455. struct dentry *dent;
  456. struct ubi_debug_info *d = &ubi->dbg;
  457. if (!IS_ENABLED(CONFIG_DEBUG_FS))
  458. return 0;
  459. n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME,
  460. ubi->ubi_num);
  461. if (n == UBI_DFS_DIR_LEN) {
  462. /* The array size is too small */
  463. fname = UBI_DFS_DIR_NAME;
  464. dent = ERR_PTR(-EINVAL);
  465. goto out;
  466. }
  467. fname = d->dfs_dir_name;
  468. dent = debugfs_create_dir(fname, dfs_rootdir);
  469. if (IS_ERR_OR_NULL(dent))
  470. goto out;
  471. d->dfs_dir = dent;
  472. fname = "chk_gen";
  473. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  474. &dfs_fops);
  475. if (IS_ERR_OR_NULL(dent))
  476. goto out_remove;
  477. d->dfs_chk_gen = dent;
  478. fname = "chk_io";
  479. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  480. &dfs_fops);
  481. if (IS_ERR_OR_NULL(dent))
  482. goto out_remove;
  483. d->dfs_chk_io = dent;
  484. fname = "chk_fastmap";
  485. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  486. &dfs_fops);
  487. if (IS_ERR_OR_NULL(dent))
  488. goto out_remove;
  489. d->dfs_chk_fastmap = dent;
  490. fname = "tst_disable_bgt";
  491. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  492. &dfs_fops);
  493. if (IS_ERR_OR_NULL(dent))
  494. goto out_remove;
  495. d->dfs_disable_bgt = dent;
  496. fname = "tst_emulate_bitflips";
  497. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  498. &dfs_fops);
  499. if (IS_ERR_OR_NULL(dent))
  500. goto out_remove;
  501. d->dfs_emulate_bitflips = dent;
  502. fname = "tst_emulate_io_failures";
  503. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  504. &dfs_fops);
  505. if (IS_ERR_OR_NULL(dent))
  506. goto out_remove;
  507. d->dfs_emulate_io_failures = dent;
  508. fname = "tst_emulate_power_cut";
  509. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  510. &dfs_fops);
  511. if (IS_ERR_OR_NULL(dent))
  512. goto out_remove;
  513. d->dfs_emulate_power_cut = dent;
  514. fname = "tst_emulate_power_cut_min";
  515. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  516. &dfs_fops);
  517. if (IS_ERR_OR_NULL(dent))
  518. goto out_remove;
  519. d->dfs_power_cut_min = dent;
  520. fname = "tst_emulate_power_cut_max";
  521. dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
  522. &dfs_fops);
  523. if (IS_ERR_OR_NULL(dent))
  524. goto out_remove;
  525. d->dfs_power_cut_max = dent;
  526. fname = "detailed_erase_block_info";
  527. dent = debugfs_create_file(fname, S_IRUSR, d->dfs_dir, (void *)ubi_num,
  528. &eraseblk_count_fops);
  529. if (IS_ERR_OR_NULL(dent))
  530. goto out_remove;
  531. return 0;
  532. out_remove:
  533. debugfs_remove_recursive(d->dfs_dir);
  534. out:
  535. err = dent ? PTR_ERR(dent) : -ENODEV;
  536. ubi_err(ubi, "cannot create \"%s\" debugfs file or directory, error %d\n",
  537. fname, err);
  538. return err;
  539. }
  540. /**
  541. * dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi
  542. * @ubi: UBI device description object
  543. */
  544. void ubi_debugfs_exit_dev(struct ubi_device *ubi)
  545. {
  546. if (IS_ENABLED(CONFIG_DEBUG_FS))
  547. debugfs_remove_recursive(ubi->dbg.dfs_dir);
  548. }
  549. /**
  550. * ubi_dbg_power_cut - emulate a power cut if it is time to do so
  551. * @ubi: UBI device description object
  552. * @caller: Flags set to indicate from where the function is being called
  553. *
  554. * Returns non-zero if a power cut was emulated, zero if not.
  555. */
  556. int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
  557. {
  558. unsigned int range;
  559. if ((ubi->dbg.emulate_power_cut & caller) == 0)
  560. return 0;
  561. if (ubi->dbg.power_cut_counter == 0) {
  562. ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min;
  563. if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) {
  564. range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min;
  565. ubi->dbg.power_cut_counter += prandom_u32() % range;
  566. }
  567. return 0;
  568. }
  569. ubi->dbg.power_cut_counter--;
  570. if (ubi->dbg.power_cut_counter)
  571. return 0;
  572. ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
  573. ubi_ro_mode(ubi);
  574. return 1;
  575. }