Skip to contentSkip to conversation

XATTR issues on JFFS2

PATCH In review Kaigai Kohei 6 participants 32 messages Aug 23, 2005 – Dec 3, 2005

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 XATTR issues on JFFS2

Hello,

The attached patch provids XATTR support in JFFS2. We can apply it to mtd-snapshot-20050822.tar.bz2 tree.

I hope your worthwhile comments for improvement.
# By coincidence, two patches for similar functionality are posted in same day :) # I changed the subject of this mail a bit to avoid confusion.

This implementation added two new node types JFFS2_NODETYPE_XATTR and JFFS2_NODETYPE_XREF.
JFFS2_NODETYPE_XATTR node has a set of XATTR entry which contains name and value. It's represented as jffs2_raw_xattr structure on MTD-device. JFFS2_NODETYPE_XREF node has a set of reference to associate inode with XATTR. It's represented as jffs2_raw_xref structure on MTD-device.

* Data Structure
- jffs2_xattr_cache
This object contains XATTR name/value. It must be refered by an inode at least. When the last inode which refers jffs2_xattr_cache is unlinked, jffs2_xattr_cache will be deleted.
XATTR name/value is not loaded until inode object is allocated.

- jffs2_xattr_ref
This object refers jffs2_inode_cache and jffs2_xattr_cache, and chains each other. When we walk on ref->ilist from jffs2_inode_cache, we can scan all the XATTR which is bound to this inode. Adversely, we can scan all the inode which refers this XATTR, when we walk on ref->xlist from jffs2_xattr_cache.

struct jffs2_xattr_cache
{
struct list_head xcache; <-- It's chained from struct jffs2_sb_info (global hash list). struct list_head xlist; <-- jffs2_xattr_ref is chained on this list. struct jffs2_raw_node_ref *node;

uint32_t xid; <-- Unique Identifier
uint32_t version;

uint32_t crc;
char *xname; /* XATTR name */ <--
char *xvalue; /* XATTR value */
int xsize; /* size of XATTR value */
};

struct jffs2_xattr_ref

{
        uint32_t seqno;         /* sequencial number */
        uint32_t flags;
        struct list_head ilist; /* list from jffs2_inode_cache */
        struct list_head xlist; /* list from jffs2_xattr_cache */
        struct jffs2_xattr_cache *xc;
        struct jffs2_inode_cache *ic;
        struct jffs2_raw_node_ref *node;
};

* How to work

[1] FS mounting
When jffs2 is mounting, xattrcache which is array of list_head is created by kmalloc() on jffs2_sb_info first.

Then jffs2_scan_eraseblock() is called on each erase block, and jffs2_scan_xattr_node() and jffs2_scan_xref_node() are used to treat two new node-type. jffs2_scan_xattr_node() create jffs2_xattr_cache object and chain it to xattrcache. jffs2_scan_xref_node() create jffs2_xattr_ref object and chain it to temporary list.

Next, jffs2_build_xattr_caches() is called. This function associate jffs2_inode_cache with jffs2_xattr_cache by using jffs2_xattr_ref. (struct jffs2_xattr_ref *)ref->ilist ... Chained jffs2_inode_cache (struct jffs2_xattr_ref *)ref->xlist ... Chained jffs2_xattr_cache

[2] inode-creation
When inode object is created, jffs2_get_xattr_inode() will be called. It walks on ilist on inode-cache and calls do_load_xattr_cache() for related XATTR object to load XATTR name/value.

[3] getxattr/setxattr
We can refer an jffs2_inode_cache object in {get|set}xattr handler, and walks on jffs2_inode_cache->ilist for looking up target XATTR. In setxattr case, do_create_xattr_cache() is called for creation new XATTR-node, then do_delete_xattr_ref() is used for old-node.

* Example of use

[root@saba ~]# dd if=jffs2.xattr.img of=/dev/mtdblock0 8192+0 records in
8192+0 records out
[root@saba ~]# mount -t jffs2 /dev/mtdblock0 /mnt/0 [root@saba ~]# ls -lZ /mnt/0

drwxr-xr-x  root     root     system_u:object_r:bin_t          bin/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          dev/
drwxr-xr-x  root     root     system_u:object_r:etc_t          etc/
-rw-r--r--  root     root     system_u:object_r:mnt_t          hoge
-rwxr-xr-x  root     root     system_u:object_r:mnt_t          init*
drwxr-xr-x  root     root     system_u:object_r:lib_t          lib/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          loopfs/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          proc/
lrwxrwxrwx  root     root     system_u:object_r:bin_t          sbin
drwxr-xr-x  root     root     system_u:object_r:mnt_t          sys/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          sysroot/

[root@saba ~]#

* ToDo List

(1) stabilization
o more tests and debugging are necessary. I hope any trouble reporting. I don't have real MTD device. This implementation is developed on MTD-RAM pseudo device. Does it work on real MTD-devices ?

(2) performance & scalability
o Currently, any XATTR objects are guarded by a xattr_sem. But this implementation is not scale, I guess. To divid locking is necessary.
o When setxattr() is called, the system scans XATTR cache to look for same combination of name/value and share it.
But it's so expensive process, to reduce finding-step is necessary.

(3) more functionality
o Currently, only XATTR has "security.*" prefix is supported. It's enough to use SELinux, but that's more useful if we can use POSIX-ACL and so on.
o modifying mkfs.jffs2 command.

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
fs/Kconfig +9 -0
diff -rpNU3 mtd/fs/Kconfig mtd-xattr/fs/Kconfig
@@ -51,6 +51,15 @@ config JFFS2_FS_DEBUG
 	  If reporting bugs, please try to have available a full dump of the
 	  messages at debug level 1 while the misbehaviour was occurring.
 
+config JFFS2_XATTR
+	bool "JFFS2 XATTR support (EXPERIMENTAL)"
+	depends on JFFS2_FS
+	default n
+	help
+	 This enables the XATTR support in JFFS2.
+	 
+	 It's neccesary for persistent security context in SELinux.
+
 config JFFS2_FS_WRITEBUFFER
 	bool "JFFS2 write-buffering support"
 	depends on JFFS2_FS
fs/jffs2/Makefile.common +1 -0
diff -rpNU3 mtd/fs/jffs2/Makefile.common mtd-xattr/fs/jffs2/Makefile.common
@@ -11,6 +11,7 @@ jffs2-y	+= read.o nodemgmt.o readinode.o
 jffs2-y	+= symlink.o build.o erase.o background.o fs.o writev.o
 jffs2-y	+= super.o debug.o
 
+jffs2-$(CONFIG_JFFS2_XATTR)	+= xattr.o
 jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= wbuf.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
fs/jffs2/build.c +3 -0
diff -rpNU3 mtd/fs/jffs2/build.c mtd-xattr/fs/jffs2/build.c
@@ -165,6 +165,7 @@ static int jffs2_build_filesystem(struct
 		ic->scan_dents = NULL;
 		cond_resched();
 	}
+	jffs2_build_xattr_caches(c);
 	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
 	
 	D1(printk(KERN_DEBUG "Pass 3 complete\n"));
@@ -184,6 +185,7 @@ exit:
 				jffs2_free_full_dirent(fd);
 			}
 		}
+		jffs2_clear_xattr_caches(c);
 	}
 
 	return ret;
@@ -353,6 +355,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 
 	if (jffs2_build_filesystem(c)) {
 		D1(printk(KERN_DEBUG "build_fs failed\n"));
+		jffs2_clear_xattr_caches(c);
 		jffs2_free_ino_caches(c);
 		jffs2_free_raw_node_refs(c);
 #ifndef __ECOS
fs/jffs2/dir.c +8 -1
diff -rpNU3 mtd/fs/jffs2/dir.c mtd-xattr/fs/jffs2/dir.c
@@ -58,6 +58,10 @@ struct inode_operations jffs2_dir_inode_
 	.mknod =	jffs2_mknod,
 	.rename =	jffs2_rename,
 	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 /***********************************************************************/
@@ -236,8 +240,11 @@ static int jffs2_unlink(struct inode *di
 
 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, 
 			      dentry->d_name.len, dead_f, now);
-	if (dead_f->inocache)
+	if (dead_f->inocache) {
 		dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+		if (!dead_f->inocache->nlink)
+			jffs2_unlink_xattr_inode(c, dead_f->inocache);
+	}
 	if (!ret)
 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
 	return ret;
fs/jffs2/file.c +5 -1
diff -rpNU3 mtd/fs/jffs2/file.c mtd-xattr/fs/jffs2/file.c
@@ -57,7 +57,11 @@ struct file_operations jffs2_file_operat
 
 struct inode_operations jffs2_file_inode_operations =
 {
-	.setattr =	jffs2_setattr
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 struct address_space_operations jffs2_file_address_operations =
fs/jffs2/fs.c +27 -0
diff -rpNU3 mtd/fs/jffs2/fs.c mtd-xattr/fs/jffs2/fs.c
@@ -310,6 +310,15 @@ void jffs2_read_inode (struct inode *ino
 		printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino);
 	}
 
+#ifdef CONFIG_JFFS2_XATTR
+	ret = jffs2_get_xattr_inode(c, f->inocache);
+	if (ret) {
+		up(&f->sem);
+		jffs2_do_clear_inode(c, f);
+		make_bad_inode(inode);
+		return;
+	}
+#endif
 	up(&f->sem);
 
 	D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
@@ -504,6 +513,20 @@ int jffs2_do_fill_super(struct super_blo
 	}
 	memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
+#ifdef CONFIG_JFFS2_XATTR
+	/* Initialization of XATTR related members */
+	c->xattrcache = kmalloc(XATTRCACHE_HASHSIZE * sizeof(struct list_head), GFP_KERNEL);
+	if (!c->xattrcache) {
+		kfree(c->inocache_list);
+		ret = -ENOMEM;
+		goto out_wbuf;
+	}
+	for (ret=0; ret<XATTRCACHE_HASHSIZE; ret++)
+		INIT_LIST_HEAD(&c->xattrcache[ret]);
+	INIT_LIST_HEAD(&c->xattr_temp);
+	init_rwsem(&c->xattr_sem);
+#endif
+
 	if ((ret = jffs2_do_mount_fs(c)))
 		goto out_inohash;
 
@@ -531,6 +554,7 @@ int jffs2_do_fill_super(struct super_blo
 
  out_root_i:
 	iput(root_i);
+	jffs2_clear_xattr_caches(c);
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
@@ -538,6 +562,9 @@ int jffs2_do_fill_super(struct super_blo
 	else
 		kfree(c->blocks);
  out_inohash:
+#ifdef CONFIG_JFFS2_XATTR
+	kfree(c->xattrcache);
+#endif
 	kfree(c->inocache_list);
  out_wbuf:
 	jffs2_flash_cleanup(c);
fs/jffs2/malloc.c +60 -2

83 lines not on this page · raw message

fs/jffs2/nodelist.h +11 -0
diff -rpNU3 mtd/fs/jffs2/nodelist.h mtd-xattr/fs/jffs2/nodelist.h
@@ -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>
 
 #ifdef __ECOS
 #include "os-ecos.h"
@@ -111,6 +112,9 @@ struct jffs2_inode_cache {
 	uint32_t ino;
 	int nlink;
 	int state;
+#ifdef CONFIG_JFFS2_XATTR
+	struct list_head ilist;
+#endif
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
@@ -367,6 +371,13 @@ void jffs2_free_node_frag(struct jffs2_n
 struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
 void jffs2_free_inode_cache(struct jffs2_inode_cache *);
 
+#ifdef CONFIG_JFFS2_XATTR
+struct jffs2_xattr_cache *jffs2_alloc_xattr_cache(void);
+void jffs2_free_xattr_cache(struct jffs2_xattr_cache *);
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void);
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *);
+#endif /* CONFIG_JFFS2_XATTR */
+
 /* gc.c */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 
fs/jffs2/readinode.c +3 -0
diff -rpNU3 mtd/fs/jffs2/readinode.c mtd-xattr/fs/jffs2/readinode.c
@@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_
 		f->inocache->ino = f->inocache->nlink = 1;
 		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 		f->inocache->state = INO_STATE_READING;
+		initxattr_jffs2_inode_cache(f->inocache);
 		jffs2_add_ino_cache(c, f->inocache);
 	}
 	if (!f->inocache) {
@@ -965,6 +966,8 @@ void jffs2_do_clear_inode(struct jffs2_s
 		jffs2_free_full_dirent(fd);
 	}
 
+	jffs2_put_xattr_inode(c, f->inocache);
+
 	if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
 		jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 		if (f->inocache->nodes == (void *)f->inocache)
fs/jffs2/scan.c +219 -1

244 lines not on this page · raw message

fs/jffs2/super.c +4 -0
diff -rpNU3 mtd/fs/jffs2/super.c mtd-xattr/fs/jffs2/super.c
@@ -282,6 +282,7 @@ static void jffs2_put_super (struct supe
 	down(&c->alloc_sem);
 	jffs2_flush_wbuf_pad(c);
 	up(&c->alloc_sem);
+	jffs2_clear_xattr_caches(c);
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
@@ -290,6 +291,9 @@ static void jffs2_put_super (struct supe
 		kfree(c->blocks);
 	jffs2_flash_cleanup(c);
 	kfree(c->inocache_list);
+#ifdef CONFIG_JFFS2_XATTR
+	kfree(c->xattrcache);
+#endif
 	if (c->mtd->sync)
 		c->mtd->sync(c->mtd);
 
fs/jffs2/symlink.c +5 -1
diff -rpNU3 mtd/fs/jffs2/symlink.c mtd-xattr/fs/jffs2/symlink.c
@@ -24,7 +24,11 @@ struct inode_operations jffs2_symlink_in
 {	
 	.readlink =	generic_readlink,
 	.follow_link =	jffs2_follow_link,
-	.setattr =	jffs2_setattr
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
fs/jffs2/write.c +1 -1
diff -rpNU3 mtd/fs/jffs2/write.c mtd-xattr/fs/jffs2/write.c
@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_i
 	f->inocache->nlink = 1;
 	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 	f->inocache->state = INO_STATE_PRESENT;
-
+	initxattr_jffs2_inode_cache(f->inocache);
 
 	jffs2_add_ino_cache(c, f->inocache);
 	D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
fs/jffs2/xattr.c +704 -0

704 lines not on this page · raw message

include/linux/jffs2.h +33 -0
diff -rpNU3 mtd/include/linux/jffs2.h mtd-xattr/include/linux/jffs2.h
@@ -59,6 +59,8 @@
 #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
 #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
 
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
@@ -146,9 +148,40 @@ struct jffs2_raw_inode
 	uint8_t data[0];
 } __attribute__((packed));
 
+struct jffs2_raw_xattr
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* JFFS2_NODETYPE_XATTR */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t version;	/* XATTR version number */
+	jint32_t length;	/* upper 12bit = the length of xname */
+				/* lower 20bit = the length of xvalue */
+	jint32_t data_crc;
+	jint32_t node_crc;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* JFFS2_NODETYPE_XREF */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+
+	jint32_t seqno;		/* sequencial number */
+	jint32_t ino;		/* inode number */
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t node_crc;
+} __attribute__((packed));
+
 union jffs2_node_union {
 	struct jffs2_raw_inode i;
 	struct jffs2_raw_dirent d;
+	struct jffs2_raw_xattr x;
+	struct jffs2_raw_xref r;
 	struct jffs2_unknown_node u;
 };
 
include/linux/jffs2_fs_sb.h +7 -0
diff -rpNU3 mtd/include/linux/jffs2_fs_sb.h mtd-xattr/include/linux/jffs2_fs_sb.h
@@ -112,6 +112,13 @@ struct jffs2_sb_info {
 	uint32_t fsdata_len;
 #endif
 
+#ifdef CONFIG_JFFS2_XATTR
+	uint32_t highest_xid;		/* version number for XATTR-Node */
+	uint32_t highest_seqno;		/* seqno for XREF-Node */
+	struct list_head *xattrcache;
+	struct list_head xattr_temp;	/* temporary use in mounting */
+	struct rw_semaphore xattr_sem;
+#endif
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };
include/linux/jffs2_fs_x.h +119 -0

119 lines not on this page · raw message

#1 lore raw

Hello,

In recent days, I'm interrested in XATTR support in JFFS2.

I have started a discussion about it on MTD-ML.
http://lists.infradead.org/pipermail/linux-mtd/2005-August/013415.html

By ML-archive, an implementation use hidden-file to store XATTR was rejected finally. Thus, I adopted different approach. This implementation added two new node types JFFS2_NODETYPE_XATTR and JFFS2_NODETYPE_XREF for XATTR representation.

If your comment can be gotten, I'm so glad.

# I think it's not appropriate to discuss JFFS2 at SELinux-ML. # Please comment it on MTD-ML, if possible.

Thanks,

*---- Example of use ------------

In my desktop PC, "fs_use_xattr jffs2 system_u:object_r:fs_t;" was configured. :)

[root@saba ~]# dd if=jffs2.xattr.img of=/dev/mtdblock0 8192+0 records in
8192+0 records out
[root@saba ~]# mount -t jffs2 /dev/mtdblock0 /mnt/0 [root@saba ~]# ls -lZ /mnt/0

drwxr-xr-x  root     root     system_u:object_r:bin_t          bin/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          dev/
drwxr-xr-x  root     root     system_u:object_r:etc_t          etc/
-rw-r--r--  root     root     system_u:object_r:mnt_t          hoge
-rwxr-xr-x  root     root     system_u:object_r:mnt_t          init*
drwxr-xr-x  root     root     system_u:object_r:lib_t          lib/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          loopfs/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          proc/
lrwxrwxrwx  root     root     system_u:object_r:bin_t          sbin
drwxr-xr-x  root     root     system_u:object_r:mnt_t          sys/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          sysroot/

[root@saba ~]#

Signature · 8 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#2 lore raw
Quoted 40 lines · KaiGai Kohei

Hello,

In recent days, I'm interrested in XATTR support in JFFS2.

I have started a discussion about it on MTD-ML.
http://lists.infradead.org/pipermail/linux-mtd/2005-August/013415.html

By ML-archive, an implementation use hidden-file to store XATTR was rejected finally. Thus, I adopted different approach. This implementation added two new node types JFFS2_NODETYPE_XATTR and JFFS2_NODETYPE_XREF for XATTR representation.

If your comment can be gotten, I'm so glad.

# I think it's not appropriate to discuss JFFS2 at SELinux-ML. # Please comment it on MTD-ML, if possible.

Thanks,

*---- Example of use ------------

In my desktop PC, "fs_use_xattr jffs2 system_u:object_r:fs_t;" was configured. :)

[root@saba ~]# dd if=jffs2.xattr.img of=/dev/mtdblock0 8192+0 records in
8192+0 records out
[root@saba ~]# mount -t jffs2 /dev/mtdblock0 /mnt/0 [root@saba ~]# ls -lZ /mnt/0

drwxr-xr-x  root     root     system_u:object_r:bin_t          bin/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          dev/
drwxr-xr-x  root     root     system_u:object_r:etc_t          etc/
(quoted diff) +0 -2
-rw-r--r--  root     root     system_u:object_r:mnt_t          hoge
-rwxr-xr-x  root     root     system_u:object_r:mnt_t          init*
drwxr-xr-x  root     root     system_u:object_r:lib_t          lib/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          loopfs/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          proc/
lrwxrwxrwx  root     root     system_u:object_r:bin_t          sbin
drwxr-xr-x  root     root     system_u:object_r:mnt_t          sys/
drwxr-xr-x  root     root     system_u:object_r:mnt_t          sysroot/
Quoted 1 line

[root@saba ~]#

Thanks for working on this functionality. From a very brief look at the patch, one question I had was whether you could be using the generic xattr methods introduced by James Morris' earlier xattr code consolidation patches that are now in the mainline kernel. See the generic_* functions in fs/xattr.c and how they are used by the fs code (e.g. look at the ext3 xattr implementation). Per recent discussions on linux-fsdevel, using those helpers is the preferred approach for the future. You can then just set sb->s_xattr for the specific handlers in jffs2, e.g. see the ext3 code for an example.

Might be worth mentioning this work on acl-devel as well, although you don't yet support ACLs or other xattrs. But I'm sure Andreas Gruenbacher would be interested, as he did the original xattr and ACL development work for ext[23], and he may be able to give feedback on your approach to various aspects like the attribute caching.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#3 lore raw

Hello,

Thanks for your comments.

The original reason not to use generic XATTR methods is that {get|set|list}_xattr methods are called with XATTR-name which prefix is omitted.
e.g, sys_getxattr("security.selinux", ...)

      -> generic_getxattr("security.selinux", ...)
        -> jffs2_security_getxattr("selinux", ...)
                                    ~~~~~~~<- "security." was omitted.

In my implementation, the full-name is used to identify XATTR-entry.

But I noticed that we can use a combination of integer index number (such as EXT2_XATTR_INDEX_SECURITY) and omitted XATTR-name for the replacement of full-XATTR-name, and can use generic_xxxx().

I'll modify it in "take-2" patch.
(Why didn't I notice before posting...)

Quoted 9 lines

Thanks for working on this functionality. From a very brief look at the patch, one question I had was whether you could be using the generic xattr methods introduced by James Morris' earlier xattr code consolidation patches that are now in the mainline kernel. See the generic_* functions in fs/xattr.c and how they are used by the fs code (e.g. look at the ext3 xattr implementation). Per recent discussions on linux-fsdevel, using those helpers is the preferred approach for the future. You can then just set sb->s_xattr for the specific handlers in jffs2, e.g. see the ext3 code for an example.

Thanks for this information. I'll contact to him before ACL implementation.

Quoted 5 lines

Might be worth mentioning this work on acl-devel as well, although you don't yet support ACLs or other xattrs. But I'm sure Andreas Gruenbacher would be interested, as he did the original xattr and ACL development work for ext[23], and he may be able to give feedback on your approach to various aspects like the attribute caching.

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#4 lore raw
Quoted 7 lines · KaiGai Kohei

The original reason not to use generic XATTR methods is that {get|set|list}_xattr methods are called with XATTR-name which prefix is omitted.
e.g, sys_getxattr("security.selinux", ...)

      -> generic_getxattr("security.selinux", ...)
        -> jffs2_security_getxattr("selinux", ...)
                                    ~~~~~~~<- "security." was omitted.

In my implementation, the full-name is used to identify XATTR-entry.

reiserfs has the same issue, so they are proposing changing the generic functions to pass the entire name down to the fs code. See
http://marc.theaimsgroup.com/?l=linux-fsdevel&m=112448411323801&w=2

Quoted 3 lines

But I noticed that we can use a combination of integer index number (such as EXT2_XATTR_INDEX_SECURITY) and omitted XATTR-name for the replacement of full-XATTR-name, and can use generic_xxxx().

Yes, that is an option as well.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#5 lore raw
In reply to Kaigai Kohei
Quoted 6 lines · Kaigai Kohei

The attached patch provids XATTR support in JFFS2. We can apply it to mtd-snapshot-20050822.tar.bz2 tree.

I hope your worthwhile comments for improvement.
# By coincidence, two patches for similar functionality are posted in same day :)

Which is quite nice. Would you two mind reading the others patch and stating what is bad at that one and why your's is better? If there is a clear winner in this batter, we should merge that one. Most likely, the result is that both patches are lacking details and a new one with elements from both should be used instead. At this moment, we just don't know yet, what those details are.

Jörn

Signature · 3 lines
Mundie uses a textbook tactic of manipulation: start with some
reasonable talk, and lead the audience to an unreasonable conclusion.
-- Bruce Perens
maintainer
#6 lore raw
Quoted 3 lines · Jörn Engel

Which is quite nice. Would you two mind reading the others patch and stating what is bad at that one and why your's is better? If there is a clear winner in this batter, we should merge that one.

I'm happier with inventing new node types for xattrs instead of re-using existing nodes, I think. And I'd also like to make sure we can share xattr data on the medium where appropriate. In an selinux system, you'll end up with a _multitude_ of xattrs used for selinux, many of which will have precisely the same contents. Each should be stored only once on the flash, like hard links. The ext2 implementation manages this.

Signature · 1 line
dwmw2
#7 lore raw

Hello, Thanks for your comments.

Quoted 6 lines · David Woodhouse

I'm happier with inventing new node types for xattrs instead of re-using existing nodes, I think. And I'd also like to make sure we can share xattr data on the medium where appropriate. In an selinux system, you'll end up with a _multitude_ of xattrs used for selinux, many of which will have precisely the same contents. Each should be stored only once on the flash, like hard links. The ext2 implementation manages this.

Indeed, it is key concept to separate the relationship between inode and XATTR from XATTR-entry which contain name/value.
In my implementation, an increase/decrease of inode which shares XATTR-entry does not need to update the XATTR-entry. It's represented by an existance of XATTR-reference node. Therefore, it's possible to update less frequently.

If this approach is acceptable, I'm willing to implement something to do.
* Dividing the global xattr_sem semaphore into more small lock.
* Indexing the XATTR-entry by its contains, for fast looking-up shared entry. and, Stephen suggested as follows:
* Using generic_{set|get|list}xattr method like ext2/3.

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#8 lore raw

Hi,

Today, I think about appropriate locking in JFFS2's XATTR. I hope to get some comments about dividing locking.

Quoted 1 line

* Dividing the global xattr_sem semaphore into more small lock.

xattr_sem is a global read/write semaphore stored in jffs2_sb_info to protect any XATTR structure.
In common case, dividing lock/semaphore has good effects for scalability toward the number of CPUs. But JFFS2 is frequently used for small and embedded region in my understanding.

If global semaphore is divided into many per-entry locks, we may be able to execute setxattr() concurrently. But each locking/un-locking cost may also exceed the scalability effect.
Since I don't have much experience in this region, I hope any professional's worthwhile comments.

Now, I think one global read/write semaphore is enough for 1-2 CPUs, if assumption of the XATTR processing with wrinting does not happen so much is permitted. In almost case, we can execute get/listxattr cuncurrently with one lock/un-locking, I think.

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#9 lore raw
Quoted 18 lines · Kaigai Kohei

Today, I think about appropriate locking in JFFS2's XATTR. I hope to get some comments about dividing locking.

Quoted 1 line

* Dividing the global xattr_sem semaphore into more small lock.

xattr_sem is a global read/write semaphore stored in jffs2_sb_info to protect any XATTR structure.
In common case, dividing lock/semaphore has good effects for scalability toward the number of CPUs. But JFFS2 is frequently used for small and embedded region in my understanding.

If global semaphore is divided into many per-entry locks, we may be able to execute setxattr() concurrently. But each locking/un-locking cost may also exceed the scalability effect.
Since I don't have much experience in this region, I hope any professional's worthwhile comments.

Quoted 4 lines

Now, I think one global read/write semaphore is enough for 1-2 CPUs, if assumption of the XATTR processing with wrinting does not happen so much is permitted. In almost case, we can execute get/listxattr cuncurrently with one lock/un-locking, I think.

Your idea to go to fine-grained locking surprised me a bit when I first saw it. JFFS2 is hardly the fs that cares much about SMP scalability. Unless you can prove real contentions around the xattr_lock in realistic benchmarks, I would ignore this issue.

Correctness is another issue. I guess you have read fs/jffs2/README.Locking and started a graph on paper to visualize locking order. This is more important, as a deadlock is about the worst performance you can get. ;)

Jörn

Signature · 2 lines
He that composes himself is wiser than he that composes a book.
-- B. Franklin
#10 lore raw
In reply to Kaigai Kohei

Hello,

This attached patch enables XATTR support in JFFS2. (take-2) # The contribution has slowed due to the trouble related to GC :-(

The my first patch posted in Aug 23 is revised at the points as follows.

- get/setxattr are implemented as a method of generic XATTR handler.
- new methods for "user.*" and "trusted.*" prefix were added.

- Time to retrieve the duplicate XATTR-cache shortened, when setxattr(). In first implementation, we must scan all XATTR-cache to find the duplicate one, and it's so expensive. Now, we cau use the hash-list of XATTR-cache which is indexed by own contents.

- Now, Garbage Collector can deal JFFS2_NODETYPE_XATTR and JFFS2_NODETYPE_XREF. It seems to me that GC can mark unconditionally any nodes without inode as obsolete. But new JFFS2_NODETYPE_XATTR/XREF should be an exception. GC must not mark them as obsolete, although their "next_in_ino" is NULL.

----[ jffs2_garbage_collect_pass() in gc.c ]------------------------
249 if (!raw->next_in_ino) { <-- unconditionally mark it as obsolete.
250 /* Inode-less node. Clean marker, snapshot or something like that */
251 /* FIXME: If it's something that needs to be copied, including something
252 we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */

  253      spin_unlock(&c->erase_completion_lock);
  254      jffs2_mark_node_obsolete(c, raw);
  255      up(&c->alloc_sem);
  256      goto eraseit_lock;

257 }
--------------------------------------------------------------------

I added a new variable 'owner' into jffs2_raw_node_ref to resolve this. It refers jffs2_xattr_cache or jffs2_xattr_ref object when raw-node reflect XATTR-node. Thus, we can distinguish XATTR-node and others by whether 'owner' is NULL or not.

- Consistency has improved.
check_xattr_ref_ilist() checks XATTRs which are binded to same inode. If multiple XATTR has same name exist, older one is marked as obsolete. In first implementation, there are possibilities to be created multiple XATTRs have same name in an inode, when system-crash happens durling setxattr()

The remaining work is as follows:
- Test & Stabilization.
- The implementation for POSIX ACL support.
- The implementation for XATTR support in mkfs.jffs2.

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
fs/Kconfig +16 -0
diff -rpNU3 mtd-0829/fs/Kconfig mtd-0829.xattr/fs/Kconfig
@@ -64,6 +64,22 @@ config JFFS2_FS_WRITEBUFFER
 	    - NOR flash with transparent ECC
 	    - DataFlash
 
+config JFFS2_XATTR
+	bool "JFFS2 XATTR support (EXPERIMENTAL)"
+	depends on JFFS2_FS
+	default n
+	help
+	  This enables the XATTR support in JFFS2.
+	  
+	  It's neccesary for persistent security context in SELinux.
+	  Now, we can use the following kinds of prefix.
+	  
+	  - security.*
+	  - user.*
+	  - trust.*
+	  
+	  - system.posix_acl_{access|default} are in TODO list now.
+
 config JFFS2_COMPRESSION_OPTIONS
 	bool "Advanced compression options for JFFS2"
 	default n
fs/jffs2/Makefile.common +1 -0
diff -rpNU3 mtd-0829/fs/jffs2/Makefile.common mtd-0829.xattr/fs/jffs2/Makefile.common
@@ -12,6 +12,7 @@ jffs2-y	+= symlink.o build.o erase.o bac
 jffs2-y	+= super.o debug.o
 
 jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= wbuf.o
+jffs2-$(CONFIG_JFFS2_XATTR)	+= xattr.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
fs/jffs2/build.c +2 -0
diff -rpNU3 mtd-0829/fs/jffs2/build.c mtd-0829.xattr/fs/jffs2/build.c
@@ -165,6 +165,7 @@ static int jffs2_build_filesystem(struct
 		ic->scan_dents = NULL;
 		cond_resched();
 	}
+	jffs2_build_xattr_caches(c);
 	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
 	
 	D1(printk(KERN_DEBUG "Pass 3 complete\n"));
@@ -184,6 +185,7 @@ exit:
 				jffs2_free_full_dirent(fd);
 			}
 		}
+		jffs2_clear_xattr_caches(c);
 	}
 
 	return ret;
fs/jffs2/dir.c +5 -0
diff -rpNU3 mtd-0829/fs/jffs2/dir.c mtd-0829.xattr/fs/jffs2/dir.c
@@ -57,7 +57,12 @@ struct inode_operations jffs2_dir_inode_
 	.rmdir =	jffs2_rmdir,
 	.mknod =	jffs2_mknod,
 	.rename =	jffs2_rename,
+	.permission =	jffs2_permission,
 	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 /***********************************************************************/
fs/jffs2/file.c +6 -1
diff -rpNU3 mtd-0829/fs/jffs2/file.c mtd-0829.xattr/fs/jffs2/file.c
@@ -57,7 +57,12 @@ struct file_operations jffs2_file_operat
 
 struct inode_operations jffs2_file_inode_operations =
 {
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 struct address_space_operations jffs2_file_address_operations =
fs/jffs2/fs.c +6 -0
diff -rpNU3 mtd-0829/fs/jffs2/fs.c mtd-0829.xattr/fs/jffs2/fs.c
@@ -217,6 +217,8 @@ void jffs2_clear_inode (struct inode *in
 	
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	if (f->inocache && !f->inocache->nlink)
+		jffs2_xattr_clear_inode(c, f->inocache);
 	jffs2_do_clear_inode(c, f);
 }
 
@@ -504,6 +506,9 @@ int jffs2_do_fill_super(struct super_blo
 	}
 	memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
+	if ((ret = jffs2_init_xattr_caches(c)))
+		goto out_inohash;
+
 	if ((ret = jffs2_do_mount_fs(c)))
 		goto out_inohash;
 
@@ -537,6 +542,7 @@ int jffs2_do_fill_super(struct super_blo
 		vfree(c->blocks);
 	else
 		kfree(c->blocks);
+	jffs2_clear_xattr_caches(c);
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:
fs/jffs2/gc.c +6 -1
diff -rpNU3 mtd-0829/fs/jffs2/gc.c mtd-0829.xattr/fs/jffs2/gc.c
@@ -251,7 +251,12 @@ int jffs2_garbage_collect_pass(struct jf
 		/* FIXME: If it's something that needs to be copied, including something
 		   we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
 		spin_unlock(&c->erase_completion_lock);
-		jffs2_mark_node_obsolete(c, raw);
+		if (raw->owner) {
+			/* JFFS2_NODETYPE_XATTR or JFFS2_NODETYPE_XREF */
+			ret = jffs2_garbage_collect_xattr(c, raw);
+		} else {
+			jffs2_mark_node_obsolete(c, raw);
+		}
 		up(&c->alloc_sem);
 		goto eraseit_lock;
 	}
fs/jffs2/malloc.c +61 -2

90 lines not on this page · raw message

fs/jffs2/nodelist.c +1 -0
diff -rpNU3 mtd-0829/fs/jffs2/nodelist.c mtd-0829.xattr/fs/jffs2/nodelist.c
@@ -934,6 +934,7 @@ void jffs2_free_ino_caches(struct jffs2_
 		this = c->inocache_list[i];
 		while (this) {
 			next = this->next;
+			jffs2_xattr_free_inode(c, this);
 			jffs2_free_inode_cache(this);
 			this = next;
 		}
fs/jffs2/nodelist.h +13 -0
diff -rpNU3 mtd-0829/fs/jffs2/nodelist.h mtd-0829.xattr/fs/jffs2/nodelist.h
@@ -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>
 
 #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;
 };
 
         /* flash_offset & 3 always has to be zero, because nodes are
@@ -111,6 +113,10 @@ struct jffs2_inode_cache {
 	uint32_t ino;
 	int nlink;
 	int state;
+#ifdef CONFIG_JFFS2_XATTR
+	struct list_head ilist;
+	uint8_t ilist_checked;
+#endif
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
@@ -367,6 +373,13 @@ void jffs2_free_node_frag(struct jffs2_n
 struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
 void jffs2_free_inode_cache(struct jffs2_inode_cache *);
 
+#ifdef CONFIG_JFFS2_XATTR
+struct jffs2_xattr_cache *jffs2_alloc_xattr_cache(void);
+void jffs2_free_xattr_cache(struct jffs2_xattr_cache *);
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void);
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *);
+#endif /* CONFIG_JFFS2_XATTR */
+
 /* gc.c */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 
fs/jffs2/readinode.c +1 -0
diff -rpNU3 mtd-0829/fs/jffs2/readinode.c mtd-0829.xattr/fs/jffs2/readinode.c
@@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_
 		f->inocache->ino = f->inocache->nlink = 1;
 		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 		f->inocache->state = INO_STATE_READING;
+		initxattr_jffs2_inode_cache(f->inocache);
 		jffs2_add_ino_cache(c, f->inocache);
 	}
 	if (!f->inocache) {
fs/jffs2/scan.c +225 -1

250 lines not on this page · raw message

fs/jffs2/super.c +2 -0
diff -rpNU3 mtd-0829/fs/jffs2/super.c mtd-0829.xattr/fs/jffs2/super.c
@@ -151,6 +151,7 @@ static struct super_block *jffs2_get_sb_
 
 	sb->s_op = &jffs2_super_operations;
 	sb->s_flags = flags | MS_NOATIME;
+	sb->s_xattr = jffs2_xattr_handlers;
 
 	ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
 
@@ -290,6 +291,7 @@ static void jffs2_put_super (struct supe
 		kfree(c->blocks);
 	jffs2_flash_cleanup(c);
 	kfree(c->inocache_list);
+	jffs2_clear_xattr_caches(c);
 	if (c->mtd->sync)
 		c->mtd->sync(c->mtd);
 
fs/jffs2/symlink.c +6 -1
diff -rpNU3 mtd-0829/fs/jffs2/symlink.c mtd-0829.xattr/fs/jffs2/symlink.c
@@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_in
 {	
 	.readlink =	generic_readlink,
 	.follow_link =	jffs2_follow_link,
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
fs/jffs2/write.c +1 -1
diff -rpNU3 mtd-0829/fs/jffs2/write.c mtd-0829.xattr/fs/jffs2/write.c
@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_i
 	f->inocache->nlink = 1;
 	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 	f->inocache->state = INO_STATE_PRESENT;
-
+	initxattr_jffs2_inode_cache(f->inocache);
 
 	jffs2_add_ino_cache(c, f->inocache);
 	D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
fs/jffs2/xattr.c +1170 -0

1,170 lines not on this page · raw message

include/linux/jffs2.h +32 -0
diff -rpNU3 mtd-0829/include/linux/jffs2.h mtd-0829.xattr/include/linux/jffs2.h
@@ -59,6 +59,8 @@
 #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
 #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
 
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
@@ -146,9 +148,39 @@ struct jffs2_raw_inode
 	uint8_t data[0];
 } __attribute__((packed));
 
+struct jffs2_raw_xattr
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* JFFS2_NODETYPE_XATTR */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t length;	/* upper 12bit = length of name */
+				/* lower 20bit = length of value */
+	jint32_t data_crc;
+	jint32_t node_crc;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* JFFS2_NODETYPE_XREF */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+
+	jint32_t seqno;		/* sequencial number */
+	jint32_t ino;		/* inode number */
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t node_crc;
+} __attribute__((packed));
+
 union jffs2_node_union {
 	struct jffs2_raw_inode i;
 	struct jffs2_raw_dirent d;
+	struct jffs2_raw_xattr x;
+	struct jffs2_raw_xref r;
 	struct jffs2_unknown_node u;
 };
 
include/linux/jffs2_fs_sb.h +10 -0
diff -rpNU3 mtd-0829/include/linux/jffs2_fs_sb.h mtd-0829.xattr/include/linux/jffs2_fs_sb.h
@@ -112,6 +112,16 @@ struct jffs2_sb_info {
 	uint32_t fsdata_len;
 #endif
 
+#ifdef CONFIG_JFFS2_XATTR
+	uint32_t highest_xid;
+	uint32_t highest_seqno;
+	struct list_head *xattrcache;
+#define xattr_temp xattrcache[XATTRCACHE_HASHSIZE]
+	struct rw_semaphore xattr_sem;
+
+	uint32_t xcache_mem_usage;
+	uint32_t xcache_mem_threshold;
+#endif
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };
include/linux/jffs2_fs_x.h +140 -0

140 lines not on this page · raw message

#11 lore raw
Quoted 44 lines · Kaigai Kohei

This attached patch enables XATTR support in JFFS2. (take-2) # The contribution has slowed due to the trouble related to GC :-(

The my first patch posted in Aug 23 is revised at the points as follows.

- get/setxattr are implemented as a method of generic XATTR handler.
- new methods for "user.*" and "trusted.*" prefix were added.

- Time to retrieve the duplicate XATTR-cache shortened, when setxattr(). In first implementation, we must scan all XATTR-cache to find the duplicate
one, and it's so expensive. Now, we cau use the hash-list of XATTR-cache which is indexed by own contents.

- Now, Garbage Collector can deal JFFS2_NODETYPE_XATTR and JFFS2_NODETYPE_XREF.
It seems to me that GC can mark unconditionally any nodes without inode as obsolete. But new JFFS2_NODETYPE_XATTR/XREF should be an exception. GC must not mark them as obsolete, although their "next_in_ino" is NULL.

----[ jffs2_garbage_collect_pass() in gc.c ]------------------------
249 if (!raw->next_in_ino) { <-- unconditionally mark it as
obsolete.
250 /* Inode-less node. Clean marker, snapshot or something like
that */
251 /* FIXME: If it's something that needs to be copied, including
something
252 we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we
should do so */

  253      spin_unlock(&c->erase_completion_lock);
  254      jffs2_mark_node_obsolete(c, raw);
  255      up(&c->alloc_sem);
  256      goto eraseit_lock;

257 }
--------------------------------------------------------------------

I added a new variable 'owner' into jffs2_raw_node_ref to resolve this. It refers jffs2_xattr_cache or jffs2_xattr_ref object when raw-node reflect
XATTR-node. Thus, we can distinguish XATTR-node and others by whether 'owner'
is NULL or not.

Quoted 6 lines

- Consistency has improved.
check_xattr_ref_ilist() checks XATTRs which are binded to same inode. If multiple XATTR has same name exist, older one is marked as obsolete. In first implementation, there are possibilities to be created multiple XATTRs have same name in an inode, when system-crash happens durling setxattr()

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.

Review is just partial. It's late enough already and I need to get some sleep.

Quoted 93 lines

diff -rpNU3 mtd-0829/fs/Kconfig mtd-0829.xattr/fs/Kconfig

fs/Kconfig +16 -0
@@ -64,6 +64,22 @@ config JFFS2_FS_WRITEBUFFER
 	    - NOR flash with transparent ECC
 	    - DataFlash
 
+config JFFS2_XATTR
+	bool "JFFS2 XATTR support (EXPERIMENTAL)"
+	depends on JFFS2_FS
+	default n
+	help
+	  This enables the XATTR support in JFFS2.
+	  
+	  It's neccesary for persistent security context in SELinux.
+	  Now, we can use the following kinds of prefix.
+	  
+	  - security.*
+	  - user.*
+	  - trust.*
+	  
+	  - system.posix_acl_{access|default} are in TODO list now.
+
 config JFFS2_COMPRESSION_OPTIONS
 	bool "Advanced compression options for JFFS2"
 	default n

diff -rpNU3 mtd-0829/fs/jffs2/Makefile.common mtd-0829.xattr/fs/jffs2/Makefile.common

fs/jffs2/Makefile.common +1 -0
@@ -12,6 +12,7 @@ jffs2-y	+= symlink.o build.o erase.o bac
 jffs2-y	+= super.o debug.o
 
 jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= wbuf.o
+jffs2-$(CONFIG_JFFS2_XATTR)	+= xattr.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o

diff -rpNU3 mtd-0829/fs/jffs2/build.c mtd-0829.xattr/fs/jffs2/build.c

fs/jffs2/build.c +2 -0
@@ -165,6 +165,7 @@ static int jffs2_build_filesystem(struct
 		ic->scan_dents = NULL;
 		cond_resched();
 	}
+	jffs2_build_xattr_caches(c);
 	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
 
 	D1(printk(KERN_DEBUG "Pass 3 complete\n"));
@@ -184,6 +185,7 @@ exit:
 				jffs2_free_full_dirent(fd);
 			}
 		}
+		jffs2_clear_xattr_caches(c);
 	}
 
 	return ret;

diff -rpNU3 mtd-0829/fs/jffs2/dir.c mtd-0829.xattr/fs/jffs2/dir.c

fs/jffs2/dir.c +5 -0
@@ -57,7 +57,12 @@ struct inode_operations jffs2_dir_inode_
 	.rmdir =	jffs2_rmdir,
 	.mknod =	jffs2_mknod,
 	.rename =	jffs2_rename,
+	.permission =	jffs2_permission,
 	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 /***********************************************************************/

diff -rpNU3 mtd-0829/fs/jffs2/file.c mtd-0829.xattr/fs/jffs2/file.c

fs/jffs2/file.c +6 -1
@@ -57,7 +57,12 @@ struct file_operations jffs2_file_operat
 
 struct inode_operations jffs2_file_inode_operations =
 {
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 struct address_space_operations jffs2_file_address_operations =

diff -rpNU3 mtd-0829/fs/jffs2/fs.c mtd-0829.xattr/fs/jffs2/fs.c

fs/jffs2/fs.c void jffs2_clear_inode (struct inode *in · line 221

Quoted 5 lines
fs/jffs2/fs.c +2 -0
@@ -217,6 +217,8 @@ void jffs2_clear_inode (struct inode *in
 
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	if (f->inocache && !f->inocache->nlink)
+		jffs2_xattr_clear_inode(c, f->inocache);

Move the test into jffs2_xattr_clear_inode().

fs/jffs2/fs.c int jffs2_do_fill_super(struct super_blo · line 511

Quoted 10 lines
fs/jffs2/fs.c +3 -0
 	jffs2_do_clear_inode(c, f);
 }
 
@@ -504,6 +506,9 @@ int jffs2_do_fill_super(struct super_blo
 	}
 	memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
+	if ((ret = jffs2_init_xattr_caches(c)))
+		goto out_inohash;
+
	ret = jffs2_init_xattr_caches(c);
	if (ret)
		goto out_inohash;

I agree with gcc, when it warns about assignments in conditions. What I don't agree with is the proposal to use double brackets.

Quoted 83 lines
fs/jffs2/fs.c +1 -0
 	if ((ret = jffs2_do_mount_fs(c)))
 		goto out_inohash;
 
@@ -537,6 +542,7 @@ int jffs2_do_fill_super(struct super_blo
 		vfree(c->blocks);
 	else
 		kfree(c->blocks);
+	jffs2_clear_xattr_caches(c);
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:

diff -rpNU3 mtd-0829/fs/jffs2/gc.c mtd-0829.xattr/fs/jffs2/gc.c

fs/jffs2/gc.c +6 -1
@@ -251,7 +251,12 @@ int jffs2_garbage_collect_pass(struct jf
 		/* FIXME: If it's something that needs to be copied, including something
 		   we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
 		spin_unlock(&c->erase_completion_lock);
-		jffs2_mark_node_obsolete(c, raw);
+		if (raw->owner) {
+			/* JFFS2_NODETYPE_XATTR or JFFS2_NODETYPE_XREF */
+			ret = jffs2_garbage_collect_xattr(c, raw);
+		} else {
+			jffs2_mark_node_obsolete(c, raw);
+		}
 		up(&c->alloc_sem);
 		goto eraseit_lock;
 	}

diff -rpNU3 mtd-0829/fs/jffs2/malloc.c mtd-0829.xattr/fs/jffs2/malloc.c

fs/jffs2/malloc.c +28 -2
@@ -26,6 +26,10 @@ static kmem_cache_t *tmp_dnode_info_slab
 static kmem_cache_t *raw_node_ref_slab;
 static kmem_cache_t *node_frag_slab;
 static kmem_cache_t *inode_cache_slab;
+#ifdef CONFIG_JFFS2_XATTR
+static kmem_cache_t *xattr_cache_slab;
+static kmem_cache_t *xattr_ref_slab;
+#endif
 
 int __init jffs2_create_slab_caches(void)
 {
@@ -68,8 +72,24 @@ int __init jffs2_create_slab_caches(void
 	inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
 					     sizeof(struct jffs2_inode_cache),
 					     0, 0, NULL, NULL);
-	if (inode_cache_slab)
-		return 0;
+	if (!inode_cache_slab)
+		goto err;
+
+#ifdef CONFIG_JFFS2_XATTR
+	xattr_cache_slab = kmem_cache_create("jffs2_xattr_cache",
+					     sizeof(struct jffs2_xattr_cache),
+					     0, 0, NULL, NULL);
+	if (!xattr_cache_slab)
+		goto err;
+
+	xattr_ref_slab = kmem_cache_create("jffs2_xattr_ref",
+					   sizeof(struct jffs2_xattr_ref),
+					   0, 0, NULL, NULL);
+	if (!xattr_ref_slab)
+		goto err;
+#endif
+
+	return 0;
  err:
 	jffs2_destroy_slab_caches();
 	return -ENOMEM;
@@ -91,6 +111,12 @@ void jffs2_destroy_slab_caches(void)
 		kmem_cache_destroy(node_frag_slab);
 	if(inode_cache_slab)
 		kmem_cache_destroy(inode_cache_slab);
+#ifdef CONFIG_JFFS2_XATTR
+	if(xattr_cache_slab)
+		kmem_cache_destroy(xattr_cache_slab);
+	if(xattr_ref_slab)
+		kmem_cache_destroy(xattr_ref_slab);
+#endif
 }
 
 struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)

fs/jffs2/malloc.c struct jffs2_raw_node_ref *jffs2_alloc_r · line 198

Quoted 4 lines
fs/jffs2/malloc.c +1 -0
@@ -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.

fs/jffs2/malloc.c void jffs2_free_inode_cache(struct jffs2 · line 240

Quoted 13 lines
fs/jffs2/malloc.c +6 -0
 	return ret;
 }
 
@@ -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.

fs/jffs2/malloc.c void jffs2_free_inode_cache(struct jffs2 · line 241

Quoted 1 line
fs/jffs2/malloc.c +1 -0
+	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.

fs/jffs2/malloc.c void jffs2_free_inode_cache(struct jffs2 · line 254

Quoted 13 lines
fs/jffs2/malloc.c +13 -0
+	JFFS2_DBG_MEMALLOC("%p\n", xc);
+	return xc;
+}
+
+void jffs2_free_xattr_cache(struct jffs2_xattr_cache *xc)
+{
+	JFFS2_DBG_MEMALLOC("%p\n", xc);
+	kmem_cache_free(xattr_cache_slab, xc);
+}
+
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
+{
+	struct jffs2_xattr_ref *ref;

This name makes sense.

fs/jffs2/malloc.c void jffs2_free_inode_cache(struct jffs2 · line 255

Quoted 1 line
fs/jffs2/malloc.c +1 -0
+	ref = kmem_cache_alloc(xattr_ref_slab, GFP_KERNEL);

s/slab/cache/

Quoted 26 lines
fs/jffs2/malloc.c +11 -0
+	JFFS2_DBG_MEMALLOC("%p\n", ref);
+	return ref;
+}
+
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref)
+{
+	JFFS2_DBG_MEMALLOC("%p\n", ref);
+	kmem_cache_free(xattr_ref_slab, ref);
+}
+
+#endif

diff -rpNU3 mtd-0829/fs/jffs2/nodelist.c mtd-0829.xattr/fs/jffs2/nodelist.c

fs/jffs2/nodelist.c +1 -0
@@ -934,6 +934,7 @@ void jffs2_free_ino_caches(struct jffs2_
 		this = c->inocache_list[i];
 		while (this) {
 			next = this->next;
+			jffs2_xattr_free_inode(c, this);
 			jffs2_free_inode_cache(this);
 			this = next;
 		}

diff -rpNU3 mtd-0829/fs/jffs2/nodelist.h mtd-0829.xattr/fs/jffs2/nodelist.h

fs/jffs2/nodelist.h line 23

Quoted 4 lines
fs/jffs2/nodelist.h +1 -0
@@ -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".

fs/jffs2/nodelist.h struct jffs2_raw_node_ref · line 84

Quoted 8 lines
fs/jffs2/nodelist.h +1 -0
 #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.

Quoted 43 lines
fs/jffs2/nodelist.h +11 -0
 };
 
         /* flash_offset & 3 always has to be zero, because nodes are
@@ -111,6 +113,10 @@ struct jffs2_inode_cache {
 	uint32_t ino;
 	int nlink;
 	int state;
+#ifdef CONFIG_JFFS2_XATTR
+	struct list_head ilist;
+	uint8_t ilist_checked;
+#endif
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
@@ -367,6 +373,13 @@ void jffs2_free_node_frag(struct jffs2_n
 struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
 void jffs2_free_inode_cache(struct jffs2_inode_cache *);
 
+#ifdef CONFIG_JFFS2_XATTR
+struct jffs2_xattr_cache *jffs2_alloc_xattr_cache(void);
+void jffs2_free_xattr_cache(struct jffs2_xattr_cache *);
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void);
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *);
+#endif /* CONFIG_JFFS2_XATTR */
+
 /* gc.c */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 

diff -rpNU3 mtd-0829/fs/jffs2/readinode.c mtd-0829.xattr/fs/jffs2/readinode.c

fs/jffs2/readinode.c +1 -0
@@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_
 		f->inocache->ino = f->inocache->nlink = 1;
 		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 		f->inocache->state = INO_STATE_READING;
+		initxattr_jffs2_inode_cache(f->inocache);
 		jffs2_add_ino_cache(c, f->inocache);
 	}
 	if (!f->inocache) {

diff -rpNU3 mtd-0829/fs/jffs2/scan.c mtd-0829.xattr/fs/jffs2/scan.c

fs/jffs2/scan.c static int jffs2_scan_inode_node(struct · line 65

Quoted 9 lines
fs/jffs2/scan.c +6 -0
@@ -57,6 +57,12 @@ static int jffs2_scan_inode_node(struct 
 				 struct jffs2_raw_inode *ri, uint32_t ofs);
 static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 				 struct jffs2_raw_dirent *rd, uint32_t ofs);
+#ifdef CONFIG_JFFS2_XATTR
+static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				 struct jffs2_raw_xattr *rx, uint32_t ofs);
+static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				struct jffs2_raw_xref *rr, uint32_t ofs);
+#endif

You don't need the function definitions if you change the order inside the file.

Quoted 31 lines
fs/jffs2/scan.c +24 -1
 #define BLK_STATE_ALLFF		0
 #define BLK_STATE_CLEAN		1
@@ -552,7 +558,40 @@ scan_more:	
 			if (err) return err;
 			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
-
+#ifdef CONFIG_JFFS2_XATTR
+		case JFFS2_NODETYPE_XATTR:
+			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
+				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+				D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node) left to end of buf."
+				          " Reading 0x%x at 0x%08x\n",je32_to_cpu(node->totlen), buf_len, ofs));
+				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+				if (err)
+					return err;
+				buf_ofs = ofs;
+				node = (void *)buf;
+			}
+			err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs);
+			if (err)
+				return err;
+			ofs += PAD(je32_to_cpu(node->totlen));
+			break;
+		case JFFS2_NODETYPE_XREF:
+			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
+				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+				D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node) left to end of buf."
+				          " Reading 0x%x at 0x%08x\n",je32_to_cpu(node->totlen), buf_len, ofs));
+				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+				if (err)

fs/jffs2/scan.c scan_more: · line 594

Quoted 10 lines
fs/jffs2/scan.c +10 -0
+					return err;
+				buf_ofs = ofs;
+				node = (void *)buf;
+			}
+			err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs);
+			if (err)
+				return err;
+			ofs += PAD(je32_to_cpu(node->totlen));
+			break;
+#endif

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.

Quoted 25 lines
fs/jffs2/scan.c +11 -0
 		case JFFS2_NODETYPE_CLEANMARKER:
 			D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
 			if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
@@ -665,6 +704,7 @@ static struct jffs2_inode_cache *jffs2_s
 
 	ic->ino = ino;
 	ic->nodes = (void *)ic;
+	initxattr_jffs2_inode_cache(ic);
 	jffs2_add_ino_cache(c, ic);
 	if (ino == 1)
 		ic->nlink = 1;
@@ -820,6 +860,190 @@ static int jffs2_scan_dirent_node(struct
 	return 0;
 }
 
+#ifdef CONFIG_JFFS2_XATTR
+static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				 struct jffs2_raw_xattr *rx, uint32_t ofs)
+{
+	struct jffs2_raw_node_ref *raw;
+	struct jffs2_xattr_cache *xc;
+	uint32_t crc;
+	int xtype, nlen, vlen;
+
+	crc = crc32(0, rx, sizeof(*rx)-8);

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 882

Quoted 10 lines
fs/jffs2/scan.c +10 -0
+	if (crc != je32_to_cpu(rx->node_crc)) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Node CRC failed"
+		       " on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+		       ofs, je32_to_cpu(rx->node_crc), crc);
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
+		return 0;
+	}
+
+	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.

Btw, I agree with Linus. u32 is _much_ nicer than uint32_t, not to speak of the uint32_fast_t insanity.

Quoted 14 lines
fs/jffs2/scan.c +14 -0
+	if (je32_to_cpu(rx->totlen) != sizeof(*rx)+PAD(nlen+1)+PAD(vlen)) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): length mimatch!"
+		       " totlen=%d length=0x%08x nlen=%d vlen=%d on 0x%08x\n",
+		       je32_to_cpu(rx->totlen), je32_to_cpu(rx->length), nlen, vlen, ofs);
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
+		return 0;
+	}
+
+	crc = crc32(0, rx->data, PAD(nlen+1)+PAD(vlen));
+	if (crc != je32_to_cpu(rx->data_crc)) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Data CRC failed"
+		       " on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+		       ofs, je32_to_cpu(rx->data_crc), crc);
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 906

Quoted 10 lines
fs/jffs2/scan.c +10 -0
+		return 0;
+	}
+
+	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?

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 914

Quoted 7 lines
fs/jffs2/scan.c +7 -0
+	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?

Quoted 33 lines
fs/jffs2/scan.c +33 -0
+
+	raw = jffs2_alloc_raw_node_ref();
+	if (!raw)
+		return -ENOMEM;
+
+	xc = jffs2_alloc_xattr_cache();
+	if (!xc) {
+		jffs2_free_raw_node_ref(raw);
+		return -ENOMEM;
+	}
+	initxattr_jffs2_xattr_cache(xc);
+
+	xc->xid = je32_to_cpu(rx->xid);
+	if (xc->xid > c->highest_xid)
+		c->highest_xid = xc->xid;
+	xc->xtype = xtype;
+	xc->node = raw;
+	xc->name_len = nlen;
+	xc->value_len = vlen;
+	xc->data_crc = crc;
+
+	raw->__totlen = PAD(je32_to_cpu(rx->totlen));
+	raw->flash_offset = ofs | REF_PRISTINE;
+	raw->next_phys = NULL;
+	raw->next_in_ino = NULL;
+	if (!jeb->first_node)
+		jeb->first_node = raw;
+	if (jeb->last_node)
+		jeb->last_node->next_phys = raw;
+	jeb->last_node = raw;
+	USED_SPACE(PAD(je32_to_cpu(rx->totlen)));
+
+	jffs2_attach_xattr_cache(c, xc);

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 957

