/* This function creates a new shiny flash memory control structure. */ struct jffs_fmcontrol * jffs_build_begin(struct jffs_control *c, kdev_t dev) { struct jffs_fmcontrol *fmc; struct mtd_info *mtd; D3(printk("jffs_build_begin()\n")); fmc = (struct jffs_fmcontrol *)kmalloc(sizeof(struct jffs_fmcontrol), GFP_KERNEL); if (!fmc) { D(printk("jffs_build_begin(): Allocation of " "struct jffs_fmcontrol failed!\n")); return (struct jffs_fmcontrol *)0; } DJM(no_jffs_fmcontrol++); mtd = get_mtd_device(NULL, MINOR(dev)); if (!mtd) { kfree(fmc); DJM(no_jffs_fmcontrol--); return NULL; } /* Retrieve the size of the flash memory. */ fmc->flash_size = mtd->size; D3(printk(" fmc->flash_size = %d bytes\n", fmc->flash_size)); fmc->used_size = 0; fmc->dirty_size = 0; fmc->free_size = mtd->size; fmc->sector_size = mtd->erasesize; fmc->max_chunk_size = fmc->sector_size >> 1; /* min_free_size: 1 sector, obviously. + 1 x max_chunk_size, for when a nodes overlaps the end of a sector + 1 x max_chunk_size again, which ought to be enough to handle the case where a rename causes a name to grow, and GC has to write out larger nodes than the ones it's obsoleting. We should fix it so it doesn't have to write the name _every_ time. Later. + another 2 sectors because people keep getting GC stuck and we don't know why. This scares me - I want formal proof of correctness of whatever number we put here. dwmw2. */ fmc->min_free_size = fmc->sector_size << 2; fmc->mtd = mtd; fmc->c = c; fmc->head = 0; fmc->tail = 0; fmc->head_extra = 0; fmc->tail_extra = 0; init_MUTEX(&fmc->biglock); return fmc; }
/* Call this function when the file system is unmounted. This function frees all memory used by this module. */ void jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc) { if (fmc) { struct jffs_fm *next = fmc->head; while (next) { struct jffs_fm *cur = next; next = next->next; jffs_free_fm(cur); } put_mtd_device(fmc->mtd); kfree(fmc); DJM(no_jffs_fmcontrol--); } }
/* This function creates a new shiny flash memory control structure. */ struct jffs_fmcontrol *jffs_build_begin(struct jffs_control *c, kdev_t dev) { struct jffs_fmcontrol *fmc; struct mtd_info *mtd; D3(printk("jffs_build_begin()\n")); fmc = kmalloc(sizeof(*fmc), GFP_KERNEL); if (!fmc) { D(printk("jffs_build_begin(): Allocation of " "struct jffs_fmcontrol failed!\n")); return (struct jffs_fmcontrol *)0; } memset(fmc, 0, sizeof(struct jffs_fmcontrol)); DJM(no_jffs_fmcontrol++); mtd = get_mtd_device(NULL, MINOR(dev)); if (IS_ERR(mtd)) { kfree(fmc); DJM(no_jffs_fmcontrol--); return NULL; } #if JFFS_RAM_BLOCKS > 0 mtd->size = JFFS_RAM_BLOCKS * 64 * 1024; mtd->erasesize = 64 * 1024; #endif /* Retrieve the size of the flash memory. */ D3(printk(" fmc->flash_size = %d bytes\n", mtd->size)); fmc->free_size = fmc->flash_size = mtd->size; fmc->sector_size = mtd->erasesize; fmc->max_chunk_size = fmc->sector_size / 2; /* min_free_size: 1 sector, obviously. + 1 x max_chunk_size, for when a nodes overlaps the end of a sector + 1 x max_chunk_size again, which ought to be enough to handle the case where a rename causes a name to grow, and GC has to write out larger nodes than the ones it's obsoleting. We should fix it so it doesn't have to write the name _every_ time. Later. + another 2 sectors because people keep getting GC stuck and we don't know why. This scares me - I want formal proof of correctness of whatever number we put here. dwmw2. I know why! (rvt) 1) During a GC, the code blindly copied N bytes of the file whose node was the first non-dirty node. If some of those bytes were on a different sector (EB) they got copied, thus needlessly creating dirty nodes that were not on the head sector. In a worst case, we could create as many as 16 * 32kb = 8 sectors of needlessly dirty nodes. A pathological case was where there are several files with one (small) node on the head block followed by large node(s) (up to a total of 32KB) just before the tail. When a GC took place, the small node got copied--thereby creating free-able space on the head block--GOOD. And the large nodes also got copied--thereby creating dirty space that was very far away from the head page and therefore would not be freeable until much much later--BAD. Until a GC occurs on that block, a re-written node appears twice in the flash---once as the (old) dirty node and once as the (new) used/valid node. Worse, if there is another small node that gets GC'ed, and the re-write address range also includes the later (large & rewritten) node again, there will be ANOTHER copy of the dirty node, for *3* appearances in the flash! 2) Holes got expanded to zero bytes during a GC. There is no need to do this; we now just leave the holes as-is. N.B. I won't worry about the rename case. In a small JFFS we can't afford this safety margin. We'll just warn the user to don't do that. */ fmc->min_free_size = fmc->sector_size * 1; fmc->mtd = mtd; fmc->c = c; mutex_init(&fmc->biglock); fmc->low_free_size = fmc->free_size; fmc->low_frewst_size = fmc->free_size; return fmc; }
/* When the flash memory scan has completed, this function should be called before use of the control structure. */ int jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset) { D3(printk("jffs_build_end()\n")); if (!fmc->head) { fmc->head = fmc->head_extra; fmc->tail = fmc->tail_extra; } else if (fmc->head_extra) { struct jffs_fm *fm, *cur; if (head_offset == fmc->head->offset){ fmc->tail->next = fmc->head_extra; fmc->head_extra->prev = fmc->tail; fmc->tail = fmc->tail_extra; } else { fmc->tail_extra->next = fmc->head; fmc->head->prev = fmc->tail_extra; fmc->head = fmc->head_extra; while (fmc->head->offset != head_offset){ fmc->tail->next = fmc->head; fmc->head = fmc->head->next; fmc->head->prev = 0; fmc->tail->next->prev = fmc->tail; fmc->tail = fmc->tail->next; fmc->tail->next = 0; } } /* Make sure the only free space we have is between tail and head. */ for (cur = fmc->head; cur && cur != fmc->tail;) { if (cur->offset + cur->size < cur->next->offset) { if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))) { D(printk("jffs_buid_end(): kmalloc failed!\n")); return -ENOMEM; } DJM(no_jffs_fm++); fm->size = cur->next->offset - cur->offset - cur->size; fm->offset = cur->offset + cur->size; fm->nodes = 0; fm->next = cur->next; fm->prev = cur; cur->next->prev = fm; cur->next = fm; cur = fm->next; fmc->free_size -= fm->size; fmc->dirty_size += fm->size; } else if (cur->offset > cur->next->offset) { if (cur->offset + cur->size < fmc->flash_size){ if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))){ D(printk("jffs_buid_end(): kmalloc failed!\n")); return -ENOMEM; } DJM(no_jffs_fm++); fm->size = fmc->flash_size - cur->offset - cur->size; fm->nodes = 0; fm->offset = cur->offset + cur->size; fm->next = cur->next; fm->prev = cur; cur->next->prev = fm; cur->next = fm; cur = fm->next; fmc->free_size -= fm->size; fmc->dirty_size += fm->size; } else { cur = cur->next; } if (cur->offset > 0) { if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))) { D(printk("jffs_buid_end(): kmalloc failed!\n")); return -ENOMEM; } DJM(no_jffs_fm++); fm->size = cur->offset; fm->nodes = 0; fm->offset = 0; fm->next = cur; fm->prev = cur->prev; cur->prev->next = fm; cur->prev = fm; fmc->free_size -= fm->size; fmc->dirty_size += fm->size; } } else if (cur->offset + cur->size != cur->next->offset) { printk("jffs_build_end(): Internal error.\n"); return -EINVAL; } else { cur = cur->next; } } } fmc->head_extra = 0; /* These two instructions should be omitted. */ fmc->tail_extra = 0; D3(jffs_print_fmcontrol(fmc)); return 0; }