Merge git://git.infradead.org/jffs2-devel-2.6
This commit is contained in:
Коммит
0d25971d7c
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.
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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) {
|
||||
|
|
|
@ -30,7 +30,6 @@ static void jffs2_erase_callback(struct erase_info *);
|
|||
#endif
|
||||
static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
|
||||
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
|
||||
static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
|
||||
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
|
||||
|
||||
static void jffs2_erase_block(struct jffs2_sb_info *c,
|
||||
|
@ -283,7 +282,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
|
|||
jffs2_del_ino_cache(c, ic);
|
||||
}
|
||||
|
||||
static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
{
|
||||
struct jffs2_raw_node_ref *ref;
|
||||
D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset));
|
||||
|
@ -373,12 +372,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
|||
goto filebad;
|
||||
}
|
||||
|
||||
jeb->first_node = jeb->last_node = NULL;
|
||||
/* Everything else got zeroed before the erase */
|
||||
jeb->free_size = c->sector_size;
|
||||
jeb->used_size = 0;
|
||||
jeb->dirty_size = 0;
|
||||
jeb->wasted_size = 0;
|
||||
|
||||
} else {
|
||||
|
||||
struct kvec vecs[1];
|
||||
|
@ -412,17 +407,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
|||
goto filebad;
|
||||
}
|
||||
|
||||
/* Everything else got zeroed before the erase */
|
||||
jeb->free_size = c->sector_size;
|
||||
|
||||
marker_ref->next_in_ino = NULL;
|
||||
marker_ref->next_phys = NULL;
|
||||
marker_ref->flash_offset = jeb->offset | REF_NORMAL;
|
||||
marker_ref->__totlen = c->cleanmarker_size;
|
||||
|
||||
jeb->first_node = jeb->last_node = marker_ref;
|
||||
|
||||
jeb->free_size = c->sector_size - c->cleanmarker_size;
|
||||
jeb->used_size = c->cleanmarker_size;
|
||||
jeb->dirty_size = 0;
|
||||
jeb->wasted_size = 0;
|
||||
jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size);
|
||||
}
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
|
|
@ -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++);
|
||||
|
@ -252,16 +256,37 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
|||
|
||||
if (!raw->next_in_ino) {
|
||||
/* Inode-less node. Clean marker, snapshot or something like that */
|
||||
/* FIXME: If it's something that needs to be copied, including something
|
||||
we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
jffs2_mark_node_obsolete(c, raw);
|
||||
if (ref_flags(raw) == REF_PRISTINE) {
|
||||
/* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */
|
||||
jffs2_garbage_collect_pristine(c, NULL, raw);
|
||||
} else {
|
||||
/* Just mark it obsolete */
|
||||
jffs2_mark_node_obsolete(c, raw);
|
||||
}
|
||||
up(&c->alloc_sem);
|
||||
goto eraseit_lock;
|
||||
}
|
||||
|
||||
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. */
|
||||
|
@ -512,15 +537,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
|||
|
||||
D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
|
||||
|
||||
rawlen = ref_totlen(c, c->gcblock, raw);
|
||||
alloclen = rawlen = ref_totlen(c, c->gcblock, raw);
|
||||
|
||||
/* Ask for a small amount of space (or the totlen if smaller) because we
|
||||
don't want to force wastage of the end of a block if splitting would
|
||||
work. */
|
||||
ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
|
||||
JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen);
|
||||
/* this is not the exact summary size of it,
|
||||
it is only an upper estimation */
|
||||
if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
|
||||
alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN;
|
||||
|
||||
ret = jffs2_reserve_space_gc(c, alloclen, &phys_ofs, &alloclen, rawlen);
|
||||
/* 'rawlen' is not the exact summary size; it is only an upper estimation */
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -584,9 +610,12 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
|||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
|
||||
ref_offset(raw), je16_to_cpu(node->u.nodetype));
|
||||
goto bail;
|
||||
/* If it's inode-less, we don't _know_ what it is. Just copy it intact */
|
||||
if (ic) {
|
||||
printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
|
||||
ref_offset(raw), je16_to_cpu(node->u.nodetype));
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
nraw = jffs2_alloc_raw_node_ref();
|
||||
|
@ -598,8 +627,6 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
|||
/* OK, all the CRCs are good; this node can just be copied as-is. */
|
||||
retry:
|
||||
nraw->flash_offset = phys_ofs;
|
||||
nraw->__totlen = rawlen;
|
||||
nraw->next_phys = NULL;
|
||||
|
||||
ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);
|
||||
|
||||
|
@ -611,7 +638,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
|||
nraw->next_in_ino = NULL;
|
||||
|
||||
nraw->flash_offset |= REF_OBSOLETE;
|
||||
jffs2_add_physical_node_ref(c, nraw);
|
||||
jffs2_add_physical_node_ref(c, nraw, rawlen);
|
||||
jffs2_mark_node_obsolete(c, nraw);
|
||||
} else {
|
||||
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
|
||||
|
@ -651,17 +678,18 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
|
|||
goto out_node;
|
||||
}
|
||||
nraw->flash_offset |= REF_PRISTINE;
|
||||
jffs2_add_physical_node_ref(c, nraw);
|
||||
|
||||
/* Link into per-inode list. This is safe because of the ic
|
||||
state being INO_STATE_GC. Note that if we're doing this
|
||||
for an inode which is in-core, the 'nraw' pointer is then
|
||||
going to be fetched from ic->nodes by our caller. */
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
nraw->next_in_ino = ic->nodes;
|
||||
ic->nodes = nraw;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
jffs2_add_physical_node_ref(c, nraw, rawlen);
|
||||
|
||||
if (ic) {
|
||||
/* Link into per-inode list. This is safe because of the ic
|
||||
state being INO_STATE_GC. Note that if we're doing this
|
||||
for an inode which is in-core, the 'nraw' pointer is then
|
||||
going to be fetched from ic->nodes by our caller. */
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
nraw->next_in_ino = ic->nodes;
|
||||
ic->nodes = nraw;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
}
|
||||
jffs2_mark_node_obsolete(c, raw);
|
||||
D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -1045,3 +1046,149 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
|
|||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
struct jffs2_raw_node_ref *ref, uint32_t len)
|
||||
{
|
||||
if (!jeb->first_node)
|
||||
jeb->first_node = ref;
|
||||
if (jeb->last_node) {
|
||||
jeb->last_node->next_phys = ref;
|
||||
#ifdef TEST_TOTLEN
|
||||
if (ref_offset(jeb->last_node) + jeb->last_node->__totlen != ref_offset(ref)) {
|
||||
printk(KERN_CRIT "Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n",
|
||||
ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
|
||||
ref_offset(jeb->last_node), ref_offset(jeb->last_node)+jeb->last_node->__totlen);
|
||||
WARN_ON(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
jeb->last_node = ref;
|
||||
|
||||
switch(ref_flags(ref)) {
|
||||
case REF_UNCHECKED:
|
||||
c->unchecked_size += len;
|
||||
jeb->unchecked_size += len;
|
||||
break;
|
||||
|
||||
case REF_NORMAL:
|
||||
case REF_PRISTINE:
|
||||
c->used_size += len;
|
||||
jeb->used_size += len;
|
||||
break;
|
||||
|
||||
case REF_OBSOLETE:
|
||||
c->dirty_size += len;
|
||||
jeb->used_size += len;
|
||||
break;
|
||||
}
|
||||
c->free_size -= len;
|
||||
jeb->free_size -= len;
|
||||
|
||||
ref->next_phys = NULL;
|
||||
#ifdef TEST_TOTLEN
|
||||
/* Set (and test) __totlen field... for now */
|
||||
ref->__totlen = len;
|
||||
ref_totlen(c, jeb, ref);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* No locking. Do not use on a live file system */
|
||||
int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
uint32_t size)
|
||||
{
|
||||
if (!size)
|
||||
return 0;
|
||||
if (size > c->sector_size - jeb->used_size) {
|
||||
printk(KERN_CRIT "Dirty space 0x%x larger then used_size 0x%x (wasted 0x%x)\n",
|
||||
size, jeb->used_size, jeb->wasted_size);
|
||||
BUG();
|
||||
}
|
||||
if (jeb->last_node && ref_obsolete(jeb->last_node)) {
|
||||
#ifdef TEST_TOTLEN
|
||||
jeb->last_node->__totlen += size;
|
||||
#endif
|
||||
c->dirty_size += size;
|
||||
c->free_size -= size;
|
||||
jeb->dirty_size += size;
|
||||
jeb->free_size -= size;
|
||||
} else {
|
||||
struct jffs2_raw_node_ref *ref;
|
||||
ref = jffs2_alloc_raw_node_ref();
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
|
||||
ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size;
|
||||
ref->flash_offset |= REF_OBSOLETE;
|
||||
ref->next_in_ino = 0;
|
||||
#ifdef TEST_TOTLEN
|
||||
ref->__totlen = size;
|
||||
#endif
|
||||
|
||||
jffs2_link_node_ref(c, jeb, ref, size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate totlen from surrounding nodes or eraseblock */
|
||||
static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
|
||||
struct jffs2_eraseblock *jeb,
|
||||
struct jffs2_raw_node_ref *ref)
|
||||
{
|
||||
uint32_t ref_end;
|
||||
|
||||
if (ref->next_phys)
|
||||
ref_end = ref_offset(ref->next_phys);
|
||||
else {
|
||||
if (!jeb)
|
||||
jeb = &c->blocks[ref->flash_offset / c->sector_size];
|
||||
|
||||
/* Last node in block. Use free_space */
|
||||
if (ref != jeb->last_node) {
|
||||
printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n",
|
||||
ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0);
|
||||
BUG();
|
||||
}
|
||||
ref_end = jeb->offset + c->sector_size - jeb->free_size;
|
||||
}
|
||||
return ref_end - ref_offset(ref);
|
||||
}
|
||||
|
||||
uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
struct jffs2_raw_node_ref *ref)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
#if CONFIG_JFFS2_FS_DEBUG > 0
|
||||
if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
|
||||
printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
|
||||
jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = __ref_totlen(c, jeb, ref);
|
||||
#ifdef TEST_TOTLEN
|
||||
if (ret != ref->__totlen) {
|
||||
printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
|
||||
ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
|
||||
ret, ref->__totlen);
|
||||
if (ref->next_phys) {
|
||||
printk(KERN_CRIT "next_phys %p (0x%08x-0x%08x)\n", ref->next_phys, ref_offset(ref->next_phys),
|
||||
ref_offset(ref->next_phys)+ref->__totlen);
|
||||
} else
|
||||
printk(KERN_CRIT "No next_phys. jeb->last_node is %p\n", jeb->last_node);
|
||||
|
||||
printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size);
|
||||
ret = ref->__totlen;
|
||||
if (!jeb)
|
||||
jeb = &c->blocks[ref->flash_offset / c->sector_size];
|
||||
#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
|
||||
__jffs2_dbg_dump_node_refs_nolock(c, jeb);
|
||||
#endif
|
||||
WARN_ON(1);
|
||||
}
|
||||
#endif /* TEST_TOTLEN */
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -80,7 +82,10 @@ struct jffs2_raw_node_ref
|
|||
word so you know when you've got there :) */
|
||||
struct jffs2_raw_node_ref *next_phys;
|
||||
uint32_t flash_offset;
|
||||
#define TEST_TOTLEN
|
||||
#ifdef TEST_TOTLEN
|
||||
uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* flash_offset & 3 always has to be zero, because nodes are
|
||||
|
@ -95,6 +100,11 @@ struct jffs2_raw_node_ref
|
|||
#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
|
||||
#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
|
||||
|
||||
/* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates
|
||||
it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get
|
||||
copied. If you need to do anything different to GC inode-less nodes, then
|
||||
you need to modify gc.c accordingly. */
|
||||
|
||||
/* For each inode in the filesystem, we need to keep a record of
|
||||
nlink, because it would be a PITA to scan the whole directory tree
|
||||
at read_inode() time to calculate it, and to keep sufficient information
|
||||
|
@ -107,11 +117,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 +140,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
|
||||
|
||||
/*
|
||||
|
@ -203,57 +224,7 @@ static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c)
|
|||
return ((c->flash_size / c->sector_size) * sizeof (struct jffs2_eraseblock)) > (128 * 1024);
|
||||
}
|
||||
|
||||
/* Calculate totlen from surrounding nodes or eraseblock */
|
||||
static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
|
||||
struct jffs2_eraseblock *jeb,
|
||||
struct jffs2_raw_node_ref *ref)
|
||||
{
|
||||
uint32_t ref_end;
|
||||
|
||||
if (ref->next_phys)
|
||||
ref_end = ref_offset(ref->next_phys);
|
||||
else {
|
||||
if (!jeb)
|
||||
jeb = &c->blocks[ref->flash_offset / c->sector_size];
|
||||
|
||||
/* Last node in block. Use free_space */
|
||||
BUG_ON(ref != jeb->last_node);
|
||||
ref_end = jeb->offset + c->sector_size - jeb->free_size;
|
||||
}
|
||||
return ref_end - ref_offset(ref);
|
||||
}
|
||||
|
||||
static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
|
||||
struct jffs2_eraseblock *jeb,
|
||||
struct jffs2_raw_node_ref *ref)
|
||||
{
|
||||
uint32_t ret;
|
||||
|
||||
#if CONFIG_JFFS2_FS_DEBUG > 0
|
||||
if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
|
||||
printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
|
||||
jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
ret = ref->__totlen;
|
||||
#else
|
||||
/* This doesn't actually work yet */
|
||||
ret = __ref_totlen(c, jeb, ref);
|
||||
if (ret != ref->__totlen) {
|
||||
printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
|
||||
ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
|
||||
ret, ref->__totlen);
|
||||
if (!jeb)
|
||||
jeb = &c->blocks[ref->flash_offset / c->sector_size];
|
||||
jffs2_dbg_dump_node_refs_nolock(c, jeb);
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
#define ref_totlen(a, b, c) __jffs2_ref_totlen((a), (b), (c))
|
||||
|
||||
#define ALLOC_NORMAL 0 /* Normal allocation */
|
||||
#define ALLOC_DELETION 1 /* Deletion node. Best to allow it */
|
||||
|
@ -335,6 +306,11 @@ void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *t
|
|||
int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
|
||||
void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
|
||||
int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn);
|
||||
void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
struct jffs2_raw_node_ref *ref, uint32_t len);
|
||||
extern uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c,
|
||||
struct jffs2_eraseblock *jeb,
|
||||
struct jffs2_raw_node_ref *ref);
|
||||
|
||||
/* nodemgmt.c */
|
||||
int jffs2_thread_should_wake(struct jffs2_sb_info *c);
|
||||
|
@ -342,7 +318,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
|
|||
uint32_t *len, int prio, uint32_t sumsize);
|
||||
int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
|
||||
uint32_t *len, uint32_t sumsize);
|
||||
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
|
||||
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, uint32_t len);
|
||||
void jffs2_complete_reservation(struct jffs2_sb_info *c);
|
||||
void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
|
||||
|
||||
|
@ -385,6 +361,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);
|
||||
|
@ -404,12 +386,14 @@ int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
|
|||
uint32_t ofs, uint32_t len);
|
||||
struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
|
||||
int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
|
||||
int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t size);
|
||||
|
||||
/* build.c */
|
||||
int jffs2_do_mount_fs(struct jffs2_sb_info *c);
|
||||
|
||||
/* erase.c */
|
||||
void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
|
||||
void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
|
||||
|
||||
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
|
||||
/* wbuf.c */
|
||||
|
|
|
@ -374,7 +374,6 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin
|
|||
* @c: superblock info
|
||||
* @new: new node reference to add
|
||||
* @len: length of this physical node
|
||||
* @dirty: dirty flag for new node
|
||||
*
|
||||
* Should only be used to report nodes for which space has been allocated
|
||||
* by jffs2_reserve_space.
|
||||
|
@ -382,13 +381,14 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin
|
|||
* Must be called with the alloc_sem held.
|
||||
*/
|
||||
|
||||
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new)
|
||||
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, uint32_t len)
|
||||
{
|
||||
struct jffs2_eraseblock *jeb;
|
||||
uint32_t len;
|
||||
|
||||
jeb = &c->blocks[new->flash_offset / c->sector_size];
|
||||
len = ref_totlen(c, jeb, new);
|
||||
#ifdef TEST_TOTLEN
|
||||
new->__totlen = len;
|
||||
#endif
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
|
||||
#if 1
|
||||
|
@ -403,21 +403,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
|
|||
#endif
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
if (!jeb->first_node)
|
||||
jeb->first_node = new;
|
||||
if (jeb->last_node)
|
||||
jeb->last_node->next_phys = new;
|
||||
jeb->last_node = new;
|
||||
|
||||
jeb->free_size -= len;
|
||||
c->free_size -= len;
|
||||
if (ref_obsolete(new)) {
|
||||
jeb->dirty_size += len;
|
||||
c->dirty_size += len;
|
||||
} else {
|
||||
jeb->used_size += len;
|
||||
c->used_size += len;
|
||||
}
|
||||
jffs2_link_node_ref(c, jeb, new, len);
|
||||
|
||||
if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) {
|
||||
/* If it lives on the dirty_list, jffs2_reserve_space will put it there */
|
||||
|
@ -470,6 +456,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
struct jffs2_unknown_node n;
|
||||
int ret, addedsize;
|
||||
size_t retlen;
|
||||
uint32_t freed_len;
|
||||
|
||||
if(!ref) {
|
||||
printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
|
||||
|
@ -499,32 +486,34 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
freed_len = ref_totlen(c, jeb, ref);
|
||||
|
||||
if (ref_flags(ref) == REF_UNCHECKED) {
|
||||
D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) {
|
||||
D1(if (unlikely(jeb->unchecked_size < freed_len)) {
|
||||
printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
|
||||
ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
|
||||
freed_len, blocknr, ref->flash_offset, jeb->used_size);
|
||||
BUG();
|
||||
})
|
||||
D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
|
||||
jeb->unchecked_size -= ref_totlen(c, jeb, ref);
|
||||
c->unchecked_size -= ref_totlen(c, jeb, ref);
|
||||
D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), freed_len));
|
||||
jeb->unchecked_size -= freed_len;
|
||||
c->unchecked_size -= freed_len;
|
||||
} else {
|
||||
D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) {
|
||||
D1(if (unlikely(jeb->used_size < freed_len)) {
|
||||
printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
|
||||
ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
|
||||
freed_len, blocknr, ref->flash_offset, jeb->used_size);
|
||||
BUG();
|
||||
})
|
||||
D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
|
||||
jeb->used_size -= ref_totlen(c, jeb, ref);
|
||||
c->used_size -= ref_totlen(c, jeb, ref);
|
||||
D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), freed_len));
|
||||
jeb->used_size -= freed_len;
|
||||
c->used_size -= freed_len;
|
||||
}
|
||||
|
||||
// Take care, that wasted size is taken into concern
|
||||
if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
|
||||
if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + freed_len)) && jeb != c->nextblock) {
|
||||
D1(printk(KERN_DEBUG "Dirtying\n"));
|
||||
addedsize = ref_totlen(c, jeb, ref);
|
||||
jeb->dirty_size += ref_totlen(c, jeb, ref);
|
||||
c->dirty_size += ref_totlen(c, jeb, ref);
|
||||
addedsize = freed_len;
|
||||
jeb->dirty_size += freed_len;
|
||||
c->dirty_size += freed_len;
|
||||
|
||||
/* Convert wasted space to dirty, if not a bad block */
|
||||
if (jeb->wasted_size) {
|
||||
|
@ -545,8 +534,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
} else {
|
||||
D1(printk(KERN_DEBUG "Wasting\n"));
|
||||
addedsize = 0;
|
||||
jeb->wasted_size += ref_totlen(c, jeb, ref);
|
||||
c->wasted_size += ref_totlen(c, jeb, ref);
|
||||
jeb->wasted_size += freed_len;
|
||||
c->wasted_size += freed_len;
|
||||
}
|
||||
ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
|
||||
|
||||
|
@ -634,8 +623,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
|
||||
goto out_erase_sem;
|
||||
}
|
||||
if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
|
||||
printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
|
||||
if (PAD(je32_to_cpu(n.totlen)) != PAD(freed_len)) {
|
||||
printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), freed_len);
|
||||
goto out_erase_sem;
|
||||
}
|
||||
if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
|
||||
|
@ -692,7 +681,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
#ifdef TEST_TOTLEN
|
||||
ref->__totlen += n->__totlen;
|
||||
#endif
|
||||
ref->next_phys = n->next_phys;
|
||||
if (jeb->last_node == n) jeb->last_node = ref;
|
||||
if (jeb->gc_node == n) {
|
||||
|
@ -715,7 +706,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
|||
p = p->next_phys;
|
||||
|
||||
if (ref_obsolete(p) && !ref->next_in_ino) {
|
||||
#ifdef TEST_TOTLEN
|
||||
p->__totlen += ref->__totlen;
|
||||
#endif
|
||||
if (jeb->last_node == ref) {
|
||||
jeb->last_node = p;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
396
fs/jffs2/scan.c
396
fs/jffs2/scan.c
|
@ -65,6 +65,25 @@ static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) {
|
|||
return DEFAULT_EMPTY_SCAN_SIZE;
|
||||
}
|
||||
|
||||
static int file_dirty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
{
|
||||
int ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Turned wasted size into dirty, since we apparently
|
||||
think it's recoverable now. */
|
||||
jeb->dirty_size += jeb->wasted_size;
|
||||
c->dirty_size += jeb->wasted_size;
|
||||
c->wasted_size -= jeb->wasted_size;
|
||||
jeb->wasted_size = 0;
|
||||
if (VERYDIRTY(c, jeb->dirty_size)) {
|
||||
list_add(&jeb->list, &c->very_dirty_list);
|
||||
} else {
|
||||
list_add(&jeb->list, &c->dirty_list);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jffs2_scan_medium(struct jffs2_sb_info *c)
|
||||
{
|
||||
int i, ret;
|
||||
|
@ -170,34 +189,20 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
|
|||
(!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
|
||||
/* Better candidate for the next writes to go to */
|
||||
if (c->nextblock) {
|
||||
c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
|
||||
c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
|
||||
c->free_size -= c->nextblock->free_size;
|
||||
c->wasted_size -= c->nextblock->wasted_size;
|
||||
c->nextblock->free_size = c->nextblock->wasted_size = 0;
|
||||
if (VERYDIRTY(c, c->nextblock->dirty_size)) {
|
||||
list_add(&c->nextblock->list, &c->very_dirty_list);
|
||||
} else {
|
||||
list_add(&c->nextblock->list, &c->dirty_list);
|
||||
}
|
||||
ret = file_dirty(c, c->nextblock);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* deleting summary information of the old nextblock */
|
||||
jffs2_sum_reset_collected(c->summary);
|
||||
}
|
||||
/* update collected summary infromation for the current nextblock */
|
||||
/* update collected summary information for the current nextblock */
|
||||
jffs2_sum_move_collected(c, s);
|
||||
D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset));
|
||||
c->nextblock = jeb;
|
||||
} else {
|
||||
jeb->dirty_size += jeb->free_size + jeb->wasted_size;
|
||||
c->dirty_size += jeb->free_size + jeb->wasted_size;
|
||||
c->free_size -= jeb->free_size;
|
||||
c->wasted_size -= jeb->wasted_size;
|
||||
jeb->free_size = jeb->wasted_size = 0;
|
||||
if (VERYDIRTY(c, jeb->dirty_size)) {
|
||||
list_add(&jeb->list, &c->very_dirty_list);
|
||||
} else {
|
||||
list_add(&jeb->list, &c->dirty_list);
|
||||
}
|
||||
ret = file_dirty(c, jeb);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -306,11 +311,138 @@ 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;
|
||||
int err;
|
||||
|
||||
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);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen))))
|
||||
return err;
|
||||
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);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen))))
|
||||
return err;
|
||||
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) {
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen)))))
|
||||
return err;
|
||||
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->flash_offset = ofs | REF_PRISTINE;
|
||||
raw->next_in_ino = (void *)xd;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, raw, 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;
|
||||
int err;
|
||||
|
||||
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);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rr->totlen)))))
|
||||
return err;
|
||||
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)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rr->totlen))))
|
||||
return err;
|
||||
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->flash_offset = ofs | REF_PRISTINE;
|
||||
raw->next_in_ino = (void *)ref;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, raw, 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,
|
||||
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 crcnode;
|
||||
struct jffs2_sum_marker *sm;
|
||||
uint32_t ofs, prevofs;
|
||||
uint32_t hdr_crc, buf_ofs, buf_len;
|
||||
int err;
|
||||
|
@ -344,32 +476,74 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
#endif
|
||||
|
||||
if (jffs2_sum_active()) {
|
||||
sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL);
|
||||
if (!sm) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size -
|
||||
sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker));
|
||||
if (err) {
|
||||
kfree(sm);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) {
|
||||
err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random);
|
||||
if (err) {
|
||||
kfree(sm);
|
||||
return err;
|
||||
struct jffs2_sum_marker *sm;
|
||||
void *sumptr = NULL;
|
||||
uint32_t sumlen;
|
||||
|
||||
if (!buf_size) {
|
||||
/* XIP case. Just look, point at the summary if it's there */
|
||||
sm = (void *)buf + jeb->offset - sizeof(*sm);
|
||||
if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
|
||||
sumptr = buf + je32_to_cpu(sm->offset);
|
||||
sumlen = c->sector_size - je32_to_cpu(sm->offset);
|
||||
}
|
||||
} else {
|
||||
/* If NAND flash, read a whole page of it. Else just the end */
|
||||
if (c->wbuf_pagesize)
|
||||
buf_len = c->wbuf_pagesize;
|
||||
else
|
||||
buf_len = sizeof(*sm);
|
||||
|
||||
/* Read as much as we want into the _end_ of the preallocated buffer */
|
||||
err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
|
||||
jeb->offset + c->sector_size - buf_len,
|
||||
buf_len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sm = (void *)buf + buf_size - sizeof(*sm);
|
||||
if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
|
||||
sumlen = c->sector_size - je32_to_cpu(sm->offset);
|
||||
sumptr = buf + buf_size - sumlen;
|
||||
|
||||
/* Now, make sure the summary itself is available */
|
||||
if (sumlen > buf_size) {
|
||||
/* Need to kmalloc for this. */
|
||||
sumptr = kmalloc(sumlen, GFP_KERNEL);
|
||||
if (!sumptr)
|
||||
return -ENOMEM;
|
||||
memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len);
|
||||
}
|
||||
if (buf_len < sumlen) {
|
||||
/* Need to read more so that the entire summary node is present */
|
||||
err = jffs2_fill_scan_buf(c, sumptr,
|
||||
jeb->offset + c->sector_size - sumlen,
|
||||
sumlen - buf_len);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
kfree(sm);
|
||||
if (sumptr) {
|
||||
err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random);
|
||||
|
||||
if (buf_size && sumlen > buf_size)
|
||||
kfree(sumptr);
|
||||
/* If it returns with a real error, bail.
|
||||
If it returns positive, that's a block classification
|
||||
(i.e. BLK_STATE_xxx) so return that too.
|
||||
If it returns zero, fall through to full scan. */
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
buf_ofs = jeb->offset;
|
||||
|
||||
if (!buf_size) {
|
||||
/* This is the XIP case -- we're reading _directly_ from the flash chip */
|
||||
buf_len = c->sector_size;
|
||||
} else {
|
||||
buf_len = EMPTY_SCAN_SIZE(c->sector_size);
|
||||
|
@ -407,7 +581,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
if (ofs) {
|
||||
D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
|
||||
jeb->offset + ofs));
|
||||
DIRTY_SPACE(ofs);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, ofs)))
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Now ofs is a complete physical flash offset as it always was... */
|
||||
|
@ -431,7 +606,8 @@ scan_more:
|
|||
}
|
||||
if (ofs == prevofs) {
|
||||
printk(KERN_WARNING "ofs 0x%08x has already been seen. Skipping\n", ofs);
|
||||
DIRTY_SPACE(4);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
|
@ -440,7 +616,8 @@ scan_more:
|
|||
if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
|
||||
D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
|
||||
jeb->offset, c->sector_size, ofs, sizeof(*node)));
|
||||
DIRTY_SPACE((jeb->offset + c->sector_size)-ofs);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, (jeb->offset + c->sector_size)-ofs)))
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -470,7 +647,8 @@ scan_more:
|
|||
if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
|
||||
printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
|
||||
empty_start, ofs);
|
||||
DIRTY_SPACE(ofs-empty_start);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start)))
|
||||
return err;
|
||||
goto scan_more;
|
||||
}
|
||||
|
||||
|
@ -507,20 +685,23 @@ scan_more:
|
|||
|
||||
if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
|
||||
printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
|
||||
DIRTY_SPACE(4);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
|
||||
D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
|
||||
DIRTY_SPACE(4);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
|
||||
printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
|
||||
printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
|
||||
DIRTY_SPACE(4);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
|
@ -529,7 +710,8 @@ scan_more:
|
|||
noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
|
||||
JFFS2_MAGIC_BITMASK, ofs,
|
||||
je16_to_cpu(node->magic));
|
||||
DIRTY_SPACE(4);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
|
@ -546,7 +728,8 @@ scan_more:
|
|||
je32_to_cpu(node->totlen),
|
||||
je32_to_cpu(node->hdr_crc),
|
||||
hdr_crc);
|
||||
DIRTY_SPACE(4);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
|
@ -557,7 +740,8 @@ scan_more:
|
|||
printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
|
||||
ofs, je32_to_cpu(node->totlen));
|
||||
printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
|
||||
DIRTY_SPACE(4);
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
|
||||
return err;
|
||||
ofs += 4;
|
||||
continue;
|
||||
}
|
||||
|
@ -565,7 +749,8 @@ scan_more:
|
|||
if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
|
||||
/* Wheee. This is an obsoleted node */
|
||||
D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
|
||||
DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
|
||||
return err;
|
||||
ofs += PAD(je32_to_cpu(node->totlen));
|
||||
continue;
|
||||
}
|
||||
|
@ -603,16 +788,55 @@ 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) {
|
||||
printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
|
||||
ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
|
||||
DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
|
||||
return err;
|
||||
ofs += PAD(sizeof(struct jffs2_unknown_node));
|
||||
} else if (jeb->first_node) {
|
||||
printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
|
||||
DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
|
||||
return err;
|
||||
ofs += PAD(sizeof(struct jffs2_unknown_node));
|
||||
} else {
|
||||
struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
|
||||
|
@ -621,12 +845,10 @@ scan_more:
|
|||
return -ENOMEM;
|
||||
}
|
||||
marker_ref->next_in_ino = NULL;
|
||||
marker_ref->next_phys = NULL;
|
||||
marker_ref->flash_offset = ofs | REF_NORMAL;
|
||||
marker_ref->__totlen = c->cleanmarker_size;
|
||||
jeb->first_node = jeb->last_node = marker_ref;
|
||||
|
||||
USED_SPACE(PAD(c->cleanmarker_size));
|
||||
jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size);
|
||||
|
||||
ofs += PAD(c->cleanmarker_size);
|
||||
}
|
||||
break;
|
||||
|
@ -634,7 +856,8 @@ scan_more:
|
|||
case JFFS2_NODETYPE_PADDING:
|
||||
if (jffs2_sum_active())
|
||||
jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
|
||||
DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
|
||||
return err;
|
||||
ofs += PAD(je32_to_cpu(node->totlen));
|
||||
break;
|
||||
|
||||
|
@ -645,7 +868,8 @@ scan_more:
|
|||
c->flags |= JFFS2_SB_FLAG_RO;
|
||||
if (!(jffs2_is_readonly(c)))
|
||||
return -EROFS;
|
||||
DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
|
||||
return err;
|
||||
ofs += PAD(je32_to_cpu(node->totlen));
|
||||
break;
|
||||
|
||||
|
@ -655,15 +879,27 @@ scan_more:
|
|||
|
||||
case JFFS2_FEATURE_RWCOMPAT_DELETE:
|
||||
D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
|
||||
DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
|
||||
return err;
|
||||
ofs += PAD(je32_to_cpu(node->totlen));
|
||||
break;
|
||||
|
||||
case JFFS2_FEATURE_RWCOMPAT_COPY:
|
||||
case JFFS2_FEATURE_RWCOMPAT_COPY: {
|
||||
struct jffs2_raw_node_ref *ref;
|
||||
D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
|
||||
USED_SPACE(PAD(je32_to_cpu(node->totlen)));
|
||||
|
||||
ref = jffs2_alloc_raw_node_ref();
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
ref->flash_offset = ofs | REF_PRISTINE;
|
||||
ref->next_in_ino = 0;
|
||||
jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)));
|
||||
|
||||
/* We can't summarise nodes we don't grok */
|
||||
jffs2_sum_disable_collecting(s);
|
||||
ofs += PAD(je32_to_cpu(node->totlen));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -722,6 +958,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
|
|||
struct jffs2_raw_node_ref *raw;
|
||||
struct jffs2_inode_cache *ic;
|
||||
uint32_t ino = je32_to_cpu(ri->ino);
|
||||
int err;
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
|
||||
|
||||
|
@ -751,7 +988,8 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
|
|||
printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
|
||||
ofs, je32_to_cpu(ri->node_crc), crc);
|
||||
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
|
||||
DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen)))))
|
||||
return err;
|
||||
jffs2_free_raw_node_ref(raw);
|
||||
return 0;
|
||||
}
|
||||
|
@ -765,16 +1003,11 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
|
|||
/* Wheee. It worked */
|
||||
|
||||
raw->flash_offset = ofs | REF_UNCHECKED;
|
||||
raw->__totlen = PAD(je32_to_cpu(ri->totlen));
|
||||
raw->next_phys = NULL;
|
||||
raw->next_in_ino = ic->nodes;
|
||||
|
||||
raw->next_in_ino = ic->nodes;
|
||||
ic->nodes = raw;
|
||||
if (!jeb->first_node)
|
||||
jeb->first_node = raw;
|
||||
if (jeb->last_node)
|
||||
jeb->last_node->next_phys = raw;
|
||||
jeb->last_node = raw;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen)));
|
||||
|
||||
D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
|
||||
je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
|
||||
|
@ -783,8 +1016,6 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
|
|||
|
||||
pseudo_random += je32_to_cpu(ri->version);
|
||||
|
||||
UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
|
||||
|
||||
if (jffs2_sum_active()) {
|
||||
jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset);
|
||||
}
|
||||
|
@ -799,6 +1030,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
struct jffs2_full_dirent *fd;
|
||||
struct jffs2_inode_cache *ic;
|
||||
uint32_t crc;
|
||||
int err;
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs));
|
||||
|
||||
|
@ -810,7 +1042,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
|
||||
ofs, je32_to_cpu(rd->node_crc), crc);
|
||||
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
|
||||
DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen)))))
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -831,7 +1064,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
jffs2_free_full_dirent(fd);
|
||||
/* FIXME: Why do we believe totlen? */
|
||||
/* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
|
||||
DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen)))))
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
raw = jffs2_alloc_raw_node_ref();
|
||||
|
@ -847,16 +1081,11 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
raw->__totlen = PAD(je32_to_cpu(rd->totlen));
|
||||
raw->flash_offset = ofs | REF_PRISTINE;
|
||||
raw->next_phys = NULL;
|
||||
raw->next_in_ino = ic->nodes;
|
||||
ic->nodes = raw;
|
||||
if (!jeb->first_node)
|
||||
jeb->first_node = raw;
|
||||
if (jeb->last_node)
|
||||
jeb->last_node->next_phys = raw;
|
||||
jeb->last_node = raw;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)));
|
||||
|
||||
fd->raw = raw;
|
||||
fd->next = NULL;
|
||||
|
@ -864,7 +1093,6 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
|
|||
fd->ino = je32_to_cpu(rd->ino);
|
||||
fd->nhash = full_name_hash(fd->name, rd->nsize);
|
||||
fd->type = rd->type;
|
||||
USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
|
||||
jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
|
||||
|
||||
if (jffs2_sum_active()) {
|
||||
|
|
|
@ -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);
|
||||
|
@ -288,6 +369,23 @@ no_mem:
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct jffs2_raw_node_ref *alloc_ref_at(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
uint32_t offset)
|
||||
{
|
||||
struct jffs2_raw_node_ref *ref;
|
||||
/* If there was a gap, mark it dirty */
|
||||
if (offset > c->sector_size - jeb->free_size) {
|
||||
int ret = jffs2_scan_dirty_space(c, jeb, offset - (c->sector_size - jeb->free_size));
|
||||
if (ret)
|
||||
return NULL;
|
||||
}
|
||||
ref = jffs2_alloc_raw_node_ref();
|
||||
if (!ref)
|
||||
return NULL;
|
||||
|
||||
ref->flash_offset = jeb->offset + offset;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
|
||||
|
||||
|
@ -299,6 +397,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
struct jffs2_full_dirent *fd;
|
||||
void *sp;
|
||||
int i, ino;
|
||||
int err;
|
||||
|
||||
sp = summary->sum;
|
||||
|
||||
|
@ -312,13 +411,13 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
|
||||
ino = je32_to_cpu(spi->inode);
|
||||
|
||||
dbg_summary("Inode at 0x%08x\n",
|
||||
jeb->offset + je32_to_cpu(spi->offset));
|
||||
dbg_summary("Inode at 0x%08x-0x%08x\n",
|
||||
jeb->offset + je32_to_cpu(spi->offset),
|
||||
jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spu->totlen));
|
||||
|
||||
raw = jffs2_alloc_raw_node_ref();
|
||||
raw = alloc_ref_at(c, jeb, je32_to_cpu(spi->offset));
|
||||
if (!raw) {
|
||||
JFFS2_NOTICE("allocation of node reference failed\n");
|
||||
kfree(summary);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -326,24 +425,17 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
if (!ic) {
|
||||
JFFS2_NOTICE("scan_make_ino_cache failed\n");
|
||||
jffs2_free_raw_node_ref(raw);
|
||||
kfree(summary);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
|
||||
raw->__totlen = PAD(je32_to_cpu(spi->totlen));
|
||||
raw->next_phys = NULL;
|
||||
raw->flash_offset |= REF_UNCHECKED;
|
||||
|
||||
raw->next_in_ino = ic->nodes;
|
||||
|
||||
ic->nodes = raw;
|
||||
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(spi->version);
|
||||
|
||||
UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen)));
|
||||
jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)));
|
||||
|
||||
*pseudo_random += je32_to_cpu(spi->version);
|
||||
|
||||
sp += JFFS2_SUMMARY_INODE_SIZE;
|
||||
|
||||
|
@ -355,22 +447,21 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
spd = sp;
|
||||
|
||||
dbg_summary("Dirent at 0x%08x\n",
|
||||
jeb->offset + je32_to_cpu(spd->offset));
|
||||
jeb->offset + je32_to_cpu(spd->offset),
|
||||
jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen));
|
||||
|
||||
|
||||
fd = jffs2_alloc_full_dirent(spd->nsize+1);
|
||||
if (!fd) {
|
||||
kfree(summary);
|
||||
if (!fd)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(&fd->name, spd->name, spd->nsize);
|
||||
fd->name[spd->nsize] = 0;
|
||||
|
||||
raw = jffs2_alloc_raw_node_ref();
|
||||
raw = alloc_ref_at(c, jeb, je32_to_cpu(spd->offset));
|
||||
if (!raw) {
|
||||
jffs2_free_full_dirent(fd);
|
||||
JFFS2_NOTICE("allocation of node reference failed\n");
|
||||
kfree(summary);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -378,20 +469,14 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
if (!ic) {
|
||||
jffs2_free_full_dirent(fd);
|
||||
jffs2_free_raw_node_ref(raw);
|
||||
kfree(summary);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
raw->__totlen = PAD(je32_to_cpu(spd->totlen));
|
||||
raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
|
||||
raw->next_phys = NULL;
|
||||
raw->flash_offset |= REF_PRISTINE;
|
||||
raw->next_in_ino = ic->nodes;
|
||||
ic->nodes = raw;
|
||||
if (!jeb->first_node)
|
||||
jeb->first_node = raw;
|
||||
if (jeb->last_node)
|
||||
jeb->last_node->next_phys = raw;
|
||||
jeb->last_node = raw;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)));
|
||||
|
||||
fd->raw = raw;
|
||||
fd->next = NULL;
|
||||
|
@ -399,7 +484,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
|
|||
fd->ino = je32_to_cpu(spd->ino);
|
||||
fd->nhash = full_name_hash(fd->name, spd->nsize);
|
||||
fd->type = spd->type;
|
||||
USED_SPACE(PAD(je32_to_cpu(spd->totlen)));
|
||||
|
||||
jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
|
||||
|
||||
*pseudo_random += je32_to_cpu(spd->version);
|
||||
|
@ -408,48 +493,122 @@ 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;
|
||||
|
||||
spx = (struct jffs2_sum_xattr_flash *)sp;
|
||||
dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n",
|
||||
jeb->offset + je32_to_cpu(spx->offset),
|
||||
jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen),
|
||||
je32_to_cpu(spx->xid), je32_to_cpu(spx->version));
|
||||
raw = alloc_ref_at(c, jeb, je32_to_cpu(spx->offset));
|
||||
if (!raw) {
|
||||
JFFS2_NOTICE("allocation of node reference failed\n");
|
||||
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 */
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen))))
|
||||
return err;
|
||||
sp += JFFS2_SUMMARY_XATTR_SIZE;
|
||||
break;
|
||||
}
|
||||
JFFS2_NOTICE("allocation of xattr_datum failed\n");
|
||||
return PTR_ERR(xd);
|
||||
}
|
||||
xd->node = raw;
|
||||
|
||||
raw->flash_offset |= REF_UNCHECKED;
|
||||
raw->next_in_ino = (void *)xd;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen)));
|
||||
|
||||
*pseudo_random += je32_to_cpu(spx->xid);
|
||||
sp += JFFS2_SUMMARY_XATTR_SIZE;
|
||||
|
||||
break;
|
||||
}
|
||||
case JFFS2_NODETYPE_XREF: {
|
||||
struct jffs2_xattr_ref *ref;
|
||||
struct jffs2_sum_xref_flash *spr;
|
||||
|
||||
spr = (struct jffs2_sum_xref_flash *)sp;
|
||||
dbg_summary("xref at %#08x-%#08x\n",
|
||||
jeb->offset + je32_to_cpu(spr->offset),
|
||||
jeb->offset + je32_to_cpu(spr->offset) + PAD(sizeof(struct jffs2_raw_xref)));
|
||||
|
||||
raw = alloc_ref_at(c, jeb, je32_to_cpu(spr->offset));
|
||||
if (!raw) {
|
||||
JFFS2_NOTICE("allocation of node reference failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ref = jffs2_alloc_xattr_ref();
|
||||
if (!ref) {
|
||||
JFFS2_NOTICE("allocation of xattr_datum failed\n");
|
||||
jffs2_free_raw_node_ref(raw);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ref->ino = 0xfffffffe;
|
||||
ref->xid = 0xfffffffd;
|
||||
ref->node = raw;
|
||||
ref->next = c->xref_temp;
|
||||
c->xref_temp = ref;
|
||||
|
||||
raw->flash_offset |= REF_UNCHECKED;
|
||||
raw->next_in_ino = (void *)ref;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref)));
|
||||
|
||||
*pseudo_random += raw->flash_offset;
|
||||
sp += JFFS2_SUMMARY_XREF_SIZE;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default : {
|
||||
JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
|
||||
kfree(summary);
|
||||
return -EIO;
|
||||
uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype);
|
||||
JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype);
|
||||
if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT)
|
||||
return -EIO;
|
||||
|
||||
/* For compatible node types, just fall back to the full scan */
|
||||
c->wasted_size -= jeb->wasted_size;
|
||||
c->free_size += c->sector_size - jeb->free_size;
|
||||
c->used_size -= jeb->used_size;
|
||||
c->dirty_size -= jeb->dirty_size;
|
||||
jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0;
|
||||
jeb->free_size = c->sector_size;
|
||||
|
||||
jffs2_free_all_node_refs(c, jeb);
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kfree(summary);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process the summary node - called from jffs2_scan_eraseblock() */
|
||||
|
||||
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
uint32_t ofs, uint32_t *pseudo_random)
|
||||
struct jffs2_raw_summary *summary, uint32_t sumsize,
|
||||
uint32_t *pseudo_random)
|
||||
{
|
||||
struct jffs2_unknown_node crcnode;
|
||||
struct jffs2_raw_node_ref *cache_ref;
|
||||
struct jffs2_raw_summary *summary;
|
||||
int ret, sumsize;
|
||||
int ret, ofs;
|
||||
uint32_t crc;
|
||||
int err;
|
||||
|
||||
sumsize = c->sector_size - ofs;
|
||||
ofs += jeb->offset;
|
||||
ofs = c->sector_size - sumsize;
|
||||
|
||||
dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
|
||||
jeb->offset, ofs, sumsize);
|
||||
|
||||
summary = kmalloc(sumsize, GFP_KERNEL);
|
||||
|
||||
if (!summary) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
|
||||
|
||||
if (ret) {
|
||||
kfree(summary);
|
||||
return ret;
|
||||
}
|
||||
jeb->offset, jeb->offset + ofs, sumsize);
|
||||
|
||||
/* OK, now check for node validity and CRC */
|
||||
crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
|
@ -489,40 +648,38 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
|
|||
if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
|
||||
dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
|
||||
je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
|
||||
UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
|
||||
return err;
|
||||
} else if (jeb->first_node) {
|
||||
dbg_summary("CLEANMARKER node not first node in block "
|
||||
"(0x%08x)\n", jeb->offset);
|
||||
UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
|
||||
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
|
||||
return err;
|
||||
} else {
|
||||
struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
|
||||
|
||||
if (!marker_ref) {
|
||||
JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
|
||||
kfree(summary);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
marker_ref->next_in_ino = NULL;
|
||||
marker_ref->next_phys = NULL;
|
||||
marker_ref->flash_offset = jeb->offset | REF_NORMAL;
|
||||
marker_ref->__totlen = je32_to_cpu(summary->cln_mkr);
|
||||
jeb->first_node = jeb->last_node = marker_ref;
|
||||
marker_ref->next_in_ino = NULL;
|
||||
|
||||
USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) );
|
||||
jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr));
|
||||
}
|
||||
}
|
||||
|
||||
if (je32_to_cpu(summary->padded)) {
|
||||
DIRTY_SPACE(je32_to_cpu(summary->padded));
|
||||
}
|
||||
|
||||
ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
|
||||
/* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full
|
||||
scan of this eraseblock. So return zero */
|
||||
if (ret == -ENOTRECOVERABLE)
|
||||
return 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
return ret; /* real error */
|
||||
|
||||
/* for PARANOIA_CHECK */
|
||||
cache_ref = jffs2_alloc_raw_node_ref();
|
||||
cache_ref = alloc_ref_at(c, jeb, ofs);
|
||||
|
||||
if (!cache_ref) {
|
||||
JFFS2_NOTICE("Failed to allocate node ref for cache\n");
|
||||
|
@ -530,22 +687,18 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
|
|||
}
|
||||
|
||||
cache_ref->next_in_ino = NULL;
|
||||
cache_ref->next_phys = NULL;
|
||||
cache_ref->flash_offset = ofs | REF_NORMAL;
|
||||
cache_ref->__totlen = sumsize;
|
||||
cache_ref->flash_offset |= REF_NORMAL;
|
||||
|
||||
if (!jeb->first_node)
|
||||
jeb->first_node = cache_ref;
|
||||
if (jeb->last_node)
|
||||
jeb->last_node->next_phys = cache_ref;
|
||||
jeb->last_node = cache_ref;
|
||||
jffs2_link_node_ref(c, jeb, cache_ref, sumsize);
|
||||
|
||||
USED_SPACE(sumsize);
|
||||
|
||||
jeb->wasted_size += jeb->free_size;
|
||||
c->wasted_size += jeb->free_size;
|
||||
c->free_size -= jeb->free_size;
|
||||
jeb->free_size = 0;
|
||||
if (unlikely(jeb->free_size)) {
|
||||
JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n",
|
||||
jeb->free_size, jeb->offset);
|
||||
jeb->wasted_size += jeb->free_size;
|
||||
c->wasted_size += jeb->free_size;
|
||||
c->free_size -= jeb->free_size;
|
||||
jeb->free_size = 0;
|
||||
}
|
||||
|
||||
return jffs2_scan_classify_jeb(c, jeb);
|
||||
|
||||
|
@ -617,9 +770,40 @@ 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 */
|
||||
if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK)
|
||||
== JFFS2_FEATURE_RWCOMPAT_COPY) {
|
||||
dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n",
|
||||
je16_to_cpu(temp->u.nodetype));
|
||||
jffs2_sum_disable_collecting(c->summary);
|
||||
} else {
|
||||
BUG(); /* unknown node in summary information */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -651,19 +835,32 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
|
|||
spin_unlock(&c->erase_completion_lock);
|
||||
ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size -
|
||||
jeb->free_size, &retlen, 0);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
|
||||
if (ret || (retlen != infosize)) {
|
||||
struct jffs2_raw_node_ref *ref;
|
||||
|
||||
JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n",
|
||||
infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen);
|
||||
|
||||
/* Waste remaining space */
|
||||
ref = jffs2_alloc_raw_node_ref();
|
||||
if (ref) {
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size;
|
||||
ref->flash_offset |= REF_OBSOLETE;
|
||||
ref->next_in_ino = 0;
|
||||
|
||||
jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size);
|
||||
}
|
||||
|
||||
c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
|
||||
WASTED_SPACE(infosize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -706,7 +903,6 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
|
|||
/* for ACCT_PARANOIA_CHECK */
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
summary_ref = jffs2_alloc_raw_node_ref();
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
if (!summary_ref) {
|
||||
JFFS2_NOTICE("Failed to allocate node ref for summary\n");
|
||||
|
@ -714,17 +910,10 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
|
|||
}
|
||||
|
||||
summary_ref->next_in_ino = NULL;
|
||||
summary_ref->next_phys = NULL;
|
||||
summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL;
|
||||
summary_ref->__totlen = infosize;
|
||||
|
||||
if (!jeb->first_node)
|
||||
jeb->first_node = summary_ref;
|
||||
if (jeb->last_node)
|
||||
jeb->last_node->next_phys = summary_ref;
|
||||
jeb->last_node = summary_ref;
|
||||
|
||||
USED_SPACE(infosize);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
jffs2_link_node_ref(c, jeb, summary_ref, infosize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,23 +18,6 @@
|
|||
#include <linux/uio.h>
|
||||
#include <linux/jffs2.h>
|
||||
|
||||
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->dirty_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->dirty_size += _x; \
|
||||
}while(0)
|
||||
#define USED_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->used_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->used_size += _x; \
|
||||
}while(0)
|
||||
#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->wasted_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->wasted_size += _x; \
|
||||
}while(0)
|
||||
#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
|
||||
c->free_size -= _x; c->unchecked_size += _x; \
|
||||
jeb->free_size -= _x ; jeb->unchecked_size += _x; \
|
||||
}while(0)
|
||||
|
||||
#define BLK_STATE_ALLFF 0
|
||||
#define BLK_STATE_CLEAN 1
|
||||
#define BLK_STATE_PARTDIRTY 2
|
||||
|
@ -45,6 +28,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 +60,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 +116,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,8 +180,11 @@ 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,
|
||||
uint32_t ofs, uint32_t *pseudo_random);
|
||||
struct jffs2_raw_summary *summary, uint32_t sumlen,
|
||||
uint32_t *pseudo_random);
|
||||
|
||||
#else /* SUMMARY DISABLED */
|
||||
|
||||
|
@ -176,6 +200,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)
|
||||
|
|
|
@ -312,11 +312,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
|
|||
return;
|
||||
|
||||
raw2->flash_offset = ofs | REF_OBSOLETE;
|
||||
raw2->__totlen = ref_totlen(c, jeb, *first_raw);
|
||||
raw2->next_phys = NULL;
|
||||
raw2->next_in_ino = NULL;
|
||||
|
||||
jffs2_add_physical_node_ref(c, raw2);
|
||||
jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -483,11 +481,11 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||
return ret;
|
||||
}
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
/* Adjust free size of the block if we padded. */
|
||||
if (pad) {
|
||||
struct jffs2_eraseblock *jeb;
|
||||
struct jffs2_raw_node_ref *ref;
|
||||
uint32_t waste = c->wbuf_pagesize - c->wbuf_len;
|
||||
|
||||
jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
|
||||
|
||||
|
@ -497,18 +495,29 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
|||
/* wbuf_pagesize - wbuf_len is the amount of space that's to be
|
||||
padded. If there is less free space in the block than that,
|
||||
something screwed up */
|
||||
if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
|
||||
if (jeb->free_size < waste) {
|
||||
printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
|
||||
c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len);
|
||||
c->wbuf_ofs, c->wbuf_len, waste);
|
||||
printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
|
||||
jeb->offset, jeb->free_size);
|
||||
BUG();
|
||||
}
|
||||
jeb->free_size -= (c->wbuf_pagesize - c->wbuf_len);
|
||||
c->free_size -= (c->wbuf_pagesize - c->wbuf_len);
|
||||
jeb->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
|
||||
c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
|
||||
}
|
||||
ref = jffs2_alloc_raw_node_ref();
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
ref->flash_offset = c->wbuf_ofs + c->wbuf_len;
|
||||
ref->flash_offset |= REF_OBSOLETE;
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
jffs2_link_node_ref(c, jeb, ref, waste);
|
||||
/* FIXME: that made it count as dirty. Convert to wasted */
|
||||
jeb->dirty_size -= waste;
|
||||
c->dirty_size -= waste;
|
||||
jeb->wasted_size += waste;
|
||||
c->wasted_size += waste;
|
||||
} else
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
/* Stick any now-obsoleted blocks on the erase_pending_list */
|
||||
jffs2_refile_wbuf_blocks(c);
|
||||
|
|
|
@ -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);
|
||||
|
@ -104,8 +103,6 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
|
|||
fn->raw = raw;
|
||||
|
||||
raw->flash_offset = flash_ofs;
|
||||
raw->__totlen = PAD(sizeof(*ri)+datalen);
|
||||
raw->next_phys = NULL;
|
||||
|
||||
if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
|
||||
BUG_ON(!retried);
|
||||
|
@ -134,7 +131,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
|
|||
any node we write before the original intended end of
|
||||
this node */
|
||||
raw->flash_offset |= REF_OBSOLETE;
|
||||
jffs2_add_physical_node_ref(c, raw);
|
||||
jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen));
|
||||
jffs2_mark_node_obsolete(c, raw);
|
||||
} else {
|
||||
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
|
||||
|
@ -192,7 +189,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
|
|||
} else {
|
||||
raw->flash_offset |= REF_NORMAL;
|
||||
}
|
||||
jffs2_add_physical_node_ref(c, raw);
|
||||
jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen));
|
||||
|
||||
/* Link into per-inode list */
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
@ -260,8 +257,6 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
|
|||
fd->raw = raw;
|
||||
|
||||
raw->flash_offset = flash_ofs;
|
||||
raw->__totlen = PAD(sizeof(*rd)+namelen);
|
||||
raw->next_phys = NULL;
|
||||
|
||||
if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
|
||||
BUG_ON(!retried);
|
||||
|
@ -282,7 +277,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
|
|||
if (retlen) {
|
||||
raw->next_in_ino = NULL;
|
||||
raw->flash_offset |= REF_OBSOLETE;
|
||||
jffs2_add_physical_node_ref(c, raw);
|
||||
jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen));
|
||||
jffs2_mark_node_obsolete(c, raw);
|
||||
} else {
|
||||
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
|
||||
|
@ -328,7 +323,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
|
|||
}
|
||||
/* Mark the space used */
|
||||
raw->flash_offset |= REF_PRISTINE;
|
||||
jffs2_add_physical_node_ref(c, raw);
|
||||
jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen));
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
raw->next_in_ino = f->inocache->nodes;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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_ */
|
|
@ -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
|
||||
};
|
|
@ -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;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче