?? gc.c
字號:
static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct inode *inode, struct jffs2_full_dirent *fd){ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_full_dirent *new_fd; struct jffs2_raw_dirent rd; __u32 alloclen, phys_ofs; int ret; rd.magic = JFFS2_MAGIC_BITMASK; rd.nodetype = JFFS2_NODETYPE_DIRENT; rd.nsize = strlen(fd->name); rd.totlen = sizeof(rd) + rd.nsize; rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4); rd.pino = inode->i_ino; rd.version = ++f->highest_version; rd.ino = fd->ino; rd.mctime = max(inode->i_mtime, inode->i_ctime); rd.type = fd->type; rd.node_crc = crc32(0, &rd, sizeof(rd)-8); rd.name_crc = crc32(0, fd->name, rd.nsize); ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); if (ret) { printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n", sizeof(rd)+rd.nsize, ret); return ret; } new_fd = jffs2_write_dirent(inode, &rd, fd->name, rd.nsize, phys_ofs, NULL); if (IS_ERR(new_fd)) { printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd)); return PTR_ERR(new_fd); } jffs2_add_fd_to_list(c, new_fd, &f->dents); return 0;}static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct inode *inode, struct jffs2_full_dirent *fd){ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_full_dirent **fdp = &f->dents; int found = 0; /* FIXME: When we run on NAND flash, we need to work out whether this deletion dirent is still needed to actively delete a 'real' dirent with the same name that's still somewhere else on the flash. For now, we know that we've actually obliterated all the older dirents when they became obsolete, so we didn't really need to write the deletion to flash in the first place. */ while (*fdp) { if ((*fdp) == fd) { found = 1; *fdp = fd->next; break; } fdp = &(*fdp)->next; } if (!found) { printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%lu\n", fd->name, inode->i_ino); } jffs2_mark_node_obsolete(c, fd->raw); jffs2_free_full_dirent(fd); return 0;}static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct inode *inode, struct jffs2_full_dnode *fn, __u32 start, __u32 end){ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_raw_inode ri; struct jffs2_node_frag *frag; struct jffs2_full_dnode *new_fn; __u32 alloclen, phys_ofs; int ret; D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%lu from offset 0x%x to 0x%x\n", inode->i_ino, start, end)); memset(&ri, 0, sizeof(ri)); if(fn->frags > 1) { size_t readlen; __u32 crc; /* It's partially obsoleted by a later write. So we have to write it out again with the _same_ version as before */ ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri); if (readlen != sizeof(ri) || ret) { printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen); goto fill; } if (ri.nodetype != JFFS2_NODETYPE_INODE) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n", fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE); return -EIO; } if (ri.totlen != sizeof(ri)) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n", fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri)); return -EIO; } crc = crc32(0, &ri, sizeof(ri)-8); if (crc != ri.node_crc) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", fn->raw->flash_offset & ~3, ri.node_crc, crc); /* FIXME: We could possibly deal with this by writing new holes for each frag */ printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", start, end, inode->i_ino); goto fill; } if (ri.compr != JFFS2_COMPR_ZERO) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", fn->raw->flash_offset & ~3); printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", start, end, inode->i_ino); goto fill; } } else { fill: ri.magic = JFFS2_MAGIC_BITMASK; ri.nodetype = JFFS2_NODETYPE_INODE; ri.totlen = sizeof(ri); ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); ri.ino = inode->i_ino; ri.version = ++f->highest_version; ri.offset = start; ri.dsize = end - start; ri.csize = 0; ri.compr = JFFS2_COMPR_ZERO; } ri.mode = inode->i_mode; ri.uid = inode->i_uid; ri.gid = inode->i_gid; ri.isize = inode->i_size; ri.atime = inode->i_atime; ri.ctime = inode->i_ctime; ri.mtime = inode->i_mtime; ri.data_crc = 0; ri.node_crc = crc32(0, &ri, sizeof(ri)-8); ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); if (ret) { printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n", sizeof(ri), ret); return ret; } new_fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL); if (IS_ERR(new_fn)) { printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn)); return PTR_ERR(new_fn); } if (ri.version == f->highest_version) { jffs2_add_full_dnode_to_inode(c, f, new_fn); if (f->metadata) { jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_free_full_dnode(f->metadata); f->metadata = NULL; } return 0; } /* * We should only get here in the case where the node we are * replacing had more than one frag, so we kept the same version * number as before. (Except in case of error -- see 'goto fill;' * above.) */ D1(if(unlikely(fn->frags <= 1)) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n", fn->frags, ri.version, f->highest_version, ri.ino); }); for (frag = f->fraglist; frag; frag = frag->next) { if (frag->ofs > fn->size + fn->ofs) break; if (frag->node == fn) { frag->node = new_fn; new_fn->frags++; fn->frags--; } } if (fn->frags) { printk(KERN_WARNING "jffs2_garbage_collect_hole: Old node still has frags!\n"); BUG(); } if (!new_fn->frags) { printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n"); BUG(); } jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); return 0;}static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct inode *inode, struct jffs2_full_dnode *fn, __u32 start, __u32 end){ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; __u32 alloclen, phys_ofs, offset, orig_end; int ret = 0; unsigned char *comprbuf = NULL, *writebuf; struct page *pg; unsigned char *pg_ptr; memset(&ri, 0, sizeof(ri)); D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%lu from offset 0x%x to 0x%x\n", inode->i_ino, start, end)); orig_end = end; /* If we're looking at the last node in the block we're garbage-collecting, we allow ourselves to merge as if the block was already erasing. We're likely to be GC'ing a partial page, and the next block we GC is likely to have the other half of this page right at the beginning, which means we'd expand it _then_, as nr_erasing_blocks would have increased since we checked, and in doing so would obsolete the partial node which we'd have written here. Meaning that the GC would churn and churn, and just leave dirty blocks in it's wake. */ if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) { /* Shitloads of space */ /* FIXME: Integrate this properly with GC calculations */ start &= ~(PAGE_CACHE_SIZE-1); end = min_t(__u32, start + PAGE_CACHE_SIZE, inode->i_size); D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n", start, end)); if (end < orig_end) { printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end); end = orig_end; } } /* First, use readpage() to read the appropriate page into the page cache */ /* Q: What happens if we actually try to GC the _same_ page for which commit_write() * triggered garbage collection in the first place? * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the * page OK. We'll actually write it out again in commit_write, which is a little * suboptimal, but at least we're correct. */ pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); if (IS_ERR(pg)) { printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg)); return PTR_ERR(pg); } pg_ptr = (char *)kmap(pg); comprbuf = kmalloc(end - start, GFP_KERNEL); offset = start; while(offset < orig_end) { __u32 datalen; __u32 cdatalen; char comprtype = JFFS2_COMPR_NONE; ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); if (ret) { printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n", sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret); break; } cdatalen = min(alloclen - sizeof(ri), end - offset); datalen = end - offset; writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1)); if (comprbuf) { comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen); } if (comprtype) { writebuf = comprbuf; } else { datalen = cdatalen; } ri.magic = JFFS2_MAGIC_BITMASK; ri.nodetype = JFFS2_NODETYPE_INODE; ri.totlen = sizeof(ri) + cdatalen; ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); ri.ino = inode->i_ino; ri.version = ++f->highest_version; ri.mode = inode->i_mode; ri.uid = inode->i_uid; ri.gid = inode->i_gid; ri.isize = inode->i_size; ri.atime = inode->i_atime; ri.ctime = inode->i_ctime; ri.mtime = inode->i_mtime; ri.offset = offset; ri.csize = cdatalen; ri.dsize = datalen; ri.compr = comprtype; ri.node_crc = crc32(0, &ri, sizeof(ri)-8); ri.data_crc = crc32(0, writebuf, cdatalen); new_fn = jffs2_write_dnode(inode, &ri, writebuf, cdatalen, phys_ofs, NULL); if (IS_ERR(new_fn)) { printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn)); ret = PTR_ERR(new_fn); break; } ret = jffs2_add_full_dnode_to_inode(c, f, new_fn); offset += datalen; if (f->metadata) { jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_free_full_dnode(f->metadata); f->metadata = NULL; } } if (comprbuf) kfree(comprbuf); kunmap(pg); /* XXX: Does the page get freed automatically? */ /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */ page_cache_release(pg); return ret;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -