JFFS1 scan procedure
Aleksander Sanochkin
asanochkin at Lnxw.COM
Fri Nov 30 12:26:07 EST 2001
Hi!
I've been using JFFS1 for some time and faced a problem
that the JFFS1 scan procedure is not robust enough. Namely,
it expects that the flash region it scans is either erased
or is in a state left by JFFS1 itself. That is, it doesn't
expect that the flash is containing a "garbage", which can
be the case sometimes.
I've improved the scan procedure to work smoothly in all
cases for me. Attached is a diff against the current CVS.
Best regards.
-------------- next part --------------
diff -ur cvs/fs/jffs/intrep.c scan_flash/fs/jffs/intrep.c
--- cvs/fs/jffs/intrep.c Mon Sep 24 03:28:36 2001
+++ scan_flash/fs/jffs/intrep.c Wed Nov 21 19:55:02 2001
@@ -772,6 +772,9 @@
__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
@@ -884,6 +887,22 @@
(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;
@@ -956,6 +975,20 @@
num_free_space++;
D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n",
(unsigned int) start, (unsigned int) (pos - start)));
+
+ if (largest_hole < pos - start)
+ {
+ D3(printk("was hole = %x end_offset = %x\n",
+ largest_hole, hole_end_offset));
+ if (fmc->head)
+ {
+ largest_hole = pos - start;
+ hole_end_offset = pos;
+ }
+
+ D3(printk("now = %x end_offset = %x\n",
+ largest_hole, hole_end_offset));
+ }
}else{
num_free_spc_not_accp++;
D1(printk("Free space (#%i) found but *Not* accepted: Starting "
@@ -1002,9 +1035,11 @@
to scan for the magic pattern. */
D1(printk("*************** Dirty flash memory or "
"bad inode: "
- "hexdump(pos = 0x%lx, len = 128):\n",
- (long)pos));
- D1(jffs_hexdump(fmc->mtd, pos, 128));
+ "hexdump(pos = 0x%lx, len = %d):\n",
+ (long)pos,
+ end - pos > 128 ? 128 : end - pos));
+ D1(jffs_hexdump(fmc->mtd, pos,
+ end - pos > 128 ? 128 : end - pos));
for (pos += 4; pos < end; pos += 4) {
switch (flash_read_u32(fmc->mtd, pos)) {
@@ -1197,12 +1232,6 @@
return -ENOMEM;
}
- if ((err = jffs_insert_node(c, 0, &raw_inode,
- name, node)) < 0) {
- printk("JFFS: Failed to handle raw inode. "
- "(err = %d)\n", err);
- break;
- }
if (raw_inode.rename) {
struct jffs_delete_list *dl
= (struct jffs_delete_list *)
@@ -1226,6 +1255,12 @@
c->delete_list = dl;
node->data_size = 0;
}
+ if ((err = jffs_insert_node(c, 0, &raw_inode,
+ name, node)) < 0) {
+ printk("JFFS: Failed to handle raw inode. "
+ "(err = %d)\n", err);
+ break;
+ }
D3(jffs_print_node(node));
node = 0; /* Don't free the node! */
}
@@ -1242,7 +1277,22 @@
jffs_free_node(node);
DJM(no_jffs_node--);
}
- jffs_build_end(fmc);
+ if (fmc->head && fmc->tail_extra &&
+ fmc->head->offset + fmc->flash_size -
+ fmc->tail_extra->offset - fmc->tail_extra->size > largest_hole)
+ {
+ head_offset = fmc->head->offset;
+ }
+ else
+ {
+ head_offset = hole_end_offset;
+ }
+
+ if (jffs_build_end(fmc, head_offset) < 0)
+ {
+ D(printk("jffs_build_end() failed\n"));
+ return -ENOMEM;
+ }
/* Free read buffer */
kfree (read_buf);
diff -ur cvs/fs/jffs/jffs_fm.c scan_flash/fs/jffs/jffs_fm.c
--- cvs/fs/jffs/jffs_fm.c Thu Sep 20 16:29:47 2001
+++ scan_flash/fs/jffs/jffs_fm.c Wed Nov 21 19:02:25 2001
@@ -89,8 +89,8 @@
/* When the flash memory scan has completed, this function should be called
before use of the control structure. */
-void
-jffs_build_end(struct jffs_fmcontrol *fmc)
+int
+jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset)
{
D3(printk("jffs_build_end()\n"));
@@ -99,13 +99,112 @@
fmc->tail = fmc->tail_extra;
}
else if (fmc->head_extra) {
- fmc->tail_extra->next = fmc->head;
- fmc->head->prev = fmc->tail_extra;
- fmc->head = 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;
}
diff -ur cvs/fs/jffs/jffs_fm.h scan_flash/fs/jffs/jffs_fm.h
--- cvs/fs/jffs/jffs_fm.h Thu Jan 11 15:03:25 2001
+++ scan_flash/fs/jffs/jffs_fm.h Wed Nov 21 19:03:30 2001
@@ -123,7 +123,7 @@
struct jffs_fmcontrol *jffs_build_begin(struct jffs_control *c, kdev_t dev);
-void jffs_build_end(struct jffs_fmcontrol *fmc);
+int jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset);
void jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc);
int jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size,
More information about the linux-mtd
mailing list