📄 intrep.c
字号:
struct jffs_delete_list *delete_list_element; delete_list_element = c->delete_list; c->delete_list = c->delete_list->next; kfree(delete_list_element); } /* Free all files and nodes. */ if (c->hash) { jffs_foreach_file(c, jffs_free_node_list); jffs_foreach_file(c, jffs_free_file); kfree(c->hash); DJM(no_hash--); } jffs_cleanup_fmcontrol(c->fmc); kfree(c); DJM(no_jffs_control--); D3(printk("jffs_cleanup_control(): Leaving...\n"));}/* This function adds a virtual root node to the in-RAM representation. Called by jffs_build_fs(). */static intjffs_add_virtual_root(struct jffs_control *c){ struct jffs_file *root; struct jffs_node *node; D2(printk("jffs_add_virtual_root(): " "Creating a virtual root directory.\n")); if (!(root = (struct jffs_file *)kmalloc(sizeof(struct jffs_file), GFP_KERNEL))) { return -ENOMEM; } no_jffs_file++; if (!(node = jffs_alloc_node())) { kfree(root); no_jffs_file--; return -ENOMEM; } DJM(no_jffs_node++); memset(node, 0, sizeof(struct jffs_node)); node->ino = JFFS_MIN_INO; memset(root, 0, sizeof(struct jffs_file)); root->ino = JFFS_MIN_INO; root->mode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; root->atime = root->mtime = root->ctime = CURRENT_TIME; root->nlink = 1; root->c = c; root->version_head = root->version_tail = node; jffs_insert_file_into_hash(root); return 0;}/* This is where the file system is built and initialized. */intjffs_build_fs(struct super_block *sb){ struct jffs_control *c; int err = 0; D2(printk("jffs_build_fs()\n")); if (!(c = jffs_create_control(sb->s_dev))) { return -ENOMEM; } c->building_fs = 1; c->sb = sb; if ((err = jffs_scan_flash(c)) < 0) { if(err == -EAGAIN){ /* scan_flash() wants us to try once more. A flipping bits sector was detect in the middle of the scan flash. Clean up old allocated memory before going in. */ D1(printk("jffs_build_fs: Cleaning up all control structures," " reallocating them and trying mount again.\n")); jffs_cleanup_control(c); if (!(c = jffs_create_control(sb->s_dev))) { return -ENOMEM; } c->building_fs = 1; c->sb = sb; if ((err = jffs_scan_flash(c)) < 0) { goto jffs_build_fs_fail; } }else{ goto jffs_build_fs_fail; } } /* Add a virtual root node if no one exists. */ if (!jffs_find_file(c, JFFS_MIN_INO)) { if ((err = jffs_add_virtual_root(c)) < 0) { goto jffs_build_fs_fail; } } while (c->delete_list) { struct jffs_file *f; struct jffs_delete_list *delete_list_element; if ((f = jffs_find_file(c, c->delete_list->ino))) { f->deleted = 1; } delete_list_element = c->delete_list; c->delete_list = c->delete_list->next; kfree(delete_list_element); } /* Remove deleted nodes. */ if ((err = jffs_foreach_file(c, jffs_possibly_delete_file)) < 0) { printk(KERN_ERR "JFFS: Failed to remove deleted nodes.\n"); goto jffs_build_fs_fail; } /* Remove redundant nodes. (We are not interested in the return value in this case.) */ jffs_foreach_file(c, jffs_remove_redundant_nodes); /* Try to build a tree from all the nodes. */ if ((err = jffs_foreach_file(c, jffs_insert_file_into_tree)) < 0) { printk("JFFS: Failed to build tree.\n"); goto jffs_build_fs_fail; } /* Compute the sizes of all files in the filesystem. Adjust if necessary. */ if ((err = jffs_foreach_file(c, jffs_build_file)) < 0) { printk("JFFS: Failed to build file system.\n"); goto jffs_build_fs_fail; } sb->u.generic_sbp = (void *)c; c->building_fs = 0; D1(jffs_print_hash_table(c)); D1(jffs_print_tree(c->root, 0)); return 0;jffs_build_fs_fail: jffs_cleanup_control(c); return err;} /* jffs_build_fs() *//* This checks for sectors that were being erased in their previous lifetimes and for some reason or the other (power fail etc.), the erase cycles never completed. As the flash array would have reverted back to read status, these sectors are detected by the symptom of the "flipping bits", i.e. bits being read back differently from the same location in flash if read multiple times. The only solution to this is to re-erase the entire sector. Unfortunately detecting "flipping bits" is not a simple exercise as a bit may be read back at 1 or 0 depending on the alignment of the stars in the universe. The level of confidence is in direct proportion to the number of scans done. By power fail testing I (Vipin) have been able to proove that reading twice is not enough. Maybe 4 times? Change NUM_REREADS to a higher number if you want a (even) higher degree of confidence in your mount process. A higher number would of course slow down your mount.*/int check_partly_erased_sectors(struct jffs_fmcontrol *fmc){#define NUM_REREADS 4 /* see note above */#define READ_AHEAD_BYTES 4096 /* must be a multiple of 4, usually set to kernel page size */ __u8 *read_buf1; __u8 *read_buf2; int err = 0; int retlen; int i; int cnt; __u32 offset; loff_t pos = 0; loff_t end = fmc->flash_size; /* Allocate read buffers */ read_buf1 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); if (!read_buf1) return -ENOMEM; read_buf2 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); if (!read_buf2) { kfree(read_buf1); return -ENOMEM; } CHECK_NEXT: while(pos < end){ D1(printk("check_partly_erased_sector():checking sector which contains" " offset 0x%x for flipping bits..\n", (__u32)pos)); retlen = flash_safe_read(fmc->mtd, pos, &read_buf1[0], READ_AHEAD_BYTES); retlen &= ~3; for(cnt = 0; cnt < NUM_REREADS; cnt++){ (void)flash_safe_read(fmc->mtd, pos, &read_buf2[0], READ_AHEAD_BYTES); for (i=0 ; i < retlen ; i+=4) { /* buffers MUST match, double word for word! */ if(*((__u32 *) &read_buf1[i]) != *((__u32 *) &read_buf2[i]) ){ /* flipping bits detected, time to erase sector */ /* This will help us log some statistics etc. */ D1(printk("Flipping bits detected in re-read round:%i of %i\n", cnt, NUM_REREADS)); D1(printk("check_partly_erased_sectors:flipping bits detected" " @offset:0x%x(0x%x!=0x%x)\n", (__u32)pos+i, *((__u32 *) &read_buf1[i]), *((__u32 *) &read_buf2[i]))); /* calculate start of present sector */ offset = (((__u32)pos+i)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size; D1(printk("check_partly_erased_sector():erasing sector starting 0x%x.\n", offset)); if (flash_erase_region(fmc->mtd, offset, fmc->sector_size) < 0) { printk(KERN_ERR "JFFS: Erase of flash failed. " "offset = %u, erase_size = %d\n", offset , fmc->sector_size); err = -EIO; goto returnBack; }else{ D1(printk("JFFS: Erase of flash sector @0x%x successful.\n", offset)); /* skip ahead to the next sector */ pos = (((__u32)pos+i)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size; pos += fmc->sector_size; goto CHECK_NEXT; } } } } pos += READ_AHEAD_BYTES; } returnBack: kfree(read_buf1); kfree(read_buf2); D2(printk("check_partly_erased_sector():Done checking all sectors till offset 0x%x for flipping bits.\n", (__u32)pos)); return err;}/* end check_partly_erased_sectors() *//* Scan the whole flash memory in order to find all nodes in the file systems. */static intjffs_scan_flash(struct jffs_control *c){ char name[JFFS_MAX_NAME_LEN + 2]; struct jffs_raw_inode raw_inode; struct jffs_node *node = 0; struct jffs_fmcontrol *fmc = c->fmc; __u32 checksum; __u8 tmp_accurate; __u16 tmp_chksum; __u32 deleted_file; loff_t pos = 0; loff_t start; loff_t test_start; loff_t end = fmc->flash_size; __u8 *read_buf; int i, len, retlen; __u32 offset; __u32 free_chunk_size1; __u32 free_chunk_size2; __u32 largest_hole = 0; __u32 hole_end_offset = 0; __u32 head_offset; #define NUMFREEALLOWED 2 /* 2 chunks of at least erase size space allowed */ int num_free_space = 0; /* Flag err if more than TWO free blocks found. This is NOT allowed by the current jffs design. */ int num_free_spc_not_accp = 0; /* For debugging purposed keep count of how much free space was rejected and marked dirty */ D1(printk("jffs_scan_flash(): start pos = 0x%lx, end = 0x%lx\n", (long)pos, (long)end)); flash_safe_acquire(fmc->mtd); /* check and make sure that any sector does not suffer from the "partly erased, bit flipping syndrome" (TM Vipin :) If so, offending sectors will be erased. */ if(check_partly_erased_sectors(fmc) < 0){ flash_safe_release(fmc->mtd); return -EIO; /* bad, bad, bad error. Cannot continue.*/ } /* Allocate read buffer */ read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL); if (!read_buf) { flash_safe_release(fmc->mtd); return -ENOMEM; } /* Start the scan. */ while (pos < end) { deleted_file = 0; /* Remember the position from where we started this scan. */ start = pos; switch (flash_read_u32(fmc->mtd, pos)) { case JFFS_EMPTY_BITMASK: /* We have found 0xffffffff at this position. We have to scan the rest of the flash till the end or till something else than 0xffffffff is found. Keep going till we do not find JFFS_EMPTY_BITMASK anymore */ D1(printk("jffs_scan_flash(): 0xffffffff at pos 0x%lx.\n", (long)pos)); while(pos < end){ len = end - pos < 4096 ? end - pos : 4096; retlen = flash_safe_read(fmc->mtd, pos, &read_buf[0], len); retlen &= ~3; for (i=0 ; i < retlen ; i+=4, pos += 4) { if(*((__u32 *) &read_buf[i]) != JFFS_EMPTY_BITMASK) break; } if (i == retlen) continue; else break; } D1(printk("jffs_scan_flash():0xffffffff ended at pos 0x%lx.\n", (long)pos)); /* If some free space ends in the middle of a sector, treat it as dirty rather than clean. This is to handle the case where one thread allocated space for a node, but didn't get to actually _write_ it before power was lost, leaving a gap in the log. Shifting all node writes into a single kernel thread will fix the original problem. */ if ((__u32) pos % fmc->sector_size) { /* If there was free space in previous sectors, don't mark that dirty too - only from the beginning of this sector (or from start) */ test_start = pos & ~(fmc->sector_size-1); /* end of last sector */ if (start < test_start) { /* free space started in the previous sector! */ if((num_free_space < NUMFREEALLOWED) && ((unsigned int)(test_start - start) >= fmc->sector_size)){ /* Count it in if we are still under NUMFREEALLOWED *and* it is at least 1 erase sector in length. This will keep us from picking any little ole' space as "free". */ D1(printk("Reducing end of free space to 0x%x from 0x%x\n", (unsigned int)test_start, (unsigned int)pos)); D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n", (unsigned int) start, (unsigned int)(test_start - start))); D1(printk("Reducing start to 0x%x from 0x%x\n", test_start, start)); if (largest_hole < test_start - start){ D3(printk("was hole = %x end_offset = %x\n", largest_hole, hole_end_offset)); if (fmc->head) { largest_hole = test_start - start; hole_end_offset = test_start; } } D3(printk("now = %x end_offset = %x\n", largest_hole, hole_end_offset)); /* below, space from "start" to "pos" will be marked dirty. */ start = test_start; /* Being in here means that we have found at least an entire erase sector size of free space ending on a sector boundary. Keep track of free spaces accepted. */ num_free_space++; }else{ num_free_spc_not_accp++; D1(printk("Free space (#%i) found but *Not* accepted: Starting" " 0x%x for 0x%x bytes\n", num_free_spc_not_accp, (unsigned int)start, (unsigned int)((unsigned int)(pos & ~(fmc->sector_size-1)) - (unsigned int)start))); } } if((((__u32)(pos - start)) != 0)){ D1(printk("Dirty space: Starting 0x%x for 0x%x bytes\n", (unsigned int) start, (unsigned int) (pos - start))); jffs_fmalloced(fmc, (__u32) start, (__u32) (pos - start), 0); }else{ /* "Flipping bits" detected. This means that our scan for them did not catch this offset. See check_partly_erased_sectors() for more info. */ D1(printk("jffs_scan_flash():wants to allocate dirty flash " "space for 0 bytes.\n")); D1(printk("jffs_scan_flash(): Flipping bits! We will free " "all allocated memory, erase this sector and remount\n")); /* calculate start of present sector */ offset = (((__u32)pos)/(__u32)fmc->sector_size) * (__u32)fmc->sector_size; D1(printk("jffs_scan_flash():erasing sector starting 0x%x.\n", offset)); if (flash_erase_region(fmc->mtd, offset, fmc->sector_size) < 0) { printk(KERN_ERR "JFFS: Erase of flash failed. " "offset = %u, erase_size = %d\n", offset , fmc->sector_size); flash_safe_release(fmc->mtd); kfree (read_buf); return -1; /* bad, bad, bad! */ } flash_safe_release(fmc->mtd); kfree (read_buf); return -EAGAIN; /* erased offending sector. Try mount one more time please. */ } }else{ /* Being in here means that we have found free space that ends on an erase sector boundary. Count it in if we are still under NUMFREEALLOWED *and* it is at least 1 erase sector in length. This will keep us from picking any little ole' space as "free". */ if((num_free_space < NUMFREEALLOWED) && ((unsigned int)(pos - start) >= fmc->sector_size)){ /* We really don't do anything to mark space as free, except *not* mark it dirty and just advance the "pos" location pointer. It will automatically be picked up as free space.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -