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