Esempio n. 1
0
/* 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--);
    }
}
Esempio n. 3
0
/* 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;
}
Esempio n. 4
0
/* 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;
}