[PATCH] XATTR issues on JFFS2

Jörn Engel joern at wohnheim.fh-wedel.de
Fri Sep 9 03:24:16 EDT 2005


On Fri, 9 September 2005 13:15:54 +0900, Kaigai Kohei wrote:
> Thanks for reviewing in spite of so long patch.
> 
> > Sounds good.
> >
> > It appears as if your patch or something based on it will win.  So
> > let's have a look...
> >
> > I notice that you make a couple of mistakes by copying them from
> > existing jffs2 code.  You are excused for that, no doubt.  But I still
> > don't want copies of old mistakes to go in, just because we have a bad
> > example.
> 
> Is this using uint32_t, xattr scanning code and so on ?

Yes.

> > Review is just partial.  It's late enough already and I need to get
> > some sleep.
> 
> Please take a rest slowly on the weekend.
> I'll modify my patch during this period. ;-)

Thanks.

> >> struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
> >>@@ -169,6 +195,7 @@ struct jffs2_raw_node_ref *jffs2_alloc_r
> >> 	struct jffs2_raw_node_ref *ret;
> >> 	ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
> >> 	JFFS2_DBG_MEMALLOC("%p\n", ret);
> >>+	memset(ret, 0, sizeof(*ret));	/* to guarantee owner==NULL */
> >
> >
> > This could be optimized a little by using the constructor/destructor
> > stuff in slabs.  Not too important.
> 
> I'll prepare a tiny and obvious constructor for jffs2_raw_node_ref.
> NULL is set in raw->owner by default is important, the method of setting
> is not so, I think.

Right.  One of the least important issues I had.

> >>@@ -205,3 +232,35 @@ void jffs2_free_inode_cache(struct jffs2
> >> 	JFFS2_DBG_MEMALLOC("%p\n", x);
> >> 	kmem_cache_free(inode_cache_slab, x);
> >> }
> >>+
> >>+#ifdef CONFIG_JFFS2_XATTR
> >>+
> >>+struct jffs2_xattr_cache *jffs2_alloc_xattr_cache(void)
> >>+{
> >>+	struct jffs2_xattr_cache *xc;
> >
> >                           ^^^^^^
> > The name doesn't make sense.  You're referring to a single object, not
> > the complete cache.  Quite confusing.
> >
> >
> >>+	xc = kmem_cache_alloc(xattr_cache_slab, GFP_KERNEL);
> >
> >                                          ^^^^^
> > This is the cache.  A slab is just part of the cache.  So please
> > rename the two.
> 
> For example, how about the following names ?
> "jffs2_xattr_datum" as an alternative of jffs2_xattr_cache.
> "xattr_datum_cache" as an alternative of xattr_cache_slab.
> 
> In this case, "xc" defined as jffs2_xattr_cache structure
> should be renamed to "xd" defined as jffs2_xattr_datum.

Would be fine.

> >>diff -rpNU3 mtd-0829/fs/jffs2/nodelist.h 
> mtd-0829.xattr/fs/jffs2/nodelist.h
> >>--- mtd-0829/fs/jffs2/nodelist.h	2005-08-17 18:00:12.000000000 -0400
> >>+++ mtd-0829.xattr/fs/jffs2/nodelist.h	2005-09-06 
> 10:28:53.000000000 -0400
> >>@@ -20,6 +20,7 @@
> >> #include <linux/jffs2.h>
> >> #include <linux/jffs2_fs_sb.h>
> >> #include <linux/jffs2_fs_i.h>
> >>+#include <linux/jffs2_fs_x.h>
> >
> >
> > I p a l n.
> >
> > I prefer a longer name.  jffs2_fs_xattr.h would be fine.
> > jffs2_xattr.h would also, the "_fs" is more redundant that "attr".
> 
> OK, I'll rename "jffs2_fs_x.h" to "jffs2_xattr.h" and deploy it under
> "fs/jffs2" as David says.

Can you rename it to xattr.h instead?  The prefix has lost its meaning
in fs/jffs2/.

> >> #ifdef __ECOS
> >> #include "os-ecos.h"
> >>@@ -80,6 +81,7 @@ struct jffs2_raw_node_ref
> >> 	struct jffs2_raw_node_ref *next_phys;
> >> 	uint32_t flash_offset;
> >> 	uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
> >>+	void *owner;
> >
> >
> > This grows a node reference from 16/24 bytes to 20/32 bytes for 32/64
> > bit architectures.  I'm not entirely happy about that, but don't a
> > better solution either.
> 
> Indeed, it's involved the growing of object size.
> But we must discriminate XATTR node from other non-inode node
> and indicate jffs2_xattr_cache/jffs2_xattr_ref object from this.
> I didn't have a good idea more than this.
> 
> And, I forgot to enclose the declaration of "void *owner"
> by #ifdef - #endif.

True.

Most likely this idea is stupid, but let me have a try anyway.  You
could give your xattr/xref objects an inode number - either one per
object or a special one shared for all xattr/xref objects.  That would
open a new bag of worms, but keep the size down.

Would it be possible to work with such an approach?

> > By itself, this code is not too bad.  But it add a little more crap to
> > a function that is aching for a rewrite already.  Not sure.
> 
> Hmm,,, I wrote the above part of codes with referring to existing code.
> If the policy is shown, I'll follow it. How should I do ?

In a perfect world, you should send a cleanup patch to break
jffs2_scan_eraseblock() into several smaller functions.  Have the
xattr patch depend on the cleanup.  I might still have an old patch
that I could send you for inspiration.

> >>+
> >>+	nlen = JFFS2_XATTR_NAMELEN(je32_to_cpu(rx->length));
> >>+	vlen = JFFS2_XATTR_VALUELEN(je32_to_cpu(rx->length));
> >
> >
> > Types don't match.  nlen and vlen should become u32.
> 
> Is it enought for "int"?  JFFS2_XATTR_NAMELEN has 12-bit length, and
> JFFS2_XATTR_VALUELEN has 20-bit length.

Makes sense.  But endianness conversions between je32 and int (which
can be anything from 8-64 bit signed/unsigned per c standard) should
be avoided.

> > Btw, I agree with Linus.  u32 is _much_ nicer than uint32_t, not to
> > speak of the uint32_fast_t insanity.
> 
> Is is necessary to correct the part where other uint32_t used.

Not really.  Without the above ("should become u32") I wouldn't even
have mentioned it.  Really minor.

> >>+	xc = jffs2_find_xattr_cache_xid(c, je32_to_cpu(rx->xid));
> >>+	if (xc) {
> >>+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Duplicate XID 
> Found"
> >>+		       " on node at 0x%08x XID=%d Later one ignored\n", ofs, 
> xc->xid);
> >>+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
> >>+		return 0;
> >>+	}
> >
> >
> > How do you deal with xattr reference counting and lifetime?
> 
> When xc->xlist is empty, jffs2_xattr_cache type object will be released.
> jffs2_xattr_ref type object is chained to xc->xlist.
> list_empty(xc->xlist) means nobady refers this XATTR.

...at which time you also remove the xattr from medium, I assume.  Ok.

Next question: How do you remove the xattr from medium?  How is it
garbage collected?

> >>+	xtype = jffs2_xattr_prefix_to_xtype(rx->data, nlen);
> >>+	if (JFFS2_XATTRTYPE_INVALID==xtype) {
> >>+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Unsupported 
> xattr type"
> >>+		       " on node at 0x%08x\n", ofs);
> >>+		USED_SPACE(PAD(je32_to_cpu(rx->totlen)));
> >>+		return 0;
> >>+	}
> >
> >
> > Why is it required that JFFS2 knows the type of the xattr?
> 
> Hmm,,, I added this member to discriminate the prefix of xattr
> without strncmp(). But it might be a bit ugly design.

Then why is it required that JFFS2 knows the prefix?

> >>+static inline int jffs2_scan_xref_node_helper(struct jffs2_sb_info *c,
> >>+			struct jffs2_xattr_ref *new, struct jffs2_xattr_ref 
> *old)
> >>+{
> >>+	/* (uint32_t)new->xc == (uint32_t)old->xc has been made sure. */
> >>+	if ((uint32_t)new->ic == (uint32_t)old->ic) {
> >
> >
> > Why the casts?  How can this be safe on 64bit machines?
> 
> This function is called before jffs2_build_xattr_cache() while FS-mounting.
> In this implementation, xid (uint32 value) is stored in jffs2_xattr_ref->xc
> before jffs2_build_xattr_cache(), and ino (uint32 value) is stored in
> jffs2_xattr_ref->ic.
> 
> After calling jffs2_build_xattr_cache(), xc and ic is used as a pointer
> which indicate to jffs2_xattr_cache/jffs2_inode_cache.

Ok.

> It might be bad manner, but is the following implementation preferable ?

Yes.  And you can use unnamed unions, just remove the "x" and "i".

> struct jffs2_xattr_ref {
>         uint32_t seqno;
>         struct list_head ilist;
>         struct list_head xlist;
>         union {
>                 struct jffs2_xattr_cache *xc;
>                 uint32_t xid;
>         } x;
>         union {
>                 struct jffs2_inode_cache *ic;
>                 uint32_t ino;
>         } i;
>         struct jffs2_raw_node_ref *node;
> };
> 
> 
> >>+static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct 
> jffs2_eraseblock *jeb,
> >>+				struct jffs2_raw_xref *rr, uint32_t ofs)
> >>+{
> >>+	struct jffs2_raw_node_ref *raw;
> 
>              - snip -
> 
> >>+	ref->seqno = je32_to_cpu(rr->seqno);
> >>+	if (ref->seqno > c->highest_seqno)
> >>+		c->highest_seqno = ref->seqno;
> >>+	ref->ic = (void *)je32_to_cpu(rr->ino);
> >>+	ref->xc = (void *)je32_to_cpu(rr->xid);
> >
> >
> > WTF?!?
> >
> > You read a je32 from flash and use that as a pointer?!?
> >
> > Please tell me I'm wrong.
> 
> If we use above emample, we can write it as follows:
> 
>     ref->i.ino = je32_to_cpu(rr->ino);
>     ref->x.xid = je32_to_cpu(rr->xid);

	ret->ino = je32_to_cpu(rr->ino);
	...

> In jffs2_build_xattr_cache(), we find up the jffs2_inode_cache and
> jffs2_xattr_cache by using ino/xid as a key. Then the correct pointers
> are stored in ref->ic and ref->xc after jffs2_build_xattr_cache().
> 
> Is it the situation to use union ?

Yes.  Makes more sense now.  Sorry about the tone.

Still, you can take it as an indication that your reuse-old-fields
trick is not obvious to new readers.  A comment explaining this would
be useful.  Maybe you already have it further down, in the part I
didn't review yet.

Good stuff.

Jörn

-- 
All art is but imitation of nature.
-- Lucius Annaeus Seneca




More information about the linux-mtd mailing list