Quoted 10 lines
fs/jffs2/scan.c +10 -0
+
+	D1(printk(KERN_NOTICE "XATTR_CACHE: XID=%d inserted\n", xc->xid));
+	return 0;
+}
+
+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?

Quoted 34 lines
fs/jffs2/scan.c +34 -0
+		if (new->seqno > old->seqno) {
+			jffs2_mark_node_obsolete(c, old->node);
+			old->seqno = new->seqno;
+			old->node = new->node;
+		} else {
+			jffs2_mark_node_obsolete(c, new->node);
+		}
+		return 1; /* 'new' should be released. */
+	}
+	return 0;
+}
+
+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;
+	struct jffs2_xattr_ref *ref, *pos, *pos2;
+	uint32_t crc;
+
+	crc = crc32(0, rr, sizeof(*rr)-4);
+	if (crc != je32_to_cpu(rr->node_crc)) {
+		printk(KERN_NOTICE "jffs2_scan_xref_node(): Node CRC failed"
+		       " on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+		       ofs, je32_to_cpu(rr->node_crc), crc);
+		DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen)));
+		return 0;
+	}
+
+	ref = jffs2_alloc_xattr_ref();
+	if (!ref)
+		return -ENOMEM;
+	initxattr_jffs2_xattr_ref(ref);
+
+	raw = jffs2_alloc_raw_node_ref();

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 1001

Quoted 10 lines
fs/jffs2/scan.c +10 -0
+	if (!raw) {
+		jffs2_free_xattr_ref(ref);
+		return -ENOMEM;
+	}
+
+	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.

Jörn

Signature · 4 lines
Don't worry about people stealing your ideas. If your ideas are any good,
you'll have to ram them down people's throats.
-- Howard Aiken quoted by Ken Iverson quoted by Jim Horning quoted by
   Raph Levien, 1979
maintainer
#12 lore raw
Quoted 2 lines · Jörn Engel

I prefer a longer name. jffs2_fs_xattr.h would be fine. jffs2_xattr.h would also, the "_fs" is more redundant that "attr".

Now would probably be a good time to drop jffs2_fs_i.h and jffs2_fs_sb.h anyway. We no longer have the inode and superblock unions; this stuff can be entirely contained within the fs/jffs2/ directory instead of being in include/linux/

Signature · 1 line
dwmw2
#13 lore raw
In reply to Jörn Engel

Hello,Jörn.

Thanks for reviewing in spite of so long patch.

Quoted 9 lines

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 ?

Quoted 2 lines

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. ;-)

Quoted 11 lines

fs/jffs2/fs.c void jffs2_clear_inode (struct inode *in · line 221

Quoted 8 lines
fs/jffs2/fs.c +2 -0
@@ -217,6 +217,8 @@ void jffs2_clear_inode (struct inode *in
 
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	if (f->inocache && !f->inocache->nlink)
+		jffs2_xattr_clear_inode(c, f->inocache);

Move the test into jffs2_xattr_clear_inode().

OK, I'll modify it.

Quoted 13 lines

fs/jffs2/fs.c int jffs2_do_fill_super(struct super_blo · line 511

Quoted 7 lines
fs/jffs2/fs.c +3 -0
@@ -504,6 +506,9 @@ int jffs2_do_fill_super(struct super_blo
 	}
 	memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
+	if ((ret = jffs2_init_xattr_caches(c)))
+		goto out_inohash;
+
	ret = jffs2_init_xattr_caches(c);
	if (ret)
		goto out_inohash;
Quoted 2 lines

I agree with gcc, when it warns about assignments in conditions. What I don't agree with is the proposal to use double brackets.

OK, I'll modify this and similar codes at different location if exist.

Quoted 10 lines

fs/jffs2/fs.c struct jffs2_raw_node_ref *jffs2_alloc_r · line 198

Quoted 6 lines
fs/jffs2/fs.c +1 -0
 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.

Quoted 16 lines

fs/jffs2/fs.c void jffs2_free_inode_cache(struct jffs2 · line 240

Quoted 10 lines
fs/jffs2/fs.c +6 -0
@@ -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.

Quoted 5 lines

fs/jffs2/fs.c void jffs2_free_inode_cache(struct jffs2 · line 241

Quoted 1 line
fs/jffs2/fs.c +1 -0
+	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.

Quoted 14 lines

fs/jffs2/fs.c void jffs2_free_inode_cache(struct jffs2 · line 250

Quoted 9 lines
fs/jffs2/fs.c +9 -0
+void jffs2_free_xattr_cache(struct jffs2_xattr_cache *xc)
+{
+	JFFS2_DBG_MEMALLOC("%p\n", xc);
+	kmem_cache_free(xattr_cache_slab, xc);
+}
+
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
+{
+	struct jffs2_xattr_ref *ref;

This name makes sense.

Quoted 4 lines

fs/jffs2/fs.c void jffs2_free_inode_cache(struct jffs2 · line 251

Quoted 1 line
fs/jffs2/fs.c +1 -0
+	ref = kmem_cache_alloc(xattr_ref_slab, GFP_KERNEL);

s/slab/cache/

OK, I'll rename it.

Quoted 12 lines

fs/jffs2/nodelist.h line 23

Quoted 8 lines

diff -rpNU3 mtd-0829/fs/jffs2/nodelist.h mtd-0829.xattr/fs/jffs2/nodelist.h

fs/jffs2/nodelist.h +1 -0
@@ -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.

Quoted 2 lines

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.

Quoted 4 lines
Quoted 4 lines
fs/jffs2/nodelist.h +0 -0
 #ifdef __ECOS
 #include "os-ecos.h"
@@ -80,6 +81,7 @@ struct jffs2_raw_node_ref
 	struct jffs2_raw_node_ref *next_phys;
Quoted 8 lines

fs/jffs2/nodelist.h struct jffs2_raw_node_ref · line 84

Quoted 3 lines
fs/jffs2/nodelist.h +1 -0
 	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.

Quoted 9 lines
Quoted 9 lines

diff -rpNU3 mtd-0829/fs/jffs2/scan.c mtd-0829.xattr/fs/jffs2/scan.c

fs/jffs2/scan.c +2 -0
@@ -57,6 +57,12 @@ static int jffs2_scan_inode_node(struct
 				 struct jffs2_raw_inode *ri, uint32_t ofs);
 static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 				 struct jffs2_raw_dirent *rd, uint32_t ofs);
+#ifdef CONFIG_JFFS2_XATTR
+static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
Quoted 8 lines

fs/jffs2/scan.c static int jffs2_scan_inode_node(struct · line 65

Quoted 4 lines
fs/jffs2/scan.c +4 -0
+				 struct jffs2_raw_xattr *rx, uint32_t ofs);
+static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				struct jffs2_raw_xref *rr, uint32_t ofs);
+#endif

You don't need the function definitions if you change the order inside the file.

OK, I'll change the deployment of above functions.

Quoted 37 lines
Quoted 37 lines
fs/jffs2/scan.c +30 -1
 #define BLK_STATE_ALLFF		0
 #define BLK_STATE_CLEAN		1
@@ -552,7 +558,40 @@ scan_more:	
 			if (err) return err;
 			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
-
+#ifdef CONFIG_JFFS2_XATTR
+		case JFFS2_NODETYPE_XATTR:
+			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
+				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+				D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node) left to end of buf."
+				          " Reading 0x%x at 0x%08x\n",je32_to_cpu(node->totlen), buf_len, ofs));
+				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+				if (err)
+					return err;
+				buf_ofs = ofs;
+				node = (void *)buf;
+			}
+			err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs);
+			if (err)
+				return err;
+			ofs += PAD(je32_to_cpu(node->totlen));
+			break;
+		case JFFS2_NODETYPE_XREF:
+			if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
+				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+				D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node) left to end of buf."
+				          " Reading 0x%x at 0x%08x\n",je32_to_cpu(node->totlen), buf_len, ofs));
+				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+				if (err)
+					return err;
+				buf_ofs = ofs;
+				node = (void *)buf;
+			}
+			err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs);
+			if (err)
Quoted 8 lines

fs/jffs2/scan.c scan_more: · line 594

Quoted 4 lines
fs/jffs2/scan.c +4 -0
+				return err;
+			ofs += PAD(je32_to_cpu(node->totlen));
+			break;
+#endif

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 ?

Quoted 19 lines
Quoted 19 lines
fs/jffs2/scan.c +15 -0
@@ -820,6 +860,190 @@ static int jffs2_scan_dirent_node(struct
 	return 0;
 }
 
+#ifdef CONFIG_JFFS2_XATTR
+static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				 struct jffs2_raw_xattr *rx, uint32_t ofs)
+{
+	struct jffs2_raw_node_ref *raw;
+	struct jffs2_xattr_cache *xc;
+	uint32_t crc;
+	int xtype, nlen, vlen;
+
+	crc = crc32(0, rx, sizeof(*rx)-8);
+	if (crc != je32_to_cpu(rx->node_crc)) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Node CRC failed"
+		       " on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+		       ofs, je32_to_cpu(rx->node_crc), crc);
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
Quoted 8 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 882

Quoted 5 lines
fs/jffs2/scan.c +5 -0
+		return 0;
+	}
+
+	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.

Quoted 2 lines

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.

Quoted 19 lines
Quoted 19 lines
fs/jffs2/scan.c +19 -0
+	if (je32_to_cpu(rx->totlen) != sizeof(*rx)+PAD(nlen+1)+PAD(vlen)) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): length mimatch!"
+		       " totlen=%d length=0x%08x nlen=%d vlen=%d on 0x%08x\n",
+		       je32_to_cpu(rx->totlen), je32_to_cpu(rx->length), nlen, vlen, ofs);
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
+		return 0;
+	}
+
+	crc = crc32(0, rx->data, PAD(nlen+1)+PAD(vlen));
+	if (crc != je32_to_cpu(rx->data_crc)) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Data CRC failed"
+		       " on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+		       ofs, je32_to_cpu(rx->data_crc), crc);
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
+		return 0;
+	}
+
+	xc = jffs2_find_xattr_cache_xid(c, je32_to_cpu(rx->xid));
+	if (xc) {
Quoted 8 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 906

Quoted 5 lines
fs/jffs2/scan.c +5 -0
+		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.

Quoted 10 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 914

Quoted 7 lines
fs/jffs2/scan.c +7 -0
+	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.

Quoted 8 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 957

Quoted 5 lines
fs/jffs2/scan.c +5 -0
+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.

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

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;
};
Quoted 4 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 973

Quoted 4 lines
fs/jffs2/scan.c +4 -0
+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 -

Quoted 9 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 1001

Quoted 5 lines
fs/jffs2/scan.c +5 -0
+	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?!?

Quoted 3 lines

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);

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 ?

Thanks for attentive comments.

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#14 lore raw
Quoted 7 lines · Kaigai Kohei

Thanks for reviewing in spite of so long patch.

Quoted 5 lines

Sounds good.

It appears as if your patch or something based on it will win. So let's have a look...

Quoted 6 lines
Quoted 4 lines

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.

Quoted 5 lines
Quoted 2 lines

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.

Quoted 11 lines
Quoted 10 lines

fs/jffs2/malloc.c struct jffs2_raw_node_ref *jffs2_alloc_r · line 198

Quoted 6 lines

struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)

fs/jffs2/malloc.c +1 -0
@@ -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.

Quoted 3 lines

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.

Quoted 22 lines
Quoted 16 lines

fs/jffs2/malloc.c void jffs2_free_inode_cache(struct jffs2 · line 240

Quoted 10 lines
fs/jffs2/malloc.c +6 -0
@@ -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.

Quoted 5 lines

fs/jffs2/malloc.c void jffs2_free_inode_cache(struct jffs2 · line 241

Quoted 1 line
fs/jffs2/malloc.c +1 -0
+	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.

Quoted 6 lines

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.

Quoted 14 lines
Quoted 1 line
Quoted 1 line

diff -rpNU3 mtd-0829/fs/jffs2/nodelist.h

mtd-0829.xattr/fs/jffs2/nodelist.h

Quoted 2 lines

fs/jffs2/nodelist.h

Quoted 2 lines
fs/jffs2/nodelist.h +0 -0

10:28:53.000000000 -0400

Quoted 9 lines

fs/jffs2/nodelist.h line 23

Quoted 5 lines
fs/jffs2/nodelist.h +1 -0
@@ -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.

Quoted 5 lines
Quoted 2 lines

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/.

Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
fs/jffs2/nodelist.h +0 -0
 #ifdef __ECOS
 #include "os-ecos.h"
@@ -80,6 +81,7 @@ struct jffs2_raw_node_ref
 	struct jffs2_raw_node_ref *next_phys;
Quoted 8 lines

fs/jffs2/nodelist.h struct jffs2_raw_node_ref · line 84

Quoted 3 lines
fs/jffs2/nodelist.h +1 -0
 	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.

Quoted 7 lines

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?

Quoted 5 lines
Quoted 2 lines

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.

Quoted 9 lines
Quoted 6 lines

fs/jffs2/nodelist.h struct jffs2_raw_node_ref · line 87

Quoted 3 lines
fs/jffs2/nodelist.h +3 -0
+
+	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.

Quoted 4 lines
Quoted 2 lines

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.

Quoted 13 lines
Quoted 3 lines

fs/jffs2/nodelist.h struct jffs2_raw_node_ref

Quoted 3 lines
fs/jffs2/nodelist.h +3 -0
+	xc = jffs2_find_xattr_cache_xid(c, je32_to_cpu(rx->xid));
+	if (xc) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Duplicate XID 

Found"

Quoted 1 line

fs/jffs2/nodelist.h

Quoted 1 line
fs/jffs2/nodelist.h +1 -0
+		       " on node at 0x%08x XID=%d Later one ignored\n", ofs, 

xc->xid);

Quoted 6 lines

fs/jffs2/nodelist.h

Quoted 3 lines
fs/jffs2/nodelist.h +3 -0
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
+		return 0;
+	}

How do you deal with xattr reference counting and lifetime?

Quoted 3 lines

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?

Quoted 12 lines
Quoted 3 lines

fs/jffs2/nodelist.h

Quoted 3 lines
fs/jffs2/nodelist.h +3 -0
+	xtype = jffs2_xattr_prefix_to_xtype(rx->data, nlen);
+	if (JFFS2_XATTRTYPE_INVALID==xtype) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Unsupported 

xattr type"

Quoted 7 lines

fs/jffs2/nodelist.h

Quoted 4 lines
fs/jffs2/nodelist.h +4 -0
+		       " 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?

Quoted 2 lines

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?

Quoted 10 lines
Quoted 2 lines

fs/jffs2/nodelist.h

Quoted 2 lines
fs/jffs2/nodelist.h +2 -0
+static inline int jffs2_scan_xref_node_helper(struct jffs2_sb_info *c,
+			struct jffs2_xattr_ref *new, struct jffs2_xattr_ref 

*old)

Quoted 6 lines

fs/jffs2/nodelist.h

Quoted 3 lines
fs/jffs2/nodelist.h +3 -0
+{
+	/* (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?

Quoted 7 lines

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.

Quoted 1 line

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

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

Quoted 33 lines
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;
};
Quoted 1 line
Quoted 1 line

+static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct

jffs2_eraseblock *jeb,

Quoted 3 lines

fs/jffs2/nodelist.h

Quoted 3 lines
fs/jffs2/nodelist.h +3 -0
+				struct jffs2_raw_xref *rr, uint32_t ofs)
+{
+	struct jffs2_raw_node_ref *raw;

- snip -

Quoted 9 lines

fs/jffs2/nodelist.h

Quoted 5 lines
fs/jffs2/nodelist.h +5 -0
+	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?!?

Quoted 8 lines
Quoted 3 lines

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);
	...
Quoted 5 lines

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

Signature · 2 lines
All art is but imitation of nature.
-- Lucius Annaeus Seneca
#15 lore raw

Hi,

Quoted 11 lines
Quoted 7 lines
Quoted 4 lines

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/.

Indeed, jffs2_XXX.h under fs/jffs2 is a bit redundant.

Quoted 22 lines
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines

#ifdef __ECOS
#include "os-ecos.h"

fs/jffs2/nodelist.h +0 -0
@@ -80,6 +81,7 @@ struct jffs2_raw_node_ref
 	struct jffs2_raw_node_ref *next_phys;
Quoted 8 lines

fs/jffs2/nodelist.h struct jffs2_raw_node_ref · line 84

Quoted 3 lines
fs/jffs2/nodelist.h +1 -0
 	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.

Quoted 7 lines

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.

Quoted 8 lines

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?

It accompanies a so big remodeling, and hope not to do so, if possible.

I think it is important here to be able to distinguish three kinds of raw_node by a reasonable method (1. existing raw_node_ref of inode,
2. existing raw_node_ref without inode, 3. new raw_node_ref for XATTR), and to be able to refer from the third type of raw_node to the jffs2_xattr_(cache|ref) objects.

I noticed an idea to resolve it.
Any objects refered by the last next_in_ino are allocated by slab. If we can use kmem_ptr_validate() function, we can discriminate whether this pointer indicate xattr_cache/ref or not. Then, we can keep the size of jffs2_raw_node_ref.
(the member of 'owner' will go anyware.)

The issues of this method are as follows:
- If there is an adverse effect by existing of non-inode raw_node_ref whose next_in_ino is not NULL, I must resolve this.
- It's necessary to discuss in LKML, since this function is not EXPORT_SYMBOL()ed for kernel loadable modules currently.

Quoted 11 lines
Quoted 5 lines
Quoted 2 lines

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.

I have developed this functionality based on mtd-snapshot-20050829. It means I should develop this based on mtd-snapshot-XXXX + your cleanup patches, isn't it?
If so, I think my patch should be moditied for new version. Isn't it fundamental changing ?

Quoted 17 lines
Quoted 17 lines
Quoted 3 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct

Quoted 3 lines
fs/jffs2/scan.c +3 -0
+	xc = jffs2_find_xattr_cache_xid(c, je32_to_cpu(rx->xid));
+	if (xc) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Duplicate XID

Found"

Quoted 1 line

Review struct jffs2_raw_node_ref

Quoted 1 line
(quoted diff) +1 -0
+		       " on node at 0x%08x XID=%d Later one ignored\n", ofs,

xc->xid);

Quoted 6 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 879

Quoted 3 lines
fs/jffs2/scan.c +3 -0
+		DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
+		return 0;
+	}

How do you deal with xattr reference counting and lifetime?

Quoted 6 lines
Quoted 3 lines

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.

Yes. jffs2_mark_node_obsolete() is called at this timing.

Quoted 2 lines

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

If my understanding is not wrong, an obsolete XATTR or XREF node is garbase collected as raw-node which does not have inode. (Becase next_in_ino of XATTR/XREF node is NULL.)

Quoted 14 lines
Quoted 14 lines
Quoted 3 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct

Quoted 3 lines
fs/jffs2/scan.c +3 -0
+	xtype = jffs2_xattr_prefix_to_xtype(rx->data, nlen);
+	if (JFFS2_XATTRTYPE_INVALID==xtype) {
+		printk(KERN_NOTICE "jffs2_scan_xattr_node(): Unsupported

xattr type"

Quoted 7 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 914

Quoted 4 lines
fs/jffs2/scan.c +4 -0
+		       " 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?

Quoted 5 lines
Quoted 2 lines

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?

A permittion checking policy depends on XATTR's prefix. For example, only an user has CAP_SYS_ADMIN capability can read/write "trusted.*" xattr. In the "security.*" prefix case, this checking was done in LSM module. Therefore, filesystem must know XATTR's prefix.

Quoted 41 lines
Quoted 20 lines
Quoted 1 line
Quoted 1 line

+static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct

jffs2_eraseblock *jeb,

Quoted 3 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 973

Quoted 3 lines
fs/jffs2/scan.c +3 -0
+				struct jffs2_raw_xref *rr, uint32_t ofs)
+{
+	struct jffs2_raw_node_ref *raw;

- snip -

Quoted 9 lines

fs/jffs2/scan.c static int jffs2_scan_dirent_node(struct · line 1001

Quoted 5 lines
fs/jffs2/scan.c +5 -0
+	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?!?

Quoted 8 lines
Quoted 3 lines

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);
	...
Quoted 5 lines

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 ?

Quoted 6 lines

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.

Sorry for tricky coding without comments. I'll pay attention of such coding style.

Thanks,

Signature · 1 line
KaiGai Kohei <[email protected]>
#16 lore raw
Quoted 8 lines · KaiGai Kohei
Quoted 7 lines

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?

Quoted 7 lines

It accompanies a so big remodeling, and hope not to do so, if possible.

I think it is important here to be able to distinguish three kinds of raw_node by a reasonable method (1. existing raw_node_ref of inode,
2. existing raw_node_ref without inode, 3. new raw_node_ref for XATTR), and to be able to refer from the third type of raw_node to the jffs2_xattr_(cache|ref) objects.

Yes. 1 and 2 are currently distinguished by next_in_ino being either either valid or NULL.

Quoted 6 lines

I noticed an idea to resolve it.
Any objects refered by the last next_in_ino are allocated by slab. If we can use kmem_ptr_validate() function, we can discriminate whether this pointer indicate xattr_cache/ref or not. Then, we can keep the size of jffs2_raw_node_ref.
(the member of 'owner' will go anyware.)

Sounds scary. But in principle, you are right. In case of either 1 or 3, we attach "something" to next_in_ino. Now we only have to decide whether "something" is an inode, or the new xattr-struff.

If you add an extra field to jffs2_inode_cache (which also is grossly misnamed, old mistake), you can do so. And since inodes are a lot less frequent than raw nodes, the memory consumption should have improved quite a bit.

Or you could play some magic like reserving ino 0xffffffff for xattr_object, 0xfffffffe for xattr_ref, etc. and simply decide by jffs2_inode_cache->ino having one of the magic numbers. Then you would need the extra field only for xattr_obj or xattr_ref.

Quoted 3 lines

The issues of this method are as follows:
- If there is an adverse effect by existing of non-inode raw_node_ref whose next_in_ino is not NULL, I must resolve this.

Yep.

Quoted 2 lines

- It's necessary to discuss in LKML, since this function is not EXPORT_SYMBOL()ed for kernel loadable modules currently.

Where it won't receive a lot of love. Do it with some variant of what I outlined above.

Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

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 ?

Quoted 8 lines
Quoted 4 lines

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.

I have developed this functionality based on mtd-snapshot-20050829. It means I should develop this based on mtd-snapshot-XXXX + your cleanup patches, isn't it?

No. You should develop two patches based on current cvs:
[PATCH 1/2] Cleanup of jffs2_scan_eraseblock() [PATCH 2/2] xattr for jffs2

And you may or may not use my previous attempt as a basis, that's your decision.

If you simply added further mess to jffs2_scan_eraseblock(), as you do today, people will see horrible code become even worse. Who likes that?
If instead you do a cleanup first, people will see that you helped make the function much more readable and maintainable. Anyone objecting your merge will have a tough time arguing now.

Quoted 6 lines
Quoted 2 lines

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

If my understanding is not wrong, an obsolete XATTR or XREF node is garbase collected as raw-node which does not have inode. (Becase next_in_ino of XATTR/XREF node is NULL.)

Ah, yes. Makes sense now, even to stupid people like me.

Quoted 7 lines
Quoted 1 line

Then why is it required that JFFS2 knows the prefix?

A permittion checking policy depends on XATTR's prefix. For example, only an user has CAP_SYS_ADMIN capability can read/write "trusted.*" xattr. In the "security.*" prefix case, this checking was done in LSM module. Therefore, filesystem must know XATTR's prefix.

This is just wrong. I agree that something inside the kernel must know whether users need specific capabilities to read/write the xattr. Sure. But why in hell does it have to be JFFS2?

How do other filesystems deal with this? ext[23] and reiserfs (v3) all have xattr, I believe.

Quoted 7 lines
Quoted 4 lines

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.

Sorry for tricky coding without comments. I'll pay attention of such coding style.

Thanks. This is one of the reasons for reviews. You, being the author, have a bad judgement about what people new to the code can and cannot easily understand. You're not new to the code. ;)

Jörn

Signature · 3 lines
Measure. Don't tune for speed until you've measured, and even then
don't unless one part of the code overwhelms the rest.
-- Rob Pike
#17 lore raw

Hi,

Quoted 21 lines
Quoted 7 lines

It accompanies a so big remodeling, and hope not to do so, if possible.

I think it is important here to be able to distinguish three kinds of raw_node by a reasonable method (1. existing raw_node_ref of inode,
2. existing raw_node_ref without inode, 3. new raw_node_ref for XATTR), and to be able to refer from the third type of raw_node to the jffs2_xattr_(cache|ref) objects.

Yes. 1 and 2 are currently distinguished by next_in_ino being either either valid or NULL.

Quoted 6 lines

I noticed an idea to resolve it.
Any objects refered by the last next_in_ino are allocated by slab. If we can use kmem_ptr_validate() function, we can discriminate whether this pointer indicate xattr_cache/ref or not. Then, we can keep the size of jffs2_raw_node_ref.
(the member of 'owner' will go anyware.)

Quoted 8 lines

Sounds scary. But in principle, you are right. In case of either 1 or 3, we attach "something" to next_in_ino. Now we only have to decide whether "something" is an inode, or the new xattr-struff.

If you add an extra field to jffs2_inode_cache (which also is grossly misnamed, old mistake), you can do so. And since inodes are a lot less frequent than raw nodes, the memory consumption should have improved quite a bit.

I prefer this kind of approach than other one. It's simple solution. I'm afraid of breaking something to be assumed implicitly by reserving some inode-numbers.

And, how about such an idea ?
Currently, the variable of 'state' in jffs2_inode_cache is defined as int type, but the range of this variable is between 0 and 6. In general case, 'int' has 32-bit width. It's so much for this field.

For example, we can redefine the 'state' as 16-bit width variable, and insert a new 16-bit width variable to discriminate own object. If acceptable, it can also keep the memory comsumption for jffs2_inode_cache.

In this plan, jffs2_inode_cahce and jffs2_xattr_datum will be defined as follows:

struct jffs2_inode_cache {
    struct jffs2_full_dirent *scan_dents;
    uint16_t class; /* =0 means jffs2_inode_cache */
    uint16_t state;
       :
struct jffs2_xattr_datum {
    void *dummy;    /* always NULL */
    uint16_t class; /* =1 means jffs2_xattr_datum */
       :
Quoted 10 lines
Quoted 8 lines
Quoted 4 lines

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.

I have developed this functionality based on mtd-snapshot-20050829. It means I should develop this based on mtd-snapshot-XXXX + your cleanup patches, isn't it?

Quoted 6 lines

No. You should develop two patches based on current cvs:
[PATCH 1/2] Cleanup of jffs2_scan_eraseblock() [PATCH 2/2] xattr for jffs2

And you may or may not use my previous attempt as a basis, that's your decision.

I see, jffs2_scan_eraseblock() is indeed a bit long. Please send your attempt patches at first. I'll try to cleanup it for the basis of XATTR patch.

Quoted 9 lines
Quoted 7 lines
Quoted 1 line

Then why is it required that JFFS2 knows the prefix?

A permittion checking policy depends on XATTR's prefix. For example, only an user has CAP_SYS_ADMIN capability can read/write "trusted.*" xattr. In the "security.*" prefix case, this checking was done in LSM module. Therefore, filesystem must know XATTR's prefix.

Quoted 6 lines

This is just wrong. I agree that something inside the kernel must know whether users need specific capabilities to read/write the xattr. Sure. But why in hell does it have to be JFFS2?

How do other filesystems deal with this? ext[23] and reiserfs (v3) all have xattr, I believe.

Indeed, more upper layer might be able to manage this kind of decision making as you say. But it's transferred to the filesystem currently. All of them (ext2/3, reiser and so on) have own permission checking codes like 'fs/ext2/xattr_trusted.c', and I imitated those implementations. I don't know the reason correctly.

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#18 lore raw
Quoted 19 lines · Kaigai Kohei
Quoted 9 lines

Sounds scary. But in principle, you are right. In case of either 1 or 3, we attach "something" to next_in_ino. Now we only have to decide whether "something" is an inode, or the new xattr-struff.

If you add an extra field to jffs2_inode_cache (which also is grossly misnamed, old mistake), you can do so. And since inodes are a lot less frequent than raw nodes, the memory consumption should have improved quite a bit.

I prefer this kind of approach than other one. It's simple solution. I'm afraid of breaking something to be assumed implicitly by reserving some inode-numbers.

And, how about such an idea ?
Currently, the variable of 'state' in jffs2_inode_cache is defined as int type, but the range of this variable is between 0 and 6. In general case, 'int' has 32-bit width. It's so much for this field.

Quoted 4 lines

For example, we can redefine the 'state' as 16-bit width variable, and insert a new 16-bit width variable to discriminate own object. If acceptable, it can also keep the memory comsumption for jffs2_inode_cache.

Yes, that sounds fine.

Quoted 8 lines

In this plan, jffs2_inode_cahce and jffs2_xattr_datum will be defined as follows:

struct jffs2_inode_cache {
    struct jffs2_full_dirent *scan_dents;
    uint16_t class; /* =0 means jffs2_inode_cache */
    uint16_t state;
       :
Quoted 4 lines
struct jffs2_xattr_datum {
    void *dummy;    /* always NULL */
    uint16_t class; /* =1 means jffs2_xattr_datum */
       :

You could even make the class a u8. For inodes, the remaining 8 bits would just be reserved space for proper alignment. If either of your xattr object could make use of the extra byte, it would be worth it. If not, just ignore my silly idea.

Quoted 3 lines

I see, jffs2_scan_eraseblock() is indeed a bit long. Please send your attempt patches at first. I'll try to cleanup it for the basis of XATTR patch.

It was 34 patches going over all of jffs2, actually. I guess it's easier to send the changed scan.c. The pseudo-random stuff was controversial, so I lost interest after a while.

Quoted 4 lines
Quoted 4 lines

This is just wrong. I agree that something inside the kernel must know whether users need specific capabilities to read/write the xattr. Sure. But why in hell does it have to be JFFS2?

Quoted 8 lines
Quoted 2 lines

How do other filesystems deal with this? ext[23] and reiserfs (v3) all have xattr, I believe.

Indeed, more upper layer might be able to manage this kind of decision making as you say. But it's transferred to the filesystem currently. All of them (ext2/3, reiser and so on) have own permission checking codes like 'fs/ext2/xattr_trusted.c', and I imitated those implementations. I don't know the reason correctly.

The code is not exactly easy to follow. But it appears as if they used that stuff for compression. If prefix is "trusted.", just use an e_name_index of 4 and drop the prefix. It can be reconstructed on reads.

Reiserfs doesn't worry about compression and has should-be-generic code only.

I guess it would make sense to copy the compression stuff from ext2, at least the concept.

Jörn

Signature · 2 lines
Don't patch bad code, rewrite it.
-- Kernigham and Pike, according to Rusty
#19 lore raw

Hi,

Quoted 13 lines
Quoted 11 lines

In this plan, jffs2_inode_cahce and jffs2_xattr_datum will be defined as follows:

struct jffs2_inode_cache {
   struct jffs2_full_dirent *scan_dents;
   uint16_t class; /* =0 means jffs2_inode_cache */
   uint16_t state;
      :
struct jffs2_xattr_datum {
   void *dummy;    /* always NULL */
   uint16_t class; /* =1 means jffs2_xattr_datum */
      :
Quoted 4 lines

You could even make the class a u8. For inodes, the remaining 8 bits would just be reserved space for proper alignment. If either of your xattr object could make use of the extra byte, it would be worth it. If not, just ignore my silly idea.

u8 type variable has enough width for discernment, I think.

And, is it possible to name the remaining 8-bit 'flags' than 'reserved' or 'unused' in jffs2_inode_cache/jffs2_xattr_datum ?

In my implementation, 'uint8_t ilist_checked' is added in jffs2_inode_cache for flag purpose, and 'uint16_t flags' exists in jffs2_xattr_datum(jffs2_xattr_cache in old name). If we can stuff those into the remaining 8-bit, each object size will be reduced by 4-byte, I think.

Quoted 8 lines
Quoted 3 lines

I see, jffs2_scan_eraseblock() is indeed a bit long. Please send your attempt patches at first. I'll try to cleanup it for the basis of XATTR patch.

It was 34 patches going over all of jffs2, actually. I guess it's easier to send the changed scan.c. The pseudo-random stuff was controversial, so I lost interest after a while.

'34 patches over all of jffs2' is over my expectation, orz. I prefer to pay attention on only the changed scan.c, if possible... Please send it to me,

Quoted 14 lines
Quoted 4 lines
Quoted 4 lines

This is just wrong. I agree that something inside the kernel must know whether users need specific capabilities to read/write the xattr. Sure. But why in hell does it have to be JFFS2?

Quoted 8 lines
Quoted 2 lines

How do other filesystems deal with this? ext[23] and reiserfs (v3) all have xattr, I believe.

Indeed, more upper layer might be able to manage this kind of decision making as you say. But it's transferred to the filesystem currently. All of them (ext2/3, reiser and so on) have own permission checking codes like 'fs/ext2/xattr_trusted.c', and I imitated those implementations. I don't know the reason correctly.

Quoted 4 lines

The code is not exactly easy to follow. But it appears as if they used that stuff for compression. If prefix is "trusted.", just use an e_name_index of 4 and drop the prefix. It can be reconstructed on reads.

Hmm, it's functionality certainly effective for reduction of memory and medium usage. It's not difficult to implement, I think. I'll modify the method of storing xattr in next.

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#20 lore raw

Hi,

I revised the previous xattr patch in jffs2 based on some suggestions.

[1] scanning xattr related node for cleaned-up scan.c. (jffs2_xattr_scan.c-cleanup.patch)
[2] enables xattr support in jffs2.

    (jffs2_xattr_take-3.patch)

(*) We can apply jffs2_xattr_take-3.patch for current CVS independently.

The following points are updated.

- jffs2_scan_xattr_node() and jffs2_scan_xref_node() are implemented with considering the cleaned-up scan.c. (jffs2_xattr_scan.c-cleanup.patch) Since I can't build the cleaned-up source, this patch has not been verified yet. But same code is included in jffs2_xattr_take-3.patch, and it works correctly.

- A deadlock problem was detected in take-2 patch.
Thus, the order of acquiring semaphore was changed.
There was down_write(&c->xattr_sem) under down(&c->alloc_sem) in take-2 patch. Now, I avoid such an implementation. In do_jffs2_setxattr(), xattr_sem is acquired after alloc_sem is done.

- "include/linux/jffs2_fs_x.h" was moved to "fs/jffs2/xattr.h".

- 'void *owner' in struct jffs2_raw_node_ref was removed.
- 'int state' in struct jffs2_inode_cache was removed, and 'u8 class' and 'u8 flags', 'uint16_t state' were added on instead.

GC uses raw->next_in_ino for reverse-reference to xattr_datum/xattr_ref from jffs_raw_node_ref.

- the declaration of jffs2_xattr_ref was changed. The strange cast was removed, and the variables not-used concurrently are defined as union type. ('uint32_t xid' and 'struct jffs2_xattr_datum *xd' are not used concurrently. 'uint32_t ino' and 'struct jffs2_inode_cache *ic' are not used concurrently.)

- A xattr prefixes like 'security.' are represented by 8bit code, and omit it from name-strings.

- jffs2_xattr_datum->xlist was removed, and 'uint32_t refcnt' was added. Scanning inodes which share the same xattr_datum is not used. Thus, this list is not necessary and enough in reference counter.

- some functions/variables/structures are renamed. struct jffs2_xattr_cache -> struct jffs2_xattr_datum

kmem_cache_t *xattr_cache_slab -> xattr_datum_cache kmem_cache_t *xattr_ref_slab -> xattr_ref_cache

jffs2_init_xattr_caches() -> jffs2_init_xattr_subsystem() jffs2_build_xattr_caches() -> jffs2_build_xattr_subsystem() jffs2_clear_xattr_caches() -> jffs2_clear_xattr_subsystem()

        ,,,and so on.

The remaining work is as follows:
- Additional revising besed on any comments.
- Test & Stabilization.
- The implementation for POSIX ACL support.
- The implementation for XATTR support in mkfs.jffs2.

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
fs/Kconfig +17 -0
diff -prNU3 mtd-0927/fs/Kconfig mtd-0927.xattr/fs/Kconfig
@@ -64,6 +64,23 @@ config JFFS2_FS_WRITEBUFFER
 	    - NOR flash with transparent ECC
 	    - DataFlash
 
+config JFFS2_XATTR
+	bool "JFFS2 XATTR support (EXPERIMENTAL)"
+	depends on JFFS2_FS && EXPERIMENTAL
+	default n
+	help
+	  This enables the Extended Attributes(XATTR) support in JFFS2.
+	  XATTR is name:value pairs associated with inodes by the kernel
+	  or by users.
+	  It's neccesary for persistent security context in SELinux.
+	  
+	  In addition, the following kinds of prefixes are supported now.
+	  - security.*
+	  - user.*
+	  - trusted.*
+	  
+	  - system.posix_acl_{access|default} are in TODO list now.
+
 config JFFS2_SUMMARY
 	bool "JFFS2 summary support (EXPERIMENTAL)"
 	depends on JFFS2_FS && EXPERIMENTAL
fs/jffs2/Makefile.common +1 -0
diff -prNU3 mtd-0927/fs/jffs2/Makefile.common mtd-0927.xattr/fs/jffs2/Makefile.common
@@ -12,6 +12,7 @@ jffs2-y	+= symlink.o build.o erase.o bac
 jffs2-y	+= super.o debug.o
 
 jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= wbuf.o
+jffs2-$(CONFIG_JFFS2_XATTR)	+= xattr.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
fs/jffs2/build.c +2 -0
diff -prNU3 mtd-0927/fs/jffs2/build.c mtd-0927.xattr/fs/jffs2/build.c
@@ -160,6 +160,7 @@ static int jffs2_build_filesystem(struct
 		ic->scan_dents = NULL;
 		cond_resched();
 	}
+	jffs2_build_xattr_subsystem(c);
 	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
 	
 	dbg_fsbuild("FS build complete\n");
@@ -178,6 +179,7 @@ exit:
 				jffs2_free_full_dirent(fd);
 			}
 		}
+		jffs2_clear_xattr_subsystem(c);
 	}
 
 	return ret;
fs/jffs2/dir.c +5 -0
diff -prNU3 mtd-0927/fs/jffs2/dir.c mtd-0927.xattr/fs/jffs2/dir.c
@@ -57,7 +57,12 @@ struct inode_operations jffs2_dir_inode_
 	.rmdir =	jffs2_rmdir,
 	.mknod =	jffs2_mknod,
 	.rename =	jffs2_rename,
+	.permission =	jffs2_permission,
 	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 /***********************************************************************/
fs/jffs2/file.c +6 -1
diff -prNU3 mtd-0927/fs/jffs2/file.c mtd-0927.xattr/fs/jffs2/file.c
@@ -57,7 +57,12 @@ struct file_operations jffs2_file_operat
 
 struct inode_operations jffs2_file_inode_operations =
 {
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 struct address_space_operations jffs2_file_address_operations =
fs/jffs2/fs.c +7 -1
diff -prNU3 mtd-0927/fs/jffs2/fs.c mtd-0927.xattr/fs/jffs2/fs.c
@@ -218,6 +218,7 @@ void jffs2_clear_inode (struct inode *in
 	
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	jffs2_xattr_delete_inode(c, f->inocache);
 	jffs2_do_clear_inode(c, f);
 }
 
@@ -490,9 +491,12 @@ int jffs2_do_fill_super(struct super_blo
 	}
 	memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
-	if ((ret = jffs2_do_mount_fs(c)))
+	if ((ret = jffs2_init_xattr_subsystem(c)))
 		goto out_inohash;
 
+	if ((ret = jffs2_do_mount_fs(c)))
+		goto out_xattr;
+
 	ret = -EINVAL;
 
 	D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
@@ -523,6 +527,8 @@ int jffs2_do_fill_super(struct super_blo
 		vfree(c->blocks);
 	else
 		kfree(c->blocks);
+ out_xattr:
+	jffs2_clear_xattr_subsystem(c);
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:
fs/jffs2/gc.c +10 -0
diff -prNU3 mtd-0927/fs/jffs2/gc.c mtd-0927.xattr/fs/jffs2/gc.c
@@ -258,6 +258,16 @@ int jffs2_garbage_collect_pass(struct jf
 
 	ic = jffs2_raw_ref_to_ic(raw);
 
+	/* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr.
+	   We can decide whether this node is inode or xattr by ic->class.
+	   ret = 0 : ic is xattr_datum/xattr_ref, and GC was SUCCESSED.
+	   ret < 0 : ic is xattr_datum/xattr_ref, but GC was FAILED.
+	   ret > 0 : ic is NOT xattr_datum/xattr_ref.
+	*/
+	ret = jffs2_garbage_collect_xattr(c, ic);
+	if (ret <= 0)
+		goto release_sem;
+
 	/* We need to hold the inocache. Either the erase_completion_lock or
 	   the inocache_lock are sufficient; we trade down since the inocache_lock 
 	   causes less contention. */
fs/jffs2/malloc.c +60 -2

83 lines not on this page · raw message

fs/jffs2/nodelist.c +1 -0
diff -prNU3 mtd-0927/fs/jffs2/nodelist.c mtd-0927.xattr/fs/jffs2/nodelist.c
@@ -937,6 +937,7 @@ void jffs2_free_ino_caches(struct jffs2_
 		this = c->inocache_list[i];
 		while (this) {
 			next = this->next;
+			jffs2_xattr_free_inode(c, this);
 			jffs2_free_inode_cache(this);
 			this = next;
 		}
fs/jffs2/nodelist.h +16 -1
diff -prNU3 mtd-0927/fs/jffs2/nodelist.h mtd-0927.xattr/fs/jffs2/nodelist.h
@@ -20,6 +20,7 @@
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/jffs2_fs_i.h>
+#include "xattr.h"
 #include "summary.h"
 
 #ifdef __ECOS
@@ -107,11 +108,16 @@ struct jffs2_inode_cache {
 		temporary lists of dirents, and later must be set to
 		NULL to mark the end of the raw_node_ref->next_in_ino
 		chain. */
+	u8 class;	/* It's used for identification */
+	u8 flags;
+	uint16_t state;
 	struct jffs2_inode_cache *next;
 	struct jffs2_raw_node_ref *nodes;
 	uint32_t ino;
 	int nlink;
-	int state;
+#ifdef CONFIG_JFFS2_XATTR
+	struct list_head ilist;
+#endif
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
@@ -125,6 +131,8 @@ struct jffs2_inode_cache {
 #define INO_STATE_READING	5	/* In read_inode() */
 #define INO_STATE_CLEARING	6	/* In clear_inode() */
 
+#define INO_FLAGS_XATTR_CHECKED	0x01	/* has no duplicate xattr_ref */
+
 #define INOCACHE_HASHSIZE 128
 
 /*
@@ -375,6 +383,13 @@ void jffs2_free_node_frag(struct jffs2_n
 struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
 void jffs2_free_inode_cache(struct jffs2_inode_cache *);
 
+#ifdef CONFIG_JFFS2_XATTR
+struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void);
+void jffs2_free_xattr_datum(struct jffs2_xattr_datum *);
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void);
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *);
+#endif /* CONFIG_JFFS2_XATTR */
+
 /* gc.c */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 
fs/jffs2/readinode.c +1 -0
diff -prNU3 mtd-0927/fs/jffs2/readinode.c mtd-0927.xattr/fs/jffs2/readinode.c
@@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_
 		f->inocache->ino = f->inocache->nlink = 1;
 		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 		f->inocache->state = INO_STATE_READING;
+		init_xattr_inode_cache(f->inocache);
 		jffs2_add_ino_cache(c, f->inocache);
 	}
 	if (!f->inocache) {
fs/jffs2/scan.c +191 -0

209 lines not on this page · raw message

fs/jffs2/super.c +2 -0
diff -prNU3 mtd-0927/fs/jffs2/super.c mtd-0927.xattr/fs/jffs2/super.c
@@ -151,6 +151,7 @@ static struct super_block *jffs2_get_sb_
 
 	sb->s_op = &jffs2_super_operations;
 	sb->s_flags = flags | MS_NOATIME;
+	sb->s_xattr = jffs2_xattr_handlers;
 
 	ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
 
@@ -293,6 +294,7 @@ static void jffs2_put_super (struct supe
 		kfree(c->blocks);
 	jffs2_flash_cleanup(c);
 	kfree(c->inocache_list);
+	jffs2_clear_xattr_subsystem(c);
 	if (c->mtd->sync)
 		c->mtd->sync(c->mtd);
 
fs/jffs2/symlink.c +6 -1
diff -prNU3 mtd-0927/fs/jffs2/symlink.c mtd-0927.xattr/fs/jffs2/symlink.c
@@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_in
 {	
 	.readlink =	generic_readlink,
 	.follow_link =	jffs2_follow_link,
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
fs/jffs2/write.c +1 -1
diff -prNU3 mtd-0927/fs/jffs2/write.c mtd-0927.xattr/fs/jffs2/write.c
@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_i
 	f->inocache->nlink = 1;
 	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 	f->inocache->state = INO_STATE_PRESENT;
-
+	init_xattr_inode_cache(f->inocache);
 
 	jffs2_add_ino_cache(c, f->inocache);
 	D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
fs/jffs2/xattr.c +1046 -0

1,046 lines not on this page · raw message

fs/jffs2/xattr.h +137 -0

137 lines not on this page · raw message

include/linux/jffs2.h +31 -0
diff -prNU3 mtd-0927/include/linux/jffs2.h mtd-0927.xattr/include/linux/jffs2.h
@@ -65,6 +65,9 @@
 
 #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
 
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
+
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
@@ -151,6 +154,32 @@ struct jffs2_raw_inode
 	uint8_t data[0];
 } __attribute__((packed));
 
+struct jffs2_raw_xattr {
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XATTR */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t xid;		/* XATTR identifier number */
+	uint8_t xprefix;
+	uint8_t name_len;
+	jint16_t value_len;
+	jint32_t data_crc;
+	jint32_t node_crc;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XREF */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t seqno;		/* sequencial number */
+	jint32_t ino;		/* inode number */
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t node_crc;
+} __attribute__((packed));
+
 struct jffs2_raw_summary
 {
 	jint16_t magic;
@@ -169,6 +198,8 @@ union jffs2_node_union 
 {
 	struct jffs2_raw_inode i;
 	struct jffs2_raw_dirent d;
+	struct jffs2_raw_xattr x;
+	struct jffs2_raw_xref r;
 	struct jffs2_raw_summary s;
 	struct jffs2_unknown_node u;
 };
include/linux/jffs2_fs_sb.h +8 -0
diff -prNU3 mtd-0927/include/linux/jffs2_fs_sb.h mtd-0927.xattr/include/linux/jffs2_fs_sb.h
@@ -115,6 +115,14 @@ struct jffs2_sb_info {
 
 	struct jffs2_summary *summary;		/* Summary information */
 
+#ifdef CONFIG_JFFS2_XATTR
+	uint32_t highest_xseqno;
+	struct list_head *xattrindex;
+#define xattr_temp xattrindex[XATTRINDEX_HASHSIZE]
+	struct rw_semaphore xattr_sem;
+	uint32_t xdatum_mem_usage;
+	uint32_t xdatum_mem_threshold;
+#endif
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };
cleanup-scan.xattr.c renamed from cleanup-scan.c +147 -0

159 lines not on this page · raw message

#21 lore raw
Quoted 8 lines · Kaigai Kohei

I revised the previous xattr patch in jffs2 based on some suggestions.

[1] scanning xattr related node for cleaned-up scan.c. (jffs2_xattr_scan.c-cleanup.patch)
[2] enables xattr support in jffs2.

    (jffs2_xattr_take-3.patch)

(*) We can apply jffs2_xattr_take-3.patch for current CVS independently.

Looks quite interesting. I'll take a closer look over the weekend.

Thanks!

Jörn

Signature · 2 lines
The strong give up and move away, while the weak give up and stay.
-- unknown
#22 lore raw

E-mail with attached file has not delivered yet. (Re: [PATCH] XATTR issues on JFFS2)

Hi,

The quoted E-mail seems not to have been delivered by some reasons yet. (No E-mail with attached files has been distributed on the list since 27-Sep.)

http://www.kaigai.gr.jp/patch/jffs2_xattr_take-3.patch

The above patch was what I posted on 28-Sep, but it has not been delivered yet. (Today is 03-Oct JST!)

Are there any other E-mails which has not been delivered yet ?

Thanks,

Quoted 16 lines · Jörn Engel
Quoted 7 lines · Kaigai Kohei

I revised the previous xattr patch in jffs2 based on some suggestions.

[1] scanning xattr related node for cleaned-up scan.c. (jffs2_xattr_scan.c-cleanup.patch)
[2] enables xattr support in jffs2. (jffs2_xattr_take-3.patch)
(*) We can apply jffs2_xattr_take-3.patch for current CVS independently.

Looks quite interesting. I'll take a closer look over the weekend.

Thanks!

Jörn

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#23 lore raw
In reply to Jörn Engel

Hi Jörn,

What status is the XATTR patch of JFFS2 now ??

I hope to merge it, if this patch has no problem.
Of course, I'll correct any inconvenient points which we found.

# I droped a Cc: for Ma, since his address seems to be invalid.

Quoted 16 lines · Jörn Engel
Quoted 7 lines · Kaigai Kohei

I revised the previous xattr patch in jffs2 based on some suggestions.

[1] scanning xattr related node for cleaned-up scan.c. (jffs2_xattr_scan.c-cleanup.patch)
[2] enables xattr support in jffs2. (jffs2_xattr_take-3.patch)
(*) We can apply jffs2_xattr_take-3.patch for current CVS independently.

Looks quite interesting. I'll take a closer look over the weekend.

Thanks!

Jörn

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#24 lore raw
Quoted 5 lines · Kaigai Kohei

What status is the XATTR patch of JFFS2 now ??

I hope to merge it, if this patch has no problem.
Of course, I'll correct any inconvenient points which we found.

Lack of time. I still have your patch and some from Forrest lingering in my inbox. They all should receive a thorough line-by-line review - not necessarily by me, but by someone with enough knowledge.

If it helps you, your patches are already in a relatively good state. I cannot easily find problems with it.

Quoted 1 line

# I droped a Cc: for Ma, since his address seems to be invalid.

Fair enough.

Jörn

Signature · 2 lines
"Security vulnerabilities are here to stay."
-- Scott Culp, Manager of the Microsoft Security Response Center, 2001
#25 lore raw

Hi,

Quoted 3 lines

Lack of time. I still have your patch and some from Forrest lingering in my inbox. They all should receive a thorough line-by-line review - not necessarily by me, but by someone with enough knowledge.

Sorry for hastening.

Quoted 2 lines

If it helps you, your patches are already in a relatively good state. I cannot easily find problems with it.

Thanks, I was hesitating whether I should begin to develop the ACL features based on XATTR.
If XATTR would be in a good state, I'm willing to begin the design and implementation.

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#26 lore raw
In reply to Jörn Engel

Hi,

This attached patches are enables XATTR support on JFFS2. some new functionalities are added from take-3 patches.

# Sorry for slowing update.

[NOTICE]
We can test this patch with ONLY 2.6.14 kernel.
The previous versions of kernel do not support an new LSM hook.

[1/2] jffs2_xattr_take-4.patch
* CONFIG_JFFS2_XATTR was renamed to CONFIG_JFFS2_FS_XATTR The XATTR configuration switch are named CONFIG_<fsname>_FS_XATTR on another some filesystems which support XATTR.
I also follow this manner.

* CONFIG_JFFS2_FS_POSIX_ACL and JFFS2_FS_SECURITY are selectable. this follows another FS's manner.

* POSIX-ACL support was added.
This functionality is implemented in acl.c, acl.h.
I implemented the most part of this functionalities by referring the Ext2/3's implementation of POSIX-ACL.
If I took bad manner or misunderstanding for implementation, notice me please.

* jffs2_init_security() was added for inode initialization. At 2.6.14, new LSM hook(security_inode_init_security) was added. Because of this, any filesystems obtain security attribtues must call this this hook to set the security label for new inode. It's deployed in jffs2_create(), jffs2_symlink(), jffs2_mkdir() and jffs2_mknod().

* Some patch conflicts were fixed.
We can apply this patches for latest MTD-CVS without incident.

* An obvious bug was fixed.
In jffs2_build_xattr_subsystem(), NULL checking was omitted.

[2/2] mkfs.jffs2-xattr.patch
* --with-{xattr|selinux|posix-acl} options are added. --with-xattr enables to pack all xattr-entries into jffs2 image file. --with-selinux enables to pack security related xattr-entries which are named as 'security.*' into jffs2 image file. --with-posix-acl enables to pack ACL related xattr-entries which are names as 'system.posix_acl_access' or 'system.posix_acl_default'.

I hope to merge those functionalities into MTD's CVS tree. Thanks,

Signature · 1 line
KaiGai Kohei <[email protected]>
util/mkfs.jffs2.1 +18 -0
diff -rpNU3 mtd-20051127.xattr/util/mkfs.jffs2.1 mtd-20051127.mkfs/util/mkfs.jffs2.1
@@ -49,6 +49,15 @@ mkfs.jffs2 \- Create a JFFS2 file system
 .B -P,--squash-perms
 ]
 [
+.B --with-xattr
+]
+[
+.B --with-selinux
+]
+[
+.B --with-posix-acl
+]
+[
 .B -m,--compression-mode=MODE
 ]
 [
@@ -178,6 +187,15 @@ Squash owners making all files be owned 
 .B -P, --squash-perms
 Squash permissions, removing write permission for \'group\' and \'other\'.
 .TP
+.B --with-xattr
+Enables xattr, stuff all xattr entries into jffs2 image file.
+.TP
+.B --with-selinux
+Enables xattr, stuff only SELinux Labels into jffs2 image file.
+.TP
+.B --with-posix-acl
+Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
+.TP
 .B -m, --compression-mode=MODE
 Set the default compression mode. The default mode is 
 .B priority 
util/mkfs.jffs2.c +308 -0

392 lines not on this page · raw message

fs/jffs2/acl.c +484 -0

484 lines not on this page · raw message

fs/jffs2/acl.h +46 -0

46 lines not on this page · raw message

fs/jffs2/build.c +2 -0
diff -prNU3 mtd-20051127/fs/jffs2/build.c mtd-20051127.xattr/fs/jffs2/build.c
@@ -160,6 +160,7 @@ static int jffs2_build_filesystem(struct
 		ic->scan_dents = NULL;
 		cond_resched();
 	}
+	jffs2_build_xattr_subsystem(c);
 	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
 
 	dbg_fsbuild("FS build complete\n");
@@ -178,6 +179,7 @@ exit:
 				jffs2_free_full_dirent(fd);
 			}
 		}
+		jffs2_clear_xattr_subsystem(c);
 	}
 
 	return ret;
fs/jffs2/dir.c +56 -6

99 lines not on this page · raw message

fs/jffs2/file.c +6 -1
diff -prNU3 mtd-20051127/fs/jffs2/file.c mtd-20051127.xattr/fs/jffs2/file.c
@@ -54,7 +54,12 @@ struct file_operations jffs2_file_operat
 
 struct inode_operations jffs2_file_inode_operations =
 {
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 struct address_space_operations jffs2_file_address_operations =
fs/jffs2/fs.c +13 -2
diff -prNU3 mtd-20051127/fs/jffs2/fs.c mtd-20051127.xattr/fs/jffs2/fs.c
@@ -179,7 +179,12 @@ static int jffs2_do_setattr (struct inod
 
 int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
 {
-	return jffs2_do_setattr(dentry->d_inode, iattr);
+	int rc;
+
+	rc = jffs2_do_setattr(dentry->d_inode, iattr);
+	if (!rc)
+		rc = jffs2_acl_chmod(dentry->d_inode);
+	return rc;
 }
 
 int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
@@ -218,6 +223,7 @@ void jffs2_clear_inode (struct inode *in
 
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	jffs2_xattr_delete_inode(c, f->inocache);
 	jffs2_do_clear_inode(c, f);
 }
 
@@ -492,9 +498,12 @@ int jffs2_do_fill_super(struct super_blo
 	}
 	memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
-	if ((ret = jffs2_do_mount_fs(c)))
+	if ((ret = jffs2_init_xattr_subsystem(c)))
 		goto out_inohash;
 
+	if ((ret = jffs2_do_mount_fs(c)))
+		goto out_xattr;
+
 	ret = -EINVAL;
 
 	D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
@@ -522,6 +531,8 @@ int jffs2_do_fill_super(struct super_blo
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	jffs2_free_eraseblocks(c);
+ out_xattr:
+	jffs2_clear_xattr_subsystem(c);
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:
fs/jffs2/fs.c.orig +683 -0

683 lines not on this page · raw message

fs/jffs2/gc.c +10 -0
diff -prNU3 mtd-20051127/fs/jffs2/gc.c mtd-20051127.xattr/fs/jffs2/gc.c
@@ -312,6 +312,16 @@ int jffs2_garbage_collect_pass(struct jf
 
 	ic = jffs2_raw_ref_to_ic(raw);
 
+	/* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr.
+	   We can decide whether this node is inode or xattr by ic->class.
+	   ret = 0 : ic is xattr_datum/xattr_ref, and GC was SUCCESSED.
+	   ret < 0 : ic is xattr_datum/xattr_ref, but GC was FAILED.
+	   ret > 0 : ic is NOT xattr_datum/xattr_ref.
+	*/
+	ret = jffs2_garbage_collect_xattr(c, ic);
+	if (ret <= 0)
+		goto release_sem;
+
 	/* We need to hold the inocache. Either the erase_completion_lock or
 	   the inocache_lock are sufficient; we trade down since the inocache_lock
 	   causes less contention. */
fs/jffs2/Makefile.common +3 -0
diff -prNU3 mtd-20051127/fs/jffs2/Makefile.common mtd-20051127.xattr/fs/jffs2/Makefile.common
@@ -12,6 +12,9 @@ jffs2-y	+= symlink.o build.o erase.o bac
 jffs2-y	+= super.o debug.o wear_leveling.o
 
 jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= wbuf.o
+jffs2-$(CONFIG_JFFS2_FS_XATTR)		+= xattr.o
+jffs2-$(CONFIG_JFFS2_FS_SECURITY)	+= security.o
+jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL)	+= acl.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
fs/jffs2/malloc.c +58 -2

81 lines not on this page · raw message

fs/jffs2/nodelist.c +1 -0
diff -prNU3 mtd-20051127/fs/jffs2/nodelist.c mtd-20051127.xattr/fs/jffs2/nodelist.c
@@ -919,6 +919,7 @@ void jffs2_free_ino_caches(struct jffs2_
 		this = c->inocache_list[i];
 		while (this) {
 			next = this->next;
+			jffs2_xattr_free_inode(c, this);
 			jffs2_free_inode_cache(this);
 			this = next;
 		}
fs/jffs2/nodelist.h +17 -1
diff -prNU3 mtd-20051127/fs/jffs2/nodelist.h mtd-20051127.xattr/fs/jffs2/nodelist.h
@@ -20,6 +20,8 @@
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/jffs2_fs_i.h>
+#include "xattr.h"
+#include "acl.h"
 #include "summary.h"
 
 #ifdef __ECOS
@@ -107,11 +109,16 @@ struct jffs2_inode_cache {
 		temporary lists of dirents, and later must be set to
 		NULL to mark the end of the raw_node_ref->next_in_ino
 		chain. */
+	u8 class;	/* It's used for identification */
+	u8 flags;
+	uint16_t state;
 	struct jffs2_inode_cache *next;
 	struct jffs2_raw_node_ref *nodes;
 	uint32_t ino;
 	int nlink;
-	int state;
+#ifdef CONFIG_JFFS2_FS_XATTR
+	struct list_head ilist;
+#endif
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
@@ -125,6 +132,8 @@ struct jffs2_inode_cache {
 #define INO_STATE_READING	5	/* In read_inode() */
 #define INO_STATE_CLEARING	6	/* In clear_inode() */
 
+#define INO_FLAGS_XATTR_CHECKED	0x01	/* has no duplicate xattr_ref */
+
 #define INOCACHE_HASHSIZE 128
 
 /*
@@ -388,6 +397,13 @@ struct jffs2_inode_cache *jffs2_alloc_in
 void jffs2_free_inode_cache(struct jffs2_inode_cache *);
 int jffs2_alloc_eraseblocks(struct jffs2_sb_info *c);
 void jffs2_free_eraseblocks(struct jffs2_sb_info *c);
+#ifdef CONFIG_JFFS2_FS_XATTR
+struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void);
+void jffs2_free_xattr_datum(struct jffs2_xattr_datum *);
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void);
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *);
+#endif /* CONFIG_JFFS2_FS_XATTR */
+
 /* gc.c */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 
fs/jffs2/os-linux.h +4 -0
diff -prNU3 mtd-20051127/fs/jffs2/os-linux.h mtd-20051127.xattr/fs/jffs2/os-linux.h
@@ -60,6 +60,10 @@ static inline void jffs2_init_inode_info
 	f->target = NULL;
 	f->flags = 0;
 	f->usercompr = 0;
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+	f->i_acl_access = JFFS2_ACL_NOT_CACHED;
+	f->i_acl_default = JFFS2_ACL_NOT_CACHED;
+#endif
 }
 
 
fs/jffs2/readinode.c +1 -0
diff -prNU3 mtd-20051127/fs/jffs2/readinode.c mtd-20051127.xattr/fs/jffs2/readinode.c
@@ -891,6 +891,7 @@ int jffs2_do_read_inode(struct jffs2_sb_
 		f->inocache->ino = f->inocache->nlink = 1;
 		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 		f->inocache->state = INO_STATE_READING;
+		init_xattr_inode_cache(f->inocache);
 		jffs2_add_ino_cache(c, f->inocache);
 	}
 	if (!f->inocache) {
fs/jffs2/scan.c +191 -0

209 lines not on this page · raw message

fs/jffs2/security.c +82 -0

82 lines not on this page · raw message

fs/jffs2/super.c +5 -1
diff -prNU3 mtd-20051127/fs/jffs2/super.c mtd-20051127.xattr/fs/jffs2/super.c
@@ -151,7 +151,10 @@ static struct super_block *jffs2_get_sb_
 
 	sb->s_op = &jffs2_super_operations;
 	sb->s_flags = flags | MS_NOATIME;
-
+	sb->s_xattr = jffs2_xattr_handlers;
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+	sb->s_flags |= MS_POSIXACL;
+#endif
 	ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
 
 	if (ret) {
@@ -290,6 +293,7 @@ static void jffs2_put_super (struct supe
 	jffs2_free_eraseblocks(c);
 	jffs2_flash_cleanup(c);
 	kfree(c->inocache_list);
+	jffs2_clear_xattr_subsystem(c);
 	if (c->mtd->sync)
 		c->mtd->sync(c->mtd);
 
fs/jffs2/symlink.c +6 -1
diff -prNU3 mtd-20051127/fs/jffs2/symlink.c mtd-20051127.xattr/fs/jffs2/symlink.c
@@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_in
 {
 	.readlink =	generic_readlink,
 	.follow_link =	jffs2_follow_link,
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
fs/jffs2/write.c +1 -1
diff -prNU3 mtd-20051127/fs/jffs2/write.c mtd-20051127.xattr/fs/jffs2/write.c
@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_i
 	f->inocache->nlink = 1;
 	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 	f->inocache->state = INO_STATE_PRESENT;
-
+	init_xattr_inode_cache(f->inocache);
 
 	jffs2_add_ino_cache(c, f->inocache);
 	D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
fs/jffs2/xattr.c +1021 -0

692 lines not on this page · raw message

fs/jffs2/xattr.h +144 -0

144 lines not on this page · raw message

fs/Kconfig +2 -2
diff -prNU3 mtd-20051127/fs/Kconfig mtd-20051127.xattr/fs/Kconfig

Lines of this file are not shown. View the raw message.

include/linux/jffs2_fs_i.h +5 -0
diff -prNU3 mtd-20051127/include/linux/jffs2_fs_i.h mtd-20051127.xattr/include/linux/jffs2_fs_i.h

Lines of this file are not shown. View the raw message.

include/linux/jffs2_fs_sb.h +8 -0
diff -prNU3 mtd-20051127/include/linux/jffs2_fs_sb.h mtd-20051127.xattr/include/linux/jffs2_fs_sb.h

Lines of this file are not shown. View the raw message.

include/linux/jffs2.h +40 -0
diff -prNU3 mtd-20051127/include/linux/jffs2.h mtd-20051127.xattr/include/linux/jffs2.h

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#27 lore raw

Sorry, some garbages mixed into my previous mail.

Please use those patches which are attached this mail, and discard previous one.

Quoted 50 lines · KaiGai Kohei

Hi,

This attached patches are enables XATTR support on JFFS2. some new functionalities are added from take-3 patches.

# Sorry for slowing update.

[NOTICE]
We can test this patch with ONLY 2.6.14 kernel.
The previous versions of kernel do not support an new LSM hook.

[1/2] jffs2_xattr_take-4.patch
* CONFIG_JFFS2_XATTR was renamed to CONFIG_JFFS2_FS_XATTR The XATTR configuration switch are named CONFIG_<fsname>_FS_XATTR on another some filesystems which support XATTR.
I also follow this manner.

* CONFIG_JFFS2_FS_POSIX_ACL and JFFS2_FS_SECURITY are selectable. this follows another FS's manner.

* POSIX-ACL support was added.
This functionality is implemented in acl.c, acl.h.
I implemented the most part of this functionalities by referring the Ext2/3's implementation of POSIX-ACL.
If I took bad manner or misunderstanding for implementation, notice me please.

* jffs2_init_security() was added for inode initialization. At 2.6.14, new LSM hook(security_inode_init_security) was added. Because of this, any filesystems obtain security attribtues must call this this hook to set the security label for new inode. It's deployed in jffs2_create(), jffs2_symlink(), jffs2_mkdir() and jffs2_mknod().

* Some patch conflicts were fixed.
We can apply this patches for latest MTD-CVS without incident.

* An obvious bug was fixed.
In jffs2_build_xattr_subsystem(), NULL checking was omitted.

[2/2] mkfs.jffs2-xattr.patch
* --with-{xattr|selinux|posix-acl} options are added. --with-xattr enables to pack all xattr-entries into jffs2 image file. --with-selinux enables to pack security related xattr-entries which are named as 'security.*' into jffs2 image file. --with-posix-acl enables to pack ACL related xattr-entries which are names as 'system.posix_acl_access' or 'system.posix_acl_default'.

I hope to merge those functionalities into MTD's CVS tree. Thanks,

Signature · 1 line
KaiGai Kohei <[email protected]>
util/mkfs.jffs2.1 +18 -0
diff -rpNU3 mtd-20051127.xattr/util/mkfs.jffs2.1 mtd-20051127.mkfs/util/mkfs.jffs2.1
@@ -49,6 +49,15 @@ mkfs.jffs2 \- Create a JFFS2 file system
 .B -P,--squash-perms
 ]
 [
+.B --with-xattr
+]
+[
+.B --with-selinux
+]
+[
+.B --with-posix-acl
+]
+[
 .B -m,--compression-mode=MODE
 ]
 [
@@ -178,6 +187,15 @@ Squash owners making all files be owned 
 .B -P, --squash-perms
 Squash permissions, removing write permission for \'group\' and \'other\'.
 .TP
+.B --with-xattr
+Enables xattr, stuff all xattr entries into jffs2 image file.
+.TP
+.B --with-selinux
+Enables xattr, stuff only SELinux Labels into jffs2 image file.
+.TP
+.B --with-posix-acl
+Enable xattr, stuff only POSIX ACL entries into jffs2 image file.
+.TP
 .B -m, --compression-mode=MODE
 Set the default compression mode. The default mode is 
 .B priority 
util/mkfs.jffs2.c +308 -0

392 lines not on this page · raw message

fs/jffs2/acl.c +484 -0

484 lines not on this page · raw message

fs/jffs2/acl.h +46 -0

46 lines not on this page · raw message

fs/jffs2/build.c +2 -0
diff -prNU3 mtd-20051127/fs/jffs2/build.c mtd-20051127.xattr/fs/jffs2/build.c
@@ -160,6 +160,7 @@ static int jffs2_build_filesystem(struct
 		ic->scan_dents = NULL;
 		cond_resched();
 	}
+	jffs2_build_xattr_subsystem(c);
 	c->flags &= ~JFFS2_SB_FLAG_BUILDING;
 
 	dbg_fsbuild("FS build complete\n");
@@ -178,6 +179,7 @@ exit:
 				jffs2_free_full_dirent(fd);
 			}
 		}
+		jffs2_clear_xattr_subsystem(c);
 	}
 
 	return ret;
fs/jffs2/dir.c +56 -6

99 lines not on this page · raw message

fs/jffs2/file.c +6 -1
diff -prNU3 mtd-20051127/fs/jffs2/file.c mtd-20051127.xattr/fs/jffs2/file.c
@@ -54,7 +54,12 @@ struct file_operations jffs2_file_operat
 
 struct inode_operations jffs2_file_inode_operations =
 {
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 struct address_space_operations jffs2_file_address_operations =
fs/jffs2/fs.c +13 -2
diff -prNU3 mtd-20051127/fs/jffs2/fs.c mtd-20051127.xattr/fs/jffs2/fs.c
@@ -179,7 +179,12 @@ static int jffs2_do_setattr (struct inod
 
 int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
 {
-	return jffs2_do_setattr(dentry->d_inode, iattr);
+	int rc;
+
+	rc = jffs2_do_setattr(dentry->d_inode, iattr);
+	if (!rc)
+		rc = jffs2_acl_chmod(dentry->d_inode);
+	return rc;
 }
 
 int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
@@ -218,6 +223,7 @@ void jffs2_clear_inode (struct inode *in
 
 	D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
+	jffs2_xattr_delete_inode(c, f->inocache);
 	jffs2_do_clear_inode(c, f);
 }
 
@@ -492,9 +498,12 @@ int jffs2_do_fill_super(struct super_blo
 	}
 	memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
 
-	if ((ret = jffs2_do_mount_fs(c)))
+	if ((ret = jffs2_init_xattr_subsystem(c)))
 		goto out_inohash;
 
+	if ((ret = jffs2_do_mount_fs(c)))
+		goto out_xattr;
+
 	ret = -EINVAL;
 
 	D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n"));
@@ -522,6 +531,8 @@ int jffs2_do_fill_super(struct super_blo
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	jffs2_free_eraseblocks(c);
+ out_xattr:
+	jffs2_clear_xattr_subsystem(c);
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:
fs/jffs2/gc.c +10 -0
diff -prNU3 mtd-20051127/fs/jffs2/gc.c mtd-20051127.xattr/fs/jffs2/gc.c
@@ -312,6 +312,16 @@ int jffs2_garbage_collect_pass(struct jf
 
 	ic = jffs2_raw_ref_to_ic(raw);
 
+	/* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr.
+	   We can decide whether this node is inode or xattr by ic->class.
+	   ret = 0 : ic is xattr_datum/xattr_ref, and GC was SUCCESSED.
+	   ret < 0 : ic is xattr_datum/xattr_ref, but GC was FAILED.
+	   ret > 0 : ic is NOT xattr_datum/xattr_ref.
+	*/
+	ret = jffs2_garbage_collect_xattr(c, ic);
+	if (ret <= 0)
+		goto release_sem;
+
 	/* We need to hold the inocache. Either the erase_completion_lock or
 	   the inocache_lock are sufficient; we trade down since the inocache_lock
 	   causes less contention. */
fs/jffs2/Makefile.common +3 -0
diff -prNU3 mtd-20051127/fs/jffs2/Makefile.common mtd-20051127.xattr/fs/jffs2/Makefile.common
@@ -12,6 +12,9 @@ jffs2-y	+= symlink.o build.o erase.o bac
 jffs2-y	+= super.o debug.o wear_leveling.o
 
 jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= wbuf.o
+jffs2-$(CONFIG_JFFS2_FS_XATTR)		+= xattr.o
+jffs2-$(CONFIG_JFFS2_FS_SECURITY)	+= security.o
+jffs2-$(CONFIG_JFFS2_FS_POSIX_ACL)	+= acl.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
fs/jffs2/malloc.c +58 -2

81 lines not on this page · raw message

fs/jffs2/nodelist.c +1 -0
diff -prNU3 mtd-20051127/fs/jffs2/nodelist.c mtd-20051127.xattr/fs/jffs2/nodelist.c
@@ -919,6 +919,7 @@ void jffs2_free_ino_caches(struct jffs2_
 		this = c->inocache_list[i];
 		while (this) {
 			next = this->next;
+			jffs2_xattr_free_inode(c, this);
 			jffs2_free_inode_cache(this);
 			this = next;
 		}
fs/jffs2/nodelist.h +17 -1
diff -prNU3 mtd-20051127/fs/jffs2/nodelist.h mtd-20051127.xattr/fs/jffs2/nodelist.h
@@ -20,6 +20,8 @@
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/jffs2_fs_i.h>
+#include "xattr.h"
+#include "acl.h"
 #include "summary.h"
 
 #ifdef __ECOS
@@ -107,11 +109,16 @@ struct jffs2_inode_cache {
 		temporary lists of dirents, and later must be set to
 		NULL to mark the end of the raw_node_ref->next_in_ino
 		chain. */
+	u8 class;	/* It's used for identification */
+	u8 flags;
+	uint16_t state;
 	struct jffs2_inode_cache *next;
 	struct jffs2_raw_node_ref *nodes;
 	uint32_t ino;
 	int nlink;
-	int state;
+#ifdef CONFIG_JFFS2_FS_XATTR
+	struct list_head ilist;
+#endif
 };
 
 /* Inode states for 'state' above. We need the 'GC' state to prevent
@@ -125,6 +132,8 @@ struct jffs2_inode_cache {
 #define INO_STATE_READING	5	/* In read_inode() */
 #define INO_STATE_CLEARING	6	/* In clear_inode() */
 
+#define INO_FLAGS_XATTR_CHECKED	0x01	/* has no duplicate xattr_ref */
+
 #define INOCACHE_HASHSIZE 128
 
 /*
@@ -388,6 +397,13 @@ struct jffs2_inode_cache *jffs2_alloc_in
 void jffs2_free_inode_cache(struct jffs2_inode_cache *);
 int jffs2_alloc_eraseblocks(struct jffs2_sb_info *c);
 void jffs2_free_eraseblocks(struct jffs2_sb_info *c);
+#ifdef CONFIG_JFFS2_FS_XATTR
+struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void);
+void jffs2_free_xattr_datum(struct jffs2_xattr_datum *);
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void);
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *);
+#endif /* CONFIG_JFFS2_FS_XATTR */
+
 /* gc.c */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 
fs/jffs2/os-linux.h +4 -0
diff -prNU3 mtd-20051127/fs/jffs2/os-linux.h mtd-20051127.xattr/fs/jffs2/os-linux.h
@@ -60,6 +60,10 @@ static inline void jffs2_init_inode_info
 	f->target = NULL;
 	f->flags = 0;
 	f->usercompr = 0;
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+	f->i_acl_access = JFFS2_ACL_NOT_CACHED;
+	f->i_acl_default = JFFS2_ACL_NOT_CACHED;
+#endif
 }
 
 
fs/jffs2/readinode.c +1 -0
diff -prNU3 mtd-20051127/fs/jffs2/readinode.c mtd-20051127.xattr/fs/jffs2/readinode.c
@@ -891,6 +891,7 @@ int jffs2_do_read_inode(struct jffs2_sb_
 		f->inocache->ino = f->inocache->nlink = 1;
 		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 		f->inocache->state = INO_STATE_READING;
+		init_xattr_inode_cache(f->inocache);
 		jffs2_add_ino_cache(c, f->inocache);
 	}
 	if (!f->inocache) {
fs/jffs2/scan.c +191 -0

209 lines not on this page · raw message

fs/jffs2/security.c +82 -0

82 lines not on this page · raw message

fs/jffs2/super.c +5 -1
diff -prNU3 mtd-20051127/fs/jffs2/super.c mtd-20051127.xattr/fs/jffs2/super.c
@@ -151,7 +151,10 @@ static struct super_block *jffs2_get_sb_
 
 	sb->s_op = &jffs2_super_operations;
 	sb->s_flags = flags | MS_NOATIME;
-
+	sb->s_xattr = jffs2_xattr_handlers;
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+	sb->s_flags |= MS_POSIXACL;
+#endif
 	ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0);
 
 	if (ret) {
@@ -290,6 +293,7 @@ static void jffs2_put_super (struct supe
 	jffs2_free_eraseblocks(c);
 	jffs2_flash_cleanup(c);
 	kfree(c->inocache_list);
+	jffs2_clear_xattr_subsystem(c);
 	if (c->mtd->sync)
 		c->mtd->sync(c->mtd);
 
fs/jffs2/symlink.c +6 -1
diff -prNU3 mtd-20051127/fs/jffs2/symlink.c mtd-20051127.xattr/fs/jffs2/symlink.c
@@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_in
 {
 	.readlink =	generic_readlink,
 	.follow_link =	jffs2_follow_link,
-	.setattr =	jffs2_setattr
+	.permission =	jffs2_permission,
+	.setattr =	jffs2_setattr,
+	.setxattr =	jffs2_setxattr,
+	.getxattr =	jffs2_getxattr,
+	.listxattr =	jffs2_listxattr,
+	.removexattr =	jffs2_removexattr
 };
 
 static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
fs/jffs2/write.c +1 -1
diff -prNU3 mtd-20051127/fs/jffs2/write.c mtd-20051127.xattr/fs/jffs2/write.c
@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_i
 	f->inocache->nlink = 1;
 	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
 	f->inocache->state = INO_STATE_PRESENT;
-
+	init_xattr_inode_cache(f->inocache);
 
 	jffs2_add_ino_cache(c, f->inocache);
 	D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
fs/jffs2/xattr.c +1021 -0

1,021 lines not on this page · raw message

fs/jffs2/xattr.h +144 -0

144 lines not on this page · raw message

fs/Kconfig +38 -0
diff -prNU3 mtd-20051127/fs/Kconfig mtd-20051127.xattr/fs/Kconfig
@@ -51,6 +51,44 @@ config JFFS2_FS_DEBUG
 	  If reporting bugs, please try to have available a full dump of the
 	  messages at debug level 1 while the misbehaviour was occurring.
 
+config JFFS2_FS_XATTR
+	bool "JFFS2 XATTR support (EXPERIMENTAL)"
+	depends on JFFS2_FS && EXPERIMENTAL
+	default n
+	help
+	  Extended attributes are name:value pairs associated with inodes by
+	  the kernel or by users (see the attr(5) manual page, or visit
+	  <http://acl.bestbits.at/> for details).
+	  
+	  If unsure, say N.
+
+config JFFS2_FS_POSIX_ACL
+	bool "JFFS2 POSIX Access Control Lists"
+	depends on JFFS2_FS_XATTR
+	default y
+	select FS_POSIX_ACL
+	help
+	  Posix Access Control Lists (ACLs) support permissions for users and
+	  groups beyond the owner/group/world scheme.
+	  
+	  To learn more about Access Control Lists, visit the Posix ACLs for
+	  Linux website <http://acl.bestbits.at/>.
+	  
+	  If you don't know what Access Control Lists are, say N
+
+config JFFS2_FS_SECURITY
+	bool "JFFS2 Security Labels"
+	depends on JFFS2_FS_XATTR
+	default y
+	help
+	  Security labels support alternative access control models
+	  implemented by security modules like SELinux.  This option
+	  enables an extended attribute handler for file security
+	  labels in the jffs2 filesystem.
+	  
+	  If you are not using a security module that requires using
+	  extended attributes for file security labels, say N.
+
 config JFFS2_FS_WRITEBUFFER
 	bool "JFFS2 write-buffering support"
 	depends on JFFS2_FS
include/linux/jffs2_fs_i.h +5 -0
diff -prNU3 mtd-20051127/include/linux/jffs2_fs_i.h mtd-20051127.xattr/include/linux/jffs2_fs_i.h
@@ -5,6 +5,7 @@
 
 #include <linux/version.h>
 #include <linux/rbtree.h>
+#include <linux/posix_acl.h>
 #include <asm/semaphore.h>
 
 struct jffs2_inode_info {
@@ -45,6 +46,10 @@ struct jffs2_inode_info {
 	struct inode vfs_inode;
 #endif
 #endif
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+	struct posix_acl *i_acl_access;
+	struct posix_acl *i_acl_default;
+#endif
 };
 
 #endif /* _JFFS2_FS_I */
include/linux/jffs2_fs_sb.h +8 -0
diff -prNU3 mtd-20051127/include/linux/jffs2_fs_sb.h mtd-20051127.xattr/include/linux/jffs2_fs_sb.h
@@ -140,6 +140,14 @@ struct jffs2_sb_info {
 	struct jffs2_blocks_bucket used_blocks[HASH_SIZE]; /* The hash table for both dirty and clean erase blocks */
 	struct jffs2_blocks_bucket free_blocks[HASH_SIZE]; /* The hash table for free erase blocks */
 
+#ifdef CONFIG_JFFS2_FS_XATTR
+	uint32_t highest_xseqno;
+	struct list_head *xattrindex;
+#define xattr_temp xattrindex[XATTRINDEX_HASHSIZE]
+	struct rw_semaphore xattr_sem;
+	uint32_t xdatum_mem_usage;
+	uint32_t xdatum_mem_threshold;
+#endif
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };
include/linux/jffs2.h +40 -0
diff -prNU3 mtd-20051127/include/linux/jffs2.h mtd-20051127.xattr/include/linux/jffs2.h
@@ -71,6 +71,18 @@
 #define JFFS2_NODETYPE_ERASEBLOCK_HEADER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 5)
 #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
 
+#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
+#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
+
+/* XATTR Related */
+#define JFFS2_XPREFIX_USER		1	/* for "user." */
+#define JFFS2_XPREFIX_SECURITY		2	/* for "security." */
+#define JFFS2_XPREFIX_ACL_ACCESS	3	/* for "system.posix_acl_access" */
+#define JFFS2_XPREFIX_ACL_DEFAULT	4	/* for "system.posix_acl_default" */
+#define JFFS2_XPREFIX_TRUSTED		5	/* for "trusted.*" */
+
+#define JFFS2_ACL_VERSION		0x0001
+
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
@@ -157,6 +169,32 @@ struct jffs2_raw_inode
 	uint8_t data[0];
 } __attribute__((packed));
 
+struct jffs2_raw_xattr {
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XATTR */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t xid;		/* XATTR identifier number */
+	uint8_t xprefix;
+	uint8_t name_len;
+	jint16_t value_len;
+	jint32_t data_crc;
+	jint32_t node_crc;
+	uint8_t data[0];
+} __attribute__((packed));
+
+struct jffs2_raw_xref
+{
+	jint16_t magic;
+	jint16_t nodetype;	/* = JFFS2_NODETYPE_XREF */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t seqno;		/* sequencial number */
+	jint32_t ino;		/* inode number */
+	jint32_t xid;		/* XATTR identifier number */
+	jint32_t node_crc;
+} __attribute__((packed));
+
 struct jffs2_raw_summary
 {
 	jint16_t magic;
@@ -191,6 +229,8 @@ union jffs2_node_union
 {
 	struct jffs2_raw_inode i;
 	struct jffs2_raw_dirent d;
+	struct jffs2_raw_xattr x;
+	struct jffs2_raw_xref r;
 	struct jffs2_raw_summary s;
 	struct jffs2_raw_ebh eh;
 	struct jffs2_unknown_node u;
#28 lore raw

Hello KaiGai,

to ease JFFS2 debugging I split debugging messages by subsystems and one may enable/disable debugging messages from each subsystem separately. I wonder, if it is possible to add DBG_XATTR() or the like instead of using D1()? It really makes bugs hunting easier. Please, glance at debug.h.

Thanks.

Signature · 3 lines
Best Regards,
Artem B. Bityutskiy,
St.-Petersburg, Russia.
#29 lore raw

Hello Artem,

Quoted 1 line

to ease JFFS2 debugging I split debugging messages by subsystems and one may enable/disable debugging messages from each subsystem separately. I wonder, if it is possible to add DBG_XATTR() or the like instead of using D1()? It really makes bugs hunting easier. Please, glance at debug.h.

I agree what you say.
There is especially no reason why such a stub macro is not used.

In the next patch, I'll use some stub macros as are defined in debug.h. The following definition will be added in debug.h, and I'll use JFFS2_NOTICE() and so on instead of raw-printk().

/* Watch the XATTR subsystem */
#ifdef JFFS2_DBG_XATTR_MESSAGES
#define dbg_xattr(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else
#define dbg_xattr(fmt, ...)
#endif

Thanks,

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
#30 lore raw
In reply to Artem B. Bityutskiy

Hello, Aterm.

This patch replaces any warning messages by raw-printk() with JFFS2_WARNING()/JFFS2_NOTICE() macros, and any debugging messages are replaced by dbg_xattr() which is newly defined in debug.h.

Please apply this patch after 'jffs2_xattr_take-4.patch' which
I posted at 27-Nov 2005.
Since the whole of those implementation is a bit massive, I post only difference with last time.
If you hope to get the whole of this implementation already patched, please visit http://www.kaigai.gr.jp/ and download 'jffs2_xattr_take-4.1.patch'.

[JFFS2] Provide XATTR and POSIX ACL support on JFFS2
- http://www.kaigai.gr.jp/patch/jffs2_xattr_take-4.1.patch
[JFFS2] Provide --with-{xattr|selinux|posix-acl} options for mkfs.jffs2
- http://www.kaigai.gr.jp/patch/mkfs.jffs2-xattr.patch

Thanks,

Quoted 5 lines · Artem B. Bityutskiy

Hello KaiGai,

to ease JFFS2 debugging I split debugging messages by subsystems and one may enable/disable debugging messages from each subsystem separately. I wonder, if it is possible to add DBG_XATTR() or the like instead of using D1()? It really makes bugs hunting easier. Please, glance at debug.h.

Thanks.

Signature · 1 line
KaiGai Kohei <[email protected]>
fs/jffs2/acl.c +4 -2
diff -prNU3 mtd-20051127.xattr/fs/jffs2/acl.c mtd-20051127.xattr-dbg/fs/jffs2/acl.c
@@ -53,14 +53,16 @@ static struct posix_acl *jffs2_acl_from_
 {
 	const char *end = (char *)value + size;
 	struct posix_acl *acl;
+	uint32_t ver;
 	int i, count;
 
 	if (!value)
 		return NULL;
 	if (size < sizeof(jffs2_acl_header))
 		return ERR_PTR(-EINVAL);
-	if (je32_to_cpu(((jffs2_acl_header *)value)->a_version) != JFFS2_ACL_VERSION) {
-		D1(printk(KERN_NOTICE "%s:%d invalid ACL version.\n", __FUNCTION__, __LINE__));
+	ver = je32_to_cpu(((jffs2_acl_header *)value)->a_version);
+	if (ver != JFFS2_ACL_VERSION) {
+		JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);
 		return ERR_PTR(-EINVAL);
 	}
 
fs/jffs2/debug.h +6 -0
diff -prNU3 mtd-20051127.xattr/fs/jffs2/debug.h mtd-20051127.xattr-dbg/fs/jffs2/debug.h
@@ -171,6 +171,12 @@
 #define dbg_memalloc(fmt, ...)
 #endif
 
+/* Watch the XATTR subsystem */
+#ifdef JFFS2_DBG_XATTR_MESSAGES
+#define dbg_xattr(fmt, ...)  JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_xattr(fmt, ...)
+#endif 
 
 /* "Sanity" checks */
 void
fs/jffs2/scan.c +18 -12
diff -prNU3 mtd-20051127.xattr/fs/jffs2/scan.c mtd-20051127.xattr-dbg/fs/jffs2/scan.c
@@ -329,27 +329,27 @@ static int jffs2_scan_xattr_node(struct 
 
 	crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr)-8);
 	if (crc != je32_to_cpu(rx->node_crc)) {
-		printk(KERN_NOTICE "%s node CRC failed on node at 0x%08x: "
-		       "Read 0x%08x, calculated 0x%08x\n",
-		       __FUNCTION__, ofs, je32_to_cpu(rx->node_crc), crc);
+		JFFS2_WARNING("node CRC failed on node at 0x%08x: "
+			      "Read 0x%08x, calculated 0x%08x\n",
+			      ofs, je32_to_cpu(rx->node_crc), crc);
 		dirty_space(c, jeb, je32_to_cpu(rx->totlen));
 		return 0;
 	}
 
 	xd = jffs2_find_xattr_datum(c, je32_to_cpu(rx->xid));
 	if (xd) {
-		printk(KERN_NOTICE "%s() duplicate xid=%u found. "
-		       "on node at 0x%08x, later one is ignored.\n",
-		       __FUNCTION__, je32_to_cpu(rx->xid), ofs);
+		JFFS2_WARNING("duplicate xid=%u found. "
+			      "on node at 0x%08x, later one is ignored.\n",
+			      je32_to_cpu(rx->xid), ofs);
 		dirty_space(c, jeb, je32_to_cpu(rx->totlen));
 		return 0;
 	}
 
 	crc = crc32(0, rx->data, rx->name_len + 1 + je16_to_cpu(rx->value_len));
 	if (crc != je32_to_cpu(rx->data_crc)) {
-		printk(KERN_NOTICE "%s data CRC failed on node at 0x%08x: "
-		       "Read 0x%08x, calculated 0x%08x\n",
-		       __FUNCTION__, ofs, je32_to_cpu(rx->data_crc), crc);
+		JFFS2_WARNING("data CRC failed on node at 0x%08x: "
+			      "Read 0x%08x, calculated 0x%08x\n",
+			      ofs, je32_to_cpu(rx->data_crc), crc);
 		dirty_space(c, jeb, je32_to_cpu(rx->totlen));
 		return 0;
 	}
@@ -388,6 +388,9 @@ static int jffs2_scan_xattr_node(struct 
 
 	jffs2_attach_xattr_datum(c, xd);
 
+	D2(dbg_xattr("scan JFFS2_NODETYPE_XATTR at %#08x (xid=%u, xprefix=%d)\n",
+		     ofs, xd->xid, xd->xprefix));
+
 	return 0;
 }
 
@@ -400,9 +403,9 @@ static int jffs2_scan_xref_node(struct j
 
 	crc = crc32(0, rr, sizeof(*rr)-4);
 	if (crc != je32_to_cpu(rr->node_crc)) {
-		printk(KERN_NOTICE "%s node CRC failed on node at 0x%08x: "
-		       "Read 0x%08x, calculated 0x%08x\n",
-		       __FUNCTION__, ofs, je32_to_cpu(rr->node_crc), crc);
+		JFFS2_WARNING("node CRC failed on node at 0x%08x: "
+			      "Read 0x%08x, calculated 0x%08x\n",
+			      ofs, je32_to_cpu(rr->node_crc), crc);
 		dirty_space(c, jeb, je32_to_cpu(rr->totlen));
 		return 0;
 	}
@@ -448,6 +451,9 @@ static int jffs2_scan_xref_node(struct j
 
 	list_add_tail(&ref->ilist, &c->xattr_temp);
 
+	D2(dbg_xattr("scan JFFS2_NODETYPE_XREF at %#08x (xid=%u, ino=%u)\n",
+		     ofs, ref->xid, ref->ino));
+
 	return 0;
 }
 #endif
fs/jffs2/xattr.c +35 -31

175 lines not on this page · raw message

#31 lore raw
In reply to Kaigai Kohei

Hi,

The attached patch adds an functionality for mkfs.jffs2.

'-A' or '--with-xattr' enables to stuff up any xattr-imforamations for each files into JFFS2 image file.
This patch depends on 'jffs2_xattr_take-3.patch' I posted on 28-Sep.

In addition, some constants of JFFS2_XPREFIX_* are moved from fs/jffs2/xattr.h to include/linux/jffs2.h, because I want to use those constants in mkfs.jffs2. This change has no effects in kernel-side.

Perhaps, another style like '--with-selinux' or '--with-acl' might be better than '--with-xattr'.

Any comments please,
Thanks.

Quoted 9 lines · Kaigai Kohei

Hi,

I revised the previous xattr patch in jffs2 based on some suggestions.

[1] scanning xattr related node for cleaned-up scan.c. (jffs2_xattr_scan.c-cleanup.patch)
[2] enables xattr support in jffs2.

    (jffs2_xattr_take-3.patch)

(*) We can apply jffs2_xattr_take-3.patch for current CVS independently.

Signature · 2 lines
Linux Promotion Center, NEC
KaiGai Kohei <[email protected]>
fs/jffs2/xattr.c +2 -0
diff -prNU3 mtd-051011.xattr/fs/jffs2/xattr.c mtd-051011.xattr-mkfs/fs/jffs2/xattr.c
@@ -42,6 +42,7 @@ static int do_jffs2_setxattr(struct inod
 			     const char *buffer, size_t size, int flags);
 
 /* ---- XATTR Handler for "user.*" --------------------- */
+#define XATTR_USER_PREFIX	"user."
 static int jffs2_user_getxattr(struct inode *inode, const char *name,
                                void *buffer, size_t size)
 {
@@ -97,6 +98,7 @@ static struct xattr_handler jffs2_user_x
 };
 
 /* ---- XATTR Handler for "trusted.*" ------------------ */
+#define XATTR_TRUSTED_PREFIX	"trusted."
 static int jffs2_trusted_getxattr(struct inode *inode, const char *name,
 				  void *buffer, size_t size)
 {
fs/jffs2/xattr.h +0 -10
diff -prNU3 mtd-051011.xattr/fs/jffs2/xattr.h mtd-051011.xattr-mkfs/fs/jffs2/xattr.h
@@ -14,16 +14,6 @@
 #include <linux/xattr.h>
 
 #define XATTRINDEX_HASHSIZE (57)
-#define XATTR_USER_PREFIX		"user."
-#define XATTR_TRUSTED_PREFIX		"trusted."
-
-#define JFFS2_XPREFIX_USER		1	/* for "user.*" */
-#define JFFS2_XPREFIX_SECURITY		2	/* for "security.*" */
-#define JFFS2_XPREFIX_ACL_ACCESS	3	/* for "system.posix_acl_access" */
-#define JFFS2_XPREFIX_ACL_DEFAULT	4	/* for "system.posix_acl_default" */
-#define JFFS2_XPREFIX_TRUSTED		5	/* for "trusted.*" */
-#define JFFS2_XPREFIX_INVALID		6
-
 #define JFFS2_XDATUM_FLAGS_HOT		0x01	/* This is hot xattr_datum */
 
 #define RAWNODE_CLASS_INODE_CACHE	0
include/linux/jffs2.h +7 -0
diff -prNU3 mtd-051011.xattr/include/linux/jffs2.h mtd-051011.xattr-mkfs/include/linux/jffs2.h
@@ -68,6 +68,13 @@
 #define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
 #define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
 
+/* XATTR Related */
+#define JFFS2_XPREFIX_USER		1	/* for "user." */
+#define JFFS2_XPREFIX_SECURITY		2	/* for "security." */
+#define JFFS2_XPREFIX_ACL_ACCESS	3	/* for "system.posix_acl_access" */
+#define JFFS2_XPREFIX_ACL_DEFAULT	4	/* for "system.posix_acl_default" */
+#define JFFS2_XPREFIX_TRUSTED		5	/* for "trusted.*" */
+
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
util/mkfs.jffs2.1 +6 -0
diff -prNU3 mtd-051011.xattr/util/mkfs.jffs2.1 mtd-051011.xattr-mkfs/util/mkfs.jffs2.1
@@ -49,6 +49,9 @@ mkfs.jffs2 \- Create a JFFS2 file system
 .B -P,--squash-perms
 ]
 [
+.B -A,--with-xattr
+]
+[
 .B -m,--compression-mode=MODE
 ]
 [
@@ -178,6 +181,9 @@ Squash owners making all files be owned 
 .B -P, --squash-perms
 Squash permissions, removing write permission for \'group\' and \'other\'.
 .TP
+.B -A, --with-xattr
+Include XATTR meta information. It's necessary for SELinux or ACL support.
+.TP
 .B -m, --compression-mode=MODE
 Set the default compression mode. The default mode is 
 .B priority 
util/mkfs.jffs2.c +178 -3

273 lines not on this page · raw message