* [PATCH] XATTR support on JFFS2 (version. 5)
@ 2006-05-06 6:51 KaiGai Kohei
2006-05-06 12:07 ` David Woodhouse
` (3 more replies)
0 siblings, 4 replies; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-06 6:51 UTC (permalink / raw)
To: dwmw2, joern, linux-mtd; +Cc: jmorris, sds, lorenzo, russell
[-- Attachment #1: Type: text/plain, Size: 1367 bytes --]
Hello,
This attached patches provide xattr support including POSIX-ACL and
SELinux support on JFFS2 (version.5).
We can apply those patches to the latest git-tree.
- xattr_on_jffs2.kernel.version-5.patch can be applied to mtd-2.6.git.
- xattr_on_jffs2.utils.version-5.patch can be applied to mtd-utils.git.
There are some significant differences from previous version posted
at last December.
The biggest change is addition of EBS(Erase Block Summary) support.
Currently, both kernel and usermode utility (sumtool) can recognize
xattr nodes which have JFFS2_NODETYPE_XATTR/_XREF nodetype.
In addition, some bugs are fixed.
- A potential race condition was fixed.
- Unexpected fail when updating a xattr by same name/value pair was fixed.
- A bug when removing xattr name/value pair was fixed.
The fundamental structures (such as using two new nodetypes and exclusion
mechanism by rwsem) are unchanged. But most of implementation were reviewed
and updated if necessary.
Espacially, we had to change several internal implementations related to
load_xattr_datum() to avoid a potential race condition.
[1/2] xattr_on_jffs2.kernel.version-5.patch
[2/2] xattr_on_jffs2.utils.version-5.patch
Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
We can get those patches from http://www.kaigai.gr.jp/
Any comments please. Thanks,
--
KaiGai Kohei <kaigai@ak.jp.nec.com>
[-- Attachment #2: xattr_on_jffs2.kernel.version-5.patch --]
[-- Type: text/plain, Size: 99399 bytes --]
--- mtd-2.6.git/fs/Kconfig 2006-05-05 03:14:40.000000000 +0900
+++ mtd-2.6.0506/fs/Kconfig 2006-05-06 11:28:19.000000000 +0900
@@ -1075,6 +1075,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"
+ depends on JFFS2_FS
+ 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
--- mtd-2.6.git/fs/jffs2/Makefile 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/Makefile 2006-05-06 12:50:02.000000000 +0900
@@ -12,6 +12,9 @@ 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_FS_XATTR) += xattr.o xattr_trusted.o xattr_user.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
--- mtd-2.6.git/fs/jffs2/acl.c 1970-01-01 09:00:00.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/acl.c 2006-05-06 11:28:19.000000000 +0900
@@ -0,0 +1,483 @@
+/*-------------------------------------------------------------------------*
+ * File: fs/jffs2/acl.c
+ * POSIX ACL support on JFFS2 FileSystem
+ *
+ * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright (C) 2006 NEC Corporation
+ *
+ * For licensing information, see the file 'LICENCE' in the jffs2 directory.
+ *-------------------------------------------------------------------------*/
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/crc32.h>
+#include <linux/jffs2.h>
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/mtd/mtd.h>
+#include "nodelist.h"
+
+static size_t jffs2_acl_size(int count)
+{
+ if (count <= 4) {
+ return sizeof(jffs2_acl_header)
+ + count * sizeof(jffs2_acl_entry_short);
+ } else {
+ return sizeof(jffs2_acl_header)
+ + 4 * sizeof(jffs2_acl_entry_short)
+ + (count - 4) * sizeof(jffs2_acl_entry);
+ }
+}
+
+static int jffs2_acl_count(size_t size)
+{
+ size_t s;
+
+ size -= sizeof(jffs2_acl_header);
+ s = size - 4 * sizeof(jffs2_acl_entry_short);
+ if (s < 0) {
+ if (size % sizeof(jffs2_acl_entry_short))
+ return -1;
+ return size / sizeof(jffs2_acl_entry_short);
+ } else {
+ if (s % sizeof(jffs2_acl_entry))
+ return -1;
+ return s / sizeof(jffs2_acl_entry) + 4;
+ }
+}
+
+static struct posix_acl *jffs2_acl_from_medium(const void *value, size_t size)
+{
+ 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);
+ 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);
+ }
+
+ value = (char *)value + sizeof(jffs2_acl_header);
+ count = jffs2_acl_count(size);
+ if (count < 0)
+ return ERR_PTR(-EINVAL);
+ if (count == 0)
+ return NULL;
+
+ acl = posix_acl_alloc(count, GFP_KERNEL);
+ if (!acl)
+ return ERR_PTR(-ENOMEM);
+
+ for (i=0; i < count; i++) {
+ jffs2_acl_entry *entry = (jffs2_acl_entry *)value;
+ if ((char *)value + sizeof(jffs2_acl_entry_short) > end)
+ goto fail;
+ acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);
+ acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);
+ switch (acl->a_entries[i].e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ value = (char *)value + sizeof(jffs2_acl_entry_short);
+ acl->a_entries[i].e_id = ACL_UNDEFINED_ID;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ value = (char *)value + sizeof(jffs2_acl_entry);
+ if ((char *)value > end)
+ goto fail;
+ acl->a_entries[i].e_id = je32_to_cpu(entry->e_id);
+ break;
+
+ default:
+ goto fail;
+ }
+ }
+ if (value != end)
+ goto fail;
+ return acl;
+ fail:
+ posix_acl_release(acl);
+ return ERR_PTR(-EINVAL);
+}
+
+static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
+{
+ jffs2_acl_header *jffs2_acl;
+ char *e;
+ size_t i;
+
+ *size = jffs2_acl_size(acl->a_count);
+ jffs2_acl = (jffs2_acl_header *)kmalloc(sizeof(jffs2_acl_header)
+ + acl->a_count * sizeof(jffs2_acl_entry),
+ GFP_KERNEL);
+ if (!jffs2_acl)
+ return ERR_PTR(-ENOMEM);
+ jffs2_acl->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
+ e = (char *)jffs2_acl + sizeof(jffs2_acl_header);
+ for (i=0; i < acl->a_count; i++) {
+ jffs2_acl_entry *entry = (jffs2_acl_entry *)e;
+ entry->e_tag = cpu_to_je16(acl->a_entries[i].e_tag);
+ entry->e_perm = cpu_to_je16(acl->a_entries[i].e_perm);
+ switch(acl->a_entries[i].e_tag) {
+ case ACL_USER:
+ case ACL_GROUP:
+ entry->e_id = cpu_to_je32(acl->a_entries[i].e_id);
+ e += sizeof(jffs2_acl_entry);
+ break;
+
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ e += sizeof(jffs2_acl_entry_short);
+ break;
+
+ default:
+ goto fail;
+ }
+ }
+ return (char *)jffs2_acl;
+ fail:
+ kfree(jffs2_acl);
+ return ERR_PTR(-EINVAL);
+}
+
+static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl)
+{
+ struct posix_acl *acl = JFFS2_ACL_NOT_CACHED;
+
+ spin_lock(&inode->i_lock);
+ if (*i_acl != JFFS2_ACL_NOT_CACHED)
+ acl = posix_acl_dup(*i_acl);
+ spin_unlock(&inode->i_lock);
+ return acl;
+}
+
+static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl)
+{
+ spin_lock(&inode->i_lock);
+ if (*i_acl != JFFS2_ACL_NOT_CACHED)
+ posix_acl_release(*i_acl);
+ *i_acl = posix_acl_dup(acl);
+ spin_unlock(&inode->i_lock);
+}
+
+static struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
+{
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct posix_acl *acl;
+ char *value = NULL;
+ int rc, xprefix;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ acl = jffs2_iget_acl(inode, &f->i_acl_access);
+ if (acl != JFFS2_ACL_NOT_CACHED)
+ return acl;
+ xprefix = JFFS2_XPREFIX_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ acl = jffs2_iget_acl(inode, &f->i_acl_default);
+ if (acl != JFFS2_ACL_NOT_CACHED)
+ return acl;
+ xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
+ if (rc > 0) {
+ value = kmalloc(rc, GFP_KERNEL);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+ rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);
+ }
+ if (rc > 0) {
+ acl = jffs2_acl_from_medium(value, rc);
+ } else if (rc == -ENODATA || rc == -ENOSYS) {
+ acl = NULL;
+ } else {
+ acl = ERR_PTR(rc);
+ }
+ if (value)
+ kfree(value);
+ if (!IS_ERR(acl)) {
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ jffs2_iset_acl(inode, &f->i_acl_access, acl);
+ break;
+ case ACL_TYPE_DEFAULT:
+ jffs2_iset_acl(inode, &f->i_acl_default, acl);
+ break;
+ }
+ }
+ return acl;
+}
+
+static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ size_t size = 0;
+ char *value = NULL;
+ int rc, xprefix;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ xprefix = JFFS2_XPREFIX_ACL_ACCESS;
+ if (acl) {
+ mode_t mode = inode->i_mode;
+ rc = posix_acl_equiv_mode(acl, &mode);
+ if (rc < 0)
+ return rc;
+ if (inode->i_mode != mode) {
+ inode->i_mode = mode;
+ jffs2_dirty_inode(inode);
+ }
+ if (rc == 0)
+ acl = NULL;
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+ xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
+ if (!S_ISDIR(inode->i_mode))
+ return acl ? -EACCES : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (acl) {
+ value = jffs2_acl_to_medium(acl, &size);
+ if (IS_ERR(value))
+ return PTR_ERR(value);
+ }
+
+ rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
+ if (value)
+ kfree(value);
+ if (!rc) {
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ jffs2_iset_acl(inode, &f->i_acl_access, acl);
+ break;
+ case ACL_TYPE_DEFAULT:
+ jffs2_iset_acl(inode, &f->i_acl_default, acl);
+ break;
+ }
+ }
+ return rc;
+}
+
+static int jffs2_check_acl(struct inode *inode, int mask)
+{
+ struct posix_acl *acl;
+ int rc;
+
+ acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ rc = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return rc;
+ }
+ return -EAGAIN;
+}
+
+int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ return generic_permission(inode, mask, jffs2_check_acl);
+}
+
+int jffs2_init_acl(struct inode *inode, struct inode *dir)
+{
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct posix_acl *acl = NULL, *clone;
+ mode_t mode;
+ int rc = 0;
+
+ f->i_acl_access = JFFS2_ACL_NOT_CACHED;
+ f->i_acl_default = JFFS2_ACL_NOT_CACHED;
+ if (!S_ISLNK(inode->i_mode)) {
+ acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (!acl)
+ inode->i_mode &= ~current->fs->umask;
+ }
+ if (acl) {
+ if (S_ISDIR(inode->i_mode)) {
+ rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
+ if (rc)
+ goto cleanup;
+ }
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ rc = -ENOMEM;
+ if (!clone)
+ goto cleanup;
+ mode = inode->i_mode;
+ rc = posix_acl_create_masq(clone, &mode);
+ if (rc >= 0) {
+ inode->i_mode = mode;
+ if (rc > 0)
+ rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);
+ }
+ posix_acl_release(clone);
+ }
+ cleanup:
+ posix_acl_release(acl);
+ return rc;
+}
+
+void jffs2_clear_acl(struct inode *inode)
+{
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+
+ if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) {
+ posix_acl_release(f->i_acl_access);
+ f->i_acl_access = JFFS2_ACL_NOT_CACHED;
+ }
+ if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) {
+ posix_acl_release(f->i_acl_default);
+ f->i_acl_default = JFFS2_ACL_NOT_CACHED;
+ }
+}
+
+int jffs2_acl_chmod(struct inode *inode)
+{
+ struct posix_acl *acl, *clone;
+ int rc;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+ acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl) || !acl)
+ return PTR_ERR(acl);
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ posix_acl_release(acl);
+ if (!clone)
+ return -ENOMEM;
+ rc = posix_acl_chmod_masq(clone, inode->i_mode);
+ if (!rc)
+ rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);
+ posix_acl_release(clone);
+ return rc;
+}
+
+static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS);
+
+ if (list && retlen <= list_size)
+ strcpy(list, POSIX_ACL_XATTR_ACCESS);
+ return retlen;
+}
+
+static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT);
+
+ if (list && retlen <= list_size)
+ strcpy(list, POSIX_ACL_XATTR_DEFAULT);
+ return retlen;
+}
+
+static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size)
+{
+ struct posix_acl *acl;
+ int rc;
+
+ acl = jffs2_get_acl(inode, type);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (!acl)
+ return -ENODATA;
+ rc = posix_acl_to_xattr(acl, buffer, size);
+ posix_acl_release(acl);
+
+ return rc;
+}
+
+static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
+{
+ if (name[0] != '\0')
+ return -EINVAL;
+ return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size);
+}
+
+static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size)
+{
+ if (name[0] != '\0')
+ return -EINVAL;
+ return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
+}
+
+static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size)
+{
+ struct posix_acl *acl;
+ int rc;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EPERM;
+
+ if (value) {
+ acl = posix_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ rc = posix_acl_valid(acl);
+ if (rc)
+ goto out;
+ }
+ } else {
+ acl = NULL;
+ }
+ rc = jffs2_set_acl(inode, type, acl);
+ out:
+ posix_acl_release(acl);
+ return rc;
+}
+
+static int jffs2_acl_access_setxattr(struct inode *inode, const char *name,
+ const void *buffer, size_t size, int flags)
+{
+ if (name[0] != '\0')
+ return -EINVAL;
+ return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size);
+}
+
+static int jffs2_acl_default_setxattr(struct inode *inode, const char *name,
+ const void *buffer, size_t size, int flags)
+{
+ if (name[0] != '\0')
+ return -EINVAL;
+ return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size);
+}
+
+struct xattr_handler jffs2_acl_access_xattr_handler = {
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .list = jffs2_acl_access_listxattr,
+ .get = jffs2_acl_access_getxattr,
+ .set = jffs2_acl_access_setxattr,
+};
+
+struct xattr_handler jffs2_acl_default_xattr_handler = {
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .list = jffs2_acl_default_listxattr,
+ .get = jffs2_acl_default_getxattr,
+ .set = jffs2_acl_default_setxattr,
+};
--- mtd-2.6.git/fs/jffs2/acl.h 1970-01-01 09:00:00.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/acl.h 2006-05-06 11:28:19.000000000 +0900
@@ -0,0 +1,46 @@
+/*-------------------------------------------------------------------------*
+ * File: fs/jffs2/acl.h
+ * POSIX ACL support on JFFS2 FileSystem
+ *
+ * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright (C) 2006 NEC Corporation
+ *
+ * For licensing information, see the file 'LICENCE' in the jffs2 directory.
+ *-------------------------------------------------------------------------*/
+typedef struct {
+ jint16_t e_tag;
+ jint16_t e_perm;
+ jint32_t e_id;
+} jffs2_acl_entry;
+
+typedef struct {
+ jint16_t e_tag;
+ jint16_t e_perm;
+} jffs2_acl_entry_short;
+
+typedef struct {
+ jint32_t a_version;
+} jffs2_acl_header;
+
+#ifdef __KERNEL__
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+
+#define JFFS2_ACL_NOT_CACHED ((void *)-1)
+
+extern int jffs2_permission(struct inode *, int, struct nameidata *);
+extern int jffs2_acl_chmod(struct inode *);
+extern int jffs2_init_acl(struct inode *, struct inode *);
+extern void jffs2_clear_acl(struct inode *);
+
+extern struct xattr_handler jffs2_acl_access_xattr_handler;
+extern struct xattr_handler jffs2_acl_default_xattr_handler;
+
+#else
+
+#define jffs2_permission NULL
+#define jffs2_acl_chmod(inode) (0)
+#define jffs2_init_acl(inode,dir) (0)
+#define jffs2_clear_acl(inode)
+
+#endif /* CONFIG_JFFS2_FS_POSIX_ACL */
+#endif /* __KERNEL__ */
--- mtd-2.6.git/fs/jffs2/build.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/build.c 2006-05-06 11:28:19.000000000 +0900
@@ -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;
--- mtd-2.6.git/fs/jffs2/debug.h 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/debug.h 2006-05-06 11:28:19.000000000 +0900
@@ -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
--- mtd-2.6.git/fs/jffs2/dir.c 2006-05-05 03:14:40.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/dir.c 2006-05-06 11:28:19.000000000 +0900
@@ -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
};
/***********************************************************************/
@@ -209,12 +214,15 @@ static int jffs2_create(struct inode *di
ret = jffs2_do_create(c, dir_f, f, ri,
dentry->d_name.name, dentry->d_name.len);
- if (ret) {
- make_bad_inode(inode);
- iput(inode);
- jffs2_free_raw_inode(ri);
- return ret;
- }
+ if (ret)
+ goto fail;
+
+ ret = jffs2_init_security(inode, dir_i);
+ if (ret)
+ goto fail;
+ ret = jffs2_init_acl(inode, dir_i);
+ if (ret)
+ goto fail;
dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
@@ -224,6 +232,12 @@ static int jffs2_create(struct inode *di
D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
return 0;
+
+ fail:
+ make_bad_inode(inode);
+ iput(inode);
+ jffs2_free_raw_inode(ri);
+ return ret;
}
/***********************************************************************/
@@ -374,6 +388,18 @@ static int jffs2_symlink (struct inode *
up(&f->sem);
jffs2_complete_reservation(c);
+
+ ret = jffs2_init_security(inode, dir_i);
+ if (ret) {
+ jffs2_clear_inode(inode);
+ return ret;
+ }
+ ret = jffs2_init_acl(inode, dir_i);
+ if (ret) {
+ jffs2_clear_inode(inode);
+ return ret;
+ }
+
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) {
@@ -504,6 +530,18 @@ static int jffs2_mkdir (struct inode *di
up(&f->sem);
jffs2_complete_reservation(c);
+
+ ret = jffs2_init_security(inode, dir_i);
+ if (ret) {
+ jffs2_clear_inode(inode);
+ return ret;
+ }
+ ret = jffs2_init_acl(inode, dir_i);
+ if (ret) {
+ jffs2_clear_inode(inode);
+ return ret;
+ }
+
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) {
@@ -660,6 +698,18 @@ static int jffs2_mknod (struct inode *di
up(&f->sem);
jffs2_complete_reservation(c);
+
+ ret = jffs2_init_security(inode, dir_i);
+ if (ret) {
+ jffs2_clear_inode(inode);
+ return ret;
+ }
+ ret = jffs2_init_acl(inode, dir_i);
+ if (ret) {
+ jffs2_clear_inode(inode);
+ return ret;
+ }
+
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) {
--- mtd-2.6.git/fs/jffs2/file.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/file.c 2006-05-06 11:28:19.000000000 +0900
@@ -54,7 +54,12 @@ const struct file_operations jffs2_file_
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 =
--- mtd-2.6.git/fs/jffs2/fs.c 2006-05-06 11:27:35.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/fs.c 2006-05-06 11:28:19.000000000 +0900
@@ -185,7 +185,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 && (iattr->ia_valid & ATTR_MODE))
+ rc = jffs2_acl_chmod(dentry->d_inode);
+ return rc;
}
int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
@@ -224,6 +229,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);
}
@@ -497,6 +503,8 @@ int jffs2_do_fill_super(struct super_blo
}
memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
+ jffs2_init_xattr_subsystem(c);
+
if ((ret = jffs2_do_mount_fs(c)))
goto out_inohash;
@@ -531,6 +539,7 @@ int jffs2_do_fill_super(struct super_blo
else
kfree(c->blocks);
out_inohash:
+ jffs2_clear_xattr_subsystem(c);
kfree(c->inocache_list);
out_wbuf:
jffs2_flash_cleanup(c);
--- mtd-2.6.git/fs/jffs2/gc.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/gc.c 2006-05-06 11:28:19.000000000 +0900
@@ -125,6 +125,7 @@ int jffs2_garbage_collect_pass(struct jf
struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *raw;
int ret = 0, inum, nlink;
+ int xattr = 0;
if (down_interruptible(&c->alloc_sem))
return -EINTR;
@@ -138,7 +139,7 @@ int jffs2_garbage_collect_pass(struct jf
the node CRCs etc. Do it now. */
/* checked_ino is protected by the alloc_sem */
- if (c->checked_ino > c->highest_ino) {
+ if (c->checked_ino > c->highest_ino && xattr) {
printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
c->unchecked_size);
jffs2_dbg_dump_block_lists_nolock(c);
@@ -148,6 +149,9 @@ int jffs2_garbage_collect_pass(struct jf
spin_unlock(&c->erase_completion_lock);
+ if (!xattr)
+ xattr = jffs2_verify_xattr(c);
+
spin_lock(&c->inocache_lock);
ic = jffs2_get_ino_cache(c, c->checked_ino++);
@@ -262,6 +266,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. */
--- mtd-2.6.git/fs/jffs2/jffs2_fs_i.h 2006-05-05 03:14:40.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/jffs2_fs_i.h 2006-05-06 11:28:19.000000000 +0900
@@ -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 */
--- mtd-2.6.git/fs/jffs2/jffs2_fs_sb.h 2006-05-05 03:14:40.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/jffs2_fs_sb.h 2006-05-06 11:28:19.000000000 +0900
@@ -115,6 +115,16 @@ struct jffs2_sb_info {
struct jffs2_summary *summary; /* Summary information */
+#ifdef CONFIG_JFFS2_FS_XATTR
+#define XATTRINDEX_HASHSIZE (57)
+ uint32_t highest_xid;
+ struct list_head xattrindex[XATTRINDEX_HASHSIZE];
+ struct list_head xattr_temp;
+ struct list_head xattr_unchecked;
+ 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;
};
--- mtd-2.6.git/fs/jffs2/malloc.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/malloc.c 2006-05-06 11:28:19.000000000 +0900
@@ -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_FS_XATTR
+static kmem_cache_t *xattr_datum_cache;
+static kmem_cache_t *xattr_ref_cache;
+#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_FS_XATTR
+ xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum",
+ sizeof(struct jffs2_xattr_datum),
+ 0, 0, NULL, NULL);
+ if (!xattr_datum_cache)
+ goto err;
+
+ xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref",
+ sizeof(struct jffs2_xattr_ref),
+ 0, 0, NULL, NULL);
+ if (!xattr_ref_cache)
+ 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_FS_XATTR
+ if (xattr_datum_cache)
+ kmem_cache_destroy(xattr_datum_cache);
+ if (xattr_ref_cache)
+ kmem_cache_destroy(xattr_ref_cache);
+#endif
}
struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
@@ -205,3 +231,41 @@ void jffs2_free_inode_cache(struct jffs2
dbg_memalloc("%p\n", x);
kmem_cache_free(inode_cache_slab, x);
}
+
+#ifdef CONFIG_JFFS2_FS_XATTR
+struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void)
+{
+ struct jffs2_xattr_datum *xd;
+ xd = kmem_cache_alloc(xattr_datum_cache, GFP_KERNEL);
+ dbg_memalloc("%p\n", xd);
+
+ memset(xd, 0, sizeof(struct jffs2_xattr_datum));
+ xd->class = RAWNODE_CLASS_XATTR_DATUM;
+ INIT_LIST_HEAD(&xd->xindex);
+ return xd;
+}
+
+void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd)
+{
+ dbg_memalloc("%p\n", xd);
+ kmem_cache_free(xattr_datum_cache, xd);
+}
+
+struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
+{
+ struct jffs2_xattr_ref *ref;
+ ref = kmem_cache_alloc(xattr_ref_cache, GFP_KERNEL);
+ dbg_memalloc("%p\n", ref);
+
+ memset(ref, 0, sizeof(struct jffs2_xattr_ref));
+ ref->class = RAWNODE_CLASS_XATTR_REF;
+ INIT_LIST_HEAD(&ref->ilist);
+ return ref;
+}
+
+void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref)
+{
+ dbg_memalloc("%p\n", ref);
+ kmem_cache_free(xattr_ref_cache, ref);
+}
+#endif
--- mtd-2.6.git/fs/jffs2/nodelist.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/nodelist.c 2006-05-06 11:28:19.000000000 +0900
@@ -938,6 +938,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;
}
--- mtd-2.6.git/fs/jffs2/nodelist.h 2006-05-05 03:14:40.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/nodelist.h 2006-05-06 11:28:19.000000000 +0900
@@ -20,6 +20,8 @@
#include <linux/jffs2.h>
#include "jffs2_fs_sb.h"
#include "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,12 @@ 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 RAWNODE_CLASS_INODE_CACHE 0
+#define RAWNODE_CLASS_XATTR_DATUM 1
+#define RAWNODE_CLASS_XATTR_REF 2
+
#define INOCACHE_HASHSIZE 128
/*
@@ -374,6 +387,12 @@ struct jffs2_node_frag *jffs2_alloc_node
void jffs2_free_node_frag(struct jffs2_node_frag *);
struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
void jffs2_free_inode_cache(struct jffs2_inode_cache *);
+#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
/* gc.c */
int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
--- mtd-2.6.git/fs/jffs2/os-linux.h 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/os-linux.h 2006-05-06 11:28:19.000000000 +0900
@@ -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
}
--- mtd-2.6.git/fs/jffs2/readinode.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/readinode.c 2006-05-06 11:28:19.000000000 +0900
@@ -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) {
--- mtd-2.6.git/fs/jffs2/scan.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/scan.c 2006-05-06 11:28:19.000000000 +0900
@@ -306,6 +306,136 @@ int jffs2_scan_classify_jeb(struct jffs2
return BLK_STATE_ALLDIRTY;
}
+#ifdef CONFIG_JFFS2_FS_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_summary *s)
+{
+ struct jffs2_xattr_datum *xd;
+ struct jffs2_raw_node_ref *raw;
+ uint32_t totlen, crc;
+
+ crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4);
+ if (crc != je32_to_cpu(rx->node_crc)) {
+ if (je32_to_cpu(rx->node_crc) != 0xffffffff)
+ JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+ ofs, je32_to_cpu(rx->node_crc), crc);
+ DIRTY_SPACE(je32_to_cpu(rx->totlen));
+ return 0;
+ }
+
+ totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len));
+ if (totlen != je32_to_cpu(rx->totlen)) {
+ JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
+ ofs, je32_to_cpu(rx->totlen), totlen);
+ DIRTY_SPACE(je32_to_cpu(rx->totlen));
+ return 0;
+ }
+
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw)
+ return -ENOMEM;
+
+ xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version));
+ if (IS_ERR(xd)) {
+ jffs2_free_raw_node_ref(raw);
+ if (PTR_ERR(xd) == -EEXIST) {
+ DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen)));
+ return 0;
+ }
+ return PTR_ERR(xd);
+ }
+ xd->xprefix = rx->xprefix;
+ xd->name_len = rx->name_len;
+ xd->value_len = je16_to_cpu(rx->value_len);
+ xd->data_crc = je32_to_cpu(rx->data_crc);
+ xd->node = raw;
+
+ raw->__totlen = totlen;
+ raw->flash_offset = ofs | REF_PRISTINE;
+ raw->next_phys = NULL;
+ raw->next_in_ino = (void *)xd;
+ 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)));
+ if (jffs2_sum_active())
+ jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset);
+ dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n",
+ ofs, xd->xid, xd->version);
+ 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_summary *s)
+{
+ struct jffs2_xattr_ref *ref;
+ struct jffs2_raw_node_ref *raw;
+ uint32_t crc;
+
+ crc = crc32(0, rr, sizeof(*rr) - 4);
+ if (crc != je32_to_cpu(rr->node_crc)) {
+ if (je32_to_cpu(rr->node_crc) != 0xffffffff)
+ JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+ ofs, je32_to_cpu(rr->node_crc), crc);
+ DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen)));
+ return 0;
+ }
+
+ if (PAD(sizeof(struct jffs2_raw_xref)) != je32_to_cpu(rr->totlen)) {
+ JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n",
+ ofs, je32_to_cpu(rr->totlen),
+ PAD(sizeof(struct jffs2_raw_xref)));
+ DIRTY_SPACE(je32_to_cpu(rr->totlen));
+ return 0;
+ }
+
+ ref = jffs2_alloc_xattr_ref();
+ if (!ref)
+ return -ENOMEM;
+
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw) {
+ jffs2_free_xattr_ref(ref);
+ return -ENOMEM;
+ }
+
+ /* BEFORE jffs2_build_xattr_subsystem() called,
+ * ref->xid is used to store 32bit xid, xd is not used
+ * ref->ino is used to store 32bit inode-number, ic is not used
+ * Thoes variables are declared as union, thus using those
+ * are exclusive. In a similar way, ref->ilist is temporarily
+ * used to chain all xattr_ref object. It's re-chained to
+ * jffs2_inode_cache in jffs2_build_xattr_subsystem() correctly.
+ */
+ ref->node = raw;
+ ref->ino = je32_to_cpu(rr->ino);
+ ref->xid = je32_to_cpu(rr->xid);
+ list_add_tail(&ref->ilist, &c->xattr_temp);
+
+ raw->__totlen = PAD(je32_to_cpu(rr->totlen));
+ raw->flash_offset = ofs | REF_PRISTINE;
+ raw->next_phys = NULL;
+ raw->next_in_ino = (void *)ref;
+ 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(rr->totlen)));
+ if (jffs2_sum_active())
+ jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset);
+ dbg_xattr("scan xref at %#08x (xid=%u, ino=%u)\n",
+ ofs, ref->xid, ref->ino);
+ return 0;
+}
+#endif
+
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
struct jffs2_unknown_node *node;
@@ -614,6 +744,43 @@ scan_more:
ofs += PAD(je32_to_cpu(node->totlen));
break;
+#ifdef CONFIG_JFFS2_FS_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, s);
+ 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, s);
+ if (err)
+ return err;
+ ofs += PAD(je32_to_cpu(node->totlen));
+ break;
+#endif /* CONFIG_JFFS2_FS_XATTR */
+
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) {
@@ -721,6 +888,7 @@ struct jffs2_inode_cache *jffs2_scan_mak
ic->ino = ino;
ic->nodes = (void *)ic;
+ init_xattr_inode_cache(ic);
jffs2_add_ino_cache(c, ic);
if (ino == 1)
ic->nlink = 1;
--- mtd-2.6.git/fs/jffs2/security.c 1970-01-01 09:00:00.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/security.c 2006-05-06 11:28:19.000000000 +0900
@@ -0,0 +1,82 @@
+/*-------------------------------------------------------------------------*
+ * File: fs/jffs2/security.c
+ * Security Labels support on JFFS2 FileSystem
+ *
+ * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright (C) 2006 NEC Corporation
+ *
+ * For licensing information, see the file 'LICENCE' in the jffs2 directory.
+ *-------------------------------------------------------------------------*/
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/crc32.h>
+#include <linux/jffs2.h>
+#include <linux/xattr.h>
+#include <linux/mtd/mtd.h>
+#include <linux/security.h>
+#include "nodelist.h"
+
+/* ---- Initial Security Label Attachment -------------- */
+int jffs2_init_security(struct inode *inode, struct inode *dir)
+{
+ int rc;
+ size_t len;
+ void *value;
+ char *name;
+
+ rc = security_inode_init_security(inode, dir, &name, &value, &len);
+ if (rc) {
+ if (rc == -EOPNOTSUPP)
+ return 0;
+ return rc;
+ }
+ rc = do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, value, len, 0);
+
+ kfree(name);
+ kfree(value);
+ return rc;
+}
+
+/* ---- XATTR Handler for "security.*" ----------------- */
+static int jffs2_security_getxattr(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (!strcmp(name, ""))
+ return -EINVAL;
+
+ return do_jffs2_getxattr(inode, JFFS2_XPREFIX_SECURITY, name, buffer, size);
+}
+
+static int jffs2_security_setxattr(struct inode *inode, const char *name, const void *buffer,
+ size_t size, int flags)
+{
+ if (!strcmp(name, ""))
+ return -EINVAL;
+
+ return do_jffs2_setxattr(inode, JFFS2_XPREFIX_SECURITY, name, buffer, size, flags);
+}
+
+static size_t jffs2_security_listxattr(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1;
+
+ if (list && retlen <= list_size) {
+ strcpy(list, XATTR_SECURITY_PREFIX);
+ strcpy(list + XATTR_SECURITY_PREFIX_LEN, name);
+ }
+
+ return retlen;
+}
+
+struct xattr_handler jffs2_security_xattr_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .list = jffs2_security_listxattr,
+ .set = jffs2_security_setxattr,
+ .get = jffs2_security_getxattr
+};
--- mtd-2.6.git/fs/jffs2/summary.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/summary.c 2006-05-06 11:28:19.000000000 +0900
@@ -5,6 +5,7 @@
* Zoltan Sogor <weth@inf.u-szeged.hu>,
* Patrik Kluba <pajko@halom.u-szeged.hu>,
* University of Szeged, Hungary
+ * 2005 KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
@@ -81,6 +82,19 @@ static int jffs2_sum_add_mem(struct jffs
dbg_summary("dirent (%u) added to summary\n",
je32_to_cpu(item->d.ino));
break;
+#ifdef CONFIG_JFFS2_FS_XATTR
+ case JFFS2_NODETYPE_XATTR:
+ s->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
+ s->sum_num++;
+ dbg_summary("xattr (xid=%u, version=%u) added to summary\n",
+ je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version));
+ break;
+ case JFFS2_NODETYPE_XREF:
+ s->sum_size += JFFS2_SUMMARY_XREF_SIZE;
+ s->sum_num++;
+ dbg_summary("xref added to summary\n");
+ break;
+#endif
default:
JFFS2_WARNING("UNKNOWN node type %u\n",
je16_to_cpu(item->u.nodetype));
@@ -141,6 +155,40 @@ int jffs2_sum_add_dirent_mem(struct jffs
return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
}
+#ifdef CONFIG_JFFS2_FS_XATTR
+int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs)
+{
+ struct jffs2_sum_xattr_mem *temp;
+
+ temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+
+ temp->nodetype = rx->nodetype;
+ temp->xid = rx->xid;
+ temp->version = rx->version;
+ temp->offset = cpu_to_je32(ofs);
+ temp->totlen = rx->totlen;
+ temp->next = NULL;
+
+ return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
+}
+
+int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs)
+{
+ struct jffs2_sum_xref_mem *temp;
+
+ temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+
+ temp->nodetype = rr->nodetype;
+ temp->offset = cpu_to_je32(ofs);
+ temp->next = NULL;
+
+ return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
+}
+#endif
/* Cleanup every collected summary information */
static void jffs2_sum_clean_collected(struct jffs2_summary *s)
@@ -259,7 +307,40 @@ int jffs2_sum_add_kvec(struct jffs2_sb_i
return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
}
+#ifdef CONFIG_JFFS2_FS_XATTR
+ case JFFS2_NODETYPE_XATTR: {
+ struct jffs2_sum_xattr_mem *temp;
+ if (je32_to_cpu(node->x.version) == 0xffffffff)
+ return 0;
+ temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
+ if (!temp)
+ goto no_mem;
+ temp->nodetype = node->x.nodetype;
+ temp->xid = node->x.xid;
+ temp->version = node->x.version;
+ temp->totlen = node->x.totlen;
+ temp->offset = cpu_to_je32(ofs);
+ temp->next = NULL;
+
+ return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
+ }
+ case JFFS2_NODETYPE_XREF: {
+ struct jffs2_sum_xref_mem *temp;
+
+ if (je32_to_cpu(node->r.ino) == 0xffffffff
+ && je32_to_cpu(node->r.xid) == 0xffffffff)
+ return 0;
+ temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
+ if (!temp)
+ goto no_mem;
+ temp->nodetype = node->r.nodetype;
+ temp->offset = cpu_to_je32(ofs);
+ temp->next = NULL;
+
+ return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
+ }
+#endif
case JFFS2_NODETYPE_PADDING:
dbg_summary("node PADDING\n");
c->summary->sum_padded += je32_to_cpu(node->u.totlen);
@@ -408,8 +489,94 @@ static int jffs2_sum_process_sum_data(st
break;
}
+#ifdef CONFIG_JFFS2_FS_XATTR
+ case JFFS2_NODETYPE_XATTR: {
+ struct jffs2_xattr_datum *xd;
+ struct jffs2_sum_xattr_flash *spx;
+ uint32_t ofs;
+
+ spx = (struct jffs2_sum_xattr_flash *)sp;
+ ofs = jeb->offset + je32_to_cpu(spx->offset);
+ dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", ofs,
+ je32_to_cpu(spx->xid), je32_to_cpu(spx->version));
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw) {
+ JFFS2_NOTICE("allocation of node reference failed\n");
+ kfree(summary);
+ return -ENOMEM;
+ }
+ xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
+ je32_to_cpu(spx->version));
+ if (IS_ERR(xd)) {
+ JFFS2_NOTICE("allocation of xattr_datum failed\n");
+ jffs2_free_raw_node_ref(raw);
+ kfree(summary);
+ return PTR_ERR(xd);
+ }
+ xd->node = raw;
+
+ raw->flash_offset = ofs | REF_UNCHECKED;
+ raw->__totlen = PAD(je32_to_cpu(spx->totlen));
+ raw->next_phys = NULL;
+ raw->next_in_ino = (void *)xd;
+ if (!jeb->first_node)
+ jeb->first_node = raw;
+ if (jeb->last_node)
+ jeb->last_node->next_phys = raw;
+ jeb->last_node = raw;
+
+ *pseudo_random += je32_to_cpu(spx->xid);
+ UNCHECKED_SPACE(je32_to_cpu(spx->totlen));
+ sp += JFFS2_SUMMARY_XATTR_SIZE;
+
+ break;
+ }
+ case JFFS2_NODETYPE_XREF: {
+ struct jffs2_xattr_ref *ref;
+ struct jffs2_sum_xref_flash *spr;
+ uint32_t ofs;
+
+ spr = (struct jffs2_sum_xref_flash *)sp;
+ ofs = jeb->offset + je32_to_cpu(spr->offset);
+ dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs,
+ je32_to_cpu(spr->xid), je32_to_cpu(spr->ino));
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw) {
+ JFFS2_NOTICE("allocation of node reference failed\n");
+ kfree(summary);
+ return -ENOMEM;
+ }
+ ref = jffs2_alloc_xattr_ref();
+ if (!ref) {
+ JFFS2_NOTICE("allocation of xattr_datum failed\n");
+ jffs2_free_raw_node_ref(raw);
+ kfree(summary);
+ return -ENOMEM;
+ }
+ ref->ino = 0xfffffffe;
+ ref->xid = 0xfffffffd;
+ ref->node = raw;
+ list_add_tail(&ref->ilist, &c->xattr_temp);
+ raw->__totlen = PAD(sizeof(struct jffs2_raw_xref));
+ raw->flash_offset = ofs | REF_UNCHECKED;
+ raw->next_phys = NULL;
+ raw->next_in_ino = (void *)ref;
+ if (!jeb->first_node)
+ jeb->first_node = raw;
+ if (jeb->last_node)
+ jeb->last_node->next_phys = raw;
+ jeb->last_node = raw;
+
+ UNCHECKED_SPACE(PAD(sizeof(struct jffs2_raw_xref)));
+ *pseudo_random += ofs;
+ sp += JFFS2_SUMMARY_XREF_SIZE;
+
+ break;
+ }
+#endif
default : {
+printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype));
JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
kfree(summary);
return -EIO;
@@ -616,7 +783,31 @@ static int jffs2_sum_write_data(struct j
break;
}
+#ifdef CONFIG_JFFS2_FS_XATTR
+ case JFFS2_NODETYPE_XATTR: {
+ struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
+
+ temp = c->summary->sum_list_head;
+ sxattr_ptr->nodetype = temp->x.nodetype;
+ sxattr_ptr->xid = temp->x.xid;
+ sxattr_ptr->version = temp->x.version;
+ sxattr_ptr->offset = temp->x.offset;
+ sxattr_ptr->totlen = temp->x.totlen;
+
+ wpage += JFFS2_SUMMARY_XATTR_SIZE;
+ break;
+ }
+ case JFFS2_NODETYPE_XREF: {
+ struct jffs2_sum_xref_flash *sxref_ptr = wpage;
+
+ temp = c->summary->sum_list_head;
+ sxref_ptr->nodetype = temp->r.nodetype;
+ sxref_ptr->offset = temp->r.offset;
+ wpage += JFFS2_SUMMARY_XREF_SIZE;
+ break;
+ }
+#endif
default : {
BUG(); /* unknown node in summary information */
}
--- mtd-2.6.git/fs/jffs2/summary.h 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/summary.h 2006-05-06 11:28:19.000000000 +0900
@@ -45,6 +45,8 @@
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
+#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
/* Summary structures used on flash */
@@ -75,11 +77,28 @@ struct jffs2_sum_dirent_flash
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
+struct jffs2_sum_xattr_flash
+{
+ jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */
+ jint32_t xid; /* xattr identifier */
+ jint32_t version; /* version number */
+ jint32_t offset; /* offset on jeb */
+ jint32_t totlen; /* node length */
+} __attribute__((packed));
+
+struct jffs2_sum_xref_flash
+{
+ jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */
+ jint32_t offset; /* offset on jeb */
+} __attribute__((packed));
+
union jffs2_sum_flash
{
struct jffs2_sum_unknown_flash u;
struct jffs2_sum_inode_flash i;
struct jffs2_sum_dirent_flash d;
+ struct jffs2_sum_xattr_flash x;
+ struct jffs2_sum_xref_flash r;
};
/* Summary structures used in the memory */
@@ -114,11 +133,30 @@ struct jffs2_sum_dirent_mem
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
+struct jffs2_sum_xattr_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype;
+ jint32_t xid;
+ jint32_t version;
+ jint32_t offset;
+ jint32_t totlen;
+} __attribute__((packed));
+
+struct jffs2_sum_xref_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype;
+ jint32_t offset;
+} __attribute__((packed));
+
union jffs2_sum_mem
{
struct jffs2_sum_unknown_mem u;
struct jffs2_sum_inode_mem i;
struct jffs2_sum_dirent_mem d;
+ struct jffs2_sum_xattr_mem x;
+ struct jffs2_sum_xref_mem r;
};
/* Summary related information stored in superblock */
@@ -159,6 +197,8 @@ int jffs2_sum_write_sumnode(struct jffs2
int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
+int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs);
+int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs);
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t ofs, uint32_t *pseudo_random);
@@ -176,6 +216,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_
#define jffs2_sum_add_padding_mem(a,b)
#define jffs2_sum_add_inode_mem(a,b,c)
#define jffs2_sum_add_dirent_mem(a,b,c)
+#define jffs2_sum_add_xattr_mem(a,b,c)
+#define jffs2_sum_add_xref_mem(a,b,c)
#define jffs2_sum_scan_sumnode(a,b,c,d) (0)
#endif /* CONFIG_JFFS2_SUMMARY */
--- mtd-2.6.git/fs/jffs2/super.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/super.c 2006-05-06 11:28:19.000000000 +0900
@@ -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_SILENT ? 1 : 0);
if (ret) {
@@ -293,6 +296,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);
--- mtd-2.6.git/fs/jffs2/symlink.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/symlink.c 2006-05-06 11:28:19.000000000 +0900
@@ -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)
--- mtd-2.6.git/fs/jffs2/write.c 2006-04-30 18:06:51.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/write.c 2006-05-06 11:28:19.000000000 +0900
@@ -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));
--- mtd-2.6.git/fs/jffs2/xattr.c 1970-01-01 09:00:00.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/xattr.c 2006-05-06 11:28:19.000000000 +0900
@@ -0,0 +1,1271 @@
+/* -------------------------------------------------------------------------
+ * File: fs/jffs2/xattr.c
+ * XATTR support on JFFS2 FileSystem
+ *
+ * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright (C) 2006 NEC Corporation
+ *
+ * For licensing information, see the file 'LICENCE' in the jffs2 directory.
+ * ------------------------------------------------------------------------- */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/crc32.h>
+#include <linux/jffs2.h>
+#include <linux/xattr.h>
+#include <linux/mtd/mtd.h>
+#include "nodelist.h"
+/* -------- xdatum related functions ----------------
+ * xattr_datum_hashkey(xprefix, xname, xvalue, xsize)
+ * is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is
+ * the index of the xattr name/value pair cache (c->xattrindex).
+ * unload_xattr_datum(c, xd)
+ * is used to release xattr name/value pair and detach from c->xattrindex.
+ * reclaim_xattr_datum(c)
+ * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when
+ * memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold
+ * is hard coded as 32KiB.
+ * delete_xattr_datum_node(c, xd)
+ * is used to delete a jffs2 node is dominated by xdatum. When EBS(Erase Block Summary) is
+ * enabled, it overwrites the obsolete node by myself.
+ * delete_xattr_datum(c, xd)
+ * is used to delete jffs2_xattr_datum object. It must be called with 0-value of reference
+ * counter. (It means how many jffs2_xattr_ref object refers this xdatum.)
+ * do_verify_xattr_datum(c, xd)
+ * is used to load the xdatum informations without name/value pair from the medium.
+ * It's necessary once, because those informations are not collected during mounting
+ * process when EBS is enabled.
+ * 0 will be returned, if success. An negative return value means recoverable error, and
+ * positive return value means unrecoverable error. Thus, caller must remove this xdatum
+ * and xref when it returned positive value.
+ * do_load_xattr_datum(c, xd)
+ * is used to load name/value pair from the medium.
+ * The meanings of return value is same as do_verify_xattr_datum().
+ * load_xattr_datum(c, xd)
+ * is used to be as a wrapper of do_verify_xattr_datum() and do_load_xattr_datum().
+ * If xd need to call do_verify_xattr_datum() at first, it's called before calling
+ * do_load_xattr_datum(). The meanings of return value is same as do_verify_xattr_datum().
+ * save_xattr_datum(c, xd, phys_ofs)
+ * is used to write xdatum to medium. xd->version will be incremented.
+ * create_xattr_datum(c, xprefix, xname, xvalue, xsize, phys_ofs)
+ * is used to create new xdatum and write to medium.
+ * -------------------------------------------------- */
+
+static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
+{
+ int name_len = strlen(xname);
+
+ return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize);
+}
+
+static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+ /* must be called under down_write(xattr_sem) */
+ D1(dbg_xattr("%s: xid=%u, version=%u\n", __FUNCTION__, xd->xid, xd->version));
+ if (xd->xname) {
+ c->xdatum_mem_usage -= (xd->name_len + 1 + xd->value_len);
+ kfree(xd->xname);
+ }
+
+ list_del_init(&xd->xindex);
+ xd->hashkey = 0;
+ xd->xname = NULL;
+ xd->xvalue = NULL;
+}
+
+static void reclaim_xattr_datum(struct jffs2_sb_info *c)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_xattr_datum *xd, *_xd;
+ uint32_t target, before;
+ static int index = 0;
+ int count;
+
+ if (c->xdatum_mem_threshold > c->xdatum_mem_usage)
+ return;
+
+ before = c->xdatum_mem_usage;
+ target = c->xdatum_mem_usage * 4 / 5; /* 20% reduction */
+ for (count = 0; count < XATTRINDEX_HASHSIZE; count++) {
+ list_for_each_entry_safe(xd, _xd, &c->xattrindex[index], xindex) {
+ if (xd->flags & JFFS2_XFLAGS_HOT) {
+ xd->flags &= ~JFFS2_XFLAGS_HOT;
+ } else if (!(xd->flags & JFFS2_XFLAGS_BIND)) {
+ unload_xattr_datum(c, xd);
+ }
+ if (c->xdatum_mem_usage <= target)
+ goto out;
+ }
+ index = (index+1) % XATTRINDEX_HASHSIZE;
+ }
+ out:
+ JFFS2_NOTICE("xdatum_mem_usage from %u byte to %u byte (%u byte reclaimed)\n",
+ before, c->xdatum_mem_usage, before - c->xdatum_mem_usage);
+}
+
+static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_raw_xattr rx;
+ uint32_t length;
+ int rc;
+
+ if (!xd->node) {
+ JFFS2_WARNING("xdatum (xid=%u) is removed twice.\n", xd->xid);
+ return;
+ }
+ if (jffs2_sum_active()) {
+ memset(&rx, 0xff, sizeof(struct jffs2_raw_xattr));
+ rc = jffs2_flash_read(c, ref_offset(xd->node),
+ sizeof(struct jffs2_unknown_node),
+ &length, (char *)&rx);
+ if (rc || length != sizeof(struct jffs2_unknown_node)) {
+ JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n",
+ rc, sizeof(struct jffs2_unknown_node),
+ length, ref_offset(xd->node));
+ }
+ rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx),
+ &length, (char *)&rx);
+ if (rc || length != sizeof(struct jffs2_raw_xattr)) {
+ JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u ar %#08x\n",
+ rc, sizeof(rx), length, ref_offset(xd->node));
+ }
+ }
+ spin_lock(&c->erase_completion_lock);
+ xd->node->next_in_ino = NULL;
+ spin_unlock(&c->erase_completion_lock);
+ jffs2_mark_node_obsolete(c, xd->node);
+ xd->node = NULL;
+}
+
+static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+ /* must be called under down_write(xattr_sem) */
+ BUG_ON(xd->refcnt);
+
+ unload_xattr_datum(c, xd);
+ if (xd->node) {
+ delete_xattr_datum_node(c, xd);
+ xd->node = NULL;
+ }
+ jffs2_free_xattr_datum(xd);
+}
+
+static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_eraseblock *jeb;
+ struct jffs2_raw_xattr rx;
+ size_t readlen;
+ uint32_t crc, totlen;
+ int rc;
+
+ BUG_ON(!xd->node);
+ BUG_ON(ref_flags(xd->node) != REF_UNCHECKED);
+
+ rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx);
+ if (rc || readlen != sizeof(rx)) {
+ JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n",
+ rc, sizeof(rx), readlen, ref_offset(xd->node));
+ return rc ? rc : -EIO;
+ }
+ crc = crc32(0, &rx, sizeof(rx) - 4);
+ if (crc != je32_to_cpu(rx.node_crc)) {
+ if (je32_to_cpu(rx.node_crc) != 0xffffffff)
+ JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+ ref_offset(xd->node), je32_to_cpu(rx.hdr_crc), crc);
+ return EIO;
+ }
+ totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
+ if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
+ || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR
+ || je32_to_cpu(rx.totlen) != totlen
+ || je32_to_cpu(rx.xid) != xd->xid
+ || je32_to_cpu(rx.version) != xd->version) {
+ JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, "
+ "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n",
+ ref_offset(xd->node), je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK,
+ je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR,
+ je32_to_cpu(rx.totlen), totlen,
+ je32_to_cpu(rx.xid), xd->xid,
+ je32_to_cpu(rx.version), xd->version);
+ return EIO;
+ }
+ xd->xprefix = rx.xprefix;
+ xd->name_len = rx.name_len;
+ xd->value_len = je16_to_cpu(rx.value_len);
+ xd->data_crc = je32_to_cpu(rx.data_crc);
+
+ /* This JFFS2_NODETYPE_XATTR node is checked */
+ jeb = &c->blocks[ref_offset(xd->node) / c->sector_size];
+ totlen = PAD(je32_to_cpu(rx.totlen));
+
+ spin_lock(&c->erase_completion_lock);
+ c->unchecked_size -= totlen; c->used_size += totlen;
+ jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+ xd->node->flash_offset = ref_offset(xd->node) | REF_PRISTINE;
+ spin_unlock(&c->erase_completion_lock);
+
+ /* unchecked xdatum is chained with c->xattr_unchecked */
+ list_del_init(&xd->xindex);
+
+ dbg_xattr("success on verfying xdatum (xid=%u, version=%u)\n",
+ xd->xid, xd->version);
+
+ return 0;
+}
+
+static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+ /* must be called under down_write(xattr_sem) */
+ char *data;
+ size_t readlen;
+ uint32_t crc, length;
+ int i, ret, retry = 0;
+
+ BUG_ON(!xd->node);
+ BUG_ON(ref_flags(xd->node) != REF_PRISTINE);
+ BUG_ON(!list_empty(&xd->xindex));
+ retry:
+ length = xd->name_len + 1 + xd->value_len;
+ data = kmalloc(length, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = jffs2_flash_read(c, ref_offset(xd->node)+sizeof(struct jffs2_raw_xattr),
+ length, &readlen, data);
+
+ if (ret || length!=readlen) {
+ JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%d, at %#08x\n",
+ ret, length, readlen, ref_offset(xd->node));
+ kfree(data);
+ return ret ? ret : -EIO;
+ }
+
+ data[xd->name_len] = '\0';
+ crc = crc32(0, data, length);
+ if (crc != xd->data_crc) {
+ JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XREF)"
+ " at %#08x, read: 0x%08x calculated: 0x%08x\n",
+ ref_offset(xd->node), xd->data_crc, crc);
+ kfree(data);
+ return EIO;
+ }
+
+ xd->flags |= JFFS2_XFLAGS_HOT;
+ xd->xname = data;
+ xd->xvalue = data + xd->name_len+1;
+
+ c->xdatum_mem_usage += length;
+
+ xd->hashkey = xattr_datum_hashkey(xd->xprefix, xd->xname, xd->xvalue, xd->value_len);
+ i = xd->hashkey % XATTRINDEX_HASHSIZE;
+ list_add(&xd->xindex, &c->xattrindex[i]);
+ if (!retry) {
+ retry = 1;
+ reclaim_xattr_datum(c);
+ if (!xd->xname)
+ goto retry;
+ }
+
+ dbg_xattr("success on loading xdatum (xid=%u, xprefix=%u, xname='%s')\n",
+ xd->xid, xd->xprefix, xd->xname);
+
+ return 0;
+}
+
+static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+{
+ /* must be called under down_write(xattr_sem);
+ * rc < 0 : recoverable error, try again
+ * rc = 0 : success
+ * rc > 0 : Unrecoverable error, this node should be deleted.
+ */
+ int rc = 0;
+ BUG_ON(xd->xname);
+ if (!xd->node)
+ return EIO;
+ if (unlikely(ref_flags(xd->node) != REF_PRISTINE)) {
+ rc = do_verify_xattr_datum(c, xd);
+ if (rc > 0) {
+ list_del_init(&xd->xindex);
+ delete_xattr_datum_node(c, xd);
+ }
+ }
+ if (!rc)
+ rc = do_load_xattr_datum(c, xd);
+ return rc;
+}
+
+static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, uint32_t phys_ofs)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_raw_xattr rx;
+ struct jffs2_raw_node_ref *raw;
+ struct kvec vecs[2];
+ uint32_t length;
+ int rc, totlen;
+
+ BUG_ON(!xd->xname);
+
+ vecs[0].iov_base = ℞
+ vecs[0].iov_len = PAD(sizeof(rx));
+ vecs[1].iov_base = xd->xname;
+ vecs[1].iov_len = xd->name_len + 1 + xd->value_len;
+ totlen = vecs[0].iov_len + vecs[1].iov_len;
+
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw)
+ return -ENOMEM;
+ raw->flash_offset = phys_ofs;
+ raw->__totlen = PAD(totlen);
+ raw->next_phys = NULL;
+ raw->next_in_ino = (void *)xd;
+
+ /* Setup raw-xattr */
+ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
+ rx.totlen = cpu_to_je32(PAD(totlen));
+ rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
+
+ rx.xid = cpu_to_je32(xd->xid);
+ rx.version = cpu_to_je32(++xd->version);
+ rx.xprefix = xd->xprefix;
+ rx.name_len = xd->name_len;
+ rx.value_len = cpu_to_je16(xd->value_len);
+ rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len));
+ rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4));
+
+ rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0);
+ if (rc || totlen != length) {
+ JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%u, at %#08x\n",
+ rc, totlen, length, phys_ofs);
+ rc = rc ? rc : -EIO;
+ if (length) {
+ raw->flash_offset |= REF_OBSOLETE;
+ raw->next_in_ino = NULL;
+ jffs2_add_physical_node_ref(c, raw);
+ jffs2_mark_node_obsolete(c, raw);
+ } else {
+ jffs2_free_raw_node_ref(raw);
+ }
+ return rc;
+ }
+ BUG_ON(raw->__totlen < sizeof(struct jffs2_raw_xattr));
+ /* success */
+ raw->flash_offset |= REF_PRISTINE;
+ jffs2_add_physical_node_ref(c, raw);
+ if (xd->node)
+ delete_xattr_datum_node(c, xd);
+ xd->node = raw;
+
+ dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n",
+ xd->xid, xd->version, xd->xprefix, xd->xname);
+
+ return 0;
+}
+
+static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c,
+ int xprefix, const char *xname,
+ const char *xvalue, int xsize,
+ uint32_t phys_ofs)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_xattr_datum *xd;
+ uint32_t hashkey, name_len;
+ char *data;
+ int i, rc;
+
+ /* Search xattr_datum has same xname/xvalue by index */
+ hashkey = xattr_datum_hashkey(xprefix, xname, xvalue, xsize);
+ i = hashkey % XATTRINDEX_HASHSIZE;
+ list_for_each_entry(xd, &c->xattrindex[i], xindex) {
+ if (xd->hashkey==hashkey
+ && xd->xprefix==xprefix
+ && xd->value_len==xsize
+ && !strcmp(xd->xname, xname)
+ && !memcmp(xd->xvalue, xvalue, xsize)) {
+ xd->refcnt++;
+ return xd;
+ }
+ }
+
+ /* Not found, Create NEW XATTR-Cache */
+ name_len = strlen(xname);
+
+ xd = jffs2_alloc_xattr_datum();
+ if (!xd)
+ return ERR_PTR(-ENOMEM);
+
+ data = kmalloc(name_len + 1 + xsize, GFP_KERNEL);
+ if (!data) {
+ jffs2_free_xattr_datum(xd);
+ return ERR_PTR(-ENOMEM);
+ }
+ strcpy(data, xname);
+ memcpy(data + name_len + 1, xvalue, xsize);
+
+ xd->refcnt = 1;
+ xd->xid = ++c->highest_xid;
+ xd->flags |= JFFS2_XFLAGS_HOT;
+ xd->xprefix = xprefix;
+
+ xd->hashkey = hashkey;
+ xd->xname = data;
+ xd->xvalue = data + name_len + 1;
+ xd->name_len = name_len;
+ xd->value_len = xsize;
+ xd->data_crc = crc32(0, data, xd->name_len + 1 + xd->value_len);
+
+ rc = save_xattr_datum(c, xd, phys_ofs);
+ if (rc) {
+ kfree(xd->xname);
+ jffs2_free_xattr_datum(xd);
+ return ERR_PTR(rc);
+ }
+
+ /* Insert Hash Index */
+ i = hashkey % XATTRINDEX_HASHSIZE;
+ list_add(&xd->xindex, &c->xattrindex[i]);
+
+ c->xdatum_mem_usage += (xd->name_len + 1 + xd->value_len);
+ reclaim_xattr_datum(c);
+
+ return xd;
+}
+
+/* -------- xdatum related functions ----------------
+ * verify_xattr_ref(c, ref)
+ * is used to load xref information from medium. Because summary data does not
+ * contain xid/ino, it's necessary to verify once while mounting process.
+ * delete_xattr_ref_node(c, ref)
+ * is used to delete a jffs2 node is dominated by xref. When EBS is enabled,
+ * it overwrites the obsolete node by myself.
+ * delete_xattr_ref(c, ref)
+ * is used to delete jffs2_xattr_ref object. If the reference counter of xdatum
+ * is refered by this xref become 0, delete_xattr_datum() is called later.
+ * save_xattr_ref(c, ref, phys_ofs)
+ * is used to write xref to medium.
+ * create_xattr_ref(c, ic, xd, phys_ofs)
+ * is used to create a new xref and write to medium.
+ * jffs2_xattr_delete_inode(c, ic)
+ * is called to remove xrefs related to obsolete inode when inode is unlinked.
+ * jffs2_xattr_free_inode(c, ic)
+ * is called to release xattr related objects when unmounting.
+ * check_xattr_ref_ilist(c, ic)
+ * is used to confirm inode does not have duplicate xattr name/value pair.
+ * -------------------------------------------------- */
+static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+ struct jffs2_eraseblock *jeb;
+ struct jffs2_raw_xref rr;
+ size_t readlen;
+ uint32_t crc, totlen;
+ int rc;
+
+ BUG_ON(ref_flags(ref->node) != REF_UNCHECKED);
+
+ rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr);
+ if (rc || sizeof(rr) != readlen) {
+ JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u, at %#08x\n",
+ rc, sizeof(rr), readlen, ref_offset(ref->node));
+ return rc ? rc : -EIO;
+ }
+ /* obsolete node */
+ crc = crc32(0, &rr, sizeof(rr) - 4);
+ if (crc != je32_to_cpu(rr.node_crc)) {
+ if (je32_to_cpu(rr.node_crc) != 0xffffffff)
+ JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
+ ref_offset(ref->node), je32_to_cpu(rr.node_crc), crc);
+ return EIO;
+ }
+ if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
+ || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF
+ || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) {
+ JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, "
+ "nodetype=%#04x/%#04x, totlen=%u/%u\n",
+ ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
+ je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
+ je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
+ return EIO;
+ }
+ ref->ino = je32_to_cpu(rr.ino);
+ ref->xid = je32_to_cpu(rr.xid);
+
+ /* fixup superblock/eraseblock info */
+ jeb = &c->blocks[ref_offset(ref->node) / c->sector_size];
+ totlen = PAD(sizeof(rr));
+
+ spin_lock(&c->erase_completion_lock);
+ c->unchecked_size -= totlen; c->used_size += totlen;
+ jeb->unchecked_size -= totlen; jeb->used_size += totlen;
+ ref->node->flash_offset = ref_offset(ref->node) | REF_PRISTINE;
+ spin_unlock(&c->erase_completion_lock);
+
+ dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n",
+ ref->ino, ref->xid, ref_offset(ref->node));
+ return 0;
+}
+
+static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+ struct jffs2_raw_xref rr;
+ uint32_t length;
+ int rc;
+
+ if (jffs2_sum_active()) {
+ memset(&rr, 0xff, sizeof(rr));
+ rc = jffs2_flash_read(c, ref_offset(ref->node),
+ sizeof(struct jffs2_unknown_node),
+ &length, (char *)&rr);
+ if (rc || length != sizeof(struct jffs2_unknown_node)) {
+ JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n",
+ rc, sizeof(struct jffs2_unknown_node),
+ length, ref_offset(ref->node));
+ }
+ rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr),
+ &length, (char *)&rr);
+ if (rc || length != sizeof(struct jffs2_raw_xref)) {
+ JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u at %#08x\n",
+ rc, sizeof(rr), length, ref_offset(ref->node));
+ }
+ }
+ spin_lock(&c->erase_completion_lock);
+ ref->node->next_in_ino = NULL;
+ spin_unlock(&c->erase_completion_lock);
+ jffs2_mark_node_obsolete(c, ref->node);
+ ref->node = NULL;
+}
+
+static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_xattr_datum *xd;
+
+ BUG_ON(!ref->node);
+ delete_xattr_ref_node(c, ref);
+
+ list_del(&ref->ilist);
+ xd = ref->xd;
+ xd->refcnt--;
+ if (!xd->refcnt)
+ delete_xattr_datum(c, xd);
+ jffs2_free_xattr_ref(ref);
+}
+
+static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, uint32_t phys_ofs)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_raw_node_ref *raw;
+ struct jffs2_raw_xref rr;
+ uint32_t length;
+ int ret;
+
+ raw = jffs2_alloc_raw_node_ref();
+ if (!raw)
+ return -ENOMEM;
+ raw->flash_offset = phys_ofs;
+ raw->__totlen = PAD(sizeof(rr));
+ raw->next_phys = NULL;
+ raw->next_in_ino = (void *)ref;
+
+ rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
+ rr.totlen = cpu_to_je32(PAD(sizeof(rr)));
+ rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4));
+
+ rr.ino = cpu_to_je32(ref->ic->ino);
+ rr.xid = cpu_to_je32(ref->xd->xid);
+ rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4));
+
+ ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr);
+ if (ret || sizeof(rr) != length) {
+ JFFS2_WARNING("jffs2_flash_write() returned %d, request=%u, retlen=%u, at %#08x\n",
+ ret, sizeof(rr), length, phys_ofs);
+ ret = ret ? ret : -EIO;
+ if (length) {
+ raw->flash_offset |= REF_OBSOLETE;
+ raw->next_in_ino = NULL;
+ jffs2_add_physical_node_ref(c, raw);
+ jffs2_mark_node_obsolete(c, raw);
+ } else {
+ jffs2_free_raw_node_ref(raw);
+ }
+ return ret;
+ }
+ raw->flash_offset |= REF_PRISTINE;
+
+ jffs2_add_physical_node_ref(c, raw);
+ if (ref->node)
+ delete_xattr_ref_node(c, ref);
+ ref->node = raw;
+
+ dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid);
+
+ return 0;
+}
+
+static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic,
+ struct jffs2_xattr_datum *xd, uint32_t phys_ofs)
+{
+ /* must be called under down_write(xattr_sem) */
+ struct jffs2_xattr_ref *ref;
+ int ret;
+
+ ref = jffs2_alloc_xattr_ref();
+ if (!ref)
+ return ERR_PTR(-ENOMEM);
+ ref->ic = ic;
+ ref->xd = xd;
+
+ ret = save_xattr_ref(c, ref, phys_ofs);
+ if (ret) {
+ jffs2_free_xattr_ref(ref);
+ return ERR_PTR(ret);
+ }
+
+ /* Chain to inode */
+ list_add(&ref->ilist, &ic->ilist);
+
+ return ref; /* success */
+}
+
+void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+ /* It's called from jffs2_clear_inode() on inode removing.
+ When an inode with XATTR is removed, those XATTRs must be removed. */
+ struct jffs2_xattr_ref *ref, *_ref;
+
+ if (!ic || ic->nlink > 0)
+ return;
+
+ down_write(&c->xattr_sem);
+ list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist)
+ delete_xattr_ref(c, ref);
+ up_write(&c->xattr_sem);
+}
+
+void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+ /* It's called from jffs2_free_ino_caches() until unmounting FS. */
+ struct jffs2_xattr_datum *xd;
+ struct jffs2_xattr_ref *ref, *_ref;
+
+ down_write(&c->xattr_sem);
+ list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) {
+ list_del(&ref->ilist);
+ xd = ref->xd;
+ xd->refcnt--;
+ if (!xd->refcnt) {
+ unload_xattr_datum(c, xd);
+ jffs2_free_xattr_datum(xd);
+ }
+ jffs2_free_xattr_ref(ref);
+ }
+ up_write(&c->xattr_sem);
+}
+
+static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+ /* success of check_xattr_ref_ilist() means taht inode (ic) dose not have
+ * duplicate name/value pairs. If duplicate name/value pair would be found,
+ * one will be removed.
+ */
+ struct jffs2_xattr_ref *ref, *cmp;
+ int rc = 0;
+
+ if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED))
+ return 0;
+ down_write(&c->xattr_sem);
+ retry:
+ rc = 0;
+ list_for_each_entry(ref, &ic->ilist, ilist) {
+ if (!ref->xd->xname) {
+ rc = load_xattr_datum(c, ref->xd);
+ if (unlikely(rc > 0)) {
+ delete_xattr_ref(c, ref);
+ goto retry;
+ } else if (unlikely(rc < 0))
+ goto out;
+ }
+ cmp = ref;
+ list_for_each_entry_continue(cmp, &ic->ilist, ilist) {
+ if (!cmp->xd->xname) {
+ ref->xd->flags |= JFFS2_XFLAGS_BIND;
+ rc = load_xattr_datum(c, cmp->xd);
+ ref->xd->flags &= ~JFFS2_XFLAGS_BIND;
+ if (unlikely(rc > 0)) {
+ delete_xattr_ref(c, cmp);
+ goto retry;
+ } else if (unlikely(rc < 0))
+ goto out;
+ }
+ if (ref->xd->xprefix == cmp->xd->xprefix
+ && !strcmp(ref->xd->xname, cmp->xd->xname)) {
+ delete_xattr_ref(c, cmp);
+ goto retry;
+ }
+ }
+ }
+ ic->flags |= INO_FLAGS_XATTR_CHECKED;
+ out:
+ up_write(&c->xattr_sem);
+
+ return rc;
+}
+
+/* -------- xattr subsystem functions ---------------
+ * jffs2_init_xattr_subsystem(c)
+ * is used to initialize semaphore and list_head, and some variables.
+ * jffs2_find_xattr_datum(c, xid)
+ * is used to lookup xdatum while scanning process.
+ * jffs2_clear_xattr_subsystem(c)
+ * is used to release any xattr related objects.
+ * jffs2_build_xattr_subsystem(c)
+ * is used to associate xdatum and xref while super block building process.
+ * jffs2_setup_xattr_datum(c, xid, version)
+ * is used to insert xdatum while scanning process.
+ * -------------------------------------------------- */
+void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c)
+{
+ int i;
+
+ for (i=0; i < XATTRINDEX_HASHSIZE; i++)
+ INIT_LIST_HEAD(&c->xattrindex[i]);
+ INIT_LIST_HEAD(&c->xattr_temp);
+ INIT_LIST_HEAD(&c->xattr_unchecked);
+
+ init_rwsem(&c->xattr_sem);
+ c->xdatum_mem_usage = 0;
+ c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */
+}
+
+static struct jffs2_xattr_datum *jffs2_find_xattr_datum(struct jffs2_sb_info *c, uint32_t xid)
+{
+ struct jffs2_xattr_datum *xd;
+ int i = xid % XATTRINDEX_HASHSIZE;
+
+ /* It's only used in scanning/building process. */
+ BUG_ON(!(c->flags & (JFFS2_SB_FLAG_SCANNING|JFFS2_SB_FLAG_BUILDING)));
+
+ list_for_each_entry(xd, &c->xattrindex[i], xindex) {
+ if (xd->xid==xid)
+ return xd;
+ }
+ return NULL;
+}
+
+void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c)
+{
+ struct jffs2_xattr_datum *xd, *_xd;
+ struct jffs2_xattr_ref *ref, *_ref;
+ int i;
+
+ list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist)
+ jffs2_free_xattr_ref(ref);
+
+ for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
+ list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
+ list_del(&xd->xindex);
+ if (xd->xname)
+ kfree(xd->xname);
+ jffs2_free_xattr_datum(xd);
+ }
+ }
+}
+
+void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
+{
+ struct jffs2_xattr_ref *ref, *_ref;
+ struct jffs2_xattr_datum *xd, *_xd;
+ struct jffs2_inode_cache *ic;
+ int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0;
+
+ BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING));
+
+ /* Phase.1 */
+ list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) {
+ list_del_init(&ref->ilist);
+ /* checking REF_UNCHECKED nodes */
+ if (ref_flags(ref->node) != REF_PRISTINE) {
+ if (verify_xattr_ref(c, ref)) {
+ delete_xattr_ref_node(c, ref);
+ jffs2_free_xattr_ref(ref);
+ continue;
+ }
+ }
+ /* At this point, ref->xid and ref->ino contain XID and inode number.
+ ref->xd and ref->ic are not valid yet. */
+ xd = jffs2_find_xattr_datum(c, ref->xid);
+ ic = jffs2_get_ino_cache(c, ref->ino);
+ if (!xd || !ic) {
+ if (ref_flags(ref->node) != REF_UNCHECKED)
+ JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n",
+ ref->ino, ref->xid);
+ delete_xattr_ref_node(c, ref);
+ jffs2_free_xattr_ref(ref);
+ continue;
+ }
+ ref->xd = xd;
+ ref->ic = ic;
+ xd->refcnt++;
+ list_add_tail(&ref->ilist, &ic->ilist);
+ xref_count++;
+ }
+ /* After this, ref->xid/ino are NEVER used. */
+
+ /* Phase.2 */
+ for (i=0; i < XATTRINDEX_HASHSIZE; i++) {
+ list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) {
+ list_del_init(&xd->xindex);
+ if (!xd->refcnt) {
+ if (ref_flags(xd->node) != REF_UNCHECKED)
+ JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n",
+ xd->xid, xd->version, ref_offset(xd->node));
+ delete_xattr_datum(c, xd);
+ continue;
+ }
+ if (ref_flags(xd->node) != REF_PRISTINE) {
+ dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n",
+ xd->xid, ref_offset(xd->node));
+ list_add(&xd->xindex, &c->xattr_unchecked);
+ xdatum_unchecked_count++;
+ }
+ xdatum_count++;
+ }
+ }
+ /* build complete */
+ JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and "
+ "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count);
+}
+
+struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
+ uint32_t xid, uint32_t version)
+{
+ struct jffs2_xattr_datum *xd, *_xd;
+
+ _xd = jffs2_find_xattr_datum(c, xid);
+ if (_xd) {
+ dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n",
+ xid, version, _xd->version, ref_offset(_xd->node));
+ if (version < _xd->version)
+ return ERR_PTR(-EEXIST);
+ }
+ xd = jffs2_alloc_xattr_datum();
+ if (!xd)
+ return ERR_PTR(-ENOMEM);
+ xd->xid = xid;
+ xd->version = version;
+ if (xd->xid > c->highest_xid)
+ c->highest_xid = xd->xid;
+ list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]);
+
+ if (_xd) {
+ list_del_init(&_xd->xindex);
+ delete_xattr_datum_node(c, _xd);
+ jffs2_free_xattr_datum(_xd);
+ }
+ return xd;
+}
+
+/* -------- xattr subsystem functions ---------------
+ * xprefix_to_handler(xprefix)
+ * is used to translate xprefix into xattr_handler.
+ * jffs2_listxattr(dentry, buffer, size)
+ * is an implementation of listxattr handler on jffs2.
+ * do_jffs2_getxattr(inode, xprefix, xname, buffer, size)
+ * is an implementation of getxattr handler on jffs2.
+ * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags)
+ * is an implementation of setxattr handler on jffs2.
+ * -------------------------------------------------- */
+struct xattr_handler *jffs2_xattr_handlers[] = {
+ &jffs2_user_xattr_handler,
+#ifdef CONFIG_JFFS2_FS_SECURITY
+ &jffs2_security_xattr_handler,
+#endif
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+ &jffs2_acl_access_xattr_handler,
+ &jffs2_acl_default_xattr_handler,
+#endif
+ &jffs2_trusted_xattr_handler,
+ NULL
+};
+
+static struct xattr_handler *xprefix_to_handler(int xprefix) {
+ struct xattr_handler *ret;
+
+ switch (xprefix) {
+ case JFFS2_XPREFIX_USER:
+ ret = &jffs2_user_xattr_handler;
+ break;
+#ifdef CONFIG_JFFS2_FS_SECURITY
+ case JFFS2_XPREFIX_SECURITY:
+ ret = &jffs2_security_xattr_handler;
+ break;
+#endif
+#ifdef CONFIG_JFFS2_FS_POSIX_ACL
+ case JFFS2_XPREFIX_ACL_ACCESS:
+ ret = &jffs2_acl_access_xattr_handler;
+ break;
+ case JFFS2_XPREFIX_ACL_DEFAULT:
+ ret = &jffs2_acl_default_xattr_handler;
+ break;
+#endif
+ case JFFS2_XPREFIX_TRUSTED:
+ ret = &jffs2_trusted_xattr_handler;
+ break;
+ default:
+ ret = NULL;
+ break;
+ }
+ return ret;
+}
+
+ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_inode_cache *ic = f->inocache;
+ struct jffs2_xattr_ref *ref;
+ struct jffs2_xattr_datum *xd;
+ struct xattr_handler *xhandle;
+ ssize_t len, rc;
+ int retry = 0;
+
+ rc = check_xattr_ref_ilist(c, ic);
+ if (unlikely(rc))
+ return rc;
+
+ down_read(&c->xattr_sem);
+ retry:
+ len = 0;
+ list_for_each_entry(ref, &ic->ilist, ilist) {
+ BUG_ON(ref->ic != ic);
+ xd = ref->xd;
+ if (!xd->xname) {
+ /* xdatum is unchached */
+ if (!retry) {
+ retry = 1;
+ up_read(&c->xattr_sem);
+ down_write(&c->xattr_sem);
+ goto retry;
+ } else {
+ rc = load_xattr_datum(c, xd);
+ if (unlikely(rc > 0)) {
+ delete_xattr_ref(c, ref);
+ goto retry;
+ } else if (unlikely(rc < 0))
+ goto out;
+ }
+ }
+ xhandle = xprefix_to_handler(xd->xprefix);
+ if (!xhandle)
+ continue;
+ if (buffer) {
+ rc = xhandle->list(inode, buffer+len, size-len, xd->xname, xd->name_len);
+ } else {
+ rc = xhandle->list(inode, NULL, 0, xd->xname, xd->name_len);
+ }
+ if (rc < 0)
+ goto out;
+ len += rc;
+ }
+ rc = len;
+ out:
+ if (!retry) {
+ up_read(&c->xattr_sem);
+ } else {
+ up_write(&c->xattr_sem);
+ }
+ return rc;
+}
+
+int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
+ char *buffer, size_t size)
+{
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_inode_cache *ic = f->inocache;
+ struct jffs2_xattr_datum *xd;
+ struct jffs2_xattr_ref *ref;
+ int rc, retry = 0;
+
+ rc = check_xattr_ref_ilist(c, ic);
+ if (unlikely(rc))
+ return rc;
+
+ down_read(&c->xattr_sem);
+ retry:
+ list_for_each_entry(ref, &ic->ilist, ilist) {
+ BUG_ON(ref->ic!=ic);
+
+ xd = ref->xd;
+ if (xd->xprefix != xprefix)
+ continue;
+ if (!xd->xname) {
+ /* xdatum is unchached */
+ if (!retry) {
+ retry = 1;
+ up_read(&c->xattr_sem);
+ down_write(&c->xattr_sem);
+ goto retry;
+ } else {
+ rc = load_xattr_datum(c, xd);
+ if (unlikely(rc > 0)) {
+ delete_xattr_ref(c, ref);
+ goto retry;
+ } else if (unlikely(rc < 0)) {
+ goto out;
+ }
+ }
+ }
+ if (!strcmp(xname, xd->xname)) {
+ rc = xd->value_len;
+ if (buffer) {
+ if (size < rc) {
+ rc = -ERANGE;
+ } else {
+ memcpy(buffer, xd->xvalue, rc);
+ }
+ }
+ goto out;
+ }
+ }
+ rc = -ENODATA;
+ out:
+ if (!retry) {
+ up_read(&c->xattr_sem);
+ } else {
+ up_write(&c->xattr_sem);
+ }
+ return rc;
+}
+
+int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
+ const char *buffer, size_t size, int flags)
+{
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_inode_cache *ic = f->inocache;
+ struct jffs2_xattr_datum *xd;
+ struct jffs2_xattr_ref *ref, *newref;
+ uint32_t phys_ofs, length, request;
+ int rc;
+
+ rc = check_xattr_ref_ilist(c, ic);
+ if (unlikely(rc))
+ return rc;
+
+ request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size);
+ rc = jffs2_reserve_space(c, request, &phys_ofs, &length,
+ ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE);
+ if (rc) {
+ JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
+ return rc;
+ }
+
+ /* Find existing xattr */
+ down_write(&c->xattr_sem);
+ retry:
+ list_for_each_entry(ref, &ic->ilist, ilist) {
+ xd = ref->xd;
+ if (xd->xprefix != xprefix)
+ continue;
+ if (!xd->xname) {
+ rc = load_xattr_datum(c, xd);
+ if (unlikely(rc > 0)) {
+ delete_xattr_ref(c, ref);
+ goto retry;
+ } else if (unlikely(rc < 0))
+ goto out;
+ }
+ if (!strcmp(xd->xname, xname)) {
+ if (flags & XATTR_CREATE) {
+ rc = -EEXIST;
+ goto out;
+ }
+ if (!buffer) {
+ delete_xattr_ref(c, ref);
+ rc = 0;
+ goto out;
+ }
+ goto found;
+ }
+ }
+ /* not found */
+ ref = NULL;
+ if (flags & XATTR_REPLACE) {
+ rc = -ENODATA;
+ goto out;
+ }
+ if (!buffer) {
+ rc = -EINVAL;
+ goto out;
+ }
+ found:
+ xd = create_xattr_datum(c, xprefix, xname, buffer, size, phys_ofs);
+ if (IS_ERR(xd)) {
+ rc = PTR_ERR(xd);
+ goto out;
+ }
+ up_write(&c->xattr_sem);
+ jffs2_complete_reservation(c);
+
+ /* create xattr_ref */
+ request = PAD(sizeof(struct jffs2_raw_xref));
+ rc = jffs2_reserve_space(c, request, &phys_ofs, &length,
+ ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE);
+ if (rc) {
+ JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
+ down_write(&c->xattr_sem);
+ xd->refcnt--;
+ if (!xd->refcnt)
+ delete_xattr_datum(c, xd);
+ up_write(&c->xattr_sem);
+ return rc;
+ }
+ down_write(&c->xattr_sem);
+ newref = create_xattr_ref(c, ic, xd, phys_ofs);
+ if (IS_ERR(newref)) {
+ rc = PTR_ERR(newref);
+ xd->refcnt--;
+ if (!xd->refcnt)
+ delete_xattr_datum(c, xd);
+ } else if (ref) {
+ /* If replaced xattr_ref exists */
+ delete_xattr_ref(c, ref);
+ }
+ out:
+ up_write(&c->xattr_sem);
+ jffs2_complete_reservation(c);
+ return rc;
+}
+
+/* -------- garbage collector functions -------------
+ * jffs2_garbage_collect_xattr_datum(c, xd)
+ * is used to move xdatum into new node.
+ * jffs2_garbage_collect_xattr_ref(c, ref)
+ * is used to move xref into new node.
+ * jffs2_garbage_collect_xattr(c, ic)
+ * is used to call appropriate garbage collector function, if argument
+ * pointer (ic) is the reference of xdatum/xref.
+ * jffs2_verify_xattr(c)
+ * is used to call do_verify_xattr_datum() before garbage collecting.
+ * -------------------------------------------------- */
+static int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c,
+ struct jffs2_xattr_datum *xd)
+{
+ /* must be called under down_write(xattr_sem), and called from GC thread */
+ uint32_t phys_ofs, totlen, length, old_ofs;
+ int rc;
+
+ BUG_ON(!xd->node);
+
+ old_ofs = ref_offset(xd->node);
+ totlen = ref_totlen(c, c->gcblock, xd->node);
+ if (totlen < sizeof(struct jffs2_raw_xattr))
+ return -EINVAL;
+
+ if (!xd->xname) {
+ rc = load_xattr_datum(c, xd);
+ if (unlikely(rc > 0)) {
+ delete_xattr_datum_node(c, xd);
+ return 0;
+ } else if (unlikely(rc < 0))
+ return -EINVAL;
+ }
+ rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XATTR_SIZE);
+ if (rc || length < totlen) {
+ JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen);
+ return rc ? rc : -EBADFD;
+ }
+ rc = save_xattr_datum(c, xd, phys_ofs);
+ if (!rc)
+ dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n",
+ xd->xid, xd->version, old_ofs, ref_offset(xd->node));
+ return rc;
+}
+
+
+static int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c,
+ struct jffs2_xattr_ref *ref)
+{
+ /* must be called under down(alloc_sem) */
+ uint32_t phys_ofs, totlen, length, old_ofs;
+ int rc;
+
+ BUG_ON(!ref->node);
+
+ old_ofs = ref_offset(ref->node);
+ totlen = ref_totlen(c, c->gcblock, ref->node);
+ if (totlen != sizeof(struct jffs2_raw_xref))
+ return -EINVAL;
+ rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XREF_SIZE);
+ if (rc || length < totlen) {
+ JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n",
+ __FUNCTION__, rc, totlen);
+ return rc ? rc : -EBADFD;
+ }
+ rc = save_xattr_ref(c, ref, phys_ofs);
+ if (!rc)
+ dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n",
+ ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node));
+ return rc;
+}
+
+int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+ struct jffs2_xattr_datum *xd;
+ struct jffs2_xattr_ref *ref;
+ int ret;
+
+ switch (ic->class) {
+ case RAWNODE_CLASS_XATTR_DATUM:
+ spin_unlock(&c->erase_completion_lock);
+
+ down_write(&c->xattr_sem);
+ xd = (struct jffs2_xattr_datum *)ic;
+ ret = xd ? jffs2_garbage_collect_xattr_datum(c, xd) : 0;
+ up_write(&c->xattr_sem);
+ break;
+ case RAWNODE_CLASS_XATTR_REF:
+ spin_unlock(&c->erase_completion_lock);
+
+ down_write(&c->xattr_sem);
+ ref = (struct jffs2_xattr_ref *)ic;
+ ret = ref ? jffs2_garbage_collect_xattr_ref(c, ref) : 0;
+ up_write(&c->xattr_sem);
+ break;
+ default:
+ /* This node is not xattr_datum/xattr_ref */
+ ret = 1;
+ break;
+ }
+ return ret;
+}
+
+int jffs2_verify_xattr(struct jffs2_sb_info *c)
+{
+ struct jffs2_xattr_datum *xd, *_xd;
+ int rc;
+
+ down_write(&c->xattr_sem);
+ list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) {
+ rc = do_verify_xattr_datum(c, xd);
+ if (rc == 0) {
+ list_del_init(&xd->xindex);
+ break;
+ } else if (rc > 0) {
+ list_del_init(&xd->xindex);
+ delete_xattr_datum_node(c, xd);
+ }
+ }
+ up_write(&c->xattr_sem);
+
+ return list_empty(&c->xattr_unchecked) ? 1 : 0;
+}
--- mtd-2.6.git/fs/jffs2/xattr.h 1970-01-01 09:00:00.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/xattr.h 2006-05-06 11:28:19.000000000 +0900
@@ -0,0 +1,120 @@
+/*-------------------------------------------------------------------------*
+ * File: fs/jffs2/xattr.c
+ * XATTR support on JFFS2 FileSystem
+ *
+ * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright (C) 2006 NEC Corporation
+ *
+ * For licensing information, see the file 'LICENCE' in the jffs2 directory.
+ *-------------------------------------------------------------------------*/
+
+#ifndef _JFFS2_FS_XATTR_H_
+#define _JFFS2_FS_XATTR_H_
+
+#include <linux/xattr.h>
+
+#define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */
+#define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */
+
+struct jffs2_xattr_datum
+{
+ void *always_null;
+ u8 class;
+ u8 flags;
+ u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */
+
+ struct jffs2_raw_node_ref *node;
+ struct list_head xindex; /* chained from c->xattrindex[n] */
+ uint32_t refcnt; /* # of xattr_ref refers this */
+ uint32_t xid;
+ uint32_t version;
+
+ uint32_t data_crc;
+ uint32_t hashkey;
+ char *xname; /* XATTR name without prefix */
+ uint32_t name_len; /* length of xname */
+ char *xvalue; /* XATTR value */
+ uint32_t value_len; /* length of xvalue */
+};
+
+struct jffs2_inode_cache; /* forward refence */
+struct jffs2_xattr_ref
+{
+ void *always_null;
+ u8 class;
+ u8 flags; /* Currently unused */
+ u16 unused;
+
+ struct jffs2_raw_node_ref *node;
+ union {
+ struct jffs2_inode_cache *ic; /* reference to jffs2_inode_cache */
+ uint32_t ino; /* only used in scanning/building */
+ };
+ union {
+ struct jffs2_xattr_datum *xd; /* reference to jffs2_xattr_datum */
+ uint32_t xid; /* only used in sccanning/building */
+ };
+ struct list_head ilist; /* chained from ic->ilist */
+};
+
+#ifdef CONFIG_JFFS2_FS_XATTR
+
+extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);
+extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c);
+extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c);
+
+extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
+ uint32_t xid, uint32_t version);
+
+extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
+extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
+
+extern int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
+extern int jffs2_verify_xattr(struct jffs2_sb_info *c);
+
+extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname,
+ char *buffer, size_t size);
+extern int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname,
+ const char *buffer, size_t size, int flags);
+
+extern struct xattr_handler *jffs2_xattr_handlers[];
+extern struct xattr_handler jffs2_user_xattr_handler;
+extern struct xattr_handler jffs2_trusted_xattr_handler;
+
+extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
+#define jffs2_getxattr generic_getxattr
+#define jffs2_setxattr generic_setxattr
+#define jffs2_removexattr generic_removexattr
+
+/*---- Any inline initialize functions ----*/
+#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist))
+
+#else
+
+#define jffs2_init_xattr_subsystem(c)
+#define jffs2_build_xattr_subsystem(c)
+#define jffs2_clear_xattr_subsystem(c)
+
+#define jffs2_xattr_delete_inode(c, ic)
+#define jffs2_xattr_free_inode(c, ic)
+#define jffs2_garbage_collect_xattr(c, ic) (1)
+#define jffs2_verify_xattr(c) (1)
+
+#define jffs2_xattr_handlers NULL
+#define jffs2_listxattr NULL
+#define jffs2_getxattr NULL
+#define jffs2_setxattr NULL
+#define jffs2_removexattr NULL
+
+#define init_xattr_inode_cache(x)
+
+#endif /* CONFIG_JFFS2_FS_XATTR */
+
+#ifdef CONFIG_JFFS2_FS_SECURITY
+extern int jffs2_init_security(struct inode *inode, struct inode *dir);
+extern struct xattr_handler jffs2_security_xattr_handler;
+#else
+#define jffs2_init_security(inode,dir) (0)
+#endif /* CONFIG_JFFS2_FS_SECURITY */
+
+#endif /* _JFFS2_FS_XATTR_H_ */
--- mtd-2.6.git/fs/jffs2/xattr_trusted.c 1970-01-01 09:00:00.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/xattr_trusted.c 2006-05-06 11:28:19.000000000 +0900
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------*
+ * File: fs/jffs2/xattr_trusted.c
+ * XATTR support on JFFS2 FileSystem
+ *
+ * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright (C) 2006 NEC Corporation
+ *
+ * For licensing information, see the file 'LICENCE' in the jffs2 directory.
+ *-------------------------------------------------------------------------*/
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/jffs2.h>
+#include <linux/xattr.h>
+#include <linux/mtd/mtd.h>
+#include "nodelist.h"
+
+static int jffs2_trusted_getxattr(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (!strcmp(name, ""))
+ return -EINVAL;
+ return do_jffs2_getxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size);
+}
+
+static int jffs2_trusted_setxattr(struct inode *inode, const char *name, const void *buffer,
+ size_t size, int flags)
+{
+ if (!strcmp(name, ""))
+ return -EINVAL;
+ return do_jffs2_setxattr(inode, JFFS2_XPREFIX_TRUSTED, name, buffer, size, flags);
+}
+
+static size_t jffs2_trusted_listxattr(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;
+
+ if (list && retlen<=list_size) {
+ strcpy(list, XATTR_TRUSTED_PREFIX);
+ strcpy(list + XATTR_TRUSTED_PREFIX_LEN, name);
+ }
+
+ return retlen;
+}
+
+struct xattr_handler jffs2_trusted_xattr_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .list = jffs2_trusted_listxattr,
+ .set = jffs2_trusted_setxattr,
+ .get = jffs2_trusted_getxattr
+};
--- mtd-2.6.git/fs/jffs2/xattr_user.c 1970-01-01 09:00:00.000000000 +0900
+++ mtd-2.6.0506/fs/jffs2/xattr_user.c 2006-05-06 11:28:19.000000000 +0900
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------*
+ * File: fs/jffs2/xattr_user.c
+ * XATTR support on JFFS2 FileSystem
+ *
+ * Implemented by KaiGai Kohei <kaigai@ak.jp.nec.com>
+ * Copyright (C) 2006 NEC Corporation
+ *
+ * For licensing information, see the file 'LICENCE' in the jffs2 directory.
+ *-------------------------------------------------------------------------*/
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/jffs2.h>
+#include <linux/xattr.h>
+#include <linux/mtd/mtd.h>
+#include "nodelist.h"
+
+static int jffs2_user_getxattr(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (!strcmp(name, ""))
+ return -EINVAL;
+ return do_jffs2_getxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size);
+}
+
+static int jffs2_user_setxattr(struct inode *inode, const char *name, const void *buffer,
+ size_t size, int flags)
+{
+ if (!strcmp(name, ""))
+ return -EINVAL;
+ return do_jffs2_setxattr(inode, JFFS2_XPREFIX_USER, name, buffer, size, flags);
+}
+
+static size_t jffs2_user_listxattr(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;
+
+ if (list && retlen <= list_size) {
+ strcpy(list, XATTR_USER_PREFIX);
+ strcpy(list + XATTR_USER_PREFIX_LEN, name);
+ }
+
+ return retlen;
+}
+
+struct xattr_handler jffs2_user_xattr_handler = {
+ .prefix = XATTR_USER_PREFIX,
+ .list = jffs2_user_listxattr,
+ .set = jffs2_user_setxattr,
+ .get = jffs2_user_getxattr
+};
--- mtd-2.6.git/include/linux/jffs2.h 2006-04-30 18:06:54.000000000 +0900
+++ mtd-2.6.0506/include/linux/jffs2.h 2006-05-06 11:28:19.000000000 +0900
@@ -65,6 +65,18 @@
#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)
@@ -151,6 +163,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 */
+ jint32_t version;
+ 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 ino; /* inode number */
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t node_crc;
+} __attribute__((packed));
+
struct jffs2_raw_summary
{
jint16_t magic;
@@ -169,6 +207,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;
};
[-- Attachment #3: xattr_on_jffs2.utils.version-5.patch --]
[-- Type: text/plain, Size: 24162 bytes --]
diff -prNU3 mtd-utils.git/include/linux/jffs2.h mtd-utils.xattr/include/linux/jffs2.h
--- mtd-utils.git/include/linux/jffs2.h 2006-05-05 20:24:18.000000000 +0900
+++ mtd-utils.xattr/include/linux/jffs2.h 2006-05-05 21:33:48.000000000 +0900
@@ -65,6 +65,18 @@
#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)
@@ -151,6 +163,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 */
+ jint32_t version;
+ 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 ino; /* inode number */
+ jint32_t xid; /* XATTR identifier number */
+ jint32_t node_crc;
+} __attribute__((packed));
+
struct jffs2_raw_summary
{
jint16_t magic;
@@ -169,6 +207,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;
};
diff -prNU3 mtd-utils.git/include/mtd/jffs2-user.h mtd-utils.xattr/include/mtd/jffs2-user.h
--- mtd-utils.git/include/mtd/jffs2-user.h 2006-05-05 20:24:18.000000000 +0900
+++ mtd-utils.xattr/include/mtd/jffs2-user.h 2006-05-05 23:29:13.000000000 +0900
@@ -32,4 +32,51 @@ extern int target_endian;
#define je32_to_cpu(x) (t32((x).v32))
#define jemode_to_cpu(x) (t32((x).m))
+#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
+#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
+
+/* XATTR/POSIX-ACL related definition */
+/* Namespaces copied from xattr.h and posix_acl_xattr.h */
+#define XATTR_USER_PREFIX "user."
+#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
+#define XATTR_SECURITY_PREFIX "security."
+#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
+#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
+#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1)
+#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default"
+#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1)
+#define XATTR_TRUSTED_PREFIX "trusted."
+#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
+
+typedef struct {
+ jint16_t e_tag;
+ jint16_t e_perm;
+ jint32_t e_id;
+} jffs2_acl_entry;
+
+typedef struct {
+ jint16_t e_tag;
+ jint16_t e_perm;
+} jffs2_acl_entry_short;
+
+typedef struct {
+ jint32_t a_version;
+} jffs2_acl_header;
+
+/* copied from include/linux/posix_acl_xattr.h */
+#define POSIX_ACL_XATTR_VERSION 0x0002
+
+typedef struct {
+ uint16_t e_tag;
+ uint16_t e_perm;
+ uint32_t e_id;
+} posix_acl_xattr_entry;
+
+typedef struct {
+ uint32_t a_version;
+ posix_acl_xattr_entry a_entries[0];
+} posix_acl_xattr_header;
+
#endif /* __JFFS2_USER_H__ */
--- mtd-utils.git/mkfs.jffs2.1 2006-05-05 20:24:18.000000000 +0900
+++ mtd-utils.xattr/mkfs.jffs2.1 2006-05-05 21:12:47.000000000 +0900
@@ -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
--- mtd-utils.git/mkfs.jffs2.c 2006-05-05 20:24:18.000000000 +0900
+++ mtd-utils.xattr/mkfs.jffs2.c 2006-05-06 10:44:26.000000000 +0900
@@ -7,6 +7,7 @@
* 2002 Axis Communications AB
* 2001, 2002 Erik Andersen <andersen@codepoet.org>
* 2004 University of Szeged, Hungary
+ * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -63,6 +64,8 @@
#include <ctype.h>
#include <time.h>
#include <getopt.h>
+#include <sys/xattr.h>
+#include <sys/acl.h>
#include <byteswap.h>
#define crc32 __complete_crap
#include <zlib.h>
@@ -1022,6 +1025,233 @@ static void write_special_file(struct fi
padword();
}
+typedef struct xattr_entry {
+ struct xattr_entry *next;
+ uint32_t xid;
+ int xprefix;
+ char *xname;
+ char *xvalue;
+ int name_len;
+ int value_len;
+} xattr_entry_t;
+
+#define XATTR_BUFFER_SIZE (64 * 1024) /* 64KB */
+static uint32_t enable_xattr = 0;
+static uint32_t highest_xid = 0;
+
+static struct {
+ int xprefix;
+ char *string;
+ int length;
+} xprefix_tbl[] = {
+ { JFFS2_XPREFIX_USER, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN },
+ { JFFS2_XPREFIX_SECURITY, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
+ { JFFS2_XPREFIX_ACL_ACCESS, POSIX_ACL_XATTR_ACCESS, POSIX_ACL_XATTR_ACCESS_LEN },
+ { JFFS2_XPREFIX_ACL_DEFAULT, POSIX_ACL_XATTR_DEFAULT, POSIX_ACL_XATTR_DEFAULT_LEN },
+ { JFFS2_XPREFIX_TRUSTED, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN },
+ { 0, NULL, 0 }
+};
+
+static void formalize_posix_acl(char *xvalue, int *value_len)
+{
+ posix_acl_xattr_header *pacl_header;
+ posix_acl_xattr_entry *pent, *plim;
+ jffs2_acl_header *jacl_header;
+ jffs2_acl_entry *jent;
+ jffs2_acl_entry_short *jent_s;
+ char buffer[XATTR_BUFFER_SIZE];
+ int offset = 0;
+
+ pacl_header = (posix_acl_xattr_header *)xvalue;;
+ pent = pacl_header->a_entries;
+ plim = (posix_acl_xattr_entry *)(xvalue + *value_len);
+
+ jacl_header = (jffs2_acl_header *)buffer;
+ offset += sizeof(jffs2_acl_header);
+ jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
+
+ while (pent < plim) {
+ switch(le16_to_cpu(pent->e_tag)) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ jent_s = (jffs2_acl_entry_short *)(buffer + offset);
+ offset += sizeof(jffs2_acl_entry_short);
+ jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+ jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+ break;
+ case ACL_USER:
+ case ACL_GROUP:
+ jent = (jffs2_acl_entry *)(buffer + offset);
+ offset += sizeof(jffs2_acl_entry);
+ jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
+ jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
+ jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id));
+ break;
+ default:
+ printf("%04x : Unknown XATTR entry tag.\n", le16_to_cpu(pent->e_tag));
+ exit(1);
+ }
+ pent++;
+ }
+ if (offset > *value_len) {
+ printf("Length of JFFS2 ACL expression(%u) is longer than general one(%u).\n",
+ offset, *value_len);
+ exit(1);
+ }
+ memcpy(xvalue, buffer, offset);
+ *value_len = offset;
+}
+
+static xattr_entry_t *create_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+ xattr_entry_t *xe;
+ struct jffs2_raw_xattr rx;
+ int name_len;
+
+ /* create xattr entry */
+ name_len = strlen(xname);
+ xe = xcalloc(1, sizeof(xattr_entry_t) + name_len + 1 + value_len);
+ xe->next = NULL;
+ xe->xid = ++highest_xid;
+ xe->xprefix = xprefix;
+ xe->xname = ((char *)xe) + sizeof(xattr_entry_t);
+ xe->xvalue = xe->xname + name_len + 1;
+ xe->name_len = name_len;
+ xe->value_len = value_len;
+ strcpy(xe->xname, xname);
+ memcpy(xe->xvalue, xvalue, value_len);
+
+ /* write xattr node */
+ memset(&rx, 0, sizeof(rx));
+ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR);
+ rx.totlen = cpu_to_je32(PAD(sizeof(rx) + xe->name_len + 1 + xe->value_len));
+ rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4));
+
+ rx.xid = cpu_to_je32(xe->xid);
+ rx.version = cpu_to_je32(1); /* initial version */
+ rx.xprefix = xprefix;
+ rx.name_len = xe->name_len;
+ rx.value_len = cpu_to_je16(xe->value_len);
+ rx.data_crc = cpu_to_je32(crc32(0, xe->xname, xe->name_len + 1 + xe->value_len));
+ rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(rx) - 4));
+
+ pad_block_if_less_than(sizeof(rx) + xe->name_len + 1 + xe->value_len);
+ full_write(out_fd, &rx, sizeof(rx));
+ full_write(out_fd, xe->xname, xe->name_len + 1 + xe->value_len);
+ padword();
+
+ return xe;
+}
+
+#define XATTRENTRY_HASHSIZE 57
+static xattr_entry_t *find_xattr_entry(int xprefix, char *xname, char *xvalue, int value_len)
+{
+ static xattr_entry_t **xentry_hash = NULL;
+ xattr_entry_t *xe;
+ int index, name_len;
+
+ /* create hash table */
+ if (!xentry_hash)
+ xentry_hash = xcalloc(1, sizeof(xe) * XATTRENTRY_HASHSIZE);
+
+ if (xprefix == JFFS2_XPREFIX_ACL_ACCESS
+ || xprefix == JFFS2_XPREFIX_ACL_DEFAULT)
+ formalize_posix_acl(xvalue, &value_len);
+
+ name_len = strlen(xname);
+ index = (crc32(0, xname, name_len) ^ crc32(0, xvalue, value_len)) % XATTRENTRY_HASHSIZE;
+ for (xe = xentry_hash[index]; xe; xe = xe->next) {
+ if (xe->xprefix == xprefix
+ && xe->value_len == value_len
+ && !strcmp(xe->xname, xname)
+ && !memcmp(xe->xvalue, xvalue, value_len))
+ break;
+ }
+ if (!xe) {
+ xe = create_xattr_entry(xprefix, xname, xvalue, value_len);
+ xe->next = xentry_hash[index];
+ xentry_hash[index] = xe;
+ }
+ return xe;
+}
+
+static void write_xattr_entry(struct filesystem_entry *e)
+{
+ struct jffs2_raw_xref ref;
+ struct xattr_entry *xe;
+ char xlist[XATTR_BUFFER_SIZE], xvalue[XATTR_BUFFER_SIZE];
+ char *xname, *prefix_str;
+ int i, xprefix, prefix_len;
+ int list_sz, offset, name_len, value_len;
+
+ if (!enable_xattr)
+ return;
+
+ list_sz = llistxattr(e->hostname, xlist, XATTR_BUFFER_SIZE);
+ if (list_sz < 0) {
+ if (verbose)
+ printf("llistxattr('%s') = %d : %s\n",
+ e->hostname, errno, strerror(errno));
+ return;
+ }
+
+ for (offset = 0; offset < list_sz; offset += name_len) {
+ xname = xlist + offset;
+ name_len = strlen(xname) + 1;
+
+ for (i = 0; (xprefix = xprefix_tbl[i].xprefix); i++) {
+ prefix_str = xprefix_tbl[i].string;
+ prefix_len = xprefix_tbl[i].length;
+ if (prefix_str[prefix_len - 1] == '.') {
+ if (!strncmp(xname, prefix_str, prefix_len - 1))
+ break;
+ } else {
+ if (!strcmp(xname, prefix_str))
+ break;
+ }
+ }
+ if (!xprefix) {
+ if (verbose)
+ printf("%s: xattr '%s' is not supported.\n",
+ e->hostname, xname);
+ continue;
+ }
+ if ((enable_xattr & (1 << xprefix)) == 0)
+ continue;
+
+ value_len = lgetxattr(e->hostname, xname, xvalue, XATTR_BUFFER_SIZE);
+ if (value_len < 0) {
+ if (verbose)
+ printf("lgetxattr('%s', '%s') = %d : %s\n",
+ e->hostname, xname, errno, strerror(errno));
+ continue;
+ }
+ xe = find_xattr_entry(xprefix, xname + prefix_len, xvalue, value_len);
+ if (!xe) {
+ if (verbose)
+ printf("%s : xattr '%s' was ignored.\n",
+ e->hostname, xname);
+ continue;
+ }
+
+ memset(&ref, 0, sizeof(ref));
+ ref.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ref.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF);
+ ref.totlen = cpu_to_je32(sizeof(ref));
+ ref.hdr_crc = cpu_to_je32(crc32(0, &ref, sizeof(struct jffs2_unknown_node) - 4));
+ ref.ino = cpu_to_je32(e->sb.st_ino);
+ ref.xid = cpu_to_je32(xe->xid);
+ ref.node_crc = cpu_to_je32(crc32(0, &ref, sizeof(ref) - 4));
+
+ pad_block_if_less_than(sizeof(ref));
+ full_write(out_fd, &ref, sizeof(ref));
+ padword();
+ }
+}
+
static void recursive_populate_directory(struct filesystem_entry *dir)
{
struct filesystem_entry *e;
@@ -1029,6 +1259,8 @@ static void recursive_populate_directory
if (verbose) {
printf("%s\n", dir->fullname);
}
+ write_xattr_entry(dir); /* for '/' */
+
e = dir->files;
while (e) {
@@ -1041,6 +1273,7 @@ static void recursive_populate_directory
e->name);
}
write_pipe(e);
+ write_xattr_entry(e);
break;
case S_IFSOCK:
if (verbose) {
@@ -1049,6 +1282,7 @@ static void recursive_populate_directory
(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
}
write_pipe(e);
+ write_xattr_entry(e);
break;
case S_IFIFO:
if (verbose) {
@@ -1057,6 +1291,7 @@ static void recursive_populate_directory
(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
}
write_pipe(e);
+ write_xattr_entry(e);
break;
case S_IFCHR:
if (verbose) {
@@ -1066,6 +1301,7 @@ static void recursive_populate_directory
(int) e->sb.st_gid, e->name);
}
write_special_file(e);
+ write_xattr_entry(e);
break;
case S_IFBLK:
if (verbose) {
@@ -1075,6 +1311,7 @@ static void recursive_populate_directory
(int) e->sb.st_gid, e->name);
}
write_special_file(e);
+ write_xattr_entry(e);
break;
case S_IFLNK:
if (verbose) {
@@ -1084,6 +1321,7 @@ static void recursive_populate_directory
e->link);
}
write_symlink(e);
+ write_xattr_entry(e);
break;
case S_IFREG:
if (verbose) {
@@ -1092,6 +1330,7 @@ static void recursive_populate_directory
(int) e->sb.st_uid, (int) e->sb.st_gid, e->name);
}
write_regular_file(e);
+ write_xattr_entry(e);
break;
default:
error_msg("Unknown mode %o for %s", e->sb.st_mode,
@@ -1169,6 +1408,9 @@ static struct option long_options[] = {
{"test-compression", 0, NULL, 't'},
{"compressor-priority", 1, NULL, 'y'},
{"incremental", 1, NULL, 'i'},
+ {"with-xattr", 0, NULL, 1000 },
+ {"with-selinux", 0, NULL, 1001 },
+ {"with-posix-acl", 0, NULL, 1002 },
{NULL, 0, NULL, 0}
};
@@ -1201,6 +1443,9 @@ static char *helptext =
" -q, --squash Squash permissions and owners making all files be owned by root\n"
" -U, --squash-uids Squash owners making all files be owned by root\n"
" -P, --squash-perms Squash permissions on all files\n"
+ " --with-xattr stuff all xattr entries into image\n"
+ " --with-selinux stuff only SELinux Labels into jffs2 image\n"
+ " --with-posix-acl stuff only POSIX ACL entries into jffs2 image\n"
" -h, --help Display this help text\n"
" -v, --verbose Verbose operation\n"
" -V, --version Display version information\n"
@@ -1519,6 +1764,20 @@ int main(int argc, char **argv)
perror_msg_and_die("cannot open (incremental) file");
}
break;
+ case 1000: /* --with-xattr */
+ enable_xattr |= (1 << JFFS2_XPREFIX_USER)
+ | (1 << JFFS2_XPREFIX_SECURITY)
+ | (1 << JFFS2_XPREFIX_ACL_ACCESS)
+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT)
+ | (1 << JFFS2_XPREFIX_TRUSTED);
+ break;
+ case 1001: /* --with-selinux */
+ enable_xattr |= (1 << JFFS2_XPREFIX_SECURITY);
+ break;
+ case 1002: /* --with-posix-acl */
+ enable_xattr |= (1 << JFFS2_XPREFIX_ACL_ACCESS)
+ | (1 << JFFS2_XPREFIX_ACL_DEFAULT);
+ break;
}
}
if (out_fd == -1) {
--- mtd-utils.git/summary.h 2006-05-05 20:24:18.000000000 +0900
+++ mtd-utils.xattr/summary.h 2006-05-06 10:15:03.000000000 +0900
@@ -45,6 +45,8 @@
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
+#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
/* Summary structures used on flash */
@@ -75,11 +77,28 @@ struct jffs2_sum_dirent_flash
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
+struct jffs2_sum_xattr_flash
+{
+ jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */
+ jint32_t xid; /* xattr identifier */
+ jint32_t version; /* version number */
+ jint32_t offset; /* offset on jeb */
+ jint32_t totlen; /* node length */
+} __attribute__((packed));
+
+struct jffs2_sum_xref_flash
+{
+ jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */
+ jint32_t offset; /* offset on jeb */
+} __attribute__((packed));
+
union jffs2_sum_flash
{
struct jffs2_sum_unknown_flash u;
struct jffs2_sum_inode_flash i;
struct jffs2_sum_dirent_flash d;
+ struct jffs2_sum_xattr_flash x;
+ struct jffs2_sum_xref_flash r;
};
/* Summary structures used in the memory */
@@ -114,11 +133,30 @@ struct jffs2_sum_dirent_mem
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
+struct jffs2_sum_xattr_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype;
+ jint32_t xid;
+ jint32_t version;
+ jint32_t offset;
+ jint32_t totlen;
+} __attribute__((packed));
+
+struct jffs2_sum_xref_mem
+{
+ union jffs2_sum_mem *next;
+ jint16_t nodetype;
+ jint32_t offset;
+} __attribute__((packed));
+
union jffs2_sum_mem
{
struct jffs2_sum_unknown_mem u;
struct jffs2_sum_inode_mem i;
struct jffs2_sum_dirent_mem d;
+ struct jffs2_sum_xattr_mem x;
+ struct jffs2_sum_xref_mem r;
};
struct jffs2_summary
--- mtd-utils.git/sumtool.c 2006-05-05 20:24:18.000000000 +0900
+++ mtd-utils.xattr/sumtool.c 2006-05-06 10:27:50.000000000 +0900
@@ -4,6 +4,7 @@
* Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
* Ferenc Havasi <havasi@inf.u-szeged.hu>
* University of Szeged, Hungary
+ * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* $Id: sumtool.c,v 1.9 2006/01/23 08:22:45 havasi Exp $
*
@@ -442,6 +443,29 @@ void dump_sum_records()
break;
}
+ case JFFS2_NODETYPE_XATTR: {
+ struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
+
+ sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
+ sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
+ sxattr_ptr->version = sum_collected->sum_list_head->x.version;
+ sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
+ sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
+
+ wpage += JFFS2_SUMMARY_XATTR_SIZE;
+ break;
+ }
+
+ case JFFS2_NODETYPE_XREF: {
+ struct jffs2_sum_xref_flash *sxref_ptr = wpage;
+
+ sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
+ sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
+
+ wpage += JFFS2_SUMMARY_XREF_SIZE;
+ break;
+ }
+
default : {
printf("Unknown node type!\n");
}
@@ -577,6 +601,16 @@ int add_sum_mem(union jffs2_sum_mem *ite
sum_collected->sum_num++;
break;
+ case JFFS2_NODETYPE_XATTR:
+ sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
+ sum_collected->sum_num++;
+ break;
+
+ case JFFS2_NODETYPE_XREF:
+ sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
+ sum_collected->sum_num++;
+ break;
+
default:
error_msg_and_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
}
@@ -622,6 +656,37 @@ void add_sum_dirent_mem(union jffs2_node
add_sum_mem((union jffs2_sum_mem *) temp);
}
+void add_sum_xattr_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_xattr_mem *temp = (struct jffs2_sum_xattr_mem *)
+ malloc(sizeof(struct jffs2_sum_xattr_mem));
+ if (!temp)
+ error_msg_and_die("Can't allocate memory for summary information!\n");
+
+ temp->nodetype = node->x.nodetype;
+ temp->xid = node->x.xid;
+ temp->version = node->x.version;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->totlen = node->x.totlen;
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_xref_mem(union jffs2_node_union *node)
+{
+ struct jffs2_sum_xref_mem *temp = (struct jffs2_sum_xref_mem *)
+ malloc(sizeof(struct jffs2_sum_xref_mem));
+ if (!temp)
+ error_msg_and_die("Can't allocate memory for summary information!\n");
+
+ temp->nodetype = node->r.nodetype;
+ temp->offset = cpu_to_je32(data_ofs);
+ temp->next = NULL;
+
+ add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
void write_dirent_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
@@ -639,11 +704,27 @@ void write_inode_to_buff(union jffs2_nod
padword();
}
+void write_xattr_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
+ add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
+ padword();
+}
+
+void write_xref_to_buff(union jffs2_node_union *node)
+{
+ pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
+ add_sum_xref_mem(node); /* Add xref summary mem to summary list */
+ full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
+ padword();
+}
+
void create_summed_image(int inp_size)
{
uint8_t *p = file_buffer;
union jffs2_node_union *node;
- uint32_t crc;
+ uint32_t crc, length;
uint16_t type;
int bitchbitmask = 0;
int obsolete;
@@ -743,6 +824,56 @@ void create_summed_image(int inp_size)
p += PAD(je32_to_cpu (node->d.totlen));
break;
+ case JFFS2_NODETYPE_XATTR:
+ if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
+ obsolete = 1;
+ if (verbose)
+ printf("%8s Xdatum node at 0x%08x, totlen 0x%08x, "
+ "#xid %5u, version %5u\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu (node->x.totlen),
+ je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
+ crc = crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
+ if (crc != je32_to_cpu(node->x.node_crc)) {
+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ continue;
+ }
+ length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
+ crc = crc32(0, node->x.data, length);
+ if (crc != je32_to_cpu(node->x.data_crc)) {
+ printf("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ continue;
+ }
+
+ write_xattr_to_buff(node);
+ p += PAD(je32_to_cpu (node->x.totlen));
+ break;
+
+ case JFFS2_NODETYPE_XREF:
+ if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
+ obsolete = 1;
+ if (verbose)
+ printf("%8s Xref node at 0x%08x, totlen 0x%08x, "
+ "#ino %5u, xid %5u\n",
+ obsolete ? "Obsolete" : "",
+ p - file_buffer, je32_to_cpu(node->r.totlen),
+ je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
+ crc = crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
+ if (crc != je32_to_cpu(node->r.node_crc)) {
+ printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
+ p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
+ p += PAD(je32_to_cpu (node->r.totlen));
+ continue;
+ }
+
+ write_xref_to_buff(node);
+ p += PAD(je32_to_cpu (node->r.totlen));
+ break;
+
case JFFS2_NODETYPE_CLEANMARKER:
if (verbose) {
printf ("%8s Cleanmarker at 0x%08x, totlen 0x%08x\n",
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 6:51 [PATCH] XATTR support on JFFS2 (version. 5) KaiGai Kohei
@ 2006-05-06 12:07 ` David Woodhouse
2006-05-06 12:38 ` David Woodhouse
2006-05-07 12:46 ` Artem B. Bityutskiy
` (2 subsequent siblings)
3 siblings, 1 reply; 30+ messages in thread
From: David Woodhouse @ 2006-05-06 12:07 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: jmorris, sds, russell, linux-mtd, lorenzo, joern
On Sat, 2006-05-06 at 15:51 +0900, KaiGai Kohei wrote:
> Hello,
>
> This attached patches provide xattr support including POSIX-ACL and
> SELinux support on JFFS2 (version.5).
> We can apply those patches to the latest git-tree.
> - xattr_on_jffs2.kernel.version-5.patch can be applied to mtd-2.6.git.
> - xattr_on_jffs2.utils.version-5.patch can be applied to mtd-utils.git.
Thank you. These patches look good to me, in general. I do have a couple
of minor comments to make, but I'll do that with a slightly shorter Cc
list.
In the meantime I've committed the utils patch directly to the mtd-utils
git tree at git://git.infradead.org/mtd-utils.git and I have created a
new kernel git tree at git://git.infradead.org/jffs2-xattr-2.6.git.
(Both of these are browsable at http://git.infradead.org for non-git
users).
I've created a new git tree for the kernel side because I want Linus to
pull from the existing MTD git tree immediately after he releases
2.6.17, and I'd like the xattr code to be in public view (and the -mm
tree) for a bit longer than that. As soon as Linus releases 2.6.17 and
pulls from the MTD tree for 2.6.18, I intend to pull the xattr code into
the main mtd tree -- as long as other reviewers are happy. OK?
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 12:07 ` David Woodhouse
@ 2006-05-06 12:38 ` David Woodhouse
2006-05-06 16:47 ` KaiGai Kohei
0 siblings, 1 reply; 30+ messages in thread
From: David Woodhouse @ 2006-05-06 12:38 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: linux-mtd, joern
On Sat, 2006-05-06 at 13:07 +0100, David Woodhouse wrote:
> Thank you. These patches look good to me, in general. I do have a couple
> of minor comments to make, but I'll do that with a slightly shorter Cc
> list.
As I said, it looks good in general. A few minor points though. I
haven't looked _too_ hard yet at the details, but this is what jumped
out at me when I scrolled through it.
1. Please don't use typedefs. Just 'struct jffs2_acl_header' instead of
this:
typedef struct {
jint32_t a_version;
} jffs2_acl_header;
2. You're adding locks without documenting them in README.Locking.
Please make sure any new locks (c->xattr_sem) are fully documented.
3. You have very strange locking behaviour in
jffs2_garbage_collect_xattr() -- sometimes you return with the lock
still held, sometimes without. I think it would be best to check
ic->class within the jffs2_garbage_collect_passs() function instead.
4. You add a list_head to struct jffs2_inode_cache. That's two pointers
-- could we get away with only a single pointer instead?
How much has your code been tested on SMP machines?
Please let me know if you'd like an account with direct access to the
jffs2-xattr-2.6.git tree. I can continue to apply patches if you prefer,
but git is quite easy to use.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 12:38 ` David Woodhouse
@ 2006-05-06 16:47 ` KaiGai Kohei
2006-05-06 17:53 ` David Woodhouse
2006-05-07 13:25 ` Artem B. Bityutskiy
0 siblings, 2 replies; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-06 16:47 UTC (permalink / raw)
To: David Woodhouse; +Cc: linux-mtd, joern
Thanks for your comments.
> 1. Please don't use typedefs. Just 'struct jffs2_acl_header' instead of
> this:
> typedef struct {
> jint32_t a_version;
> } jffs2_acl_header;
OK, I'll fix it.
> 2. You're adding locks without documenting them in README.Locking.
> Please make sure any new locks (c->xattr_sem) are fully documented.
OK, I'll prepare it.
Please notice me, if storange English expressions are included.
> 3. You have very strange locking behaviour in
> jffs2_garbage_collect_xattr() -- sometimes you return with the lock
> still held, sometimes without. I think it would be best to check
> ic->class within the jffs2_garbage_collect_passs() function instead.
Do you prefer the following style implementation?
I also agree your opinion, if so. I'll fix it.
@ gc.c
if (jffs2_garbage_collect_passs(c, ic)) { /* returns 1, if ic is xdatum or xref */
spin_unlock(&c->erase_completion_lock);
jffs2_garbage_collect_xattr(c, ic); /* ic is xdatum or xref */
goto release_sem;
}
:
> 4. You add a list_head to struct jffs2_inode_cache. That's two pointers
> -- could we get away with only a single pointer instead?
It's probably possible. Please wait for a while, since there is a bit much
points to be fixed.
> How much has your code been tested on SMP machines?
It's not evaluated on SMP machine yet.
(And, I've not prepated SMP evaluation environment yet.)
I hope to make collaboration with MTD people.
> Please let me know if you'd like an account with direct access to the
> jffs2-xattr-2.6.git tree. I can continue to apply patches if you prefer,
> but git is quite easy to use.
I haven't known much about detailed git operations yet. But I'm already
doing basical operations such as pull/push/... in my local environment.
Maybe, here is not significant problem. I'm willing to manage jffs2-xattr-2.6.git
tree. Is it necessary to send you my ssh public key, isn't it?
Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 16:47 ` KaiGai Kohei
@ 2006-05-06 17:53 ` David Woodhouse
2006-05-07 0:22 ` KaiGai Kohei
2006-05-07 10:19 ` Artem B. Bityutskiy
2006-05-07 13:25 ` Artem B. Bityutskiy
1 sibling, 2 replies; 30+ messages in thread
From: David Woodhouse @ 2006-05-06 17:53 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: linux-mtd, joern
On Sun, 2006-05-07 at 01:47 +0900, KaiGai Kohei wrote:
> OK, I'll fix it.
<...>
> OK, I'll prepare it.
> Please notice me, if storange English expressions are included.
OK, thanks. I'm happy to proof-read for you.
> > 3. You have very strange locking behaviour in
> > jffs2_garbage_collect_xattr() -- sometimes you return with the lock
> > still held, sometimes without. I think it would be best to check
> > ic->class within the jffs2_garbage_collect_passs() function instead.
>
> Do you prefer the following style implementation?
> I also agree your opinion, if so. I'll fix it.
>
> @ gc.c
> if (jffs2_garbage_collect_passs(c, ic)) { /* returns 1, if ic is xdatum or xref */
> spin_unlock(&c->erase_completion_lock);
> jffs2_garbage_collect_xattr(c, ic); /* ic is xdatum or xref */
> goto release_sem;
> }
I don't like that very much either, to be honest. How about getting rid
of jffs2_garbage_collect_xattr() altogether, and using this in gc.c
instead...
#ifdef CONFIG_JFFS2_FS_XATTR
/* 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. */
if (ic->class == RAWNODE_CLASS_XATTR_DATUM ||
ic->class == RAWNODE_CLASS_XATTR_REF) {
spin_unlock(&c->erase_completion_lock);
/* XXXXXX? */
down_write(&c->xattr_sem);
if (ic->class == RAWNODE_CLASS_XATTR_DATUM)
ret = jffs2_garbage_collect_xattr_datum(c, (void *)ic);
else
ret = jffs2_garbage_collect_xattr_ref(c, (void *)ic);
up_write(&c->xattr_sem);
goto release_sem;
}
#endif
>
> > 4. You add a list_head to struct jffs2_inode_cache. That's two pointers
> > -- could we get away with only a single pointer instead?
>
> It's probably possible. Please wait for a while, since there is a bit much
> points to be fixed.
OK, thanks. I think it's worth doing, because there will be many
instances of struct jffs2_inode_cache, and it's best to keep them as
small as possible.
> > How much has your code been tested on SMP machines?
>
> It's not evaluated on SMP machine yet.
> (And, I've not prepated SMP evaluation environment yet.)
> I hope to make collaboration with MTD people.
Any SMP machine will work, using the 'mtdram' driver instead of real
flash.
> I haven't known much about detailed git operations yet. But I'm already
> doing basical operations such as pull/push/... in my local environment.
> Maybe, here is not significant problem. I'm willing to manage jffs2-xattr-2.6.git
> tree. Is it necessary to send you my ssh public key, isn't it?
Yes, please. I'll add an account for you.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 17:53 ` David Woodhouse
@ 2006-05-07 0:22 ` KaiGai Kohei
2006-05-07 0:29 ` David Woodhouse
2006-05-07 10:19 ` Artem B. Bityutskiy
1 sibling, 1 reply; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-07 0:22 UTC (permalink / raw)
To: David Woodhouse; +Cc: joern, linux-mtd, KaiGai Kohei
Hello,
David Woodhouse wrote:
> I don't like that very much either, to be honest. How about getting rid
> of jffs2_garbage_collect_xattr() altogether, and using this in gc.c
> instead...
>
> #ifdef CONFIG_JFFS2_FS_XATTR
> /* 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. */
> if (ic->class == RAWNODE_CLASS_XATTR_DATUM ||
> ic->class == RAWNODE_CLASS_XATTR_REF) {
> spin_unlock(&c->erase_completion_lock);
> /* XXXXXX? */
> down_write(&c->xattr_sem);
> if (ic->class == RAWNODE_CLASS_XATTR_DATUM)
> ret = jffs2_garbage_collect_xattr_datum(c, (void *)ic);
> else
> ret = jffs2_garbage_collect_xattr_ref(c, (void *)ic);
> up_write(&c->xattr_sem);
> goto release_sem;
> }
> #endif
OK, I'll fix according to your suggestion.
Only one point, I think xattr_sem should be modified in xattr.c for readability.
>>I haven't known much about detailed git operations yet. But I'm already
>>doing basical operations such as pull/push/... in my local environment.
>>Maybe, here is not significant problem. I'm willing to manage jffs2-xattr-2.6.git
>>tree. Is it necessary to send you my ssh public key, isn't it?
>
>
> Yes, please. I'll add an account for you.
I'll send it to you directly.
Thanks,
--
KaiGai Kohei <kaigai@ak.jp.nec.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-07 0:22 ` KaiGai Kohei
@ 2006-05-07 0:29 ` David Woodhouse
0 siblings, 0 replies; 30+ messages in thread
From: David Woodhouse @ 2006-05-07 0:29 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: joern, linux-mtd, KaiGai Kohei
On Sun, 2006-05-07 at 09:22 +0900, KaiGai Kohei wrote:
> OK, I'll fix according to your suggestion.
> Only one point, I think xattr_sem should be modified in xattr.c for
> readability.
Yes, you are probably right.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 17:53 ` David Woodhouse
2006-05-07 0:22 ` KaiGai Kohei
@ 2006-05-07 10:19 ` Artem B. Bityutskiy
1 sibling, 0 replies; 30+ messages in thread
From: Artem B. Bityutskiy @ 2006-05-07 10:19 UTC (permalink / raw)
To: David Woodhouse; +Cc: joern, linux-mtd, KaiGai Kohei
David Woodhouse wrote:
> Any SMP machine will work, using the 'mtdram' driver instead of real
> flash.
>
Yes, I aways use an i686 boxen + a RAM flash simulator for development -
saves a great deal of time.
--
Best Regards,
Artem B. Bityutskiy,
St.-Petersburg, Russia.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 6:51 [PATCH] XATTR support on JFFS2 (version. 5) KaiGai Kohei
2006-05-06 12:07 ` David Woodhouse
@ 2006-05-07 12:46 ` Artem B. Bityutskiy
2006-05-07 13:12 ` Artem B. Bityutskiy
2006-05-07 13:18 ` David Woodhouse
2006-05-07 17:16 ` Jörn Engel
2006-05-10 10:03 ` Artem B. Bityutskiy
3 siblings, 2 replies; 30+ messages in thread
From: Artem B. Bityutskiy @ 2006-05-07 12:46 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: joern, dwmw2, linux-mtd
KaiGai Kohei wrote:
> Hello,
>
> This attached patches provide xattr support including POSIX-ACL and
> SELinux support on JFFS2 (version.5).
> We can apply those patches to the latest git-tree.
> - xattr_on_jffs2.kernel.version-5.patch can be applied to mtd-2.6.git.
> - xattr_on_jffs2.utils.version-5.patch can be applied to mtd-utils.git
I've quickly glanced at the xattr.h file.
>
+/*-------------------------------------------------------------------------*
> + * File: fs/jffs2/xattr.c
Not sure it makes sense to specify file name here.
> +#include <linux/xattr.h>
You're using 'struct list_head' in your 'xattr.h' file, wouldn't it be a
good tone to add #include <linux/lists.h> then?
> +struct jffs2_xattr_datum
> +{
> + void *always_null;
> + u8 class;
> + u8 flags;
> + u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */
> +
> + struct jffs2_raw_node_ref *node;
> + struct list_head xindex; /* chained from c->xattrindex[n] */
> + uint32_t refcnt; /* # of xattr_ref refers this */
> + uint32_t xid;
> + uint32_t version;
> +
> + uint32_t data_crc;
> + uint32_t hashkey;
> + char *xname; /* XATTR name without prefix */
> + uint32_t name_len; /* length of xname */
> + char *xvalue; /* XATTR value */
> + uint32_t value_len; /* length of xvalue */
> +};
Would be cuter to use Linux-style comments.
> +struct jffs2_inode_cache; /* forward refence */
A classic example of a senseless comment :-)
> +extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct
jffs2_sb_info *c,
> + uint32_t xid,
uint32_t version);
> +
> +extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct
jffs2_inode_cache *ic);
> +extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct
jffs2_inode_cache *ic);
> +
> +extern int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c,
struct jffs2_inode_cache *ic);
I wouldn't follow old JFFS2 style and would not exceed the 80-characters
per line limit.
> +/*---- Any inline initialize functions ----*/
> +#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist))
Wierd comment.
--
Best Regards,
Artem B. Bityutskiy,
St.-Petersburg, Russia.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-07 12:46 ` Artem B. Bityutskiy
@ 2006-05-07 13:12 ` Artem B. Bityutskiy
2006-05-07 13:18 ` David Woodhouse
1 sibling, 0 replies; 30+ messages in thread
From: Artem B. Bityutskiy @ 2006-05-07 13:12 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: dwmw2, joern, linux-mtd
Hi, few refinements,
On Sun, 2006-05-07 at 16:46 +0400, Artem B. Bityutskiy wrote:
> > +#include <linux/xattr.h>
> You're using 'struct list_head' in your 'xattr.h' file, wouldn't it be a
> good tone to add #include <linux/lists.h> then?
>
> > +struct jffs2_xattr_datum
> > +{
> > + void *always_null;
> > + u8 class;
> > + u8 flags;
> > + u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */
> > +
> > + struct jffs2_raw_node_ref *node;
> > + struct list_head xindex; /* chained from c->xattrindex[n] */
> > + uint32_t refcnt; /* # of xattr_ref refers this */
> > + uint32_t xid;
> > + uint32_t version;
> > +
> > + uint32_t data_crc;
> > + uint32_t hashkey;
> > + char *xname; /* XATTR name without prefix */
> > + uint32_t name_len; /* length of xname */
> > + char *xvalue; /* XATTR value */
> > + uint32_t value_len; /* length of xvalue */
> > +};
> Would be cuter to use Linux-style comments.
I mean, this is not a requirement, this is just my opinion. But David is
the maintainer, and he does not agree here, so please, ignore this.
> > +struct jffs2_inode_cache; /* forward refence */
> A classic example of a senseless comment :-)
Err, sorry, I meant, this comment is not really useful and might be
removed.
> > +/*---- Any inline initialize functions ----*/
> > +#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist))
> Wierd comment.
How about to just remove this comment?
--
Best Regards,
Artem B. Bityutskiy,
St.-Petersburg, Russia.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-07 12:46 ` Artem B. Bityutskiy
2006-05-07 13:12 ` Artem B. Bityutskiy
@ 2006-05-07 13:18 ` David Woodhouse
2006-05-08 1:01 ` KaiGai Kohei
1 sibling, 1 reply; 30+ messages in thread
From: David Woodhouse @ 2006-05-07 13:18 UTC (permalink / raw)
To: dedekind; +Cc: linux-mtd, joern, KaiGai Kohei
On Sun, 2006-05-07 at 16:46 +0400, Artem B. Bityutskiy wrote:
> +/*-------------------------------------------------------------------------*
> > + * File: fs/jffs2/xattr.c
> Not sure it makes sense to specify file name here.
It's a common thing to do though; I don't think it matters much.
I would prefer to to have a consistent 'header' across all the JFFS2
files though -- I would have been inclined to copy the form used in
those. It's purely cosmetic though.
> > +#include <linux/xattr.h>
> You're using 'struct list_head' in your 'xattr.h' file, wouldn't it be a
> good tone to add #include <linux/lists.h> then?
Yes, it's good practice to include the header files you need directly,
rather than relying on the C file to include stuff like <linux/list.h>
before including "xattr.h".
It's not inefficient -- the compiler has a special optimisation where it
notices the 'include guards' we put around header files (#ifndef
__LIST_H\n#define __LIST_H\n....#endif) and doesn't even _open_ the
header file the second time it's included.
> > +struct jffs2_xattr_datum
> > +{
> > + void *always_null;
> > + u8 class;
> > + u8 flags;
> > + u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */
> > +
> > + struct jffs2_raw_node_ref *node;
> > + struct list_head xindex; /* chained from c->xattrindex[n] */
> > + uint32_t refcnt; /* # of xattr_ref refers this */
> > + uint32_t xid;
> > + uint32_t version;
> > +
> > + uint32_t data_crc;
> > + uint32_t hashkey;
> > + char *xname; /* XATTR name without prefix */
> > + uint32_t name_len; /* length of xname */
> > + char *xvalue; /* XATTR value */
> > + uint32_t value_len; /* length of xvalue */
> > +};
> Would be cuter to use Linux-style comments.
I think Artem is referring to kernel-doc style comments, which look like
this...
/**
* struct jffs2_xattr_datum - inode_cache equivalent for XATTR data
*
* @always_null: Equivalent of ic->scan_dents. Must be NULL
* @class: Used to distinguish from jffs2_inode_cache/jffs2_xattr_ref
...
I suppose it _might_ be nice if we were to do kerneldoc-style comments
all through JFFS2, and create a proper set of documentation for the
source code. I don't think it's fair to expert _you_ to start on that
though; there's plenty of work for Artem to do first if he wants that.
Personally, I prefer the comments _with_ the struct members, on the
right-hand-side as you've placed them. I'd want to keep those even if we
_do_ also have the kerneldoc comments which produce _external_
documentation for printing.
> > +struct jffs2_inode_cache; /* forward refence */
> A classic example of a senseless comment :-)
Yes, it's best to avoid commenting on things which don't need it.
> > +extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
> > + uint32_t xid, uint32_t version);
> > +
> > +extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
> > +extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
> > +
> > +extern int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
> I wouldn't follow old JFFS2 style and would not exceed the 80-characters
> per line limit.
Even in prototypes? I disagree. Limiting yourself to 80 characters just
makes it messier.
> > +/*---- Any inline initialize functions ----*/
> > +#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist))
> Wierd comment.
I think it was meant to read something like:
/*----- inline initialisation functions -----*/
But yes, since there's only one 'function' defined there and it's fairly
obvious that it's an initialisation function, the comment is probably
not needed.
If all Artem can come up with is cosmetics, then I'm sure we're doing
well :)
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 16:47 ` KaiGai Kohei
2006-05-06 17:53 ` David Woodhouse
@ 2006-05-07 13:25 ` Artem B. Bityutskiy
2006-05-07 13:29 ` David Woodhouse
1 sibling, 1 reply; 30+ messages in thread
From: Artem B. Bityutskiy @ 2006-05-07 13:25 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: linux-mtd, David Woodhouse, joern
BTW, is xattr being friends with summary?
--
Best Regards,
Artem B. Bityutskiy,
St.-Petersburg, Russia.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-07 13:25 ` Artem B. Bityutskiy
@ 2006-05-07 13:29 ` David Woodhouse
0 siblings, 0 replies; 30+ messages in thread
From: David Woodhouse @ 2006-05-07 13:29 UTC (permalink / raw)
To: dedekind; +Cc: joern, linux-mtd, KaiGai Kohei
On Sun, 2006-05-07 at 17:25 +0400, Artem B. Bityutskiy wrote:
> BTW, is xattr being friends with summary?
On Sat, 2006-05-06 at 15:51 +0900, KaiGai Kohei wrote:
> There are some significant differences from previous version posted
> at last December.
> The biggest change is addition of EBS(Erase Block Summary) support.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 6:51 [PATCH] XATTR support on JFFS2 (version. 5) KaiGai Kohei
2006-05-06 12:07 ` David Woodhouse
2006-05-07 12:46 ` Artem B. Bityutskiy
@ 2006-05-07 17:16 ` Jörn Engel
2006-05-08 2:03 ` KaiGai Kohei
2006-05-10 10:03 ` Artem B. Bityutskiy
3 siblings, 1 reply; 30+ messages in thread
From: Jörn Engel @ 2006-05-07 17:16 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: jmorris, sds, russell, linux-mtd, lorenzo, dwmw2
The code already looks quite good on the surface. Finding deeper
problems takes more time, which I lack. So there are not many
comments in this round.
On Sat, 6 May 2006 15:51:22 +0900, KaiGai Kohei wrote:
> +
> +static struct posix_acl *jffs2_acl_from_medium(const void *value, size_t size)
> +{
> + const char *end = (char *)value + size;
This cast appears to be unnecessary. Gcc has an extention that allows
arithmetic on void* pointers. The behaviour is just as if the pointer
was casted to unsigned long and back - quite useful.
> + ver = je32_to_cpu(((jffs2_acl_header *)value)->a_version);
In this case, it might make sense to create a local variable:
jffs2_acl_header *header = value;
...
ver = je32_to_cpu(header->a_version);
If only a single field is used from the header, this is a matter of
taste. If it occurs more often, the local variable helps with
readability.
> + value = (char *)value + sizeof(jffs2_acl_header);
Can be removed.
> + for (i=0; i < count; i++) {
> + jffs2_acl_entry *entry = (jffs2_acl_entry *)value;
This cast can be removed. void* can implicitly be cast to any pointer
type. Also, would it be possible to move this variable to the
beginning of the function and use it for the version check?
> + if ((char *)value + sizeof(jffs2_acl_entry_short) > end)
This and two more can be removed.
There is a reason to remove explicit casts whereever possible - and
why a strongly typed language like C++ can cause problems. With every
explicit cast, the compiler has to assume that everything is correct
here, even if it isn't. And if explicit casts are used everywhere in
the source, a human will usually do the same and ignore bugs that
should have been obvious.
In C, esp. with the gcc extension for void* arithmetic, explicit casts
are very rarely needed. And those few cases are easily checked by
humans for correctness.
Strong typing can also help to avoid bugs, but usually 95% of the code
is better off with weak typing, as in C. Some of the remaining cases
are caught by sparse with __bitwise and friends, so by my estimate 99%
of the code is better off without strong typing.
> + jffs2_acl = (jffs2_acl_header *)kmalloc(sizeof(jffs2_acl_header)
kmalloc() returns a void*, so no explicit cast is needed.
> + return (char *)jffs2_acl;
And this function returns void*, so this explicit cast isn't needed
either.
> --- mtd-2.6.git/fs/jffs2/acl.h 1970-01-01 09:00:00.000000000 +0900
> +++ mtd-2.6.0506/fs/jffs2/acl.h 2006-05-06 11:28:19.000000000 +0900
> @@ -0,0 +1,46 @@
#ifndef JFFS2_ACL_H
#define JFFS2_ACL_H
...
#endif
> +#ifdef __KERNEL__
> +#ifdef CONFIG_JFFS2_FS_POSIX_ACL
> +
> +#define JFFS2_ACL_NOT_CACHED ((void *)-1)
> +
> +extern int jffs2_permission(struct inode *, int, struct nameidata *);
> +extern int jffs2_acl_chmod(struct inode *);
> +extern int jffs2_init_acl(struct inode *, struct inode *);
> +extern void jffs2_clear_acl(struct inode *);
> +
> +extern struct xattr_handler jffs2_acl_access_xattr_handler;
> +extern struct xattr_handler jffs2_acl_default_xattr_handler;
> +
> +#else
> +
> +#define jffs2_permission NULL
> +#define jffs2_acl_chmod(inode) (0)
> +#define jffs2_init_acl(inode,dir) (0)
> +#define jffs2_clear_acl(inode)
> +
> +#endif /* CONFIG_JFFS2_FS_POSIX_ACL */
> +#endif /* __KERNEL__ */
The kernel is in a fairly bad shape wrt. seperating userspace
interface and in-kernel headers. dwmw2 is currently trying to sort
things out. Splitting this part into a seperate file would make his
job a bit easier.
> @@ -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
> };
Why does this field depend on CONFIG_JFFS2_FS_XATTR, while the above
doesn't? It looks as if splitting state into several fields is a
generic cleanup and can be merged independently of xattr support.
> [...]
Overall, the code looks nicer than most of the current jffs2, that is
good. What worries me a bit is the number of #ifdef's in it. In
sufficient number, those can make any code unmaintainable. In the
headers and in malloc.c, they are fine. In other files, it would be
good if they could get removed somehow.
Jörn
--
He who knows that enough is enough will always have enough.
-- Lao Tsu
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-07 13:18 ` David Woodhouse
@ 2006-05-08 1:01 ` KaiGai Kohei
0 siblings, 0 replies; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-08 1:01 UTC (permalink / raw)
To: David Woodhouse; +Cc: linux-mtd, joern
Hi, David and Aterm.
Thanks for your comments.
David Woodhouse wrote:
> On Sun, 2006-05-07 at 16:46 +0400, Artem B. Bityutskiy wrote:
>
>> +/*-------------------------------------------------------------------------*
>>> + * File: fs/jffs2/xattr.c
>> Not sure it makes sense to specify file name here.
>
> It's a common thing to do though; I don't think it matters much.
>
> I would prefer to to have a consistent 'header' across all the JFFS2
> files though -- I would have been inclined to copy the form used in
> those. It's purely cosmetic though.
I agree. The file header part at xattr.[ch], acl.[ch], security.c,
xattr_user.c and xattr_trusted.c should be updated.
>>> +#include <linux/xattr.h>
>> You're using 'struct list_head' in your 'xattr.h' file, wouldn't it be a
>> good tone to add #include <linux/lists.h> then?
>
> Yes, it's good practice to include the header files you need directly,
> rather than relying on the C file to include stuff like <linux/list.h>
> before including "xattr.h".
OK, I'll fix it.
>>> +struct jffs2_xattr_datum
>>> +{
>>> + void *always_null;
>>> + u8 class;
>>> + u8 flags;
>>> + u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */
>>> +
>>> + struct jffs2_raw_node_ref *node;
>>> + struct list_head xindex; /* chained from c->xattrindex[n] */
>>> + uint32_t refcnt; /* # of xattr_ref refers this */
>>> + uint32_t xid;
>>> + uint32_t version;
>>> +
>>> + uint32_t data_crc;
>>> + uint32_t hashkey;
>>> + char *xname; /* XATTR name without prefix */
>>> + uint32_t name_len; /* length of xname */
>>> + char *xvalue; /* XATTR value */
>>> + uint32_t value_len; /* length of xvalue */
>>> +};
>
>> Would be cuter to use Linux-style comments.
>
> I think Artem is referring to kernel-doc style comments, which look like
> this...
>
> /**
> * struct jffs2_xattr_datum - inode_cache equivalent for XATTR data
> *
> * @always_null: Equivalent of ic->scan_dents. Must be NULL
> * @class: Used to distinguish from jffs2_inode_cache/jffs2_xattr_ref
> ...
>
> I suppose it _might_ be nice if we were to do kerneldoc-style comments
> all through JFFS2, and create a proper set of documentation for the
> source code. I don't think it's fair to expert _you_ to start on that
> though; there's plenty of work for Artem to do first if he wants that.
>
> Personally, I prefer the comments _with_ the struct members, on the
> right-hand-side as you've placed them. I'd want to keep those even if we
> _do_ also have the kerneldoc comments which produce _external_
> documentation for printing.
I'll follow the common style on jffs2 implementation, when we can arrive
at an agreement. Now, I hope to suspend it.
>>> +struct jffs2_inode_cache; /* forward refence */
>> A classic example of a senseless comment :-)
>
> Yes, it's best to avoid commenting on things which don't need it.
I'll remove it.
(Futhermore, it's wrong in spelling. orz)
>>> +extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
>>> + uint32_t xid, uint32_t version);
>>> +
>>> +extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
>>> +extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
>>> +
>>> +extern int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
>
>> I wouldn't follow old JFFS2 style and would not exceed the 80-characters
>> per line limit.
>
> Even in prototypes? I disagree. Limiting yourself to 80 characters just
> makes it messier.
I'll follow the common style on jffs2 implementation, when we can arrive
at an agreement. Now, I hope to suspend it.
>>> +/*---- Any inline initialize functions ----*/
>>> +#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist))
>> Wierd comment.
>
> I think it was meant to read something like:
>
> /*----- inline initialisation functions -----*/
>
> But yes, since there's only one 'function' defined there and it's fairly
> obvious that it's an initialisation function, the comment is probably
> not needed.
>
> If all Artem can come up with is cosmetics, then I'm sure we're doing
> well :)
Ah, some inline functions were defined here at the previous versions of
xattr patches. This comment remained with old information.
Futhermore, init_xattr_inode_cache() will become also unnecesary because
'list_head ilist' will be replaced by 'struct jffs2_xattr_ref *xref' and
'xref' will be initialized as NULL by memset(ic, 0, sizeof(*ic)).
David suggested me to use single direction list instead of list_head for
memory usage reduction at previous reply.
Thus, I'll remove both this comment and definition of init_xattr_inode_cache().
Thanks,
--
Open Source Software Promotion Center, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-07 17:16 ` Jörn Engel
@ 2006-05-08 2:03 ` KaiGai Kohei
2006-05-08 12:49 ` David Woodhouse
0 siblings, 1 reply; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-08 2:03 UTC (permalink / raw)
To: Jörn Engel; +Cc: jmorris, sds, lorenzo, russell, linux-mtd, dwmw2
Hi, Jörn. Thanks for your comments.
> On Sat, 6 May 2006 15:51:22 +0900, KaiGai Kohei wrote:
>> +
>> +static struct posix_acl *jffs2_acl_from_medium(const void *value, size_t size)
>> +{
>> + const char *end = (char *)value + size;
>
> This cast appears to be unnecessary. Gcc has an extention that allows
> arithmetic on void* pointers. The behaviour is just as if the pointer
> was casted to unsigned long and back - quite useful.
Hmm, I'll review the implementation and reduce the unnecessary casts.
>> + ver = je32_to_cpu(((jffs2_acl_header *)value)->a_version);
>
> In this case, it might make sense to create a local variable:
> jffs2_acl_header *header = value;
> ...
> ver = je32_to_cpu(header->a_version);
>
> If only a single field is used from the header, this is a matter of
> taste. If it occurs more often, the local variable helps with
> readability.
The most of posix-acl implementation on jffs2 is mede with referring
to ext2/3's implementation. The jffs2_acl_header structure is reflection
of ext2_acl_header.
I also think using local variable is good idea for readability. I'll fix it.
>> + value = (char *)value + sizeof(jffs2_acl_header);
>
> Can be removed.
>
>> + for (i=0; i < count; i++) {
>> + jffs2_acl_entry *entry = (jffs2_acl_entry *)value;
>
> This cast can be removed. void* can implicitly be cast to any pointer
> type. Also, would it be possible to move this variable to the
> beginning of the function and use it for the version check?
jffs2_acl_header is used for version checking, not jffs2_acl_entry.
Thus, it's not possible to use version checking. But I'll remove
unnecessary cast.
>> + jffs2_acl = (jffs2_acl_header *)kmalloc(sizeof(jffs2_acl_header)
>
> kmalloc() returns a void*, so no explicit cast is needed.
>
>> + return (char *)jffs2_acl;
>
> And this function returns void*, so this explicit cast isn't needed
> either.
I agreed. Those should be reduced.
> #ifndef JFFS2_ACL_H
> #define JFFS2_ACL_H
> ...
> #endif
>
>> +#ifdef __KERNEL__
>> +#ifdef CONFIG_JFFS2_FS_POSIX_ACL
... <snip> ...
>> +#endif /* CONFIG_JFFS2_FS_POSIX_ACL */
>> +#endif /* __KERNEL__ */
>
> The kernel is in a fairly bad shape wrt. seperating userspace
> interface and in-kernel headers. dwmw2 is currently trying to sort
> things out. Splitting this part into a seperate file would make his
> job a bit easier.
Because 'acl.h' was shared by mkfs.jffs2 at previous version of xattr
patches. But the __KERNEL__ ifdef block is unnecessary now.
I'll remove it.
>> @@ -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
>> };
>
> Why does this field depend on CONFIG_JFFS2_FS_XATTR, while the above
> doesn't? It looks as if splitting state into several fields is a
> generic cleanup and can be merged independently of xattr support.
If ilist would be always enabled, it will enforce any users the amount
of 2 * sizeof(void *) bytes memory usage increase per inode_cache
whether they hope to use xattr or not regardless of.
Thus, this field is defined with depending on CONFIG_JFFS2_FS_XATTR.
About the state variable, I splited it into three variable unconditionaly
because it didn't have such a bad effect (if int has 32-bit width).
Thanks,
[Current TODO list]
* Fix the declaration of jffs2_acl_header and so on by using 'struct'
instead of 'typedef' in kernel space.
- Fix the declaration of jffs2_acl_header and so on by using 'struct'
instead of 'typedef' in user space header.
* Add documentation about xattr_sem into README.Locking.
* Call jffs2_garbage_collect_xattr_datum/ref() from gc.c directly
instead of jffs2_garbage_collect_xattr()
- Use unidirection list beween inode_chache and xattr_ref, instead of
list_head.
- Add '#include <linux/list.h>' into xattr.h.
- Unify each file header part with any jffs2 files.
- Remove a senseless comment. ("/* forward refence */")
- Remove unneccesary pointer casts.
- Remove unneccesary '#ifdef __KERNEL__' on acl.h
*: It has already prepared, but I've not publicated yet.
-: It has not prepated yet. I should work from now.
--
Open Source Software Promotion Center, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-08 2:03 ` KaiGai Kohei
@ 2006-05-08 12:49 ` David Woodhouse
2006-05-09 16:10 ` KaiGai Kohei
2006-05-10 13:28 ` Jörn Engel
0 siblings, 2 replies; 30+ messages in thread
From: David Woodhouse @ 2006-05-08 12:49 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: jmorris, sds, russell, lorenzo, linux-mtd, Jörn Engel
On Mon, 2006-05-08 at 11:03 +0900, KaiGai Kohei wrote:
> [Current TODO list]
> * Fix the declaration of jffs2_acl_header and so on by using 'struct'
> instead of 'typedef' in kernel space.
> - Fix the declaration of jffs2_acl_header and so on by using 'struct'
> instead of 'typedef' in user space header.
> * Add documentation about xattr_sem into README.Locking.
> * Call jffs2_garbage_collect_xattr_datum/ref() from gc.c directly
> instead of jffs2_garbage_collect_xattr()
> - Use unidirection list beween inode_chache and xattr_ref, instead of
> list_head.
> - Add '#include <linux/list.h>' into xattr.h.
> - Unify each file header part with any jffs2 files.
> - Remove a senseless comment. ("/* forward refence */")
> - Remove unneccesary pointer casts.
> - Remove unneccesary '#ifdef __KERNEL__' on acl.h
>
> *: It has already prepared, but I've not publicated yet.
> -: It has not prepated yet. I should work from now.
That's an excellent summary; thanks. It does serve to show that we've
mostly picked on cosmetic details so far though :)
If you have patches committed into a git tree, you should be able to
just 'git-push ssh://git.infradead.org/home/git/jffs2-xattr-2.6.git' to
make it available.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-08 12:49 ` David Woodhouse
@ 2006-05-09 16:10 ` KaiGai Kohei
2006-05-11 23:16 ` KaiGai Kohei
2006-05-10 13:28 ` Jörn Engel
1 sibling, 1 reply; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-09 16:10 UTC (permalink / raw)
To: David Woodhouse
Cc: jmorris, KaiGai Kohei, russell, lorenzo, linux-mtd, sds,
Jörn Engel
[-- Attachment #1: Type: text/plain, Size: 2234 bytes --]
Hi,
Some fixes and updates on the todo list are already
pushed to git://git.infradead.org/jffs2-xattr-2.6.git .
The broken-out patches are available at here:
http://www.kaigai.gr.jp/index.php?FrontPage#vd169842
01. jffs2-xattr-v5.1-01-remove_typedef_kernel.patch
02. jffs2-xattr-v5.1-02-remove_typedef_utils.patch
03. jffs2-xattr-v5.1-03-append_README.Locking.patch
04. jffs2-xattr-v5.1-04-remove_ilist_from_ic.patch
05. jffs2-xattr-v5.1-05-update_xattr_gc.patch
06. jffs2-xattr-v5.1-06-add_list.h.patch
07. jffs2-xattr-v5.1-07-unify_file_header.patch
08. jffs2-xattr-v5.1-08-remove_senseless_comment.patch
09. jffs2-xattr-v5.1-09-remove__KERNEL__.patch
10. jffs2-xattr-v5.1-10-remove_pointer_cast.patch
I hope to merge the second patch (jffs2-xattr-v5.1-02-remove_typedef_utils.patch),
because this patch is for mtd-utils.git, not jffs2-xattr-2.6.git.
P.S.
Thanks David for your introduction about git on infradead.org.
David Woodhouse wrote:
> On Mon, 2006-05-08 at 11:03 +0900, KaiGai Kohei wrote:
>
>>[Current TODO list]
>>* Fix the declaration of jffs2_acl_header and so on by using 'struct'
>> instead of 'typedef' in kernel space.
>>- Fix the declaration of jffs2_acl_header and so on by using 'struct'
>> instead of 'typedef' in user space header.
>>* Add documentation about xattr_sem into README.Locking.
>>* Call jffs2_garbage_collect_xattr_datum/ref() from gc.c directly
>> instead of jffs2_garbage_collect_xattr()
>>- Use unidirection list beween inode_chache and xattr_ref, instead of
>> list_head.
>>- Add '#include <linux/list.h>' into xattr.h.
>>- Unify each file header part with any jffs2 files.
>>- Remove a senseless comment. ("/* forward refence */")
>>- Remove unneccesary pointer casts.
>>- Remove unneccesary '#ifdef __KERNEL__' on acl.h
>>
>>*: It has already prepared, but I've not publicated yet.
>>-: It has not prepated yet. I should work from now.
>
>
> That's an excellent summary; thanks. It does serve to show that we've
> mostly picked on cosmetic details so far though :)
>
> If you have patches committed into a git tree, you should be able to
> just 'git-push ssh://git.infradead.org/home/git/jffs2-xattr-2.6.git' to
> make it available.
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
[-- Attachment #2: jffs2-xattr-v5.1-02-remove_typedef_utils.patch --]
[-- Type: text/plain, Size: 3190 bytes --]
diff --git a/include/mtd/jffs2-user.h b/include/mtd/jffs2-user.h
index 8b53990..bc5d99a 100644
--- a/include/mtd/jffs2-user.h
+++ b/include/mtd/jffs2-user.h
@@ -50,33 +50,33 @@ extern int target_endian;
#define XATTR_TRUSTED_PREFIX "trusted."
#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
-typedef struct {
+struct jffs2_acl_entry {
jint16_t e_tag;
jint16_t e_perm;
jint32_t e_id;
-} jffs2_acl_entry;
+};
-typedef struct {
+struct jffs2_acl_entry_short {
jint16_t e_tag;
jint16_t e_perm;
-} jffs2_acl_entry_short;
+};
-typedef struct {
+struct jffs2_acl_header {
jint32_t a_version;
-} jffs2_acl_header;
+};
/* copied from include/linux/posix_acl_xattr.h */
#define POSIX_ACL_XATTR_VERSION 0x0002
-typedef struct {
+struct posix_acl_xattr_entry {
uint16_t e_tag;
uint16_t e_perm;
uint32_t e_id;
-} posix_acl_xattr_entry;
+};
-typedef struct {
- uint32_t a_version;
- posix_acl_xattr_entry a_entries[0];
-} posix_acl_xattr_header;
+struct posix_acl_xattr_header {
+ uint32_t a_version;
+ struct posix_acl_xattr_entry a_entries[0];
+};
#endif /* __JFFS2_USER_H__ */
diff --git a/mkfs.jffs2.c b/mkfs.jffs2.c
index 02f57f9..fa4a5f3 100644
--- a/mkfs.jffs2.c
+++ b/mkfs.jffs2.c
@@ -1052,22 +1052,22 @@ static struct {
{ 0, NULL, 0 }
};
-static void formalize_posix_acl(char *xvalue, int *value_len)
+static void formalize_posix_acl(void *xvalue, int *value_len)
{
- posix_acl_xattr_header *pacl_header;
- posix_acl_xattr_entry *pent, *plim;
- jffs2_acl_header *jacl_header;
- jffs2_acl_entry *jent;
- jffs2_acl_entry_short *jent_s;
+ struct posix_acl_xattr_header *pacl_header;
+ struct posix_acl_xattr_entry *pent, *plim;
+ struct jffs2_acl_header *jacl_header;
+ struct jffs2_acl_entry *jent;
+ struct jffs2_acl_entry_short *jent_s;
char buffer[XATTR_BUFFER_SIZE];
int offset = 0;
- pacl_header = (posix_acl_xattr_header *)xvalue;;
+ pacl_header = xvalue;;
pent = pacl_header->a_entries;
- plim = (posix_acl_xattr_entry *)(xvalue + *value_len);
+ plim = xvalue + *value_len;
- jacl_header = (jffs2_acl_header *)buffer;
- offset += sizeof(jffs2_acl_header);
+ jacl_header = (struct jffs2_acl_header *)buffer;
+ offset += sizeof(struct jffs2_acl_header);
jacl_header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
while (pent < plim) {
@@ -1076,15 +1076,15 @@ static void formalize_posix_acl(char *xv
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
- jent_s = (jffs2_acl_entry_short *)(buffer + offset);
- offset += sizeof(jffs2_acl_entry_short);
+ jent_s = (struct jffs2_acl_entry_short *)(buffer + offset);
+ offset += sizeof(struct jffs2_acl_entry_short);
jent_s->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
jent_s->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
break;
case ACL_USER:
case ACL_GROUP:
- jent = (jffs2_acl_entry *)(buffer + offset);
- offset += sizeof(jffs2_acl_entry);
+ jent = (struct jffs2_acl_entry *)(buffer + offset);
+ offset += sizeof(struct jffs2_acl_entry);
jent->e_tag = cpu_to_je16(le16_to_cpu(pent->e_tag));
jent->e_perm = cpu_to_je16(le16_to_cpu(pent->e_perm));
jent->e_id = cpu_to_je32(le32_to_cpu(pent->e_id));
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-06 6:51 [PATCH] XATTR support on JFFS2 (version. 5) KaiGai Kohei
` (2 preceding siblings ...)
2006-05-07 17:16 ` Jörn Engel
@ 2006-05-10 10:03 ` Artem B. Bityutskiy
2006-05-10 11:06 ` David Woodhouse
3 siblings, 1 reply; 30+ messages in thread
From: Artem B. Bityutskiy @ 2006-05-10 10:03 UTC (permalink / raw)
To: KaiGai Kohei; +Cc: joern, dwmw2, linux-mtd
On Sat, 2006-05-06 at 15:51 +0900, KaiGai Kohei wrote:
> This attached patches provide xattr support including POSIX-ACL and
> SELinux support on JFFS2 (version.5).
> We can apply those patches to the latest git-tree.
> - xattr_on_jffs2.kernel.version-5.patch can be applied to mtd-2.6.git.
> - xattr_on_jffs2.utils.version-5.patch can be applied to mtd-utils.git.
The patch in general looks nice. I have got no real
suggestions/objections for now, slowly trying to read it and delve into
(the patch is quite large, my time is very limited).
Few suggestions for now (again cosmetic):
1. GC-related functions and summary-related functions should be moved to
gc.c and summary.c
2. JFFS2 uses namings we all are used to. E.g., c - JFFS2 superblock
structure, ref - struct jffs2_node_ref. I've noticed you use 'ref' as
jffs2_xattr_ref pointers which is just a bit confusing. I would suggest
you calling them 'xref' - this would improve readability a bit.
Example of confusing code:
> + down_write(&c->xattr_sem);
> + list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist)
> + delete_xattr_ref(c, ref);
> + up_write(&c->xattr_sem);
This would be more readable for those aware with "older" JFFS2
internals:
> + down_write(&c->xattr_sem);
> + list_for_each_entry_safe(xref, _xref, &ic->ilist, ilist)
> + delete_xattr_ref(c, xref);
> + up_write(&c->xattr_sem);
It's minor, but still.
Will you object if I just do some changes I consider useful in xattr
GIT? Or should I first mail you?
--
Best Regards,
Artem B. Bityutskiy,
St.-Petersburg, Russia.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-10 10:03 ` Artem B. Bityutskiy
@ 2006-05-10 11:06 ` David Woodhouse
2006-05-10 11:22 ` Artem B. Bityutskiy
2006-05-10 12:03 ` KaiGai Kohei
0 siblings, 2 replies; 30+ messages in thread
From: David Woodhouse @ 2006-05-10 11:06 UTC (permalink / raw)
To: dedekind; +Cc: linux-mtd, joern, KaiGai Kohei
On Wed, 2006-05-10 at 14:03 +0400, Artem B. Bityutskiy wrote:
> Few suggestions for now (again cosmetic):
>
> 1. GC-related functions and summary-related functions should be moved to
> gc.c and summary.c
Then they'd need ifdefs. I'd prefer to keep them where they are, in
separate files which aren't compiled if the XATTR options are disabled.
> 2. JFFS2 uses namings we all are used to. E.g., c - JFFS2 superblock
> structure, ref - struct jffs2_node_ref. I've noticed you use 'ref' as
> jffs2_xattr_ref pointers which is just a bit confusing. I would suggest
> you calling them 'xref' - this would improve readability a bit.
Really, I don't think it matters.
> > + delete_xattr_ref(c, ref);
> > + delete_xattr_ref(c, xref);
> It's minor, but still.
It's not even 'minor'. It's total bullshit. If you can't look at the
function name "delete_XATTR_REF" and work out what 'ref' is in that
context, then you really shouldn't be trying to read the code. Life is
hard; let's go shopping.
I got annoyed with you when you started on stuff like this in JFFS2
code. Don't start on the XATTR code too.
I do see your point to a _certain_ extent, but let's concentrate on
things that actually matter instead, OK?
> Will you object if I just do some changes I consider useful in xattr
> GIT? Or should I first mail you?
Feel free to make your own tree in ~dedekind/public_git and _ask_ people
to pull from it. Please do not commit directly
to /home/git/jffs2-xattr-2.6 (not that I think you can anyway).
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-10 11:06 ` David Woodhouse
@ 2006-05-10 11:22 ` Artem B. Bityutskiy
2006-05-10 12:03 ` KaiGai Kohei
1 sibling, 0 replies; 30+ messages in thread
From: Artem B. Bityutskiy @ 2006-05-10 11:22 UTC (permalink / raw)
To: David Woodhouse; +Cc: linux-mtd, joern, KaiGai Kohei
On Wed, 2006-05-10 at 12:06 +0100, David Woodhouse wrote:
> It's not even 'minor'. It's total bullshit. If you can't look at the
> function name "delete_XATTR_REF" and work out what 'ref' is in that
> context, then you really shouldn't be trying to read the code. Life is
> hard; let's go shopping.
It's not bullshit. The name of function has nothing to do here - there
are many places like that (1), the function name does not have to
correlate (2).
> I got annoyed with you when you started on stuff like this in JFFS2
> code. Don't start on the XATTR code too.
I remember - you prevented me from many clean-ups and tidy-ups.
> I do see your point to a _certain_ extent, but let's concentrate on
> things that actually matter instead, OK?
I also see your point. Sorry, but I do not agree with this strategy.
Many things which "don't matter" may start mattering sooner or later.
Thanks.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-10 11:06 ` David Woodhouse
2006-05-10 11:22 ` Artem B. Bityutskiy
@ 2006-05-10 12:03 ` KaiGai Kohei
1 sibling, 0 replies; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-10 12:03 UTC (permalink / raw)
To: David Woodhouse, dedekind; +Cc: linux-mtd, joern
Hi,
>> Few suggestions for now (again cosmetic):
>>
>> 1. GC-related functions and summary-related functions should be moved to
>> gc.c and summary.c
>
> Then they'd need ifdefs. I'd prefer to keep them where they are, in
> separate files which aren't compiled if the XATTR options are disabled.
I also agree David's opinion.
In addition, those functions are deployed enough locally-separating
in xattr.c.
Sorry, I could not understand your dissatisfaction.
>> 2. JFFS2 uses namings we all are used to. E.g., c - JFFS2 superblock
>> structure, ref - struct jffs2_node_ref. I've noticed you use 'ref' as
>> jffs2_xattr_ref pointers which is just a bit confusing. I would suggest
>> you calling them 'xref' - this would improve readability a bit.
>
> Really, I don't think it matters.
>
>>> + delete_xattr_ref(c, ref);
>>> + delete_xattr_ref(c, xref);
>
>> It's minor, but still.
>
> It's not even 'minor'. It's total bullshit. If you can't look at the
> function name "delete_XATTR_REF" and work out what 'ref' is in that
> context, then you really shouldn't be trying to read the code. Life is
> hard; let's go shopping.
Is the 'raw' used as the common name for jffs2_raw_node_ref, not 'ref',
isn't it? Because I thought those are not confusable, I adopted 'ref'
as a name of jffs2_xattr_ref.
If we can arrive an agreement that it's confusable naming scheme,
I'll prepare to change the common name of jffs2_xattr_ref.
Both naming schemes are acceptable for me.
It's important to decide what should be decided at first, I think.
Thanks,
--
Open Source Software Promotion Center, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-08 12:49 ` David Woodhouse
2006-05-09 16:10 ` KaiGai Kohei
@ 2006-05-10 13:28 ` Jörn Engel
1 sibling, 0 replies; 30+ messages in thread
From: Jörn Engel @ 2006-05-10 13:28 UTC (permalink / raw)
To: David Woodhouse; +Cc: jmorris, KaiGai Kohei, russell, lorenzo, linux-mtd, sds
On Mon, 8 May 2006 13:49:27 +0100, David Woodhouse wrote:
> On Mon, 2006-05-08 at 11:03 +0900, KaiGai Kohei wrote:
> > [Current TODO list]
> > * Fix the declaration of jffs2_acl_header and so on by using 'struct'
> > instead of 'typedef' in kernel space.
> > - Fix the declaration of jffs2_acl_header and so on by using 'struct'
> > instead of 'typedef' in user space header.
> > * Add documentation about xattr_sem into README.Locking.
> > * Call jffs2_garbage_collect_xattr_datum/ref() from gc.c directly
> > instead of jffs2_garbage_collect_xattr()
> > - Use unidirection list beween inode_chache and xattr_ref, instead of
> > list_head.
> > - Add '#include <linux/list.h>' into xattr.h.
> > - Unify each file header part with any jffs2 files.
> > - Remove a senseless comment. ("/* forward refence */")
> > - Remove unneccesary pointer casts.
> > - Remove unneccesary '#ifdef __KERNEL__' on acl.h
> >
> > *: It has already prepared, but I've not publicated yet.
> > -: It has not prepated yet. I should work from now.
>
> That's an excellent summary; thanks. It does serve to show that we've
> mostly picked on cosmetic details so far though :)
Correct. The basic design makes sense, the code is good. I don't
feel opposed to merging it once above list is handled. The number of
new #ifdefs still concerns me a bit, but we can still deal with that
after the merge. There has been worse.
Jörn
--
You can't tell where a program is going to spend its time. Bottlenecks
occur in surprising places, so don't try to second guess and put in a
speed hack until you've proven that's where the bottleneck is.
-- Rob Pike
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-09 16:10 ` KaiGai Kohei
@ 2006-05-11 23:16 ` KaiGai Kohei
2006-05-11 23:31 ` David Woodhouse
0 siblings, 1 reply; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-11 23:16 UTC (permalink / raw)
To: linux-mtd
Cc: jmorris, sds, russell, KaiGai Kohei, lorenzo, David Woodhouse,
Jörn Engel
Hi,
I'll push two patches into jffs2-xattr-2.6.git tree.
The one of them is obvious. It fixes a typo in comments.
I want any comments for another one before commiting into tree.
There is a possibility that jffs2_setup_xattr_datum() returns
-EEXIST, if a xattr_datum which has same xid and newer version
number is already registered.
The pre-patched implementation ignores this error code and
doesn't care. Theredore, total process of FS-mounting failed.
This patch fixes this problem, When we found such a obsolete
node, it will be dealt as a DIRTY_SPACE() and FS-mounting
will be continued.
It works correctly, and I belive this solution is right.
Thanks,
The broken-out patches are available at here:
http://www.kaigai.gr.jp/index.php?FrontPage#vd16984
01. jffs2-xattr-v5.2-01-fix-duplicate-xdatum.patch
02. jffs2-xattr-v5.2-02-fix_obvious_typo.patch
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
index 5cde227..d7884e3 100644
--- a/fs/jffs2/summary.c
+++ b/fs/jffs2/summary.c
@@ -508,8 +508,14 @@ static int jffs2_sum_process_sum_data(st
xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
je32_to_cpu(spx->version));
if (IS_ERR(xd)) {
- JFFS2_NOTICE("allocation of xattr_datum failed\n");
jffs2_free_raw_node_ref(raw);
+ if (PTR_ERR(xd) == -EEXIST) {
+ /* a newer version of xd exists */
+ DIRTY_SPACE(je32_to_cpu(spx->totlen));
+ sp += JFFS2_SUMMARY_XATTR_SIZE;
+ break;
+ }
+ JFFS2_NOTICE("allocation of xattr_datum failed\n");
kfree(summary);
return PTR_ERR(xd);
}
KaiGai Kohei wrote:
> Hi,
>
> Some fixes and updates on the todo list are already
> pushed to git://git.infradead.org/jffs2-xattr-2.6.git .
>
> The broken-out patches are available at here:
> http://www.kaigai.gr.jp/index.php?FrontPage#vd169842
>
> 01. jffs2-xattr-v5.1-01-remove_typedef_kernel.patch
> 02. jffs2-xattr-v5.1-02-remove_typedef_utils.patch
> 03. jffs2-xattr-v5.1-03-append_README.Locking.patch
> 04. jffs2-xattr-v5.1-04-remove_ilist_from_ic.patch
> 05. jffs2-xattr-v5.1-05-update_xattr_gc.patch
> 06. jffs2-xattr-v5.1-06-add_list.h.patch
> 07. jffs2-xattr-v5.1-07-unify_file_header.patch
> 08. jffs2-xattr-v5.1-08-remove_senseless_comment.patch
> 09. jffs2-xattr-v5.1-09-remove__KERNEL__.patch
> 10. jffs2-xattr-v5.1-10-remove_pointer_cast.patch
>
> I hope to merge the second patch
> (jffs2-xattr-v5.1-02-remove_typedef_utils.patch),
> because this patch is for mtd-utils.git, not jffs2-xattr-2.6.git.
>
> P.S.
> Thanks David for your introduction about git on infradead.org.
>
> David Woodhouse wrote:
>
>> On Mon, 2006-05-08 at 11:03 +0900, KaiGai Kohei wrote:
>>
>>> [Current TODO list]
>>> * Fix the declaration of jffs2_acl_header and so on by using 'struct'
>>> instead of 'typedef' in kernel space.
>>> - Fix the declaration of jffs2_acl_header and so on by using 'struct'
>>> instead of 'typedef' in user space header.
>>> * Add documentation about xattr_sem into README.Locking.
>>> * Call jffs2_garbage_collect_xattr_datum/ref() from gc.c directly
>>> instead of jffs2_garbage_collect_xattr()
>>> - Use unidirection list beween inode_chache and xattr_ref, instead of
>>> list_head.
>>> - Add '#include <linux/list.h>' into xattr.h.
>>> - Unify each file header part with any jffs2 files.
>>> - Remove a senseless comment. ("/* forward refence */")
>>> - Remove unneccesary pointer casts.
>>> - Remove unneccesary '#ifdef __KERNEL__' on acl.h
>>>
>>> *: It has already prepared, but I've not publicated yet.
>>> -: It has not prepated yet. I should work from now.
>>
>>
>>
>> That's an excellent summary; thanks. It does serve to show that we've
>> mostly picked on cosmetic details so far though :)
>>
>> If you have patches committed into a git tree, you should be able to
>> just 'git-push ssh://git.infradead.org/home/git/jffs2-xattr-2.6.git' to
>> make it available.
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-11 23:16 ` KaiGai Kohei
@ 2006-05-11 23:31 ` David Woodhouse
2006-05-12 15:20 ` KaiGai Kohei
0 siblings, 1 reply; 30+ messages in thread
From: David Woodhouse @ 2006-05-11 23:31 UTC (permalink / raw)
To: KaiGai Kohei
Cc: jmorris, KaiGai Kohei, russell, linux-mtd, lorenzo, sds,
Jörn Engel
On Fri, 2006-05-12 at 08:16 +0900, KaiGai Kohei wrote:
>
> The pre-patched implementation ignores this error code and
> doesn't care. Theredore, total process of FS-mounting failed.
> This patch fixes this problem, When we found such a obsolete
> node, it will be dealt as a DIRTY_SPACE() and FS-mounting
> will be continued.
>
> It works correctly, and I belive this solution is right.
It does look correct to me. The patch seems to highlight some
inconsistency of tabs vs. spaces in the indenting though.
When committing to the a git tree, please remember that if I pull from
it and then Linux pulls from it, the 'subject' of your commit should be
meaningful in that context. So it should mention 'JFFS2' at the very
least.
That's probably not quite so important for your jffs2-xattr tree, since
I think I'll probably import that as a _patch_ when we're ready, rather
than just pulling the whole thing. But in general, it's a useful thing
to remember for people committing to git trees and expecting me to pull
from them.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-11 23:31 ` David Woodhouse
@ 2006-05-12 15:20 ` KaiGai Kohei
2006-05-12 15:32 ` Jörn Engel
2006-05-12 15:38 ` David Woodhouse
0 siblings, 2 replies; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-12 15:20 UTC (permalink / raw)
To: David Woodhouse
Cc: jmorris, KaiGai Kohei, russell, linux-mtd, lorenzo, sds,
Jörn Engel
Hi, Thanks for yout comments.
> It does look correct to me. The patch seems to highlight some
> inconsistency of tabs vs. spaces in the indenting though.
Sorry, it's translated by terminal emulator automatically.
The patch keeps consistency of tabs in the indenting.
> When committing to the a git tree, please remember that if I pull from
> it and then Linux pulls from it, the 'subject' of your commit should be
> meaningful in that context. So it should mention 'JFFS2' at the very
> least.
OK, I'll pay attention to attach 'JFFS2' to the subject.
But nine of previous patches which have been already commited did not
attach such a keyword. Is it necessary to update the subject of them ?
(But I don't know how to operate for this. Hmm...)
Thanks,
> That's probably not quite so important for your jffs2-xattr tree, since
> I think I'll probably import that as a _patch_ when we're ready, rather
> than just pulling the whole thing. But in general, it's a useful thing
> to remember for people committing to git trees and expecting me to pull
> from them.
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-12 15:20 ` KaiGai Kohei
@ 2006-05-12 15:32 ` Jörn Engel
2006-05-12 15:38 ` David Woodhouse
1 sibling, 0 replies; 30+ messages in thread
From: Jörn Engel @ 2006-05-12 15:32 UTC (permalink / raw)
To: KaiGai Kohei
Cc: jmorris, KaiGai Kohei, russell, linux-mtd, lorenzo,
Thomas Gleixner, David Woodhouse, sds
On Sat, 13 May 2006 00:20:17 +0900, KaiGai Kohei wrote:
>
> OK, I'll pay attention to attach 'JFFS2' to the subject.
> But nine of previous patches which have been already commited did not
> attach such a keyword. Is it necessary to update the subject of them ?
> (But I don't know how to operate for this. Hmm...)
Quite likely, the easiest way would be to work with two scripts. One
to convert a git tree into a quilt series and another to convert the
quilt series back into a git tree.
Advantage of quilt is the ease with which one can cherry-pick patches,
change patches or descriptions, reorder patches, rebase them for a new
kernel, etc.
I believe tglx (added to Cc:) has some scripts like that. And since
many kernel hacker have similar needs, google should find even more.
[ Note to self: I need them as well. ]
Jörn
--
This above all: to thine own self be true.
-- Shakespeare
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-12 15:20 ` KaiGai Kohei
2006-05-12 15:32 ` Jörn Engel
@ 2006-05-12 15:38 ` David Woodhouse
2006-05-13 6:37 ` KaiGai Kohei
1 sibling, 1 reply; 30+ messages in thread
From: David Woodhouse @ 2006-05-12 15:38 UTC (permalink / raw)
To: KaiGai Kohei
Cc: jmorris, KaiGai Kohei, russell, linux-mtd, lorenzo, sds,
Jörn Engel
On Sat, 2006-05-13 at 00:20 +0900, KaiGai Kohei wrote:
> Sorry, it's translated by terminal emulator automatically.
> The patch keeps consistency of tabs in the indenting.
OK, that's good.
> OK, I'll pay attention to attach 'JFFS2' to the subject.
> But nine of previous patches which have been already commited did not
> attach such a keyword. Is it necessary to update the subject of them ?
> (But I don't know how to operate for this. Hmm...)
It is possible, I think -- the 'cg-admin-rewritehist' tool in Cogito
allows it. Alternatively, it's easy enough to cherry-pick patches from
git and apply them to a new branch, then make that new branch your
'master'. If you do this, remember to push with the '--force' option so
that your new tree overwrites the remote.
If you like, we can leave the XATTR tree as it is, and import it as a
patch instead of with git-pull. Then the history doesn't matter.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-12 15:38 ` David Woodhouse
@ 2006-05-13 6:37 ` KaiGai Kohei
2006-05-13 10:46 ` David Woodhouse
0 siblings, 1 reply; 30+ messages in thread
From: KaiGai Kohei @ 2006-05-13 6:37 UTC (permalink / raw)
To: David Woodhouse
Cc: jmorris, KaiGai Kohei, russell, linux-mtd, lorenzo, sds,
Jörn Engel
Hi,
I have fixed the subject of patches in jffs2-xattr-2.6.git tree
by the following method.
> Alternatively, it's easy enough to cherry-pick patches from
> git and apply them to a new branch, then make that new branch your
> 'master'. If you do this, remember to push with the '--force' option so
> that your new tree overwrites the remote.
The all of previous 12 patches has '[JFFS2][XATTR]' prefix now.
Please confirm at http://git.infradead.org/?p=jffs2-xattr-2.6.git;a=log
Thanks for those indications at early phase.
--
KaiGai Kohei <kaigai@kaigai.gr.jp>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH] XATTR support on JFFS2 (version. 5)
2006-05-13 6:37 ` KaiGai Kohei
@ 2006-05-13 10:46 ` David Woodhouse
0 siblings, 0 replies; 30+ messages in thread
From: David Woodhouse @ 2006-05-13 10:46 UTC (permalink / raw)
To: KaiGai Kohei
Cc: jmorris, KaiGai Kohei, russell, linux-mtd, lorenzo, sds,
Jörn Engel
On Sat, 2006-05-13 at 15:37 +0900, KaiGai Kohei wrote:
> The all of previous 12 patches has '[JFFS2][XATTR]' prefix now.
> Please confirm at http://git.infradead.org/?p=jffs2-xattr-2.6.git;a=log
That looks good; thanks.
--
dwmw2
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2006-05-13 10:46 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-06 6:51 [PATCH] XATTR support on JFFS2 (version. 5) KaiGai Kohei
2006-05-06 12:07 ` David Woodhouse
2006-05-06 12:38 ` David Woodhouse
2006-05-06 16:47 ` KaiGai Kohei
2006-05-06 17:53 ` David Woodhouse
2006-05-07 0:22 ` KaiGai Kohei
2006-05-07 0:29 ` David Woodhouse
2006-05-07 10:19 ` Artem B. Bityutskiy
2006-05-07 13:25 ` Artem B. Bityutskiy
2006-05-07 13:29 ` David Woodhouse
2006-05-07 12:46 ` Artem B. Bityutskiy
2006-05-07 13:12 ` Artem B. Bityutskiy
2006-05-07 13:18 ` David Woodhouse
2006-05-08 1:01 ` KaiGai Kohei
2006-05-07 17:16 ` Jörn Engel
2006-05-08 2:03 ` KaiGai Kohei
2006-05-08 12:49 ` David Woodhouse
2006-05-09 16:10 ` KaiGai Kohei
2006-05-11 23:16 ` KaiGai Kohei
2006-05-11 23:31 ` David Woodhouse
2006-05-12 15:20 ` KaiGai Kohei
2006-05-12 15:32 ` Jörn Engel
2006-05-12 15:38 ` David Woodhouse
2006-05-13 6:37 ` KaiGai Kohei
2006-05-13 10:46 ` David Woodhouse
2006-05-10 13:28 ` Jörn Engel
2006-05-10 10:03 ` Artem B. Bityutskiy
2006-05-10 11:06 ` David Woodhouse
2006-05-10 11:22 ` Artem B. Bityutskiy
2006-05-10 12:03 ` KaiGai Kohei
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox