root/drivers/mtd/ubi/debug.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ubi_dump_flash
  2. ubi_dump_ec_hdr
  3. ubi_dump_vid_hdr
  4. ubi_dump_vol_info
  5. ubi_dump_vtbl_record
  6. ubi_dump_av
  7. ubi_dump_aeb
  8. ubi_dump_mkvol_req
  9. ubi_debugfs_init
  10. ubi_debugfs_exit
  11. dfs_file_read
  12. dfs_file_write
  13. eraseblk_count_seq_start
  14. eraseblk_count_seq_next
  15. eraseblk_count_seq_stop
  16. eraseblk_count_seq_show
  17. eraseblk_count_open
  18. eraseblk_count_release
  19. ubi_debugfs_init_dev
  20. ubi_debugfs_exit_dev
  21. ubi_dbg_power_cut

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

/* [<][>][^][v][top][bottom][index][help] */