Merge git://git.infradead.org/jffs2-xattr-2.6
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
This commit is contained in:
commit
0cfc7da3ff
29 changed files with 2822 additions and 15 deletions
38
fs/Kconfig
38
fs/Kconfig
|
@ -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
|
||||
|
|
|
@ -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-$(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
|
||||
|
|
|
@ -150,3 +150,24 @@ the buffer.
|
|||
|
||||
Ordering constraints:
|
||||
Lock wbuf_sem last, after the alloc_sem or and f->sem.
|
||||
|
||||
|
||||
c->xattr_sem
|
||||
------------
|
||||
|
||||
This read/write semaphore protects against concurrent access to the
|
||||
xattr related objects which include stuff in superblock and ic->xref.
|
||||
In read-only path, write-semaphore is too much exclusion. It's enough
|
||||
by read-semaphore. But you must hold write-semaphore when updating,
|
||||
creating or deleting any xattr related object.
|
||||
|
||||
Once xattr_sem released, there would be no assurance for the existence
|
||||
of those objects. Thus, a series of processes is often required to retry,
|
||||
when updating such a object is necessary under holding read semaphore.
|
||||
For example, do_jffs2_getxattr() holds read-semaphore to scan xref and
|
||||
xdatum at first. But it retries this process with holding write-semaphore
|
||||
after release read-semaphore, if it's necessary to load name/value pair
|
||||
from medium.
|
||||
|
||||
Ordering constraints:
|
||||
Lock xattr_sem last, after the alloc_sem.
|
||||
|
|
485
fs/jffs2/acl.c
Normal file
485
fs/jffs2/acl.c
Normal file
|
@ -0,0 +1,485 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this 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(struct jffs2_acl_header)
|
||||
+ count * sizeof(struct jffs2_acl_entry_short);
|
||||
} else {
|
||||
return sizeof(struct jffs2_acl_header)
|
||||
+ 4 * sizeof(struct jffs2_acl_entry_short)
|
||||
+ (count - 4) * sizeof(struct jffs2_acl_entry);
|
||||
}
|
||||
}
|
||||
|
||||
static int jffs2_acl_count(size_t size)
|
||||
{
|
||||
size_t s;
|
||||
|
||||
size -= sizeof(struct jffs2_acl_header);
|
||||
s = size - 4 * sizeof(struct jffs2_acl_entry_short);
|
||||
if (s < 0) {
|
||||
if (size % sizeof(struct jffs2_acl_entry_short))
|
||||
return -1;
|
||||
return size / sizeof(struct jffs2_acl_entry_short);
|
||||
} else {
|
||||
if (s % sizeof(struct jffs2_acl_entry))
|
||||
return -1;
|
||||
return s / sizeof(struct jffs2_acl_entry) + 4;
|
||||
}
|
||||
}
|
||||
|
||||
static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size)
|
||||
{
|
||||
void *end = value + size;
|
||||
struct jffs2_acl_header *header = value;
|
||||
struct jffs2_acl_entry *entry;
|
||||
struct posix_acl *acl;
|
||||
uint32_t ver;
|
||||
int i, count;
|
||||
|
||||
if (!value)
|
||||
return NULL;
|
||||
if (size < sizeof(struct jffs2_acl_header))
|
||||
return ERR_PTR(-EINVAL);
|
||||
ver = je32_to_cpu(header->a_version);
|
||||
if (ver != JFFS2_ACL_VERSION) {
|
||||
JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
value += sizeof(struct 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++) {
|
||||
entry = value;
|
||||
if (value + sizeof(struct 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 += sizeof(struct jffs2_acl_entry_short);
|
||||
acl->a_entries[i].e_id = ACL_UNDEFINED_ID;
|
||||
break;
|
||||
|
||||
case ACL_USER:
|
||||
case ACL_GROUP:
|
||||
value += sizeof(struct jffs2_acl_entry);
|
||||
if (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)
|
||||
{
|
||||
struct jffs2_acl_header *header;
|
||||
struct jffs2_acl_entry *entry;
|
||||
void *e;
|
||||
size_t i;
|
||||
|
||||
*size = jffs2_acl_size(acl->a_count);
|
||||
header = kmalloc(sizeof(*header) + acl->a_count * sizeof(*entry), GFP_KERNEL);
|
||||
if (!header)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
|
||||
e = header + 1;
|
||||
for (i=0; i < acl->a_count; i++) {
|
||||
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(struct jffs2_acl_entry);
|
||||
break;
|
||||
|
||||
case ACL_USER_OBJ:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_MASK:
|
||||
case ACL_OTHER:
|
||||
e += sizeof(struct jffs2_acl_entry_short);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return header;
|
||||
fail:
|
||||
kfree(header);
|
||||
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,
|
||||
};
|
45
fs/jffs2/acl.h
Normal file
45
fs/jffs2/acl.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
struct jffs2_acl_entry {
|
||||
jint16_t e_tag;
|
||||
jint16_t e_perm;
|
||||
jint32_t e_id;
|
||||
};
|
||||
|
||||
struct jffs2_acl_entry_short {
|
||||
jint16_t e_tag;
|
||||
jint16_t e_perm;
|
||||
};
|
||||
|
||||
struct jffs2_acl_header {
|
||||
jint32_t a_version;
|
||||
};
|
||||
|
||||
#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 */
|
|
@ -160,6 +160,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
|
|||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -57,7 +57,12 @@ struct inode_operations jffs2_dir_inode_operations =
|
|||
.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 *dir_i, struct dentry *dentry, int mode,
|
|||
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 *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",
|
||||
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 *dir_i, struct dentry *dentry, const char
|
|||
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 *dir_i, struct dentry *dentry, int mode)
|
|||
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) {
|
||||
|
@ -658,6 +696,18 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
|
|||
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) {
|
||||
|
|
|
@ -54,7 +54,12 @@ const struct file_operations jffs2_file_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 =
|
||||
|
|
|
@ -184,7 +184,12 @@ static int jffs2_do_setattr (struct inode *inode, 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)
|
||||
|
@ -223,6 +228,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));
|
||||
|
||||
jffs2_xattr_delete_inode(c, f->inocache);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
}
|
||||
|
||||
|
@ -508,6 +514,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 *));
|
||||
|
||||
jffs2_init_xattr_subsystem(c);
|
||||
|
||||
if ((ret = jffs2_do_mount_fs(c)))
|
||||
goto out_inohash;
|
||||
|
||||
|
@ -542,6 +550,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
|
|||
else
|
||||
kfree(c->blocks);
|
||||
out_inohash:
|
||||
jffs2_clear_xattr_subsystem(c);
|
||||
kfree(c->inocache_list);
|
||||
out_wbuf:
|
||||
jffs2_flash_cleanup(c);
|
||||
|
|
|
@ -125,6 +125,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
|||
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 jffs2_sb_info *c)
|
|||
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 jffs2_sb_info *c)
|
|||
|
||||
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,23 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
|||
|
||||
ic = jffs2_raw_ref_to_ic(raw);
|
||||
|
||||
#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) {
|
||||
BUG_ON(raw->next_in_ino != (void *)ic);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
|
||||
if (ic->class == RAWNODE_CLASS_XATTR_DATUM) {
|
||||
ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
|
||||
} else {
|
||||
ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
|
||||
}
|
||||
goto release_sem;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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_unchecked;
|
||||
struct jffs2_xattr_ref *xref_temp;
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -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,40 @@ void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
|
|||
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;
|
||||
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)
|
|||
this = c->inocache_list[i];
|
||||
while (this) {
|
||||
next = this->next;
|
||||
jffs2_xattr_free_inode(c, this);
|
||||
jffs2_free_inode_cache(this);
|
||||
this = next;
|
||||
}
|
||||
|
|
|
@ -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 jffs2_xattr_ref *xref;
|
||||
#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
|
||||
|
||||
/*
|
||||
|
@ -385,6 +398,12 @@ struct jffs2_node_frag *jffs2_alloc_node_frag(void);
|
|||
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);
|
||||
|
|
|
@ -58,6 +58,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
|
|||
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
|
||||
}
|
||||
|
||||
|
||||
|
|
168
fs/jffs2/scan.c
168
fs/jffs2/scan.c
|
@ -306,6 +306,137 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
|
|||
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->next 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);
|
||||
ref->next = c->xref_temp;
|
||||
c->xref_temp = ref;
|
||||
|
||||
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
|
||||
|
||||
/* Called with 'buf_size == 0' if buf is in fact a pointer _directly_ into
|
||||
the flash, XIP-style */
|
||||
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
|
@ -641,6 +772,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) {
|
||||
|
|
82
fs/jffs2/security.c
Normal file
82
fs/jffs2/security.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this 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 @@
|
|||
* 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 jffs2_summary *s, union jffs2_sum_mem *item)
|
|||
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 jffs2_summary *s, struct jffs2_raw_dirent *r
|
|||
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_info *c, const struct kvec *invecs,
|
|||
|
||||
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);
|
||||
|
@ -402,8 +483,101 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
|
||||
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_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);
|
||||
}
|
||||
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;
|
||||
ref->next = c->xref_temp;
|
||||
c->xref_temp = ref;
|
||||
|
||||
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...");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -593,7 +767,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
|
|||
|
||||
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 */
|
||||
}
|
||||
|
|
|
@ -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_sb_info *c);
|
|||
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,
|
||||
struct jffs2_raw_summary *summary, uint32_t sumlen,
|
||||
uint32_t *pseudo_random);
|
||||
|
@ -177,6 +217,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_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 */
|
||||
|
|
|
@ -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_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 super_block *sb)
|
|||
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);
|
||||
|
||||
|
|
|
@ -24,7 +24,12 @@ struct inode_operations jffs2_symlink_inode_operations =
|
|||
{
|
||||
.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)
|
||||
|
|
|
@ -37,7 +37,6 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
|
|||
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
|
||||
f->inocache->state = INO_STATE_PRESENT;
|
||||
|
||||
|
||||
jffs2_add_ino_cache(c, f->inocache);
|
||||
D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
|
||||
ri->ino = cpu_to_je32(f->inocache->ino);
|
||||
|
|
1262
fs/jffs2/xattr.c
Normal file
1262
fs/jffs2/xattr.c
Normal file
File diff suppressed because it is too large
Load diff
116
fs/jffs2/xattr.h
Normal file
116
fs/jffs2/xattr.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
*/
|
||||
#ifndef _JFFS2_FS_XATTR_H_
|
||||
#define _JFFS2_FS_XATTR_H_
|
||||
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/list.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;
|
||||
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 jffs2_xattr_ref *next; /* chained from ic->xref_list */
|
||||
};
|
||||
|
||||
#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_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd);
|
||||
extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref);
|
||||
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
|
||||
|
||||
#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_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
|
||||
|
||||
#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_ */
|
52
fs/jffs2/xattr_trusted.c
Normal file
52
fs/jffs2/xattr_trusted.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this 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
|
||||
};
|
52
fs/jffs2/xattr_user.c
Normal file
52
fs/jffs2/xattr_user.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2006 NEC Corporation
|
||||
*
|
||||
* Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this 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 @@
|
|||
|
||||
#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];
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue