Commit aa98d7cf authored by KaiGai Kohei's avatar KaiGai Kohei

[JFFS2][XATTR] XATTR support on JFFS2 (version. 5)

This attached patches provide xattr support including POSIX-ACL and
SELinux support on JFFS2 (version.5).

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: default avatarKaiGai Kohei <kaigai@ak.jp.nec.com>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 4992a9e8
...@@ -1075,6 +1075,44 @@ config JFFS2_FS_DEBUG ...@@ -1075,6 +1075,44 @@ config JFFS2_FS_DEBUG
If reporting bugs, please try to have available a full dump of the If reporting bugs, please try to have available a full dump of the
messages at debug level 1 while the misbehaviour was occurring. 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 config JFFS2_FS_WRITEBUFFER
bool "JFFS2 write-buffering support" bool "JFFS2 write-buffering support"
depends on JFFS2_FS depends on JFFS2_FS
......
...@@ -12,6 +12,9 @@ jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o ...@@ -12,6 +12,9 @@ jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
jffs2-y += super.o debug.o jffs2-y += super.o debug.o
jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.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_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
......
This diff is collapsed.
/*-------------------------------------------------------------------------*
* 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__ */
...@@ -160,6 +160,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ...@@ -160,6 +160,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
ic->scan_dents = NULL; ic->scan_dents = NULL;
cond_resched(); cond_resched();
} }
jffs2_build_xattr_subsystem(c);
c->flags &= ~JFFS2_SB_FLAG_BUILDING; c->flags &= ~JFFS2_SB_FLAG_BUILDING;
dbg_fsbuild("FS build complete\n"); dbg_fsbuild("FS build complete\n");
...@@ -178,6 +179,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ...@@ -178,6 +179,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
} }
} }
jffs2_clear_xattr_subsystem(c);
} }
return ret; return ret;
......
...@@ -171,6 +171,12 @@ ...@@ -171,6 +171,12 @@
#define dbg_memalloc(fmt, ...) #define dbg_memalloc(fmt, ...)
#endif #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 */ /* "Sanity" checks */
void void
......
...@@ -57,7 +57,12 @@ struct inode_operations jffs2_dir_inode_operations = ...@@ -57,7 +57,12 @@ struct inode_operations jffs2_dir_inode_operations =
.rmdir = jffs2_rmdir, .rmdir = jffs2_rmdir,
.mknod = jffs2_mknod, .mknod = jffs2_mknod,
.rename = jffs2_rename, .rename = jffs2_rename,
.permission = jffs2_permission,
.setattr = jffs2_setattr, .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 *dir_i, struct dentry *dentry, int mode, ...@@ -209,12 +214,15 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
ret = jffs2_do_create(c, dir_f, f, ri, ret = jffs2_do_create(c, dir_f, f, ri,
dentry->d_name.name, dentry->d_name.len); dentry->d_name.name, dentry->d_name.len);
if (ret) { if (ret)
make_bad_inode(inode); goto fail;
iput(inode);
jffs2_free_raw_inode(ri); ret = jffs2_init_security(inode, dir_i);
return ret; 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)); dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
...@@ -224,6 +232,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, ...@@ -224,6 +232,12 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", 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)); inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
return 0; 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 *dir_i, struct dentry *dentry, const char ...@@ -374,6 +388,18 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); 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, ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) { if (ret) {
...@@ -504,6 +530,18 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -504,6 +530,18 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); 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, ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) { if (ret) {
...@@ -660,6 +698,18 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de ...@@ -660,6 +698,18 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); 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, ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) { if (ret) {
......
...@@ -54,7 +54,12 @@ const struct file_operations jffs2_file_operations = ...@@ -54,7 +54,12 @@ const struct file_operations jffs2_file_operations =
struct inode_operations jffs2_file_inode_operations = 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 = struct address_space_operations jffs2_file_address_operations =
......
...@@ -185,7 +185,12 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) ...@@ -185,7 +185,12 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) 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) int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
...@@ -224,6 +229,7 @@ void jffs2_clear_inode (struct inode *inode) ...@@ -224,6 +229,7 @@ void jffs2_clear_inode (struct inode *inode)
D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); 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); jffs2_do_clear_inode(c, f);
} }
...@@ -497,6 +503,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) ...@@ -497,6 +503,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
} }
memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *)); memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
jffs2_init_xattr_subsystem(c);
if ((ret = jffs2_do_mount_fs(c))) if ((ret = jffs2_do_mount_fs(c)))
goto out_inohash; goto out_inohash;
...@@ -531,6 +539,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) ...@@ -531,6 +539,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
else else
kfree(c->blocks); kfree(c->blocks);
out_inohash: out_inohash:
jffs2_clear_xattr_subsystem(c);
kfree(c->inocache_list); kfree(c->inocache_list);
out_wbuf: out_wbuf:
jffs2_flash_cleanup(c); jffs2_flash_cleanup(c);
......
...@@ -125,6 +125,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -125,6 +125,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
struct jffs2_eraseblock *jeb; struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *raw; struct jffs2_raw_node_ref *raw;
int ret = 0, inum, nlink; int ret = 0, inum, nlink;
int xattr = 0;
if (down_interruptible(&c->alloc_sem)) if (down_interruptible(&c->alloc_sem))
return -EINTR; return -EINTR;
...@@ -138,7 +139,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -138,7 +139,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
the node CRCs etc. Do it now. */ the node CRCs etc. Do it now. */
/* checked_ino is protected by the alloc_sem */ /* 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", printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
c->unchecked_size); c->unchecked_size);
jffs2_dbg_dump_block_lists_nolock(c); jffs2_dbg_dump_block_lists_nolock(c);
...@@ -148,6 +149,9 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -148,6 +149,9 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
spin_unlock(&c->erase_completion_lock); spin_unlock(&c->erase_completion_lock);
if (!xattr)
xattr = jffs2_verify_xattr(c);
spin_lock(&c->inocache_lock); spin_lock(&c->inocache_lock);
ic = jffs2_get_ino_cache(c, c->checked_ino++); ic = jffs2_get_ino_cache(c, c->checked_ino++);
...@@ -262,6 +266,16 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -262,6 +266,16 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
ic = jffs2_raw_ref_to_ic(raw); 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 /* We need to hold the inocache. Either the erase_completion_lock or
the inocache_lock are sufficient; we trade down since the inocache_lock the inocache_lock are sufficient; we trade down since the inocache_lock
causes less contention. */ causes less contention. */
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <linux/posix_acl.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
struct jffs2_inode_info { struct jffs2_inode_info {
...@@ -45,6 +46,10 @@ struct jffs2_inode_info { ...@@ -45,6 +46,10 @@ struct jffs2_inode_info {
struct inode vfs_inode; struct inode vfs_inode;
#endif #endif
#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 */ #endif /* _JFFS2_FS_I */
...@@ -115,6 +115,16 @@ struct jffs2_sb_info { ...@@ -115,6 +115,16 @@ struct jffs2_sb_info {
struct jffs2_summary *summary; /* Summary information */ 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 */ /* OS-private pointer for getting back to master superblock info */
void *os_priv; void *os_priv;
}; };
......
...@@ -26,6 +26,10 @@ static kmem_cache_t *tmp_dnode_info_slab; ...@@ -26,6 +26,10 @@ static kmem_cache_t *tmp_dnode_info_slab;
static kmem_cache_t *raw_node_ref_slab; static kmem_cache_t *raw_node_ref_slab;
static kmem_cache_t *node_frag_slab; static kmem_cache_t *node_frag_slab;
static kmem_cache_t *inode_cache_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) int __init jffs2_create_slab_caches(void)
{ {
...@@ -68,7 +72,23 @@ int __init jffs2_create_slab_caches(void) ...@@ -68,7 +72,23 @@ int __init jffs2_create_slab_caches(void)
inode_cache_slab = kmem_cache_create("jffs2_inode_cache", inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
sizeof(struct jffs2_inode_cache), sizeof(struct jffs2_inode_cache),
0, 0, NULL, NULL); 0, 0, NULL, NULL);
if (inode_cache_slab) 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; return 0;
err: err:
jffs2_destroy_slab_caches(); jffs2_destroy_slab_caches();
...@@ -91,6 +111,12 @@ void jffs2_destroy_slab_caches(void) ...@@ -91,6 +111,12 @@ void jffs2_destroy_slab_caches(void)
kmem_cache_destroy(node_frag_slab); kmem_cache_destroy(node_frag_slab);
if(inode_cache_slab) if(inode_cache_slab)
kmem_cache_destroy(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) struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
...@@ -205,3 +231,41 @@ void jffs2_free_inode_cache(struct jffs2_inode_cache *x) ...@@ -205,3 +231,41 @@ void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
dbg_memalloc("%p\n", x); dbg_memalloc("%p\n", x);
kmem_cache_free(inode_cache_slab, 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
...@@ -938,6 +938,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) ...@@ -938,6 +938,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c)
this = c->inocache_list[i]; this = c->inocache_list[i];
while (this) { while (this) {
next = this->next; next = this->next;
jffs2_xattr_free_inode(c, this);
jffs2_free_inode_cache(this); jffs2_free_inode_cache(this);
this = next; this = next;
} }
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <linux/jffs2.h> #include <linux/jffs2.h>
#include "jffs2_fs_sb.h" #include "jffs2_fs_sb.h"
#include "jffs2_fs_i.h" #include "jffs2_fs_i.h"
#include "xattr.h"
#include "acl.h"
#include "summary.h" #include "summary.h"
#ifdef __ECOS #ifdef __ECOS
...@@ -107,11 +109,16 @@ struct jffs2_inode_cache { ...@@ -107,11 +109,16 @@ struct jffs2_inode_cache {
temporary lists of dirents, and later must be set to temporary lists of dirents, and later must be set to
NULL to mark the end of the raw_node_ref->next_in_ino NULL to mark the end of the raw_node_ref->next_in_ino
chain. */ chain. */
u8 class; /* It's used for identification */
u8 flags;
uint16_t state;
struct jffs2_inode_cache *next; struct jffs2_inode_cache *next;
struct jffs2_raw_node_ref *nodes; struct jffs2_raw_node_ref *nodes;
uint32_t ino; uint32_t ino;
int nlink; 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 /* Inode states for 'state' above. We need the 'GC' state to prevent
...@@ -125,6 +132,12 @@ struct jffs2_inode_cache { ...@@ -125,6 +132,12 @@ struct jffs2_inode_cache {
#define INO_STATE_READING 5 /* In read_inode() */ #define INO_STATE_READING 5 /* In read_inode() */
#define INO_STATE_CLEARING 6 /* In clear_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 #define INOCACHE_HASHSIZE 128
/* /*
...@@ -374,6 +387,12 @@ struct jffs2_node_frag *jffs2_alloc_node_frag(void); ...@@ -374,6 +387,12 @@ struct jffs2_node_frag *jffs2_alloc_node_frag(void);
void jffs2_free_node_frag(struct jffs2_node_frag *); void jffs2_free_node_frag(struct jffs2_node_frag *);
struct jffs2_inode_cache *jffs2_alloc_inode_cache(void); struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
void jffs2_free_inode_cache(struct jffs2_inode_cache *); 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 */ /* gc.c */
int jffs2_garbage_collect_pass(struct jffs2_sb_info *c); int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
......
...@@ -60,6 +60,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) ...@@ -60,6 +60,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
f->target = NULL; f->target = NULL;
f->flags = 0; f->flags = 0;
f->usercompr = 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
} }
......
...@@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
f->inocache->ino = f->inocache->nlink = 1; f->inocache->ino = f->inocache->nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_READING; f->inocache->state = INO_STATE_READING;
init_xattr_inode_cache(f->inocache);
jffs2_add_ino_cache(c, f->inocache); jffs2_add_ino_cache(c, f->inocache);
} }
if (!f->inocache) { if (!f->inocache) {
......
...@@ -306,6 +306,136 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je ...@@ -306,6 +306,136 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
return BLK_STATE_ALLDIRTY; 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, 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) { unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
struct jffs2_unknown_node *node; struct jffs2_unknown_node *node;
...@@ -614,6 +744,43 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -614,6 +744,43 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
ofs += PAD(je32_to_cpu(node->totlen)); ofs += PAD(je32_to_cpu(node->totlen));
break; 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: case JFFS2_NODETYPE_CLEANMARKER:
D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
...@@ -721,6 +888,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin ...@@ -721,6 +888,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin
ic->ino = ino; ic->ino = ino;
ic->nodes = (void *)ic; ic->nodes = (void *)ic;
init_xattr_inode_cache(ic);
jffs2_add_ino_cache(c, ic); jffs2_add_ino_cache(c, ic);
if (ino == 1) if (ino == 1)
ic->nlink = 1; ic->nlink = 1;
......
/*-------------------------------------------------------------------------*
* 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
};
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Zoltan Sogor <weth@inf.u-szeged.hu>, * Zoltan Sogor <weth@inf.u-szeged.hu>,
* Patrik Kluba <pajko@halom.u-szeged.hu>, * Patrik Kluba <pajko@halom.u-szeged.hu>,
* University of Szeged, Hungary * University of Szeged, Hungary
* 2005 KaiGai Kohei <kaigai@ak.jp.nec.com>
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
...@@ -81,6 +82,19 @@ static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item) ...@@ -81,6 +82,19 @@ static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
dbg_summary("dirent (%u) added to summary\n", dbg_summary("dirent (%u) added to summary\n",
je32_to_cpu(item->d.ino)); je32_to_cpu(item->d.ino));
break; 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: default:
JFFS2_WARNING("UNKNOWN node type %u\n", JFFS2_WARNING("UNKNOWN node type %u\n",
je16_to_cpu(item->u.nodetype)); je16_to_cpu(item->u.nodetype));
...@@ -141,6 +155,40 @@ int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *r ...@@ -141,6 +155,40 @@ int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *r
return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); 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 */ /* Cleanup every collected summary information */
static void jffs2_sum_clean_collected(struct jffs2_summary *s) static void jffs2_sum_clean_collected(struct jffs2_summary *s)
...@@ -259,7 +307,40 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, ...@@ -259,7 +307,40 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); 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: case JFFS2_NODETYPE_PADDING:
dbg_summary("node PADDING\n"); dbg_summary("node PADDING\n");
c->summary->sum_padded += je32_to_cpu(node->u.totlen); c->summary->sum_padded += je32_to_cpu(node->u.totlen);
...@@ -408,8 +489,94 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -408,8 +489,94 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
break; 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 : { default : {
printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype));
JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
kfree(summary); kfree(summary);
return -EIO; return -EIO;
...@@ -617,7 +784,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock ...@@ -617,7 +784,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
break; 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 : { default : {
BUG(); /* unknown node in summary information */ BUG(); /* unknown node in summary information */
} }
......
...@@ -45,6 +45,8 @@ ...@@ -45,6 +45,8 @@
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff #define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) #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_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 */ /* Summary structures used on flash */
...@@ -75,11 +77,28 @@ struct jffs2_sum_dirent_flash ...@@ -75,11 +77,28 @@ struct jffs2_sum_dirent_flash
uint8_t name[0]; /* dirent name */ uint8_t name[0]; /* dirent name */
} __attribute__((packed)); } __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 union jffs2_sum_flash
{ {
struct jffs2_sum_unknown_flash u; struct jffs2_sum_unknown_flash u;
struct jffs2_sum_inode_flash i; struct jffs2_sum_inode_flash i;
struct jffs2_sum_dirent_flash d; struct jffs2_sum_dirent_flash d;
struct jffs2_sum_xattr_flash x;
struct jffs2_sum_xref_flash r;
}; };
/* Summary structures used in the memory */ /* Summary structures used in the memory */
...@@ -114,11 +133,30 @@ struct jffs2_sum_dirent_mem ...@@ -114,11 +133,30 @@ struct jffs2_sum_dirent_mem
uint8_t name[0]; /* dirent name */ uint8_t name[0]; /* dirent name */
} __attribute__((packed)); } __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 union jffs2_sum_mem
{ {
struct jffs2_sum_unknown_mem u; struct jffs2_sum_unknown_mem u;
struct jffs2_sum_inode_mem i; struct jffs2_sum_inode_mem i;
struct jffs2_sum_dirent_mem d; struct jffs2_sum_dirent_mem d;
struct jffs2_sum_xattr_mem x;
struct jffs2_sum_xref_mem r;
}; };
/* Summary related information stored in superblock */ /* Summary related information stored in superblock */
...@@ -159,6 +197,8 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c); ...@@ -159,6 +197,8 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);
int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); 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_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_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, int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t ofs, uint32_t *pseudo_random); uint32_t ofs, uint32_t *pseudo_random);
...@@ -176,6 +216,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb ...@@ -176,6 +216,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
#define jffs2_sum_add_padding_mem(a,b) #define jffs2_sum_add_padding_mem(a,b)
#define jffs2_sum_add_inode_mem(a,b,c) #define jffs2_sum_add_inode_mem(a,b,c)
#define jffs2_sum_add_dirent_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) #define jffs2_sum_scan_sumnode(a,b,c,d) (0)
#endif /* CONFIG_JFFS2_SUMMARY */ #endif /* CONFIG_JFFS2_SUMMARY */
......
...@@ -151,7 +151,10 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, ...@@ -151,7 +151,10 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
sb->s_op = &jffs2_super_operations; sb->s_op = &jffs2_super_operations;
sb->s_flags = flags | MS_NOATIME; 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); ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
if (ret) { if (ret) {
...@@ -293,6 +296,7 @@ static void jffs2_put_super (struct super_block *sb) ...@@ -293,6 +296,7 @@ static void jffs2_put_super (struct super_block *sb)
kfree(c->blocks); kfree(c->blocks);
jffs2_flash_cleanup(c); jffs2_flash_cleanup(c);
kfree(c->inocache_list); kfree(c->inocache_list);
jffs2_clear_xattr_subsystem(c);
if (c->mtd->sync) if (c->mtd->sync)
c->mtd->sync(c->mtd); c->mtd->sync(c->mtd);
......
...@@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_inode_operations = ...@@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_inode_operations =
{ {
.readlink = generic_readlink, .readlink = generic_readlink,
.follow_link = jffs2_follow_link, .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) static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
......
...@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint ...@@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
f->inocache->nlink = 1; f->inocache->nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_PRESENT; f->inocache->state = INO_STATE_PRESENT;
init_xattr_inode_cache(f->inocache);
jffs2_add_ino_cache(c, f->inocache); jffs2_add_ino_cache(c, f->inocache);
D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
......
This diff is collapsed.
/*-------------------------------------------------------------------------*
* 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_ */
/*-------------------------------------------------------------------------*
* 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
};
/*-------------------------------------------------------------------------*
* 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
};
...@@ -65,6 +65,18 @@ ...@@ -65,6 +65,18 @@
#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) #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... // Maybe later...
//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
...@@ -151,6 +163,32 @@ struct jffs2_raw_inode ...@@ -151,6 +163,32 @@ struct jffs2_raw_inode
uint8_t data[0]; uint8_t data[0];
} __attribute__((packed)); } __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 struct jffs2_raw_summary
{ {
jint16_t magic; jint16_t magic;
...@@ -169,6 +207,8 @@ union jffs2_node_union ...@@ -169,6 +207,8 @@ union jffs2_node_union
{ {
struct jffs2_raw_inode i; struct jffs2_raw_inode i;
struct jffs2_raw_dirent d; struct jffs2_raw_dirent d;
struct jffs2_raw_xattr x;
struct jffs2_raw_xref r;
struct jffs2_raw_summary s; struct jffs2_raw_summary s;
struct jffs2_unknown_node u; struct jffs2_unknown_node u;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment