[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ramblings




I think the reason I decided we needed the 'obsolete' flag to be kept in 
ram was so we can keep track properly of how much space is still used in 
each erase block. But of course it's free (gratis) anyway - nodes are 
4-byte aligned so we've got two spare bits in the flash_offset member of 
the struct we keep in-core for each flash node.

I think we might end up keeping nodetype in RAM permanently (and later in
the checkpoints) too - it'll simplify the process of reading the full 
thing into memory in read_inode() and will make it easier to check for 
nodetypes that aren't supported and DTRT.

So all we keep in core permanently per node on the flash is:

struct jffs2_raw_node_ref
{

	/* Actually this might end up a list_head. And there might be
		two of them - one list kept in ino order, one in
		flash_offset order. TBD
	*/
        struct jffs2_raw_node_ref *next;

        __u32 ino;
        /* Don't think we need size info kept permanently. */
	__u16 nodetype; /* maybe */
        __u32 flash_offset; /* and obsolete. and maybe another flag */
};

Then, while we've actually got an inode live, we keep a little more for 
each node, depending on which type it is.

struct jffs2_full_dnode
{
/*	struct jffs2_full_dnode *next; ??
		probably not. The fragments are listed, not nodes */
        struct jffs2_raw_node_ref *raw;
        __u32 ofs; /* Don't really need this, but optimisation */
        __u32 size;
        __u32 frags; /* Number of fragments which currently refer
                        to this node. When this reaches zero, 
                        the node is obsolete.
                     */
	/* Don't need version. Keep highest_version in the per-inode info
	 and we already have a fragment list after read_inode() has 
	finished */
};
struct jffs_full_dirent
{
	struct jffs_full_dirent *next;
        struct jffs2_raw_node_ref *raw;
        __u32 version; /* Each name has a version sequence. */
        __u32 ino; /* == zero for unlink */
	/* __u32 namehash? */
        unsigned char name[0];
}

Note we only need to keep version info for the data nodes while we're 
actually building the original map of which data to get from which node, 
in read_inode(). After that, we only care about whether the new node we're 
writing to the flash is newer than the previous ones - and guess what? It 
_is_ newer than the previous ones :)

So once read_inode has finished, we are left with a fragment list for the 
data inode:

struct jffs2_node_frag
{
        struct jffs2_node_frag *next;
        struct jffs2_full_node *node; /* NULL for holes */
        __u32 size;
        __u32 ofs; /* Don't really need this, but optimisation */
        __u32 node_ofs; /* offset within the physical node */
}

I think we might use the other flag in the flash_offset member of 
jffs2_raw_node_ref during the scan on mount, to show whether the 
'obsolete' flag is actually valid yet, or whether we just haven't decided. 
Not sure yet.

Thinks... if we write out a data node for a file, with no new data but 
only a metadata change, how do we know when it's obsoleted? While we were 
going linearly through the flash, we were guaranteed to have written out a 
new real data node for this inode before we got back to the empty one, but 
now we can't rely on that. We could come back and GC the same block again.

So maybe we need to be able to store a reference to one 'metadata' node to 
prevent it from being GC'd without us writing out another copy of the 
changed metadata. Or keep a record of 'earliest dnode which has correct 
metadata' for each inode. Or something. Or maybe I need to quit hacking 
for this evening and wait for you lot to tell me what I've done wrong this 
time :)
 
--
dwmw2



To unsubscribe from this list: send the line "unsubscribe jffs-dev" in
the body of a message to majordomo@xxxxxxx.com