From fb6a82c94a9c69adfb6b9f6ce9f84be36884e471 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 11 Apr 2006 20:12:10 -0400 Subject: [PATCH] jffs2: fix printk warnings Fix printk format warnings in jffs2. Signed-off-by: Randy Dunlap Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index fb9cec61fcf2..3240d62d9707 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -655,7 +655,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock if (ret || (retlen != infosize)) { - JFFS2_WARNING("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", + JFFS2_WARNING("Write of %d bytes at 0x%08x failed. returned %d, retlen %zu\n", infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; -- cgit v1.2.3 From 20ffdcb00a792073f6e620dc2c644b3c8fbab528 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 12 May 2006 11:55:51 +0100 Subject: [JFFS2] Remove number of pointer dereferences in fs/jffs2/summary.c Reduce the nr. of pointer dereferences in fs/jffs2/summary.c Benefits: - micro speed optimization due to fewer pointer derefs - generated code is slightly smaller - better readability (The first two sound like a compiler problem but I'll go with the third. dwmw2). Signed-off-by: Jesper Juhl Signed-off-by: Andrew Morton Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 3240d62d9707..7b0ed77a4c35 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -581,16 +581,17 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock wpage = c->summary->sum_buf; while (c->summary->sum_num) { + temp = c->summary->sum_list_head; - switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) { + switch (je16_to_cpu(temp->u.nodetype)) { case JFFS2_NODETYPE_INODE: { struct jffs2_sum_inode_flash *sino_ptr = wpage; - sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype; - sino_ptr->inode = c->summary->sum_list_head->i.inode; - sino_ptr->version = c->summary->sum_list_head->i.version; - sino_ptr->offset = c->summary->sum_list_head->i.offset; - sino_ptr->totlen = c->summary->sum_list_head->i.totlen; + sino_ptr->nodetype = temp->i.nodetype; + sino_ptr->inode = temp->i.inode; + sino_ptr->version = temp->i.version; + sino_ptr->offset = temp->i.offset; + sino_ptr->totlen = temp->i.totlen; wpage += JFFS2_SUMMARY_INODE_SIZE; @@ -600,19 +601,19 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock case JFFS2_NODETYPE_DIRENT: { struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; - sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype; - sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen; - sdrnt_ptr->offset = c->summary->sum_list_head->d.offset; - sdrnt_ptr->pino = c->summary->sum_list_head->d.pino; - sdrnt_ptr->version = c->summary->sum_list_head->d.version; - sdrnt_ptr->ino = c->summary->sum_list_head->d.ino; - sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize; - sdrnt_ptr->type = c->summary->sum_list_head->d.type; + sdrnt_ptr->nodetype = temp->d.nodetype; + sdrnt_ptr->totlen = temp->d.totlen; + sdrnt_ptr->offset = temp->d.offset; + sdrnt_ptr->pino = temp->d.pino; + sdrnt_ptr->version = temp->d.version; + sdrnt_ptr->ino = temp->d.ino; + sdrnt_ptr->nsize = temp->d.nsize; + sdrnt_ptr->type = temp->d.type; - memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name, - c->summary->sum_list_head->d.nsize); + memcpy(sdrnt_ptr->name, temp->d.name, + temp->d.nsize); - wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize); + wpage += JFFS2_SUMMARY_DIRENT_SIZE(temp->d.nsize); break; } @@ -622,8 +623,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock } } - temp = c->summary->sum_list_head; - c->summary->sum_list_head = c->summary->sum_list_head->u.next; + c->summary->sum_list_head = temp->u.next; kfree(temp); c->summary->sum_num--; -- cgit v1.2.3 From aa98d7cf59b5b0764d3502662053489585faf2fe Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 13 May 2006 15:09:47 +0900 Subject: [JFFS2][XATTR] XATTR support on JFFS2 (version. 5) This attached patches provide xattr support including POSIX-ACL and SELinux support on JFFS2 (version.5). There are some significant differences from previous version posted at last December. The biggest change is addition of EBS(Erase Block Summary) support. Currently, both kernel and usermode utility (sumtool) can recognize xattr nodes which have JFFS2_NODETYPE_XATTR/_XREF nodetype. In addition, some bugs are fixed. - A potential race condition was fixed. - Unexpected fail when updating a xattr by same name/value pair was fixed. - A bug when removing xattr name/value pair was fixed. The fundamental structures (such as using two new nodetypes and exclusion mechanism by rwsem) are unchanged. But most of implementation were reviewed and updated if necessary. Espacially, we had to change several internal implementations related to load_xattr_datum() to avoid a potential race condition. [1/2] xattr_on_jffs2.kernel.version-5.patch [2/2] xattr_on_jffs2.utils.version-5.patch Signed-off-by: KaiGai Kohei Signed-off-by: David Woodhouse --- fs/Kconfig | 38 ++ fs/jffs2/Makefile | 3 + fs/jffs2/acl.c | 483 ++++++++++++++++++ fs/jffs2/acl.h | 46 ++ fs/jffs2/build.c | 2 + fs/jffs2/debug.h | 6 + fs/jffs2/dir.c | 62 ++- fs/jffs2/file.c | 7 +- fs/jffs2/fs.c | 11 +- fs/jffs2/gc.c | 16 +- fs/jffs2/jffs2_fs_i.h | 5 + fs/jffs2/jffs2_fs_sb.h | 10 + fs/jffs2/malloc.c | 68 ++- fs/jffs2/nodelist.c | 1 + fs/jffs2/nodelist.h | 21 +- fs/jffs2/os-linux.h | 4 + fs/jffs2/readinode.c | 1 + fs/jffs2/scan.c | 168 ++++++ fs/jffs2/security.c | 82 +++ fs/jffs2/summary.c | 191 +++++++ fs/jffs2/summary.h | 42 ++ fs/jffs2/super.c | 6 +- fs/jffs2/symlink.c | 7 +- fs/jffs2/write.c | 2 +- fs/jffs2/xattr.c | 1271 ++++++++++++++++++++++++++++++++++++++++++++++ fs/jffs2/xattr.h | 120 +++++ fs/jffs2/xattr_trusted.c | 51 ++ fs/jffs2/xattr_user.c | 51 ++ include/linux/jffs2.h | 40 ++ 29 files changed, 2800 insertions(+), 15 deletions(-) create mode 100644 fs/jffs2/acl.c create mode 100644 fs/jffs2/acl.h create mode 100644 fs/jffs2/security.c create mode 100644 fs/jffs2/xattr.c create mode 100644 fs/jffs2/xattr.h create mode 100644 fs/jffs2/xattr_trusted.c create mode 100644 fs/jffs2/xattr_user.c (limited to 'fs/jffs2/summary.c') diff --git a/fs/Kconfig b/fs/Kconfig index f9b5842c8d2d..2496ccbe2604 100644 --- a/fs/Kconfig +++ b/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 + 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 . + + 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 diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 77dc5561a04e..7f28ee0bd132 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -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 diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c new file mode 100644 index 000000000000..080bb51e4b65 --- /dev/null +++ b/fs/jffs2/acl.c @@ -0,0 +1,483 @@ +/*-------------------------------------------------------------------------* + * File: fs/jffs2/acl.c + * POSIX ACL support on JFFS2 FileSystem + * + * Implemented by KaiGai Kohei + * Copyright (C) 2006 NEC Corporation + * + * For licensing information, see the file 'LICENCE' in the jffs2 directory. + *-------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nodelist.h" + +static size_t jffs2_acl_size(int count) +{ + if (count <= 4) { + return sizeof(jffs2_acl_header) + + count * sizeof(jffs2_acl_entry_short); + } else { + return sizeof(jffs2_acl_header) + + 4 * sizeof(jffs2_acl_entry_short) + + (count - 4) * sizeof(jffs2_acl_entry); + } +} + +static int jffs2_acl_count(size_t size) +{ + size_t s; + + size -= sizeof(jffs2_acl_header); + s = size - 4 * sizeof(jffs2_acl_entry_short); + if (s < 0) { + if (size % sizeof(jffs2_acl_entry_short)) + return -1; + return size / sizeof(jffs2_acl_entry_short); + } else { + if (s % sizeof(jffs2_acl_entry)) + return -1; + return s / sizeof(jffs2_acl_entry) + 4; + } +} + +static struct posix_acl *jffs2_acl_from_medium(const void *value, size_t size) +{ + const char *end = (char *)value + size; + struct posix_acl *acl; + uint32_t ver; + int i, count; + + if (!value) + return NULL; + if (size < sizeof(jffs2_acl_header)) + return ERR_PTR(-EINVAL); + ver = je32_to_cpu(((jffs2_acl_header *)value)->a_version); + if (ver != JFFS2_ACL_VERSION) { + JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver); + return ERR_PTR(-EINVAL); + } + + value = (char *)value + sizeof(jffs2_acl_header); + count = jffs2_acl_count(size); + if (count < 0) + return ERR_PTR(-EINVAL); + if (count == 0) + return NULL; + + acl = posix_acl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + + for (i=0; i < count; i++) { + jffs2_acl_entry *entry = (jffs2_acl_entry *)value; + if ((char *)value + sizeof(jffs2_acl_entry_short) > end) + goto fail; + acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag); + acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm); + switch (acl->a_entries[i].e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + value = (char *)value + sizeof(jffs2_acl_entry_short); + acl->a_entries[i].e_id = ACL_UNDEFINED_ID; + break; + + case ACL_USER: + case ACL_GROUP: + value = (char *)value + sizeof(jffs2_acl_entry); + if ((char *)value > end) + goto fail; + acl->a_entries[i].e_id = je32_to_cpu(entry->e_id); + break; + + default: + goto fail; + } + } + if (value != end) + goto fail; + return acl; + fail: + posix_acl_release(acl); + return ERR_PTR(-EINVAL); +} + +static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size) +{ + jffs2_acl_header *jffs2_acl; + char *e; + size_t i; + + *size = jffs2_acl_size(acl->a_count); + jffs2_acl = (jffs2_acl_header *)kmalloc(sizeof(jffs2_acl_header) + + acl->a_count * sizeof(jffs2_acl_entry), + GFP_KERNEL); + if (!jffs2_acl) + return ERR_PTR(-ENOMEM); + jffs2_acl->a_version = cpu_to_je32(JFFS2_ACL_VERSION); + e = (char *)jffs2_acl + sizeof(jffs2_acl_header); + for (i=0; i < acl->a_count; i++) { + jffs2_acl_entry *entry = (jffs2_acl_entry *)e; + entry->e_tag = cpu_to_je16(acl->a_entries[i].e_tag); + entry->e_perm = cpu_to_je16(acl->a_entries[i].e_perm); + switch(acl->a_entries[i].e_tag) { + case ACL_USER: + case ACL_GROUP: + entry->e_id = cpu_to_je32(acl->a_entries[i].e_id); + e += sizeof(jffs2_acl_entry); + break; + + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(jffs2_acl_entry_short); + break; + + default: + goto fail; + } + } + return (char *)jffs2_acl; + fail: + kfree(jffs2_acl); + return ERR_PTR(-EINVAL); +} + +static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl) +{ + struct posix_acl *acl = JFFS2_ACL_NOT_CACHED; + + spin_lock(&inode->i_lock); + if (*i_acl != JFFS2_ACL_NOT_CACHED) + acl = posix_acl_dup(*i_acl); + spin_unlock(&inode->i_lock); + return acl; +} + +static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl) +{ + spin_lock(&inode->i_lock); + if (*i_acl != JFFS2_ACL_NOT_CACHED) + posix_acl_release(*i_acl); + *i_acl = posix_acl_dup(acl); + spin_unlock(&inode->i_lock); +} + +static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct posix_acl *acl; + char *value = NULL; + int rc, xprefix; + + switch (type) { + case ACL_TYPE_ACCESS: + acl = jffs2_iget_acl(inode, &f->i_acl_access); + if (acl != JFFS2_ACL_NOT_CACHED) + return acl; + xprefix = JFFS2_XPREFIX_ACL_ACCESS; + break; + case ACL_TYPE_DEFAULT: + acl = jffs2_iget_acl(inode, &f->i_acl_default); + if (acl != JFFS2_ACL_NOT_CACHED) + return acl; + xprefix = JFFS2_XPREFIX_ACL_DEFAULT; + break; + default: + return ERR_PTR(-EINVAL); + } + rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); + if (rc > 0) { + value = kmalloc(rc, GFP_KERNEL); + if (!value) + return ERR_PTR(-ENOMEM); + rc = do_jffs2_getxattr(inode, xprefix, "", value, rc); + } + if (rc > 0) { + acl = jffs2_acl_from_medium(value, rc); + } else if (rc == -ENODATA || rc == -ENOSYS) { + acl = NULL; + } else { + acl = ERR_PTR(rc); + } + if (value) + kfree(value); + if (!IS_ERR(acl)) { + switch (type) { + case ACL_TYPE_ACCESS: + jffs2_iset_acl(inode, &f->i_acl_access, acl); + break; + case ACL_TYPE_DEFAULT: + jffs2_iset_acl(inode, &f->i_acl_default, acl); + break; + } + } + return acl; +} + +static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + size_t size = 0; + char *value = NULL; + int rc, xprefix; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + + switch (type) { + case ACL_TYPE_ACCESS: + xprefix = JFFS2_XPREFIX_ACL_ACCESS; + if (acl) { + mode_t mode = inode->i_mode; + rc = posix_acl_equiv_mode(acl, &mode); + if (rc < 0) + return rc; + if (inode->i_mode != mode) { + inode->i_mode = mode; + jffs2_dirty_inode(inode); + } + if (rc == 0) + acl = NULL; + } + break; + case ACL_TYPE_DEFAULT: + xprefix = JFFS2_XPREFIX_ACL_DEFAULT; + if (!S_ISDIR(inode->i_mode)) + return acl ? -EACCES : 0; + break; + default: + return -EINVAL; + } + if (acl) { + value = jffs2_acl_to_medium(acl, &size); + if (IS_ERR(value)) + return PTR_ERR(value); + } + + rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0); + if (value) + kfree(value); + if (!rc) { + switch(type) { + case ACL_TYPE_ACCESS: + jffs2_iset_acl(inode, &f->i_acl_access, acl); + break; + case ACL_TYPE_DEFAULT: + jffs2_iset_acl(inode, &f->i_acl_default, acl); + break; + } + } + return rc; +} + +static int jffs2_check_acl(struct inode *inode, int mask) +{ + struct posix_acl *acl; + int rc; + + acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + rc = posix_acl_permission(inode, acl, mask); + posix_acl_release(acl); + return rc; + } + return -EAGAIN; +} + +int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + return generic_permission(inode, mask, jffs2_check_acl); +} + +int jffs2_init_acl(struct inode *inode, struct inode *dir) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct posix_acl *acl = NULL, *clone; + mode_t mode; + int rc = 0; + + f->i_acl_access = JFFS2_ACL_NOT_CACHED; + f->i_acl_default = JFFS2_ACL_NOT_CACHED; + if (!S_ISLNK(inode->i_mode)) { + acl = jffs2_get_acl(dir, ACL_TYPE_DEFAULT); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (!acl) + inode->i_mode &= ~current->fs->umask; + } + if (acl) { + if (S_ISDIR(inode->i_mode)) { + rc = jffs2_set_acl(inode, ACL_TYPE_DEFAULT, acl); + if (rc) + goto cleanup; + } + clone = posix_acl_clone(acl, GFP_KERNEL); + rc = -ENOMEM; + if (!clone) + goto cleanup; + mode = inode->i_mode; + rc = posix_acl_create_masq(clone, &mode); + if (rc >= 0) { + inode->i_mode = mode; + if (rc > 0) + rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone); + } + posix_acl_release(clone); + } + cleanup: + posix_acl_release(acl); + return rc; +} + +void jffs2_clear_acl(struct inode *inode) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + + if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) { + posix_acl_release(f->i_acl_access); + f->i_acl_access = JFFS2_ACL_NOT_CACHED; + } + if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) { + posix_acl_release(f->i_acl_default); + f->i_acl_default = JFFS2_ACL_NOT_CACHED; + } +} + +int jffs2_acl_chmod(struct inode *inode) +{ + struct posix_acl *acl, *clone; + int rc; + + if (S_ISLNK(inode->i_mode)) + return -EOPNOTSUPP; + acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); + if (IS_ERR(acl) || !acl) + return PTR_ERR(acl); + clone = posix_acl_clone(acl, GFP_KERNEL); + posix_acl_release(acl); + if (!clone) + return -ENOMEM; + rc = posix_acl_chmod_masq(clone, inode->i_mode); + if (!rc) + rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone); + posix_acl_release(clone); + return rc; +} + +static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS); + + if (list && retlen <= list_size) + strcpy(list, POSIX_ACL_XATTR_ACCESS); + return retlen; +} + +static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT); + + if (list && retlen <= list_size) + strcpy(list, POSIX_ACL_XATTR_DEFAULT); + return retlen; +} + +static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size) +{ + struct posix_acl *acl; + int rc; + + acl = jffs2_get_acl(inode, type); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (!acl) + return -ENODATA; + rc = posix_acl_to_xattr(acl, buffer, size); + posix_acl_release(acl); + + return rc; +} + +static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) +{ + if (name[0] != '\0') + return -EINVAL; + return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size); +} + +static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size) +{ + if (name[0] != '\0') + return -EINVAL; + return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size); +} + +static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size) +{ + struct posix_acl *acl; + int rc; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + + if (value) { + acl = posix_acl_from_xattr(value, size); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + rc = posix_acl_valid(acl); + if (rc) + goto out; + } + } else { + acl = NULL; + } + rc = jffs2_set_acl(inode, type, acl); + out: + posix_acl_release(acl); + return rc; +} + +static int jffs2_acl_access_setxattr(struct inode *inode, const char *name, + const void *buffer, size_t size, int flags) +{ + if (name[0] != '\0') + return -EINVAL; + return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size); +} + +static int jffs2_acl_default_setxattr(struct inode *inode, const char *name, + const void *buffer, size_t size, int flags) +{ + if (name[0] != '\0') + return -EINVAL; + return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size); +} + +struct xattr_handler jffs2_acl_access_xattr_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .list = jffs2_acl_access_listxattr, + .get = jffs2_acl_access_getxattr, + .set = jffs2_acl_access_setxattr, +}; + +struct xattr_handler jffs2_acl_default_xattr_handler = { + .prefix = POSIX_ACL_XATTR_DEFAULT, + .list = jffs2_acl_default_listxattr, + .get = jffs2_acl_default_getxattr, + .set = jffs2_acl_default_setxattr, +}; diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h new file mode 100644 index 000000000000..c98610b4e81c --- /dev/null +++ b/fs/jffs2/acl.h @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------* + * File: fs/jffs2/acl.h + * POSIX ACL support on JFFS2 FileSystem + * + * Implemented by KaiGai Kohei + * Copyright (C) 2006 NEC Corporation + * + * For licensing information, see the file 'LICENCE' in the jffs2 directory. + *-------------------------------------------------------------------------*/ +typedef struct { + jint16_t e_tag; + jint16_t e_perm; + jint32_t e_id; +} jffs2_acl_entry; + +typedef struct { + jint16_t e_tag; + jint16_t e_perm; +} jffs2_acl_entry_short; + +typedef struct { + jint32_t a_version; +} jffs2_acl_header; + +#ifdef __KERNEL__ +#ifdef CONFIG_JFFS2_FS_POSIX_ACL + +#define JFFS2_ACL_NOT_CACHED ((void *)-1) + +extern int jffs2_permission(struct inode *, int, struct nameidata *); +extern int jffs2_acl_chmod(struct inode *); +extern int jffs2_init_acl(struct inode *, struct inode *); +extern void jffs2_clear_acl(struct inode *); + +extern struct xattr_handler jffs2_acl_access_xattr_handler; +extern struct xattr_handler jffs2_acl_default_xattr_handler; + +#else + +#define jffs2_permission NULL +#define jffs2_acl_chmod(inode) (0) +#define jffs2_init_acl(inode,dir) (0) +#define jffs2_clear_acl(inode) + +#endif /* CONFIG_JFFS2_FS_POSIX_ACL */ +#endif /* __KERNEL__ */ diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 70f7a896c04a..02826967ab58 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -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; diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 162af6dfe292..5fa494a792b2 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -171,6 +171,12 @@ #define dbg_memalloc(fmt, ...) #endif +/* Watch the XATTR subsystem */ +#ifdef JFFS2_DBG_XATTR_MESSAGES +#define dbg_xattr(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) +#else +#define dbg_xattr(fmt, ...) +#endif /* "Sanity" checks */ void diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 1c8e8c0f6cea..f1b18b99a3cd 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -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) { @@ -660,6 +698,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) { diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 9f4171213e58..e92187f34d5f 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -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 = diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index ea1f37d4fc58..4607cdc4c46d 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -185,7 +185,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) @@ -224,6 +229,7 @@ void jffs2_clear_inode (struct inode *inode) D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); + jffs2_xattr_delete_inode(c, f->inocache); jffs2_do_clear_inode(c, f); } @@ -497,6 +503,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) } memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *)); + jffs2_init_xattr_subsystem(c); + if ((ret = jffs2_do_mount_fs(c))) goto out_inohash; @@ -531,6 +539,7 @@ int jffs2_do_fill_super(struct super_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); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 967fb2cf8e21..4ea1b7f0ae78 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -125,6 +125,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; int ret = 0, inum, nlink; + int xattr = 0; if (down_interruptible(&c->alloc_sem)) return -EINTR; @@ -138,7 +139,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) the node CRCs etc. Do it now. */ /* checked_ino is protected by the alloc_sem */ - if (c->checked_ino > c->highest_ino) { + if (c->checked_ino > c->highest_ino && xattr) { printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", c->unchecked_size); jffs2_dbg_dump_block_lists_nolock(c); @@ -148,6 +149,9 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) spin_unlock(&c->erase_completion_lock); + if (!xattr) + xattr = jffs2_verify_xattr(c); + spin_lock(&c->inocache_lock); ic = jffs2_get_ino_cache(c, c->checked_ino++); @@ -262,6 +266,16 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ic = jffs2_raw_ref_to_ic(raw); + /* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr. + We can decide whether this node is inode or xattr by ic->class. + ret = 0 : ic is xattr_datum/xattr_ref, and GC was SUCCESSED. + ret < 0 : ic is xattr_datum/xattr_ref, but GC was FAILED. + ret > 0 : ic is NOT xattr_datum/xattr_ref. + */ + ret = jffs2_garbage_collect_xattr(c, ic); + if (ret <= 0) + goto release_sem; + /* We need to hold the inocache. Either the erase_completion_lock or the inocache_lock are sufficient; we trade down since the inocache_lock causes less contention. */ diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index ad565bf9dcc1..2e0cc8e00b85 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h @@ -5,6 +5,7 @@ #include #include +#include #include 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 */ diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 4bcfb5570221..3b4e0edd6dbb 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -115,6 +115,16 @@ struct jffs2_sb_info { struct jffs2_summary *summary; /* Summary information */ +#ifdef CONFIG_JFFS2_FS_XATTR +#define XATTRINDEX_HASHSIZE (57) + uint32_t highest_xid; + struct list_head xattrindex[XATTRINDEX_HASHSIZE]; + struct list_head xattr_temp; + struct list_head xattr_unchecked; + struct rw_semaphore xattr_sem; + uint32_t xdatum_mem_usage; + uint32_t xdatum_mem_threshold; +#endif /* OS-private pointer for getting back to master superblock info */ void *os_priv; }; diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 036cbd11c004..3d5b7ecfbf8d 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -26,6 +26,10 @@ static kmem_cache_t *tmp_dnode_info_slab; static kmem_cache_t *raw_node_ref_slab; static kmem_cache_t *node_frag_slab; static kmem_cache_t *inode_cache_slab; +#ifdef CONFIG_JFFS2_FS_XATTR +static kmem_cache_t *xattr_datum_cache; +static kmem_cache_t *xattr_ref_cache; +#endif int __init jffs2_create_slab_caches(void) { @@ -68,8 +72,24 @@ int __init jffs2_create_slab_caches(void) inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, 0, NULL, NULL); - if (inode_cache_slab) - return 0; + if (!inode_cache_slab) + goto err; + +#ifdef CONFIG_JFFS2_FS_XATTR + xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", + sizeof(struct jffs2_xattr_datum), + 0, 0, NULL, NULL); + if (!xattr_datum_cache) + goto err; + + xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", + sizeof(struct jffs2_xattr_ref), + 0, 0, NULL, NULL); + if (!xattr_ref_cache) + goto err; +#endif + + return 0; err: jffs2_destroy_slab_caches(); return -ENOMEM; @@ -91,6 +111,12 @@ void jffs2_destroy_slab_caches(void) kmem_cache_destroy(node_frag_slab); if(inode_cache_slab) kmem_cache_destroy(inode_cache_slab); +#ifdef CONFIG_JFFS2_FS_XATTR + if (xattr_datum_cache) + kmem_cache_destroy(xattr_datum_cache); + if (xattr_ref_cache) + kmem_cache_destroy(xattr_ref_cache); +#endif } struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) @@ -205,3 +231,41 @@ void jffs2_free_inode_cache(struct jffs2_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; + INIT_LIST_HEAD(&ref->ilist); + return ref; +} + +void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) +{ + dbg_memalloc("%p\n", ref); + kmem_cache_free(xattr_ref_cache, ref); +} +#endif diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index d4d0c41490cd..9c575733659b 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -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; } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index f6645afe88e4..6f6279cf4909 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -20,6 +20,8 @@ #include #include "jffs2_fs_sb.h" #include "jffs2_fs_i.h" +#include "xattr.h" +#include "acl.h" #include "summary.h" #ifdef __ECOS @@ -107,11 +109,16 @@ struct jffs2_inode_cache { temporary lists of dirents, and later must be set to NULL to mark the end of the raw_node_ref->next_in_ino chain. */ + u8 class; /* It's used for identification */ + u8 flags; + uint16_t state; struct jffs2_inode_cache *next; struct jffs2_raw_node_ref *nodes; uint32_t ino; int nlink; - int state; +#ifdef CONFIG_JFFS2_FS_XATTR + struct list_head ilist; +#endif }; /* Inode states for 'state' above. We need the 'GC' state to prevent @@ -125,6 +132,12 @@ struct jffs2_inode_cache { #define INO_STATE_READING 5 /* In read_inode() */ #define INO_STATE_CLEARING 6 /* In clear_inode() */ +#define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ + +#define RAWNODE_CLASS_INODE_CACHE 0 +#define RAWNODE_CLASS_XATTR_DATUM 1 +#define RAWNODE_CLASS_XATTR_REF 2 + #define INOCACHE_HASHSIZE 128 /* @@ -374,6 +387,12 @@ struct jffs2_node_frag *jffs2_alloc_node_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); diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index d307cf548625..9936ae23f8dc 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -60,6 +60,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 } diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index e1acce8fb2bf..61ccdf4f1042 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -902,6 +902,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, f->inocache->ino = f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->state = INO_STATE_READING; + init_xattr_inode_cache(f->inocache); jffs2_add_ino_cache(c, f->inocache); } if (!f->inocache) { diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index cf55b221fc2b..f09689e320fe 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -306,6 +306,136 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je return BLK_STATE_ALLDIRTY; } +#ifdef CONFIG_JFFS2_FS_XATTR +static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_xattr *rx, uint32_t ofs, + struct jffs2_summary *s) +{ + struct jffs2_xattr_datum *xd; + struct jffs2_raw_node_ref *raw; + uint32_t totlen, crc; + + crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4); + if (crc != je32_to_cpu(rx->node_crc)) { + if (je32_to_cpu(rx->node_crc) != 0xffffffff) + JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + ofs, je32_to_cpu(rx->node_crc), crc); + DIRTY_SPACE(je32_to_cpu(rx->totlen)); + return 0; + } + + totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len)); + if (totlen != je32_to_cpu(rx->totlen)) { + JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", + ofs, je32_to_cpu(rx->totlen), totlen); + DIRTY_SPACE(je32_to_cpu(rx->totlen)); + return 0; + } + + raw = jffs2_alloc_raw_node_ref(); + if (!raw) + return -ENOMEM; + + xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version)); + if (IS_ERR(xd)) { + jffs2_free_raw_node_ref(raw); + if (PTR_ERR(xd) == -EEXIST) { + DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen))); + return 0; + } + return PTR_ERR(xd); + } + xd->xprefix = rx->xprefix; + xd->name_len = rx->name_len; + xd->value_len = je16_to_cpu(rx->value_len); + xd->data_crc = je32_to_cpu(rx->data_crc); + xd->node = raw; + + raw->__totlen = totlen; + raw->flash_offset = ofs | REF_PRISTINE; + raw->next_phys = NULL; + raw->next_in_ino = (void *)xd; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + + USED_SPACE(PAD(je32_to_cpu(rx->totlen))); + if (jffs2_sum_active()) + jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); + dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n", + ofs, xd->xid, xd->version); + return 0; +} + +static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_xref *rr, uint32_t ofs, + struct jffs2_summary *s) +{ + struct jffs2_xattr_ref *ref; + struct jffs2_raw_node_ref *raw; + uint32_t crc; + + crc = crc32(0, rr, sizeof(*rr) - 4); + if (crc != je32_to_cpu(rr->node_crc)) { + if (je32_to_cpu(rr->node_crc) != 0xffffffff) + JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + ofs, je32_to_cpu(rr->node_crc), crc); + DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen))); + return 0; + } + + if (PAD(sizeof(struct jffs2_raw_xref)) != je32_to_cpu(rr->totlen)) { + JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", + ofs, je32_to_cpu(rr->totlen), + PAD(sizeof(struct jffs2_raw_xref))); + DIRTY_SPACE(je32_to_cpu(rr->totlen)); + return 0; + } + + ref = jffs2_alloc_xattr_ref(); + if (!ref) + return -ENOMEM; + + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + jffs2_free_xattr_ref(ref); + return -ENOMEM; + } + + /* BEFORE jffs2_build_xattr_subsystem() called, + * ref->xid is used to store 32bit xid, xd is not used + * ref->ino is used to store 32bit inode-number, ic is not used + * Thoes variables are declared as union, thus using those + * are exclusive. In a similar way, ref->ilist is temporarily + * used to chain all xattr_ref object. It's re-chained to + * jffs2_inode_cache in jffs2_build_xattr_subsystem() correctly. + */ + ref->node = raw; + ref->ino = je32_to_cpu(rr->ino); + ref->xid = je32_to_cpu(rr->xid); + list_add_tail(&ref->ilist, &c->xattr_temp); + + raw->__totlen = PAD(je32_to_cpu(rr->totlen)); + raw->flash_offset = ofs | REF_PRISTINE; + raw->next_phys = NULL; + raw->next_in_ino = (void *)ref; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + + USED_SPACE(PAD(je32_to_cpu(rr->totlen))); + if (jffs2_sum_active()) + jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); + dbg_xattr("scan xref at %#08x (xid=%u, ino=%u)\n", + ofs, ref->xid, ref->ino); + return 0; +} +#endif + static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { struct jffs2_unknown_node *node; @@ -614,6 +744,43 @@ scan_more: ofs += PAD(je32_to_cpu(node->totlen)); break; +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: + if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)" + " left to end of buf. Reading 0x%x at 0x%08x\n", + je32_to_cpu(node->totlen), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + node = (void *)buf; + } + err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s); + if (err) + return err; + ofs += PAD(je32_to_cpu(node->totlen)); + break; + case JFFS2_NODETYPE_XREF: + if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)" + " left to end of buf. Reading 0x%x at 0x%08x\n", + je32_to_cpu(node->totlen), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + node = (void *)buf; + } + err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s); + if (err) + return err; + ofs += PAD(je32_to_cpu(node->totlen)); + break; +#endif /* CONFIG_JFFS2_FS_XATTR */ + case JFFS2_NODETYPE_CLEANMARKER: D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { @@ -721,6 +888,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin ic->ino = ino; ic->nodes = (void *)ic; + init_xattr_inode_cache(ic); jffs2_add_ino_cache(c, ic); if (ino == 1) ic->nlink = 1; diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c new file mode 100644 index 000000000000..4b6c3b22524f --- /dev/null +++ b/fs/jffs2/security.c @@ -0,0 +1,82 @@ +/*-------------------------------------------------------------------------* + * File: fs/jffs2/security.c + * Security Labels support on JFFS2 FileSystem + * + * Implemented by KaiGai Kohei + * Copyright (C) 2006 NEC Corporation + * + * For licensing information, see the file 'LICENCE' in the jffs2 directory. + *-------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +}; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 7b0ed77a4c35..5d9ec8e36528 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -5,6 +5,7 @@ * Zoltan Sogor , * Patrik Kluba , * University of Szeged, Hungary + * 2005 KaiGai Kohei * * 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); @@ -408,8 +489,94 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras break; } +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: { + struct jffs2_xattr_datum *xd; + struct jffs2_sum_xattr_flash *spx; + uint32_t ofs; + + spx = (struct jffs2_sum_xattr_flash *)sp; + ofs = jeb->offset + je32_to_cpu(spx->offset); + dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", ofs, + je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + kfree(summary); + return -ENOMEM; + } + xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), + je32_to_cpu(spx->version)); + if (IS_ERR(xd)) { + JFFS2_NOTICE("allocation of xattr_datum failed\n"); + jffs2_free_raw_node_ref(raw); + kfree(summary); + return PTR_ERR(xd); + } + xd->node = raw; + raw->flash_offset = ofs | REF_UNCHECKED; + raw->__totlen = PAD(je32_to_cpu(spx->totlen)); + raw->next_phys = NULL; + raw->next_in_ino = (void *)xd; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + + *pseudo_random += je32_to_cpu(spx->xid); + UNCHECKED_SPACE(je32_to_cpu(spx->totlen)); + sp += JFFS2_SUMMARY_XATTR_SIZE; + + break; + } + case JFFS2_NODETYPE_XREF: { + struct jffs2_xattr_ref *ref; + struct jffs2_sum_xref_flash *spr; + uint32_t ofs; + + spr = (struct jffs2_sum_xref_flash *)sp; + ofs = jeb->offset + je32_to_cpu(spr->offset); + dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs, + je32_to_cpu(spr->xid), je32_to_cpu(spr->ino)); + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + kfree(summary); + return -ENOMEM; + } + ref = jffs2_alloc_xattr_ref(); + if (!ref) { + JFFS2_NOTICE("allocation of xattr_datum failed\n"); + jffs2_free_raw_node_ref(raw); + kfree(summary); + return -ENOMEM; + } + ref->ino = 0xfffffffe; + ref->xid = 0xfffffffd; + ref->node = raw; + list_add_tail(&ref->ilist, &c->xattr_temp); + + raw->__totlen = PAD(sizeof(struct jffs2_raw_xref)); + raw->flash_offset = ofs | REF_UNCHECKED; + raw->next_phys = NULL; + raw->next_in_ino = (void *)ref; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + + UNCHECKED_SPACE(PAD(sizeof(struct jffs2_raw_xref))); + *pseudo_random += ofs; + sp += JFFS2_SUMMARY_XREF_SIZE; + + break; + } +#endif default : { +printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)); JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); kfree(summary); return -EIO; @@ -617,7 +784,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock break; } +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: { + struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; + + temp = c->summary->sum_list_head; + sxattr_ptr->nodetype = temp->x.nodetype; + sxattr_ptr->xid = temp->x.xid; + sxattr_ptr->version = temp->x.version; + sxattr_ptr->offset = temp->x.offset; + sxattr_ptr->totlen = temp->x.totlen; + + wpage += JFFS2_SUMMARY_XATTR_SIZE; + break; + } + case JFFS2_NODETYPE_XREF: { + struct jffs2_sum_xref_flash *sxref_ptr = wpage; + + temp = c->summary->sum_list_head; + sxref_ptr->nodetype = temp->r.nodetype; + sxref_ptr->offset = temp->r.offset; + wpage += JFFS2_SUMMARY_XREF_SIZE; + break; + } +#endif default : { BUG(); /* unknown node in summary information */ } diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index b7a678be1709..a3b66c18aae9 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -45,6 +45,8 @@ #define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff #define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) #define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) +#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash)) +#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash)) /* Summary structures used on flash */ @@ -75,11 +77,28 @@ struct jffs2_sum_dirent_flash uint8_t name[0]; /* dirent name */ } __attribute__((packed)); +struct jffs2_sum_xattr_flash +{ + jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */ + jint32_t xid; /* xattr identifier */ + jint32_t version; /* version number */ + jint32_t offset; /* offset on jeb */ + jint32_t totlen; /* node length */ +} __attribute__((packed)); + +struct jffs2_sum_xref_flash +{ + jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */ + jint32_t offset; /* offset on jeb */ +} __attribute__((packed)); + union jffs2_sum_flash { struct jffs2_sum_unknown_flash u; struct jffs2_sum_inode_flash i; struct jffs2_sum_dirent_flash d; + struct jffs2_sum_xattr_flash x; + struct jffs2_sum_xref_flash r; }; /* Summary structures used in the memory */ @@ -114,11 +133,30 @@ struct jffs2_sum_dirent_mem uint8_t name[0]; /* dirent name */ } __attribute__((packed)); +struct jffs2_sum_xattr_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; + jint32_t xid; + jint32_t version; + jint32_t offset; + jint32_t totlen; +} __attribute__((packed)); + +struct jffs2_sum_xref_mem +{ + union jffs2_sum_mem *next; + jint16_t nodetype; + jint32_t offset; +} __attribute__((packed)); + union jffs2_sum_mem { struct jffs2_sum_unknown_mem u; struct jffs2_sum_inode_mem i; struct jffs2_sum_dirent_mem d; + struct jffs2_sum_xattr_mem x; + struct jffs2_sum_xref_mem r; }; /* Summary related information stored in superblock */ @@ -159,6 +197,8 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c); int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); +int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs); +int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs); int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t ofs, uint32_t *pseudo_random); @@ -176,6 +216,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb #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 */ diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index ffd8e84b22cc..c8b539ee7d80 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -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); diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index d55754fe8925..fc211b6e9b03 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -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) diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 1342f0158e9b..d5c78195f3b8 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -36,7 +36,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->state = INO_STATE_PRESENT; - + init_xattr_inode_cache(f->inocache); jffs2_add_ino_cache(c, f->inocache); D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c new file mode 100644 index 000000000000..c9a185c54ce7 --- /dev/null +++ b/fs/jffs2/xattr.c @@ -0,0 +1,1271 @@ +/* ------------------------------------------------------------------------- + * File: fs/jffs2/xattr.c + * XATTR support on JFFS2 FileSystem + * + * Implemented by KaiGai Kohei + * Copyright (C) 2006 NEC Corporation + * + * For licensing information, see the file 'LICENCE' in the jffs2 directory. + * ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nodelist.h" +/* -------- xdatum related functions ---------------- + * xattr_datum_hashkey(xprefix, xname, xvalue, xsize) + * is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is + * the index of the xattr name/value pair cache (c->xattrindex). + * unload_xattr_datum(c, xd) + * is used to release xattr name/value pair and detach from c->xattrindex. + * reclaim_xattr_datum(c) + * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when + * memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold + * is hard coded as 32KiB. + * delete_xattr_datum_node(c, xd) + * is used to delete a jffs2 node is dominated by xdatum. When EBS(Erase Block Summary) is + * enabled, it overwrites the obsolete node by myself. + * delete_xattr_datum(c, xd) + * is used to delete jffs2_xattr_datum object. It must be called with 0-value of reference + * counter. (It means how many jffs2_xattr_ref object refers this xdatum.) + * do_verify_xattr_datum(c, xd) + * is used to load the xdatum informations without name/value pair from the medium. + * It's necessary once, because those informations are not collected during mounting + * process when EBS is enabled. + * 0 will be returned, if success. An negative return value means recoverable error, and + * positive return value means unrecoverable error. Thus, caller must remove this xdatum + * and xref when it returned positive value. + * do_load_xattr_datum(c, xd) + * is used to load name/value pair from the medium. + * The meanings of return value is same as do_verify_xattr_datum(). + * load_xattr_datum(c, xd) + * is used to be as a wrapper of do_verify_xattr_datum() and do_load_xattr_datum(). + * If xd need to call do_verify_xattr_datum() at first, it's called before calling + * do_load_xattr_datum(). The meanings of return value is same as do_verify_xattr_datum(). + * save_xattr_datum(c, xd, phys_ofs) + * is used to write xdatum to medium. xd->version will be incremented. + * create_xattr_datum(c, xprefix, xname, xvalue, xsize, phys_ofs) + * is used to create new xdatum and write to medium. + * -------------------------------------------------- */ + +static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize) +{ + int name_len = strlen(xname); + + return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize); +} + +static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem) */ + D1(dbg_xattr("%s: xid=%u, version=%u\n", __FUNCTION__, xd->xid, xd->version)); + if (xd->xname) { + c->xdatum_mem_usage -= (xd->name_len + 1 + xd->value_len); + kfree(xd->xname); + } + + list_del_init(&xd->xindex); + xd->hashkey = 0; + xd->xname = NULL; + xd->xvalue = NULL; +} + +static void reclaim_xattr_datum(struct jffs2_sb_info *c) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_xattr_datum *xd, *_xd; + uint32_t target, before; + static int index = 0; + int count; + + if (c->xdatum_mem_threshold > c->xdatum_mem_usage) + return; + + before = c->xdatum_mem_usage; + target = c->xdatum_mem_usage * 4 / 5; /* 20% reduction */ + for (count = 0; count < XATTRINDEX_HASHSIZE; count++) { + list_for_each_entry_safe(xd, _xd, &c->xattrindex[index], xindex) { + if (xd->flags & JFFS2_XFLAGS_HOT) { + xd->flags &= ~JFFS2_XFLAGS_HOT; + } else if (!(xd->flags & JFFS2_XFLAGS_BIND)) { + unload_xattr_datum(c, xd); + } + if (c->xdatum_mem_usage <= target) + goto out; + } + index = (index+1) % XATTRINDEX_HASHSIZE; + } + out: + JFFS2_NOTICE("xdatum_mem_usage from %u byte to %u byte (%u byte reclaimed)\n", + before, c->xdatum_mem_usage, before - c->xdatum_mem_usage); +} + +static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_raw_xattr rx; + uint32_t length; + int rc; + + if (!xd->node) { + JFFS2_WARNING("xdatum (xid=%u) is removed twice.\n", xd->xid); + return; + } + if (jffs2_sum_active()) { + memset(&rx, 0xff, sizeof(struct jffs2_raw_xattr)); + rc = jffs2_flash_read(c, ref_offset(xd->node), + sizeof(struct jffs2_unknown_node), + &length, (char *)&rx); + if (rc || length != sizeof(struct jffs2_unknown_node)) { + JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n", + rc, sizeof(struct jffs2_unknown_node), + length, ref_offset(xd->node)); + } + rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx), + &length, (char *)&rx); + if (rc || length != sizeof(struct jffs2_raw_xattr)) { + JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u ar %#08x\n", + rc, sizeof(rx), length, ref_offset(xd->node)); + } + } + spin_lock(&c->erase_completion_lock); + xd->node->next_in_ino = NULL; + spin_unlock(&c->erase_completion_lock); + jffs2_mark_node_obsolete(c, xd->node); + xd->node = NULL; +} + +static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem) */ + BUG_ON(xd->refcnt); + + unload_xattr_datum(c, xd); + if (xd->node) { + delete_xattr_datum_node(c, xd); + xd->node = NULL; + } + jffs2_free_xattr_datum(xd); +} + +static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_eraseblock *jeb; + struct jffs2_raw_xattr rx; + size_t readlen; + uint32_t crc, totlen; + int rc; + + BUG_ON(!xd->node); + BUG_ON(ref_flags(xd->node) != REF_UNCHECKED); + + rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx); + if (rc || readlen != sizeof(rx)) { + JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n", + rc, sizeof(rx), readlen, ref_offset(xd->node)); + return rc ? rc : -EIO; + } + crc = crc32(0, &rx, sizeof(rx) - 4); + if (crc != je32_to_cpu(rx.node_crc)) { + if (je32_to_cpu(rx.node_crc) != 0xffffffff) + JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + ref_offset(xd->node), je32_to_cpu(rx.hdr_crc), crc); + return EIO; + } + totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len)); + if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK + || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR + || je32_to_cpu(rx.totlen) != totlen + || je32_to_cpu(rx.xid) != xd->xid + || je32_to_cpu(rx.version) != xd->version) { + JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, " + "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n", + ref_offset(xd->node), je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK, + je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR, + je32_to_cpu(rx.totlen), totlen, + je32_to_cpu(rx.xid), xd->xid, + je32_to_cpu(rx.version), xd->version); + return EIO; + } + xd->xprefix = rx.xprefix; + xd->name_len = rx.name_len; + xd->value_len = je16_to_cpu(rx.value_len); + xd->data_crc = je32_to_cpu(rx.data_crc); + + /* This JFFS2_NODETYPE_XATTR node is checked */ + jeb = &c->blocks[ref_offset(xd->node) / c->sector_size]; + totlen = PAD(je32_to_cpu(rx.totlen)); + + spin_lock(&c->erase_completion_lock); + c->unchecked_size -= totlen; c->used_size += totlen; + jeb->unchecked_size -= totlen; jeb->used_size += totlen; + xd->node->flash_offset = ref_offset(xd->node) | REF_PRISTINE; + spin_unlock(&c->erase_completion_lock); + + /* unchecked xdatum is chained with c->xattr_unchecked */ + list_del_init(&xd->xindex); + + dbg_xattr("success on verfying xdatum (xid=%u, version=%u)\n", + xd->xid, xd->version); + + return 0; +} + +static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem) */ + char *data; + size_t readlen; + uint32_t crc, length; + int i, ret, retry = 0; + + BUG_ON(!xd->node); + BUG_ON(ref_flags(xd->node) != REF_PRISTINE); + BUG_ON(!list_empty(&xd->xindex)); + retry: + length = xd->name_len + 1 + xd->value_len; + data = kmalloc(length, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = jffs2_flash_read(c, ref_offset(xd->node)+sizeof(struct jffs2_raw_xattr), + length, &readlen, data); + + if (ret || length!=readlen) { + JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%d, at %#08x\n", + ret, length, readlen, ref_offset(xd->node)); + kfree(data); + return ret ? ret : -EIO; + } + + data[xd->name_len] = '\0'; + crc = crc32(0, data, length); + if (crc != xd->data_crc) { + JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XREF)" + " at %#08x, read: 0x%08x calculated: 0x%08x\n", + ref_offset(xd->node), xd->data_crc, crc); + kfree(data); + return EIO; + } + + xd->flags |= JFFS2_XFLAGS_HOT; + xd->xname = data; + xd->xvalue = data + xd->name_len+1; + + c->xdatum_mem_usage += length; + + xd->hashkey = xattr_datum_hashkey(xd->xprefix, xd->xname, xd->xvalue, xd->value_len); + i = xd->hashkey % XATTRINDEX_HASHSIZE; + list_add(&xd->xindex, &c->xattrindex[i]); + if (!retry) { + retry = 1; + reclaim_xattr_datum(c); + if (!xd->xname) + goto retry; + } + + dbg_xattr("success on loading xdatum (xid=%u, xprefix=%u, xname='%s')\n", + xd->xid, xd->xprefix, xd->xname); + + return 0; +} + +static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem); + * rc < 0 : recoverable error, try again + * rc = 0 : success + * rc > 0 : Unrecoverable error, this node should be deleted. + */ + int rc = 0; + BUG_ON(xd->xname); + if (!xd->node) + return EIO; + if (unlikely(ref_flags(xd->node) != REF_PRISTINE)) { + rc = do_verify_xattr_datum(c, xd); + if (rc > 0) { + list_del_init(&xd->xindex); + delete_xattr_datum_node(c, xd); + } + } + if (!rc) + rc = do_load_xattr_datum(c, xd); + return rc; +} + +static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, uint32_t phys_ofs) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_raw_xattr rx; + struct jffs2_raw_node_ref *raw; + struct kvec vecs[2]; + uint32_t length; + int rc, totlen; + + BUG_ON(!xd->xname); + + vecs[0].iov_base = ℞ + vecs[0].iov_len = PAD(sizeof(rx)); + vecs[1].iov_base = xd->xname; + vecs[1].iov_len = xd->name_len + 1 + xd->value_len; + totlen = vecs[0].iov_len + vecs[1].iov_len; + + raw = jffs2_alloc_raw_node_ref(); + if (!raw) + return -ENOMEM; + raw->flash_offset = phys_ofs; + raw->__totlen = PAD(totlen); + raw->next_phys = NULL; + raw->next_in_ino = (void *)xd; + + /* Setup raw-xattr */ + rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR); + rx.totlen = cpu_to_je32(PAD(totlen)); + rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); + + rx.xid = cpu_to_je32(xd->xid); + rx.version = cpu_to_je32(++xd->version); + rx.xprefix = xd->xprefix; + rx.name_len = xd->name_len; + rx.value_len = cpu_to_je16(xd->value_len); + rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); + rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4)); + + rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0); + if (rc || totlen != length) { + JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%u, at %#08x\n", + rc, totlen, length, phys_ofs); + rc = rc ? rc : -EIO; + if (length) { + raw->flash_offset |= REF_OBSOLETE; + raw->next_in_ino = NULL; + jffs2_add_physical_node_ref(c, raw); + jffs2_mark_node_obsolete(c, raw); + } else { + jffs2_free_raw_node_ref(raw); + } + return rc; + } + BUG_ON(raw->__totlen < sizeof(struct jffs2_raw_xattr)); + /* success */ + raw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, raw); + if (xd->node) + delete_xattr_datum_node(c, xd); + xd->node = raw; + + dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n", + xd->xid, xd->version, xd->xprefix, xd->xname); + + return 0; +} + +static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, + int xprefix, const char *xname, + const char *xvalue, int xsize, + uint32_t phys_ofs) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_xattr_datum *xd; + uint32_t hashkey, name_len; + char *data; + int i, rc; + + /* Search xattr_datum has same xname/xvalue by index */ + hashkey = xattr_datum_hashkey(xprefix, xname, xvalue, xsize); + i = hashkey % XATTRINDEX_HASHSIZE; + list_for_each_entry(xd, &c->xattrindex[i], xindex) { + if (xd->hashkey==hashkey + && xd->xprefix==xprefix + && xd->value_len==xsize + && !strcmp(xd->xname, xname) + && !memcmp(xd->xvalue, xvalue, xsize)) { + xd->refcnt++; + return xd; + } + } + + /* Not found, Create NEW XATTR-Cache */ + name_len = strlen(xname); + + xd = jffs2_alloc_xattr_datum(); + if (!xd) + return ERR_PTR(-ENOMEM); + + data = kmalloc(name_len + 1 + xsize, GFP_KERNEL); + if (!data) { + jffs2_free_xattr_datum(xd); + return ERR_PTR(-ENOMEM); + } + strcpy(data, xname); + memcpy(data + name_len + 1, xvalue, xsize); + + xd->refcnt = 1; + xd->xid = ++c->highest_xid; + xd->flags |= JFFS2_XFLAGS_HOT; + xd->xprefix = xprefix; + + xd->hashkey = hashkey; + xd->xname = data; + xd->xvalue = data + name_len + 1; + xd->name_len = name_len; + xd->value_len = xsize; + xd->data_crc = crc32(0, data, xd->name_len + 1 + xd->value_len); + + rc = save_xattr_datum(c, xd, phys_ofs); + if (rc) { + kfree(xd->xname); + jffs2_free_xattr_datum(xd); + return ERR_PTR(rc); + } + + /* Insert Hash Index */ + i = hashkey % XATTRINDEX_HASHSIZE; + list_add(&xd->xindex, &c->xattrindex[i]); + + c->xdatum_mem_usage += (xd->name_len + 1 + xd->value_len); + reclaim_xattr_datum(c); + + return xd; +} + +/* -------- xdatum related functions ---------------- + * verify_xattr_ref(c, ref) + * is used to load xref information from medium. Because summary data does not + * contain xid/ino, it's necessary to verify once while mounting process. + * delete_xattr_ref_node(c, ref) + * is used to delete a jffs2 node is dominated by xref. When EBS is enabled, + * it overwrites the obsolete node by myself. + * delete_xattr_ref(c, ref) + * is used to delete jffs2_xattr_ref object. If the reference counter of xdatum + * is refered by this xref become 0, delete_xattr_datum() is called later. + * save_xattr_ref(c, ref, phys_ofs) + * is used to write xref to medium. + * create_xattr_ref(c, ic, xd, phys_ofs) + * is used to create a new xref and write to medium. + * jffs2_xattr_delete_inode(c, ic) + * is called to remove xrefs related to obsolete inode when inode is unlinked. + * jffs2_xattr_free_inode(c, ic) + * is called to release xattr related objects when unmounting. + * check_xattr_ref_ilist(c, ic) + * is used to confirm inode does not have duplicate xattr name/value pair. + * -------------------------------------------------- */ +static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +{ + struct jffs2_eraseblock *jeb; + struct jffs2_raw_xref rr; + size_t readlen; + uint32_t crc, totlen; + int rc; + + BUG_ON(ref_flags(ref->node) != REF_UNCHECKED); + + rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr); + if (rc || sizeof(rr) != readlen) { + JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u, at %#08x\n", + rc, sizeof(rr), readlen, ref_offset(ref->node)); + return rc ? rc : -EIO; + } + /* obsolete node */ + crc = crc32(0, &rr, sizeof(rr) - 4); + if (crc != je32_to_cpu(rr.node_crc)) { + if (je32_to_cpu(rr.node_crc) != 0xffffffff) + JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + ref_offset(ref->node), je32_to_cpu(rr.node_crc), crc); + return EIO; + } + if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK + || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF + || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) { + JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, " + "nodetype=%#04x/%#04x, totlen=%u/%u\n", + ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, + je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF, + je32_to_cpu(rr.totlen), PAD(sizeof(rr))); + return EIO; + } + ref->ino = je32_to_cpu(rr.ino); + ref->xid = je32_to_cpu(rr.xid); + + /* fixup superblock/eraseblock info */ + jeb = &c->blocks[ref_offset(ref->node) / c->sector_size]; + totlen = PAD(sizeof(rr)); + + spin_lock(&c->erase_completion_lock); + c->unchecked_size -= totlen; c->used_size += totlen; + jeb->unchecked_size -= totlen; jeb->used_size += totlen; + ref->node->flash_offset = ref_offset(ref->node) | REF_PRISTINE; + spin_unlock(&c->erase_completion_lock); + + dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n", + ref->ino, ref->xid, ref_offset(ref->node)); + return 0; +} + +static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +{ + struct jffs2_raw_xref rr; + uint32_t length; + int rc; + + if (jffs2_sum_active()) { + memset(&rr, 0xff, sizeof(rr)); + rc = jffs2_flash_read(c, ref_offset(ref->node), + sizeof(struct jffs2_unknown_node), + &length, (char *)&rr); + if (rc || length != sizeof(struct jffs2_unknown_node)) { + JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n", + rc, sizeof(struct jffs2_unknown_node), + length, ref_offset(ref->node)); + } + rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr), + &length, (char *)&rr); + if (rc || length != sizeof(struct jffs2_raw_xref)) { + JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u at %#08x\n", + rc, sizeof(rr), length, ref_offset(ref->node)); + } + } + spin_lock(&c->erase_completion_lock); + ref->node->next_in_ino = NULL; + spin_unlock(&c->erase_completion_lock); + jffs2_mark_node_obsolete(c, ref->node); + ref->node = NULL; +} + +static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_xattr_datum *xd; + + BUG_ON(!ref->node); + delete_xattr_ref_node(c, ref); + + list_del(&ref->ilist); + xd = ref->xd; + xd->refcnt--; + if (!xd->refcnt) + delete_xattr_datum(c, xd); + jffs2_free_xattr_ref(ref); +} + +static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, uint32_t phys_ofs) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_raw_node_ref *raw; + struct jffs2_raw_xref rr; + uint32_t length; + int ret; + + raw = jffs2_alloc_raw_node_ref(); + if (!raw) + return -ENOMEM; + raw->flash_offset = phys_ofs; + raw->__totlen = PAD(sizeof(rr)); + raw->next_phys = NULL; + raw->next_in_ino = (void *)ref; + + rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); + rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); + rr.totlen = cpu_to_je32(PAD(sizeof(rr))); + rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4)); + + rr.ino = cpu_to_je32(ref->ic->ino); + rr.xid = cpu_to_je32(ref->xd->xid); + rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4)); + + ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr); + if (ret || sizeof(rr) != length) { + JFFS2_WARNING("jffs2_flash_write() returned %d, request=%u, retlen=%u, at %#08x\n", + ret, sizeof(rr), length, phys_ofs); + ret = ret ? ret : -EIO; + if (length) { + raw->flash_offset |= REF_OBSOLETE; + raw->next_in_ino = NULL; + jffs2_add_physical_node_ref(c, raw); + jffs2_mark_node_obsolete(c, raw); + } else { + jffs2_free_raw_node_ref(raw); + } + return ret; + } + raw->flash_offset |= REF_PRISTINE; + + jffs2_add_physical_node_ref(c, raw); + if (ref->node) + delete_xattr_ref_node(c, ref); + ref->node = raw; + + dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid); + + return 0; +} + +static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, + struct jffs2_xattr_datum *xd, uint32_t phys_ofs) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_xattr_ref *ref; + int ret; + + ref = jffs2_alloc_xattr_ref(); + if (!ref) + return ERR_PTR(-ENOMEM); + ref->ic = ic; + ref->xd = xd; + + ret = save_xattr_ref(c, ref, phys_ofs); + if (ret) { + jffs2_free_xattr_ref(ref); + return ERR_PTR(ret); + } + + /* Chain to inode */ + list_add(&ref->ilist, &ic->ilist); + + return ref; /* success */ +} + +void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + /* It's called from jffs2_clear_inode() on inode removing. + When an inode with XATTR is removed, those XATTRs must be removed. */ + struct jffs2_xattr_ref *ref, *_ref; + + if (!ic || ic->nlink > 0) + return; + + down_write(&c->xattr_sem); + list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) + delete_xattr_ref(c, ref); + up_write(&c->xattr_sem); +} + +void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + /* It's called from jffs2_free_ino_caches() until unmounting FS. */ + struct jffs2_xattr_datum *xd; + struct jffs2_xattr_ref *ref, *_ref; + + down_write(&c->xattr_sem); + list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) { + list_del(&ref->ilist); + xd = ref->xd; + xd->refcnt--; + if (!xd->refcnt) { + unload_xattr_datum(c, xd); + jffs2_free_xattr_datum(xd); + } + jffs2_free_xattr_ref(ref); + } + up_write(&c->xattr_sem); +} + +static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + /* success of check_xattr_ref_ilist() means taht inode (ic) dose not have + * duplicate name/value pairs. If duplicate name/value pair would be found, + * one will be removed. + */ + struct jffs2_xattr_ref *ref, *cmp; + int rc = 0; + + if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED)) + return 0; + down_write(&c->xattr_sem); + retry: + rc = 0; + list_for_each_entry(ref, &ic->ilist, ilist) { + if (!ref->xd->xname) { + rc = load_xattr_datum(c, ref->xd); + if (unlikely(rc > 0)) { + delete_xattr_ref(c, ref); + goto retry; + } else if (unlikely(rc < 0)) + goto out; + } + cmp = ref; + list_for_each_entry_continue(cmp, &ic->ilist, ilist) { + if (!cmp->xd->xname) { + ref->xd->flags |= JFFS2_XFLAGS_BIND; + rc = load_xattr_datum(c, cmp->xd); + ref->xd->flags &= ~JFFS2_XFLAGS_BIND; + if (unlikely(rc > 0)) { + delete_xattr_ref(c, cmp); + goto retry; + } else if (unlikely(rc < 0)) + goto out; + } + if (ref->xd->xprefix == cmp->xd->xprefix + && !strcmp(ref->xd->xname, cmp->xd->xname)) { + delete_xattr_ref(c, cmp); + goto retry; + } + } + } + ic->flags |= INO_FLAGS_XATTR_CHECKED; + out: + up_write(&c->xattr_sem); + + return rc; +} + +/* -------- xattr subsystem functions --------------- + * jffs2_init_xattr_subsystem(c) + * is used to initialize semaphore and list_head, and some variables. + * jffs2_find_xattr_datum(c, xid) + * is used to lookup xdatum while scanning process. + * jffs2_clear_xattr_subsystem(c) + * is used to release any xattr related objects. + * jffs2_build_xattr_subsystem(c) + * is used to associate xdatum and xref while super block building process. + * jffs2_setup_xattr_datum(c, xid, version) + * is used to insert xdatum while scanning process. + * -------------------------------------------------- */ +void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c) +{ + int i; + + for (i=0; i < XATTRINDEX_HASHSIZE; i++) + INIT_LIST_HEAD(&c->xattrindex[i]); + INIT_LIST_HEAD(&c->xattr_temp); + INIT_LIST_HEAD(&c->xattr_unchecked); + + init_rwsem(&c->xattr_sem); + c->xdatum_mem_usage = 0; + c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */ +} + +static struct jffs2_xattr_datum *jffs2_find_xattr_datum(struct jffs2_sb_info *c, uint32_t xid) +{ + struct jffs2_xattr_datum *xd; + int i = xid % XATTRINDEX_HASHSIZE; + + /* It's only used in scanning/building process. */ + BUG_ON(!(c->flags & (JFFS2_SB_FLAG_SCANNING|JFFS2_SB_FLAG_BUILDING))); + + list_for_each_entry(xd, &c->xattrindex[i], xindex) { + if (xd->xid==xid) + return xd; + } + return NULL; +} + +void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c) +{ + struct jffs2_xattr_datum *xd, *_xd; + struct jffs2_xattr_ref *ref, *_ref; + int i; + + list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) + jffs2_free_xattr_ref(ref); + + for (i=0; i < XATTRINDEX_HASHSIZE; i++) { + list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { + list_del(&xd->xindex); + if (xd->xname) + kfree(xd->xname); + jffs2_free_xattr_datum(xd); + } + } +} + +void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) +{ + struct jffs2_xattr_ref *ref, *_ref; + struct jffs2_xattr_datum *xd, *_xd; + struct jffs2_inode_cache *ic; + int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0; + + BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); + + /* Phase.1 */ + list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) { + list_del_init(&ref->ilist); + /* checking REF_UNCHECKED nodes */ + if (ref_flags(ref->node) != REF_PRISTINE) { + if (verify_xattr_ref(c, ref)) { + delete_xattr_ref_node(c, ref); + jffs2_free_xattr_ref(ref); + continue; + } + } + /* At this point, ref->xid and ref->ino contain XID and inode number. + ref->xd and ref->ic are not valid yet. */ + xd = jffs2_find_xattr_datum(c, ref->xid); + ic = jffs2_get_ino_cache(c, ref->ino); + if (!xd || !ic) { + if (ref_flags(ref->node) != REF_UNCHECKED) + JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n", + ref->ino, ref->xid); + delete_xattr_ref_node(c, ref); + jffs2_free_xattr_ref(ref); + continue; + } + ref->xd = xd; + ref->ic = ic; + xd->refcnt++; + list_add_tail(&ref->ilist, &ic->ilist); + xref_count++; + } + /* After this, ref->xid/ino are NEVER used. */ + + /* Phase.2 */ + for (i=0; i < XATTRINDEX_HASHSIZE; i++) { + list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { + list_del_init(&xd->xindex); + if (!xd->refcnt) { + if (ref_flags(xd->node) != REF_UNCHECKED) + JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n", + xd->xid, xd->version, ref_offset(xd->node)); + delete_xattr_datum(c, xd); + continue; + } + if (ref_flags(xd->node) != REF_PRISTINE) { + dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n", + xd->xid, ref_offset(xd->node)); + list_add(&xd->xindex, &c->xattr_unchecked); + xdatum_unchecked_count++; + } + xdatum_count++; + } + } + /* build complete */ + JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and " + "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count); +} + +struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, + uint32_t xid, uint32_t version) +{ + struct jffs2_xattr_datum *xd, *_xd; + + _xd = jffs2_find_xattr_datum(c, xid); + if (_xd) { + dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n", + xid, version, _xd->version, ref_offset(_xd->node)); + if (version < _xd->version) + return ERR_PTR(-EEXIST); + } + xd = jffs2_alloc_xattr_datum(); + if (!xd) + return ERR_PTR(-ENOMEM); + xd->xid = xid; + xd->version = version; + if (xd->xid > c->highest_xid) + c->highest_xid = xd->xid; + list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]); + + if (_xd) { + list_del_init(&_xd->xindex); + delete_xattr_datum_node(c, _xd); + jffs2_free_xattr_datum(_xd); + } + return xd; +} + +/* -------- xattr subsystem functions --------------- + * xprefix_to_handler(xprefix) + * is used to translate xprefix into xattr_handler. + * jffs2_listxattr(dentry, buffer, size) + * is an implementation of listxattr handler on jffs2. + * do_jffs2_getxattr(inode, xprefix, xname, buffer, size) + * is an implementation of getxattr handler on jffs2. + * do_jffs2_setxattr(inode, xprefix, xname, buffer, size, flags) + * is an implementation of setxattr handler on jffs2. + * -------------------------------------------------- */ +struct xattr_handler *jffs2_xattr_handlers[] = { + &jffs2_user_xattr_handler, +#ifdef CONFIG_JFFS2_FS_SECURITY + &jffs2_security_xattr_handler, +#endif +#ifdef CONFIG_JFFS2_FS_POSIX_ACL + &jffs2_acl_access_xattr_handler, + &jffs2_acl_default_xattr_handler, +#endif + &jffs2_trusted_xattr_handler, + NULL +}; + +static struct xattr_handler *xprefix_to_handler(int xprefix) { + struct xattr_handler *ret; + + switch (xprefix) { + case JFFS2_XPREFIX_USER: + ret = &jffs2_user_xattr_handler; + break; +#ifdef CONFIG_JFFS2_FS_SECURITY + case JFFS2_XPREFIX_SECURITY: + ret = &jffs2_security_xattr_handler; + break; +#endif +#ifdef CONFIG_JFFS2_FS_POSIX_ACL + case JFFS2_XPREFIX_ACL_ACCESS: + ret = &jffs2_acl_access_xattr_handler; + break; + case JFFS2_XPREFIX_ACL_DEFAULT: + ret = &jffs2_acl_default_xattr_handler; + break; +#endif + case JFFS2_XPREFIX_TRUSTED: + ret = &jffs2_trusted_xattr_handler; + break; + default: + ret = NULL; + break; + } + return ret; +} + +ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + struct inode *inode = dentry->d_inode; + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_inode_cache *ic = f->inocache; + struct jffs2_xattr_ref *ref; + struct jffs2_xattr_datum *xd; + struct xattr_handler *xhandle; + ssize_t len, rc; + int retry = 0; + + rc = check_xattr_ref_ilist(c, ic); + if (unlikely(rc)) + return rc; + + down_read(&c->xattr_sem); + retry: + len = 0; + list_for_each_entry(ref, &ic->ilist, ilist) { + BUG_ON(ref->ic != ic); + xd = ref->xd; + if (!xd->xname) { + /* xdatum is unchached */ + if (!retry) { + retry = 1; + up_read(&c->xattr_sem); + down_write(&c->xattr_sem); + goto retry; + } else { + rc = load_xattr_datum(c, xd); + if (unlikely(rc > 0)) { + delete_xattr_ref(c, ref); + goto retry; + } else if (unlikely(rc < 0)) + goto out; + } + } + xhandle = xprefix_to_handler(xd->xprefix); + if (!xhandle) + continue; + if (buffer) { + rc = xhandle->list(inode, buffer+len, size-len, xd->xname, xd->name_len); + } else { + rc = xhandle->list(inode, NULL, 0, xd->xname, xd->name_len); + } + if (rc < 0) + goto out; + len += rc; + } + rc = len; + out: + if (!retry) { + up_read(&c->xattr_sem); + } else { + up_write(&c->xattr_sem); + } + return rc; +} + +int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, + char *buffer, size_t size) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_inode_cache *ic = f->inocache; + struct jffs2_xattr_datum *xd; + struct jffs2_xattr_ref *ref; + int rc, retry = 0; + + rc = check_xattr_ref_ilist(c, ic); + if (unlikely(rc)) + return rc; + + down_read(&c->xattr_sem); + retry: + list_for_each_entry(ref, &ic->ilist, ilist) { + BUG_ON(ref->ic!=ic); + + xd = ref->xd; + if (xd->xprefix != xprefix) + continue; + if (!xd->xname) { + /* xdatum is unchached */ + if (!retry) { + retry = 1; + up_read(&c->xattr_sem); + down_write(&c->xattr_sem); + goto retry; + } else { + rc = load_xattr_datum(c, xd); + if (unlikely(rc > 0)) { + delete_xattr_ref(c, ref); + goto retry; + } else if (unlikely(rc < 0)) { + goto out; + } + } + } + if (!strcmp(xname, xd->xname)) { + rc = xd->value_len; + if (buffer) { + if (size < rc) { + rc = -ERANGE; + } else { + memcpy(buffer, xd->xvalue, rc); + } + } + goto out; + } + } + rc = -ENODATA; + out: + if (!retry) { + up_read(&c->xattr_sem); + } else { + up_write(&c->xattr_sem); + } + return rc; +} + +int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, + const char *buffer, size_t size, int flags) +{ + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_inode_cache *ic = f->inocache; + struct jffs2_xattr_datum *xd; + struct jffs2_xattr_ref *ref, *newref; + uint32_t phys_ofs, length, request; + int rc; + + rc = check_xattr_ref_ilist(c, ic); + if (unlikely(rc)) + return rc; + + request = PAD(sizeof(struct jffs2_raw_xattr) + strlen(xname) + 1 + size); + rc = jffs2_reserve_space(c, request, &phys_ofs, &length, + ALLOC_NORMAL, JFFS2_SUMMARY_XATTR_SIZE); + if (rc) { + JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); + return rc; + } + + /* Find existing xattr */ + down_write(&c->xattr_sem); + retry: + list_for_each_entry(ref, &ic->ilist, ilist) { + xd = ref->xd; + if (xd->xprefix != xprefix) + continue; + if (!xd->xname) { + rc = load_xattr_datum(c, xd); + if (unlikely(rc > 0)) { + delete_xattr_ref(c, ref); + goto retry; + } else if (unlikely(rc < 0)) + goto out; + } + if (!strcmp(xd->xname, xname)) { + if (flags & XATTR_CREATE) { + rc = -EEXIST; + goto out; + } + if (!buffer) { + delete_xattr_ref(c, ref); + rc = 0; + goto out; + } + goto found; + } + } + /* not found */ + ref = NULL; + if (flags & XATTR_REPLACE) { + rc = -ENODATA; + goto out; + } + if (!buffer) { + rc = -EINVAL; + goto out; + } + found: + xd = create_xattr_datum(c, xprefix, xname, buffer, size, phys_ofs); + if (IS_ERR(xd)) { + rc = PTR_ERR(xd); + goto out; + } + up_write(&c->xattr_sem); + jffs2_complete_reservation(c); + + /* create xattr_ref */ + request = PAD(sizeof(struct jffs2_raw_xref)); + rc = jffs2_reserve_space(c, request, &phys_ofs, &length, + ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE); + if (rc) { + JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); + down_write(&c->xattr_sem); + xd->refcnt--; + if (!xd->refcnt) + delete_xattr_datum(c, xd); + up_write(&c->xattr_sem); + return rc; + } + down_write(&c->xattr_sem); + newref = create_xattr_ref(c, ic, xd, phys_ofs); + if (IS_ERR(newref)) { + rc = PTR_ERR(newref); + xd->refcnt--; + if (!xd->refcnt) + delete_xattr_datum(c, xd); + } else if (ref) { + /* If replaced xattr_ref exists */ + delete_xattr_ref(c, ref); + } + out: + up_write(&c->xattr_sem); + jffs2_complete_reservation(c); + return rc; +} + +/* -------- garbage collector functions ------------- + * jffs2_garbage_collect_xattr_datum(c, xd) + * is used to move xdatum into new node. + * jffs2_garbage_collect_xattr_ref(c, ref) + * is used to move xref into new node. + * jffs2_garbage_collect_xattr(c, ic) + * is used to call appropriate garbage collector function, if argument + * pointer (ic) is the reference of xdatum/xref. + * jffs2_verify_xattr(c) + * is used to call do_verify_xattr_datum() before garbage collecting. + * -------------------------------------------------- */ +static int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, + struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem), and called from GC thread */ + uint32_t phys_ofs, totlen, length, old_ofs; + int rc; + + BUG_ON(!xd->node); + + old_ofs = ref_offset(xd->node); + totlen = ref_totlen(c, c->gcblock, xd->node); + if (totlen < sizeof(struct jffs2_raw_xattr)) + return -EINVAL; + + if (!xd->xname) { + rc = load_xattr_datum(c, xd); + if (unlikely(rc > 0)) { + delete_xattr_datum_node(c, xd); + return 0; + } else if (unlikely(rc < 0)) + return -EINVAL; + } + rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XATTR_SIZE); + if (rc || length < totlen) { + JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen); + return rc ? rc : -EBADFD; + } + rc = save_xattr_datum(c, xd, phys_ofs); + if (!rc) + dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n", + xd->xid, xd->version, old_ofs, ref_offset(xd->node)); + return rc; +} + + +static int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, + struct jffs2_xattr_ref *ref) +{ + /* must be called under down(alloc_sem) */ + uint32_t phys_ofs, totlen, length, old_ofs; + int rc; + + BUG_ON(!ref->node); + + old_ofs = ref_offset(ref->node); + totlen = ref_totlen(c, c->gcblock, ref->node); + if (totlen != sizeof(struct jffs2_raw_xref)) + return -EINVAL; + rc = jffs2_reserve_space_gc(c, totlen, &phys_ofs, &length, JFFS2_SUMMARY_XREF_SIZE); + if (rc || length < totlen) { + JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n", + __FUNCTION__, rc, totlen); + return rc ? rc : -EBADFD; + } + rc = save_xattr_ref(c, ref, phys_ofs); + if (!rc) + dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n", + ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node)); + return rc; +} + +int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + struct jffs2_xattr_datum *xd; + struct jffs2_xattr_ref *ref; + int ret; + + switch (ic->class) { + case RAWNODE_CLASS_XATTR_DATUM: + spin_unlock(&c->erase_completion_lock); + + down_write(&c->xattr_sem); + xd = (struct jffs2_xattr_datum *)ic; + ret = xd ? jffs2_garbage_collect_xattr_datum(c, xd) : 0; + up_write(&c->xattr_sem); + break; + case RAWNODE_CLASS_XATTR_REF: + spin_unlock(&c->erase_completion_lock); + + down_write(&c->xattr_sem); + ref = (struct jffs2_xattr_ref *)ic; + ret = ref ? jffs2_garbage_collect_xattr_ref(c, ref) : 0; + up_write(&c->xattr_sem); + break; + default: + /* This node is not xattr_datum/xattr_ref */ + ret = 1; + break; + } + return ret; +} + +int jffs2_verify_xattr(struct jffs2_sb_info *c) +{ + struct jffs2_xattr_datum *xd, *_xd; + int rc; + + down_write(&c->xattr_sem); + list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) { + rc = do_verify_xattr_datum(c, xd); + if (rc == 0) { + list_del_init(&xd->xindex); + break; + } else if (rc > 0) { + list_del_init(&xd->xindex); + delete_xattr_datum_node(c, xd); + } + } + up_write(&c->xattr_sem); + + return list_empty(&c->xattr_unchecked) ? 1 : 0; +} diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h new file mode 100644 index 000000000000..d157ad641ed4 --- /dev/null +++ b/fs/jffs2/xattr.h @@ -0,0 +1,120 @@ +/*-------------------------------------------------------------------------* + * File: fs/jffs2/xattr.c + * XATTR support on JFFS2 FileSystem + * + * Implemented by KaiGai Kohei + * Copyright (C) 2006 NEC Corporation + * + * For licensing information, see the file 'LICENCE' in the jffs2 directory. + *-------------------------------------------------------------------------*/ + +#ifndef _JFFS2_FS_XATTR_H_ +#define _JFFS2_FS_XATTR_H_ + +#include + +#define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */ +#define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */ + +struct jffs2_xattr_datum +{ + void *always_null; + u8 class; + u8 flags; + u16 xprefix; /* see JFFS2_XATTR_PREFIX_* */ + + struct jffs2_raw_node_ref *node; + struct list_head xindex; /* chained from c->xattrindex[n] */ + uint32_t refcnt; /* # of xattr_ref refers this */ + uint32_t xid; + uint32_t version; + + uint32_t data_crc; + uint32_t hashkey; + char *xname; /* XATTR name without prefix */ + uint32_t name_len; /* length of xname */ + char *xvalue; /* XATTR value */ + uint32_t value_len; /* length of xvalue */ +}; + +struct jffs2_inode_cache; /* forward refence */ +struct jffs2_xattr_ref +{ + void *always_null; + u8 class; + u8 flags; /* Currently unused */ + u16 unused; + + struct jffs2_raw_node_ref *node; + union { + struct jffs2_inode_cache *ic; /* reference to jffs2_inode_cache */ + uint32_t ino; /* only used in scanning/building */ + }; + union { + struct jffs2_xattr_datum *xd; /* reference to jffs2_xattr_datum */ + uint32_t xid; /* only used in sccanning/building */ + }; + struct list_head ilist; /* chained from ic->ilist */ +}; + +#ifdef CONFIG_JFFS2_FS_XATTR + +extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c); +extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c); +extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c); + +extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, + uint32_t xid, uint32_t version); + +extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); +extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); + +extern int jffs2_garbage_collect_xattr(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); +extern int jffs2_verify_xattr(struct jffs2_sb_info *c); + +extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, + char *buffer, size_t size); +extern int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, + const char *buffer, size_t size, int flags); + +extern struct xattr_handler *jffs2_xattr_handlers[]; +extern struct xattr_handler jffs2_user_xattr_handler; +extern struct xattr_handler jffs2_trusted_xattr_handler; + +extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); +#define jffs2_getxattr generic_getxattr +#define jffs2_setxattr generic_setxattr +#define jffs2_removexattr generic_removexattr + +/*---- Any inline initialize functions ----*/ +#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist)) + +#else + +#define jffs2_init_xattr_subsystem(c) +#define jffs2_build_xattr_subsystem(c) +#define jffs2_clear_xattr_subsystem(c) + +#define jffs2_xattr_delete_inode(c, ic) +#define jffs2_xattr_free_inode(c, ic) +#define jffs2_garbage_collect_xattr(c, ic) (1) +#define jffs2_verify_xattr(c) (1) + +#define jffs2_xattr_handlers NULL +#define jffs2_listxattr NULL +#define jffs2_getxattr NULL +#define jffs2_setxattr NULL +#define jffs2_removexattr NULL + +#define init_xattr_inode_cache(x) + +#endif /* CONFIG_JFFS2_FS_XATTR */ + +#ifdef CONFIG_JFFS2_FS_SECURITY +extern int jffs2_init_security(struct inode *inode, struct inode *dir); +extern struct xattr_handler jffs2_security_xattr_handler; +#else +#define jffs2_init_security(inode,dir) (0) +#endif /* CONFIG_JFFS2_FS_SECURITY */ + +#endif /* _JFFS2_FS_XATTR_H_ */ diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c new file mode 100644 index 000000000000..a018c9c31a60 --- /dev/null +++ b/fs/jffs2/xattr_trusted.c @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------* + * File: fs/jffs2/xattr_trusted.c + * XATTR support on JFFS2 FileSystem + * + * Implemented by KaiGai Kohei + * Copyright (C) 2006 NEC Corporation + * + * For licensing information, see the file 'LICENCE' in the jffs2 directory. + *-------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#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 +}; diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c new file mode 100644 index 000000000000..d8c13636ea4c --- /dev/null +++ b/fs/jffs2/xattr_user.c @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------* + * File: fs/jffs2/xattr_user.c + * XATTR support on JFFS2 FileSystem + * + * Implemented by KaiGai Kohei + * Copyright (C) 2006 NEC Corporation + * + * For licensing information, see the file 'LICENCE' in the jffs2 directory. + *-------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#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 +}; diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index cf792bb3c726..2cac60e55322 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h @@ -65,6 +65,18 @@ #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) +#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) +#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) + +/* XATTR Related */ +#define JFFS2_XPREFIX_USER 1 /* for "user." */ +#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ +#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ +#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ +#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ + +#define JFFS2_ACL_VERSION 0x0001 + // Maybe later... //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) @@ -151,6 +163,32 @@ struct jffs2_raw_inode uint8_t data[0]; } __attribute__((packed)); +struct jffs2_raw_xattr { + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t xid; /* XATTR identifier number */ + jint32_t version; + uint8_t xprefix; + uint8_t name_len; + jint16_t value_len; + jint32_t data_crc; + jint32_t node_crc; + uint8_t data[0]; +} __attribute__((packed)); + +struct jffs2_raw_xref +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t ino; /* inode number */ + jint32_t xid; /* XATTR identifier number */ + jint32_t node_crc; +} __attribute__((packed)); + struct jffs2_raw_summary { jint16_t magic; @@ -169,6 +207,8 @@ union jffs2_node_union { struct jffs2_raw_inode i; struct jffs2_raw_dirent d; + struct jffs2_raw_xattr x; + struct jffs2_raw_xref r; struct jffs2_raw_summary s; struct jffs2_unknown_node u; }; -- cgit v1.2.3 From 8f2b6f49c656dd4597904f8c20661d6b73cdbbeb Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 13 May 2006 15:15:07 +0900 Subject: [JFFS2][XATTR] Remove 'struct list_head ilist' from jffs2_inode_cache. This patch can reduce 4-byte of memory usage per inode_cache. [4/10] jffs2-xattr-v5.1-04-remove_ilist_from_ic.patch Signed-off-by: KaiGai Kohei --- fs/jffs2/jffs2_fs_sb.h | 2 +- fs/jffs2/malloc.c | 1 - fs/jffs2/nodelist.h | 2 +- fs/jffs2/readinode.c | 1 - fs/jffs2/scan.c | 6 ++-- fs/jffs2/summary.c | 3 +- fs/jffs2/write.c | 1 - fs/jffs2/xattr.c | 75 +++++++++++++++++++++++++++++++------------------- fs/jffs2/xattr.h | 7 +---- 9 files changed, 55 insertions(+), 43 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 3b4e0edd6dbb..272fbea55192 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -119,8 +119,8 @@ struct jffs2_sb_info { #define XATTRINDEX_HASHSIZE (57) uint32_t highest_xid; struct list_head xattrindex[XATTRINDEX_HASHSIZE]; - struct list_head xattr_temp; struct list_head xattr_unchecked; + struct jffs2_xattr_ref *xref_temp; struct rw_semaphore xattr_sem; uint32_t xdatum_mem_usage; uint32_t xdatum_mem_threshold; diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 3d5b7ecfbf8d..f2473fa2fd16 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -259,7 +259,6 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) memset(ref, 0, sizeof(struct jffs2_xattr_ref)); ref->class = RAWNODE_CLASS_XATTR_REF; - INIT_LIST_HEAD(&ref->ilist); return ref; } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 6f6279cf4909..351d947c9375 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -117,7 +117,7 @@ struct jffs2_inode_cache { uint32_t ino; int nlink; #ifdef CONFIG_JFFS2_FS_XATTR - struct list_head ilist; + struct jffs2_xattr_ref *xref; #endif }; diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 61ccdf4f1042..e1acce8fb2bf 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -902,7 +902,6 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, f->inocache->ino = f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->state = INO_STATE_READING; - init_xattr_inode_cache(f->inocache); jffs2_add_ino_cache(c, f->inocache); } if (!f->inocache) { diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index f09689e320fe..0a79fc921e9f 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -408,14 +408,15 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock * ref->xid is used to store 32bit xid, xd is not used * ref->ino is used to store 32bit inode-number, ic is not used * Thoes variables are declared as union, thus using those - * are exclusive. In a similar way, ref->ilist is temporarily + * 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); - list_add_tail(&ref->ilist, &c->xattr_temp); + ref->next = c->xref_temp; + c->xref_temp = ref; raw->__totlen = PAD(je32_to_cpu(rr->totlen)); raw->flash_offset = ofs | REF_PRISTINE; @@ -888,7 +889,6 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin ic->ino = ino; ic->nodes = (void *)ic; - init_xattr_inode_cache(ic); jffs2_add_ino_cache(c, ic); if (ino == 1) ic->nlink = 1; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 5d9ec8e36528..831a42c13059 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -556,7 +556,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ref->ino = 0xfffffffe; ref->xid = 0xfffffffd; ref->node = raw; - list_add_tail(&ref->ilist, &c->xattr_temp); + ref->next = c->xref_temp; + c->xref_temp = ref; raw->__totlen = PAD(sizeof(struct jffs2_raw_xref)); raw->flash_offset = ofs | REF_UNCHECKED; diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index d5c78195f3b8..ff2b00b604ec 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -36,7 +36,6 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->state = INO_STATE_PRESENT; - init_xattr_inode_cache(f->inocache); jffs2_add_ino_cache(c, f->inocache); D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index c9a185c54ce7..b16bc71c9cd2 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -456,7 +456,7 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, * is called to remove xrefs related to obsolete inode when inode is unlinked. * jffs2_xattr_free_inode(c, ic) * is called to release xattr related objects when unmounting. - * check_xattr_ref_ilist(c, ic) + * check_xattr_ref_inode(c, ic) * is used to confirm inode does not have duplicate xattr name/value pair. * -------------------------------------------------- */ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) @@ -549,7 +549,6 @@ static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *re BUG_ON(!ref->node); delete_xattr_ref_node(c, ref); - list_del(&ref->ilist); xd = ref->xd; xd->refcnt--; if (!xd->refcnt) @@ -629,7 +628,8 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct } /* Chain to inode */ - list_add(&ref->ilist, &ic->ilist); + ref->next = ic->xref; + ic->xref = ref; return ref; /* success */ } @@ -644,8 +644,11 @@ void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache return; down_write(&c->xattr_sem); - list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) + for (ref = ic->xref; ref; ref = _ref) { + _ref = ref->next; delete_xattr_ref(c, ref); + } + ic->xref = NULL; up_write(&c->xattr_sem); } @@ -656,8 +659,8 @@ void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i struct jffs2_xattr_ref *ref, *_ref; down_write(&c->xattr_sem); - list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) { - list_del(&ref->ilist); + for (ref = ic->xref; ref; ref = _ref) { + _ref = ref->next; xd = ref->xd; xd->refcnt--; if (!xd->refcnt) { @@ -666,16 +669,17 @@ void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i } jffs2_free_xattr_ref(ref); } + ic->xref = NULL; up_write(&c->xattr_sem); } -static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) { - /* success of check_xattr_ref_ilist() means taht inode (ic) dose not have + /* success of check_xattr_ref_inode() means taht inode (ic) dose not have * duplicate name/value pairs. If duplicate name/value pair would be found, * one will be removed. */ - struct jffs2_xattr_ref *ref, *cmp; + struct jffs2_xattr_ref *ref, *cmp, **pref; int rc = 0; if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED)) @@ -683,22 +687,23 @@ static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cac down_write(&c->xattr_sem); retry: rc = 0; - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { if (!ref->xd->xname) { rc = load_xattr_datum(c, ref->xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; } - cmp = ref; - list_for_each_entry_continue(cmp, &ic->ilist, ilist) { + for (cmp=ref->next, pref=&ref->next; cmp; pref=&cmp->next, cmp=cmp->next) { if (!cmp->xd->xname) { ref->xd->flags |= JFFS2_XFLAGS_BIND; rc = load_xattr_datum(c, cmp->xd); ref->xd->flags &= ~JFFS2_XFLAGS_BIND; if (unlikely(rc > 0)) { + *pref = cmp->next; delete_xattr_ref(c, cmp); goto retry; } else if (unlikely(rc < 0)) @@ -706,6 +711,7 @@ static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cac } if (ref->xd->xprefix == cmp->xd->xprefix && !strcmp(ref->xd->xname, cmp->xd->xname)) { + *pref = cmp->next; delete_xattr_ref(c, cmp); goto retry; } @@ -736,8 +742,8 @@ void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c) for (i=0; i < XATTRINDEX_HASHSIZE; i++) INIT_LIST_HEAD(&c->xattrindex[i]); - INIT_LIST_HEAD(&c->xattr_temp); INIT_LIST_HEAD(&c->xattr_unchecked); + c->xref_temp = NULL; init_rwsem(&c->xattr_sem); c->xdatum_mem_usage = 0; @@ -765,8 +771,11 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c) struct jffs2_xattr_ref *ref, *_ref; int i; - list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) + for (ref=c->xref_temp; ref; ref = _ref) { + _ref = ref->next; jffs2_free_xattr_ref(ref); + } + c->xref_temp = NULL; for (i=0; i < XATTRINDEX_HASHSIZE; i++) { list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { @@ -788,8 +797,8 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); /* Phase.1 */ - list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) { - list_del_init(&ref->ilist); + for (ref=c->xref_temp; ref; ref=_ref) { + _ref = ref->next; /* checking REF_UNCHECKED nodes */ if (ref_flags(ref->node) != REF_PRISTINE) { if (verify_xattr_ref(c, ref)) { @@ -813,9 +822,11 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) ref->xd = xd; ref->ic = ic; xd->refcnt++; - list_add_tail(&ref->ilist, &ic->ilist); + ref->next = ic->xref; + ic->xref = ref; xref_count++; } + c->xref_temp = NULL; /* After this, ref->xid/ino are NEVER used. */ /* Phase.2 */ @@ -931,20 +942,20 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; - struct jffs2_xattr_ref *ref; + struct jffs2_xattr_ref *ref, **pref; struct jffs2_xattr_datum *xd; struct xattr_handler *xhandle; ssize_t len, rc; int retry = 0; - rc = check_xattr_ref_ilist(c, ic); + rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; down_read(&c->xattr_sem); retry: len = 0; - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { BUG_ON(ref->ic != ic); xd = ref->xd; if (!xd->xname) { @@ -957,6 +968,7 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) } else { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) @@ -992,16 +1004,16 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; struct jffs2_xattr_datum *xd; - struct jffs2_xattr_ref *ref; + struct jffs2_xattr_ref *ref, **pref; int rc, retry = 0; - rc = check_xattr_ref_ilist(c, ic); + rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; down_read(&c->xattr_sem); retry: - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { BUG_ON(ref->ic!=ic); xd = ref->xd; @@ -1017,6 +1029,7 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, } else { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) { @@ -1053,11 +1066,11 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; struct jffs2_xattr_datum *xd; - struct jffs2_xattr_ref *ref, *newref; + struct jffs2_xattr_ref *ref, *newref, **pref; uint32_t phys_ofs, length, request; int rc; - rc = check_xattr_ref_ilist(c, ic); + rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; @@ -1072,13 +1085,14 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, /* Find existing xattr */ down_write(&c->xattr_sem); retry: - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { xd = ref->xd; if (xd->xprefix != xprefix) continue; if (!xd->xname) { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) @@ -1090,6 +1104,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, goto out; } if (!buffer) { + *pref = ref->next; delete_xattr_ref(c, ref); rc = 0; goto out; @@ -1098,7 +1113,6 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, } } /* not found */ - ref = NULL; if (flags & XATTR_REPLACE) { rc = -ENODATA; goto out; @@ -1130,14 +1144,19 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, return rc; } down_write(&c->xattr_sem); + if (ref) + *pref = ref->next; newref = create_xattr_ref(c, ic, xd, phys_ofs); if (IS_ERR(newref)) { + if (ref) { + ref->next = ic->xref; + ic->xref = ref; + } rc = PTR_ERR(newref); xd->refcnt--; if (!xd->refcnt) delete_xattr_datum(c, xd); } else if (ref) { - /* If replaced xattr_ref exists */ delete_xattr_ref(c, ref); } out: diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index d157ad641ed4..0360097e5933 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -54,7 +54,7 @@ struct jffs2_xattr_ref struct jffs2_xattr_datum *xd; /* reference to jffs2_xattr_datum */ uint32_t xid; /* only used in sccanning/building */ }; - struct list_head ilist; /* chained from ic->ilist */ + struct jffs2_xattr_ref *next; /* chained from ic->xref_list */ }; #ifdef CONFIG_JFFS2_FS_XATTR @@ -86,9 +86,6 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); #define jffs2_setxattr generic_setxattr #define jffs2_removexattr generic_removexattr -/*---- Any inline initialize functions ----*/ -#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist)) - #else #define jffs2_init_xattr_subsystem(c) @@ -106,8 +103,6 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); #define jffs2_setxattr NULL #define jffs2_removexattr NULL -#define init_xattr_inode_cache(x) - #endif /* CONFIG_JFFS2_FS_XATTR */ #ifdef CONFIG_JFFS2_FS_SECURITY -- cgit v1.2.3 From c8708a9275928cc8e77bd443cd12565dda0a3ded Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 13 May 2006 15:21:38 +0900 Subject: [JFFS2][XATTR] Handling the duplicate JFFS2_NODETYPE_XATTR node cases. When jffs2_sum_process_sum_data() found a JFFS2_NODETYPE_XATTR which has duplicate xid and older version, an error was returned without appropriate process. In the result, mounting filesystem is failed. This patch fix this problem. If jffs2_setup_xattr_datum() returned -EEXIST, the caller marks this node as DIRTY_SPACE(). [1/2] jffs2-xattr-v5.2-01-fix-duplicate-xdatum.patch Signed-off-by: KaiGai Kohei --- fs/jffs2/summary.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 831a42c13059..9763d73c0da1 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -508,8 +508,14 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); if (IS_ERR(xd)) { - JFFS2_NOTICE("allocation of xattr_datum failed\n"); jffs2_free_raw_node_ref(raw); + if (PTR_ERR(xd) == -EEXIST) { + /* a newer version of xd exists */ + DIRTY_SPACE(je32_to_cpu(spx->totlen)); + sp += JFFS2_SUMMARY_XATTR_SIZE; + break; + } + JFFS2_NOTICE("allocation of xattr_datum failed\n"); kfree(summary); return PTR_ERR(xd); } -- cgit v1.2.3 From c41ff6e5f38b02ff927d0d510e28dc1392bb4690 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 16 May 2006 17:05:33 +0100 Subject: [JFFS2] Fix printk format in jffs2_sum_write_data() error message. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs/jffs2/summary.c: In function ‘jffs2_sum_write_data’: fs/jffs2/summary.c:658: warning: format ‘%zd’ expects type ‘signed size_t’, but argument 4 has type ‘uint32_t’ Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 7b0ed77a4c35..48293c197f13 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -655,7 +655,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock if (ret || (retlen != infosize)) { - JFFS2_WARNING("Write of %d bytes at 0x%08x failed. returned %d, retlen %zu\n", + 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); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; -- cgit v1.2.3 From 9641b784ff82cf0a48a6c70ef9867f5fd728de67 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 20 May 2006 16:13:34 +0100 Subject: [JFFS2] Optimise reading of eraseblock summary nodes This improves the time to mount 512MiB of NAND flash on my OLPC prototype by about 4%. We used to read the last page of the eraseblock twice -- once to find the offset of the summary node, and again to actually _read_ the summary node. Now we read the last page only once, and read more only if we need to. We also don't allocate a new buffer just for the summary code -- we use the buffer which was already allocated for the scan. Better still, if the 'buffer' for the scan is actually just a pointer directly into NOR flash, we use that too, avoiding the memcpy() which we used to do. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 74 +++++++++++++++++++++++++++++++++++++++++------------- fs/jffs2/summary.c | 36 +++++--------------------- fs/jffs2/summary.h | 3 ++- 3 files changed, 64 insertions(+), 49 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 352ada892f3e..2a24b44662bb 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -306,11 +306,12 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je return BLK_STATE_ALLDIRTY; } +/* 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 +345,69 @@ 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; - } + 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; + } + } - 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); + if (sumptr) { + err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random); + if (err) return err; - } + if (buf_size && sumlen > buf_size) + kfree(sumptr); } - - kfree(sm); } 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); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 48293c197f13..82a3706c54d8 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -318,7 +318,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras raw = jffs2_alloc_raw_node_ref(); if (!raw) { JFFS2_NOTICE("allocation of node reference failed\n"); - kfree(summary); return -ENOMEM; } @@ -326,7 +325,6 @@ 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; } @@ -358,10 +356,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spd->offset)); 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; @@ -370,7 +366,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras if (!raw) { jffs2_free_full_dirent(fd); JFFS2_NOTICE("allocation of node reference failed\n"); - kfree(summary); return -ENOMEM; } @@ -378,7 +373,6 @@ 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; } @@ -411,45 +405,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras default : { JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); - kfree(summary); return -EIO; } } } - 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; - sumsize = c->sector_size - ofs; - ofs += jeb->offset; + ofs = jeb->offset + 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, ofs, sumsize); /* OK, now check for node validity and CRC */ crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -499,7 +476,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb if (!marker_ref) { JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); - kfree(summary); return -ENOMEM; } diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index b7a678be1709..afff4bd551a1 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -160,7 +160,8 @@ 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_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 */ -- cgit v1.2.3 From f1f9671bd8f7d2ac6a918bad806ab5bdc0daaf4e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 20 May 2006 19:45:26 +0100 Subject: [JFFS2] Introduce jffs2_link_node_ref() function to reduce code duplication The same sequence of code was repeated in many places, to add a new struct jffs2_raw_node_ref to an eraseblock and adjust the space accounting accordingly. Move it out-of-line. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 18 ++++---------- fs/jffs2/nodelist.c | 34 +++++++++++++++++++++++++ fs/jffs2/nodelist.h | 2 ++ fs/jffs2/nodemgmt.c | 16 +----------- fs/jffs2/scan.c | 49 +++++++++--------------------------- fs/jffs2/summary.c | 71 +++++++++++------------------------------------------ 6 files changed, 68 insertions(+), 122 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index dad68fdffe9e..fecf5584f830 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -373,12 +373,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 +408,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); diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 4973cd648ba8..1fc8aedb56fb 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1046,3 +1046,37 @@ 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; + 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; + + /* Set __totlen field... for now */ + ref->__totlen = len; + ref->next_phys = NULL; +} diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 8dda98ff5561..bac4ec35bbd0 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -348,6 +348,8 @@ 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); /* nodemgmt.c */ int jffs2_thread_should_wake(struct jffs2_sb_info *c); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 0e1f58aa606c..d6eab1b7ad53 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -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 */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 40d62d057aa4..3cbe9f029e01 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -351,17 +351,11 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc xd->data_crc = je32_to_cpu(rx->data_crc); xd->node = raw; - raw->__totlen = totlen; raw->flash_offset = ofs | REF_PRISTINE; - raw->next_phys = NULL; raw->next_in_ino = (void *)xd; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; - USED_SPACE(PAD(je32_to_cpu(rx->totlen))); + 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", @@ -418,17 +412,11 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock ref->next = c->xref_temp; c->xref_temp = ref; - raw->__totlen = PAD(je32_to_cpu(rr->totlen)); raw->flash_offset = ofs | REF_PRISTINE; - raw->next_phys = NULL; raw->next_in_ino = (void *)ref; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; - USED_SPACE(PAD(je32_to_cpu(rr->totlen))); + 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", @@ -827,12 +815,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; @@ -971,16 +957,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), @@ -989,8 +970,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); } @@ -1053,16 +1032,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; @@ -1070,7 +1044,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()) { diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 5dbe87b67ab6..912189762323 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -410,19 +410,13 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } 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->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; - *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; @@ -457,16 +451,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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->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; @@ -474,7 +463,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); @@ -516,17 +505,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras xd->node = raw; raw->flash_offset = ofs | REF_UNCHECKED; - raw->__totlen = PAD(je32_to_cpu(spx->totlen)); - raw->next_phys = NULL; raw->next_in_ino = (void *)xd; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen))); *pseudo_random += je32_to_cpu(spx->xid); - UNCHECKED_SPACE(je32_to_cpu(spx->totlen)); sp += JFFS2_SUMMARY_XATTR_SIZE; break; @@ -559,17 +542,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ref->next = c->xref_temp; c->xref_temp = ref; - raw->__totlen = PAD(sizeof(struct jffs2_raw_xref)); raw->flash_offset = ofs | REF_UNCHECKED; - raw->next_phys = NULL; raw->next_in_ino = (void *)ref; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; - UNCHECKED_SPACE(PAD(sizeof(struct jffs2_raw_xref))); + jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref))); + *pseudo_random += ofs; sp += JFFS2_SUMMARY_XREF_SIZE; @@ -653,13 +630,10 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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)); } } @@ -682,15 +656,8 @@ 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; - - 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; - USED_SPACE(sumsize); + jffs2_link_node_ref(c, jeb, cache_ref, sumsize); jeb->wasted_size += jeb->free_size; c->wasted_size += jeb->free_size; @@ -888,17 +855,9 @@ 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); + jffs2_link_node_ref(c, jeb, summary_ref, infosize); return 0; } -- cgit v1.2.3 From fb9fbbcc9389edabb172ac1b6419c01e32046787 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 20 May 2006 20:08:42 +0100 Subject: [JFFS2] Correct accounting of erroneous cleanmarkers and failed summaries. It should all be counted as dirty space, not wasted and _definitely_ not unchecked. Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 912189762323..95b5bf8f4a99 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -617,11 +617,11 @@ 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))); + DIRTY_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); } 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))); + DIRTY_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); } else { struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); @@ -800,7 +800,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; - WASTED_SPACE(infosize); + DIRTY_SPACE(infosize); return 1; } -- cgit v1.2.3 From 6171586a7ae5198988774e8480631e8d15f65dfe Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 00:02:06 +0100 Subject: [JFFS2] Correct handling of JFFS2_FEATURE_RWCOMPAT_COPY nodes. We should preserve these when we come to garbage collect them, not let them get erased. Use jffs2_garbage_collect_pristine() for this, and make sure the summary code copes -- just refrain from writing a summary for any block which contains a node we don't understand. Signed-off-by: David Woodhouse --- fs/jffs2/gc.c | 49 +++++++++++++++++++++++++++++-------------------- fs/jffs2/nodelist.h | 5 +++++ fs/jffs2/scan.c | 15 +++++++++++++-- fs/jffs2/summary.c | 9 ++++++++- 4 files changed, 55 insertions(+), 23 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 23587f8a221f..b0a5c407b476 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -256,10 +256,14 @@ 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; } @@ -533,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; @@ -605,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(); @@ -674,15 +682,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 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); - + 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))); diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index bac4ec35bbd0..1f5d5b0100aa 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -97,6 +97,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 diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 3cbe9f029e01..06637050749d 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -851,11 +851,22 @@ scan_more: 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; + } } } } diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 95b5bf8f4a99..53a84b468cfe 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -760,7 +760,14 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock } #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 */ + } } } -- cgit v1.2.3 From 7807ef7ba2a41c05f6197381f572dd38baa6c1ce Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 03:45:27 +0100 Subject: [JFFS2] Fix summary handling of unknown but compatible nodes. For RWCOMPAT and ROCOMPAT nodes, we should still allow the mount to succeed. Just abandon the summary and fall through to the full scan. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 3 +-- fs/jffs2/nodelist.h | 1 + fs/jffs2/summary.c | 24 ++++++++++++++++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index fecf5584f830..f677d6950fd4 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -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)); diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 1f5d5b0100aa..194cff7c4853 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -436,6 +436,7 @@ 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 */ diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 53a84b468cfe..9ced3aa95818 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -554,9 +554,21 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } #endif default : { -printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)); - JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); - return -EIO; + 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; } } } @@ -642,8 +654,12 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb } 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(); -- cgit v1.2.3 From 68270995f29f1a82b3eaab01df63ea7e721e2fa6 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 03:46:05 +0100 Subject: [JFFS2] Introduce jffs2_scan_dirty_space() function. To eliminate the __totlen field from struct jffs2_raw_node_ref, we need to allocate nodes for dirty space instead of just tweaking the accounting data. Introduce jffs2_scan_dirty_space() in preparation for that. Signed-off-by: David Woodhouse --- fs/jffs2/nodelist.c | 11 ++++++++ fs/jffs2/nodelist.h | 1 + fs/jffs2/scan.c | 76 ++++++++++++++++++++++++++++++++++++----------------- fs/jffs2/summary.c | 16 +++++++---- fs/jffs2/summary.h | 17 ------------ 5 files changed, 75 insertions(+), 46 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 1fc8aedb56fb..00506857eabc 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1080,3 +1080,14 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, ref->__totlen = len; ref->next_phys = NULL; } + +int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + uint32_t size) +{ + c->dirty_size += size; + c->free_size -= size; + jeb->dirty_size += size; + jeb->free_size -= size; + + return 0; +} diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 194cff7c4853..ca15b3c731cf 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -430,6 +430,7 @@ 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); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 192b0bd21180..b3fc9fd5b03d 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -314,13 +314,15 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc 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); - DIRTY_SPACE(je32_to_cpu(rx->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen)))) + return err; return 0; } @@ -328,7 +330,8 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc if (totlen != je32_to_cpu(rx->totlen)) { JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", ofs, je32_to_cpu(rx->totlen), totlen); - DIRTY_SPACE(je32_to_cpu(rx->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen)))) + return err; return 0; } @@ -340,7 +343,8 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc if (IS_ERR(xd)) { jffs2_free_raw_node_ref(raw); if (PTR_ERR(xd) == -EEXIST) { - DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen))))) + return err; return 0; } return PTR_ERR(xd); @@ -370,13 +374,15 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock 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); - DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rr->totlen))))) + return err; return 0; } @@ -384,7 +390,8 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", ofs, je32_to_cpu(rr->totlen), PAD(sizeof(struct jffs2_raw_xref))); - DIRTY_SPACE(je32_to_cpu(rr->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rr->totlen)))) + return err; return 0; } @@ -569,7 +576,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... */ @@ -593,7 +601,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; } @@ -602,7 +611,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; } @@ -632,7 +642,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; } @@ -669,20 +680,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; } @@ -691,7 +705,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; } @@ -708,7 +723,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; } @@ -719,7 +735,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; } @@ -727,7 +744,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; } @@ -807,11 +825,13 @@ scan_more: 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(); @@ -831,7 +851,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; @@ -842,7 +863,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; @@ -852,7 +874,8 @@ 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; @@ -930,6 +953,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)); @@ -959,7 +983,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; } @@ -1000,6 +1025,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)); @@ -1011,7 +1037,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; } @@ -1032,7 +1059,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(); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 9ced3aa95818..11ea54c90f44 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -380,6 +380,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; @@ -494,7 +495,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jffs2_free_raw_node_ref(raw); if (PTR_ERR(xd) == -EEXIST) { /* a newer version of xd exists */ - DIRTY_SPACE(je32_to_cpu(spx->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen)))) + return err; sp += JFFS2_SUMMARY_XATTR_SIZE; break; } @@ -585,6 +587,7 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb struct jffs2_raw_node_ref *cache_ref; int ret, ofs; uint32_t crc; + int err; ofs = jeb->offset + c->sector_size - sumsize; @@ -629,11 +632,13 @@ 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); - DIRTY_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); - DIRTY_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(); @@ -650,7 +655,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb } if (je32_to_cpu(summary->padded)) { - DIRTY_SPACE(je32_to_cpu(summary->padded)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(summary->padded)))) + return err; } ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); @@ -823,7 +829,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; - DIRTY_SPACE(infosize); + jffs2_scan_dirty_space(c, jeb, infosize); return 1; } diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index ce892d57ad59..e7eb0c5814f6 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -18,23 +18,6 @@ #include #include -#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 -- cgit v1.2.3 From 49f11d40751b974f3b829f208eefa6f97a10cac8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 04:00:01 +0100 Subject: [JFFS2] Mark gaps in summary list as dirty space Make sure we allocate a ref for any dirty space which exists between nodes which we find in an eraseblock summary. Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 71 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 29 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 11ea54c90f44..e60289ada833 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -369,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() */ @@ -397,7 +414,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras dbg_summary("Inode at 0x%08x\n", jeb->offset + je32_to_cpu(spi->offset)); - 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"); return -ENOMEM; @@ -410,7 +427,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras return -ENOMEM; } - raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED; + raw->flash_offset |= REF_UNCHECKED; raw->next_in_ino = ic->nodes; ic->nodes = raw; @@ -438,7 +455,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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"); @@ -452,7 +469,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras return -ENOMEM; } - raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE; + raw->flash_offset |= REF_PRISTINE; raw->next_in_ino = ic->nodes; ic->nodes = raw; @@ -477,13 +494,12 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras case JFFS2_NODETYPE_XATTR: { struct jffs2_xattr_datum *xd; struct jffs2_sum_xattr_flash *spx; - uint32_t ofs; spx = (struct jffs2_sum_xattr_flash *)sp; - ofs = jeb->offset + je32_to_cpu(spx->offset); - dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", ofs, + dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", + jeb->offset + je32_to_cpu(spx->offset), je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); - raw = jffs2_alloc_raw_node_ref(); + raw = alloc_ref_at(c, jeb, je32_to_cpu(spx->offset)); if (!raw) { JFFS2_NOTICE("allocation of node reference failed\n"); kfree(summary); @@ -506,7 +522,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } xd->node = raw; - raw->flash_offset = ofs | REF_UNCHECKED; + raw->flash_offset |= REF_UNCHECKED; raw->next_in_ino = (void *)xd; jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen))); @@ -519,13 +535,12 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras case JFFS2_NODETYPE_XREF: { struct jffs2_xattr_ref *ref; struct jffs2_sum_xref_flash *spr; - uint32_t ofs; spr = (struct jffs2_sum_xref_flash *)sp; - ofs = jeb->offset + je32_to_cpu(spr->offset); - dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs, + dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", + jeb->offset + je32_to_cpu(spr->offset), je32_to_cpu(spr->xid), je32_to_cpu(spr->ino)); - raw = jffs2_alloc_raw_node_ref(); + raw = alloc_ref_at(c, jeb, je32_to_cpu(spr->offset)); if (!raw) { JFFS2_NOTICE("allocation of node reference failed\n"); kfree(summary); @@ -544,12 +559,12 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ref->next = c->xref_temp; c->xref_temp = ref; - raw->flash_offset = ofs | REF_UNCHECKED; + 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 += ofs; + *pseudo_random += raw->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; break; @@ -589,10 +604,10 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb uint32_t crc; int err; - ofs = jeb->offset + c->sector_size - sumsize; + ofs = c->sector_size - sumsize; dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", - jeb->offset, ofs, sumsize); + jeb->offset, jeb->offset + ofs, sumsize); /* OK, now check for node validity and CRC */ crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -654,11 +669,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb } } - if (je32_to_cpu(summary->padded)) { - if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(summary->padded)))) - return err; - } - 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 */ @@ -668,7 +678,7 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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"); @@ -676,15 +686,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->flash_offset |= REF_NORMAL; jffs2_link_node_ref(c, jeb, cache_ref, 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); -- cgit v1.2.3 From 9167e0f811cbe28564c44a99c2f07b0ce5b368cf Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 13:13:45 +0100 Subject: [JFFS2] Remove stray kfree of summary info in XATTR code. We don't allocate this locally any more -- it's given to us and owner by our caller. Also improve the debug messages a little. Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index e60289ada833..5a59c6188407 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -411,8 +411,9 @@ 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 = alloc_ref_at(c, jeb, je32_to_cpu(spi->offset)); if (!raw) { @@ -446,7 +447,9 @@ 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) @@ -496,13 +499,13 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras struct jffs2_sum_xattr_flash *spx; spx = (struct jffs2_sum_xattr_flash *)sp; - dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", + 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"); - kfree(summary); return -ENOMEM; } xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), @@ -517,7 +520,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras break; } JFFS2_NOTICE("allocation of xattr_datum failed\n"); - kfree(summary); return PTR_ERR(xd); } xd->node = raw; @@ -537,20 +539,19 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras struct jffs2_sum_xref_flash *spr; spr = (struct jffs2_sum_xref_flash *)sp; - dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", + dbg_summary("xref at %#08x-%#08x\n", jeb->offset + je32_to_cpu(spr->offset), - je32_to_cpu(spr->xid), je32_to_cpu(spr->ino)); + 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"); - kfree(summary); return -ENOMEM; } ref = jffs2_alloc_xattr_ref(); if (!ref) { JFFS2_NOTICE("allocation of xattr_datum failed\n"); jffs2_free_raw_node_ref(raw); - kfree(summary); return -ENOMEM; } ref->ino = 0xfffffffe; -- cgit v1.2.3 From 010b06d6d07d9fa5ea6070aa72bb3e0de1761ab7 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 13:15:59 +0100 Subject: [JFFS2] Locking issues in summary write code. We can't use jffs2_scan_dirty_space() because it doesn't do any locking; it's only for use at scan time -- hence the 'scan' in the name. Also, don't allocate refs while we have c->erase_completion_lock held. Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 5a59c6188407..1451732e1fa7 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -835,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; - jffs2_scan_dirty_space(c, jeb, infosize); return 1; } + spin_lock(&c->erase_completion_lock); + return 0; } @@ -890,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"); @@ -900,6 +912,7 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) summary_ref->next_in_ino = NULL; summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; + spin_lock(&c->erase_completion_lock); jffs2_link_node_ref(c, jeb, summary_ref, infosize); return 0; -- cgit v1.2.3 From fcb7578719529898aef9edce8e409e457a1c2d15 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 22 May 2006 15:23:10 +0100 Subject: [JFFS2] Extend jffs2_link_node_ref() to link into per-inode list too. Let's avoid the potential for forgetting to set ref->next_in_ino, by doing it within jffs2_link_node_ref() instead. This highlights the ugliness of what we're currently doing with xattr_datum and xattr_ref structures -- we should find a nicer way of dealing with that. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 3 +-- fs/jffs2/gc.c | 17 ++--------------- fs/jffs2/nodelist.c | 13 ++++++++++--- fs/jffs2/nodelist.h | 8 ++++++-- fs/jffs2/nodemgmt.c | 5 +++-- fs/jffs2/scan.c | 24 ++++++++---------------- fs/jffs2/summary.c | 30 ++++++++++-------------------- fs/jffs2/wbuf.c | 6 ++---- fs/jffs2/write.c | 23 ++++------------------- fs/jffs2/xattr.c | 15 +++++++-------- 10 files changed, 53 insertions(+), 91 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index f677d6950fd4..0fc19a2fb5d9 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -410,10 +410,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb /* Everything else got zeroed before the erase */ jeb->free_size = c->sector_size; - marker_ref->next_in_ino = NULL; marker_ref->flash_offset = jeb->offset | REF_NORMAL; - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); } spin_lock(&c->erase_completion_lock); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 4773ba24304f..153755bc1d53 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -634,11 +634,8 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", rawlen, phys_ofs, ret, retlen); if (retlen) { - /* Doesn't belong to any inode */ - nraw->next_in_ino = NULL; - nraw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, nraw, rawlen); + jffs2_add_physical_node_ref(c, nraw, rawlen, NULL); 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); @@ -678,18 +675,8 @@ 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, rawlen); + jffs2_add_physical_node_ref(c, nraw, rawlen, ic); - 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))); diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 7d563f938b1c..d25d4919ca97 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1048,7 +1048,8 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) } void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_node_ref *ref, uint32_t len) + struct jffs2_raw_node_ref *ref, uint32_t len, + struct jffs2_inode_cache *ic) { if (!jeb->first_node) jeb->first_node = ref; @@ -1065,6 +1066,13 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, } jeb->last_node = ref; + if (ic) { + ref->next_in_ino = ic->nodes; + ic->nodes = ref; + } else { + ref->next_in_ino = NULL; + } + switch(ref_flags(ref)) { case REF_UNCHECKED: c->unchecked_size += len; @@ -1120,12 +1128,11 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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); + jffs2_link_node_ref(c, jeb, ref, size, NULL); } return 0; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 80d1fda2212b..ee5aedcffc12 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -307,7 +307,8 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in 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); + struct jffs2_raw_node_ref *ref, uint32_t len, + struct jffs2_inode_cache *ic); extern uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *ref); @@ -318,7 +319,10 @@ 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, uint32_t len); +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, + struct jffs2_raw_node_ref *new, + uint32_t len, + struct jffs2_inode_cache *ic); 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); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 9a0f312cfcda..e10e58eab8e5 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -381,7 +381,8 @@ 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, uint32_t len) +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, + uint32_t len, struct jffs2_inode_cache *ic) { struct jffs2_eraseblock *jeb; @@ -403,7 +404,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r #endif spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, new, len); + jffs2_link_node_ref(c, jeb, new, len, ic); 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 */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index cffafec01e48..6fce703c0543 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -361,9 +361,9 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc xd->node = raw; raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = (void *)xd; - jffs2_link_node_ref(c, jeb, raw, totlen); + jffs2_link_node_ref(c, jeb, raw, totlen, NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); @@ -425,9 +425,9 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock 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))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; if (jffs2_sum_active()) jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); @@ -844,10 +844,9 @@ scan_more: printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n"); return -ENOMEM; } - marker_ref->next_in_ino = NULL; marker_ref->flash_offset = ofs | REF_NORMAL; - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); ofs += PAD(c->cleanmarker_size); } @@ -892,8 +891,7 @@ scan_more: 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))); + jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)), NULL); /* We can't summarise nodes we don't grok */ jffs2_sum_disable_collecting(s); @@ -1004,10 +1002,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc raw->flash_offset = ofs | REF_UNCHECKED; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen)), ic); 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), @@ -1082,10 +1077,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo } raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)), ic); fd->raw = raw; fd->next = NULL; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 1451732e1fa7..351ba9f8185e 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -430,10 +430,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras raw->flash_offset |= REF_UNCHECKED; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)), ic); *pseudo_random += je32_to_cpu(spi->version); @@ -473,10 +470,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } raw->flash_offset |= REF_PRISTINE; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)), ic); fd->raw = raw; fd->next = NULL; @@ -525,9 +519,9 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen)), NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; *pseudo_random += je32_to_cpu(spx->xid); sp += JFFS2_SUMMARY_XATTR_SIZE; @@ -561,9 +555,9 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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))); + jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; *pseudo_random += raw->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; @@ -664,9 +658,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb } marker_ref->flash_offset = jeb->offset | REF_NORMAL; - marker_ref->next_in_ino = NULL; - jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr)); + jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr), NULL); } } @@ -686,10 +679,9 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return -ENOMEM; } - cache_ref->next_in_ino = NULL; cache_ref->flash_offset |= REF_NORMAL; - jffs2_link_node_ref(c, jeb, cache_ref, sumsize); + jffs2_link_node_ref(c, jeb, cache_ref, sumsize, NULL); if (unlikely(jeb->free_size)) { JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", @@ -849,9 +841,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock 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); + jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size, NULL); } c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; @@ -909,11 +900,10 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) return -ENOMEM; } - summary_ref->next_in_ino = NULL; summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, summary_ref, infosize); + jffs2_link_node_ref(c, jeb, summary_ref, infosize, NULL); return 0; } diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 45e3573cf107..62f685faeba8 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -312,9 +312,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) return; raw2->flash_offset = ofs | REF_OBSOLETE; - raw2->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw)); + jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw), NULL); } return; } @@ -507,11 +506,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) return -ENOMEM; ref->flash_offset = c->wbuf_ofs + c->wbuf_len; ref->flash_offset |= REF_OBSOLETE; - ref->next_in_ino = NULL; spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, ref, waste); + jffs2_link_node_ref(c, jeb, ref, waste, NULL); /* FIXME: that made it count as dirty. Convert to wasted */ jeb->dirty_size -= waste; c->dirty_size -= waste; diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 4462541d11f8..319a70f531f8 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -122,16 +122,13 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 /* Mark the space as dirtied */ if (retlen) { - /* Doesn't belong to any inode */ - raw->next_in_ino = NULL; - /* Don't change raw->size to match retlen. We may have written the node header already, and only the data will seem corrupted, in which case the scan would skip over any node we write before the original intended end of this node */ raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen)); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), NULL); 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); @@ -189,13 +186,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, PAD(sizeof(*ri)+datalen)); - - /* Link into per-inode list */ - spin_lock(&c->erase_completion_lock); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - spin_unlock(&c->erase_completion_lock); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), f->inocache); D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), @@ -275,9 +266,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { - raw->next_in_ino = NULL; raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen)); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), NULL); 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); @@ -323,12 +313,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, PAD(sizeof(*rd)+namelen)); - - spin_lock(&c->erase_completion_lock); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - spin_unlock(&c->erase_completion_lock); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), f->inocache); if (retried) { jffs2_dbg_acct_sanity_check(c,NULL); diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index e16f8460ff04..76d166140381 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -322,7 +322,6 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x if (!raw) return -ENOMEM; raw->flash_offset = phys_ofs; - raw->next_in_ino = (void *)xd; /* Setup raw-xattr */ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -345,8 +344,7 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x rc = rc ? rc : -EIO; if (length) { raw->flash_offset |= REF_OBSOLETE; - raw->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw, PAD(totlen)); + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); jffs2_mark_node_obsolete(c, raw); } else { jffs2_free_raw_node_ref(raw); @@ -356,7 +354,9 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x /* success */ raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(totlen)); + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; + if (xd->node) delete_xattr_datum_node(c, xd); xd->node = raw; @@ -566,7 +566,6 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, if (!raw) return -ENOMEM; raw->flash_offset = phys_ofs; - raw->next_in_ino = (void *)ref; rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); @@ -584,8 +583,7 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, ret = ret ? ret : -EIO; if (length) { raw->flash_offset |= REF_OBSOLETE; - raw->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr))); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); jffs2_mark_node_obsolete(c, raw); } else { jffs2_free_raw_node_ref(raw); @@ -594,7 +592,8 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, } raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr))); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; if (ref->node) delete_xattr_ref_node(c, ref); ref->node = raw; -- cgit v1.2.3 From 2f785402f39b96a077b6e62bf26164bfb8e0c980 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 24 May 2006 02:04:45 +0100 Subject: [JFFS2] Reduce visibility of raw_node_ref to upper layers of JFFS2 code. As the first step towards eliminating the ref->next_phys member and saving memory by using an _array_ of struct jffs2_raw_node_ref per eraseblock, stop the write functions from allocating their own refs; have them just _reserve_ the appropriate number instead. Then jffs2_link_node_ref() can just fill them in. Use a linked list of pre-allocated refs in the superblock, for now. Once we switch to an array, it'll just be a case of extending that array. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 16 ++--- fs/jffs2/gc.c | 25 ++------ fs/jffs2/jffs2_fs_sb.h | 3 + fs/jffs2/malloc.c | 26 +++++++- fs/jffs2/nodelist.c | 51 ++++++++++------ fs/jffs2/nodelist.h | 19 +++--- fs/jffs2/nodemgmt.c | 39 ++++++------ fs/jffs2/scan.c | 77 +++++------------------ fs/jffs2/summary.c | 162 +++++++++++++++---------------------------------- fs/jffs2/wbuf.c | 26 +++----- fs/jffs2/write.c | 71 +++++++--------------- fs/jffs2/xattr.c | 38 +++--------- 12 files changed, 204 insertions(+), 349 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 4616fed75730..f939f908b948 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -296,7 +296,7 @@ void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock * jffs2_remove_node_refs_from_ino_list(c, ref, jeb); /* else it was a non-inode node or already removed, so don't bother */ - jffs2_free_raw_node_ref(ref); + __jffs2_free_raw_node_ref(ref); } jeb->last_node = NULL; } @@ -351,7 +351,6 @@ fail: static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - struct jffs2_raw_node_ref *marker_ref = NULL; size_t retlen; int ret; uint32_t bad_offset; @@ -384,11 +383,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb .totlen = cpu_to_je32(c->cleanmarker_size) }; - marker_ref = jffs2_alloc_raw_node_ref(); - if (!marker_ref) { - printk(KERN_WARNING "Failed to allocate raw node ref for clean marker. Refiling\n"); - goto refile; - } + jffs2_prealloc_raw_node_refs(c, 1); marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); @@ -404,16 +399,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n", jeb->offset, sizeof(marker), retlen); - jffs2_free_raw_node_ref(marker_ref); goto filebad; } /* Everything else got zeroed before the erase */ jeb->free_size = c->sector_size; - - marker_ref->flash_offset = jeb->offset | REF_NORMAL; - - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); + /* FIXME Special case for cleanmarker in empty block */ + jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); } spin_lock(&c->erase_completion_lock); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index f9e982a65ac2..a22ff5df7fcc 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -528,7 +528,6 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw) { union jffs2_node_union *node; - struct jffs2_raw_node_ref *nraw; size_t retlen; int ret; uint32_t phys_ofs, alloclen; @@ -618,30 +617,21 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, } } - nraw = jffs2_alloc_raw_node_ref(); - if (!nraw) { - ret = -ENOMEM; - goto out_node; - } - /* OK, all the CRCs are good; this node can just be copied as-is. */ retry: - nraw->flash_offset = phys_ofs = write_ofs(c); + phys_ofs = write_ofs(c); ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); if (ret || (retlen != rawlen)) { printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", - rawlen, nraw->flash_offset, ret, retlen); + rawlen, phys_ofs, ret, retlen); if (retlen) { - nraw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, nraw, rawlen, NULL); - jffs2_mark_node_obsolete(c, nraw); + jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); - jffs2_free_raw_node_ref(nraw); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", phys_ofs); } - if (!retried && (nraw = jffs2_alloc_raw_node_ref())) { + if (!retried) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; @@ -666,16 +656,13 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, goto retry; } D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); - jffs2_free_raw_node_ref(nraw); } - jffs2_free_raw_node_ref(nraw); if (!ret) ret = -EIO; goto out_node; } - nraw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, nraw, rawlen, ic); + jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic); jffs2_mark_node_obsolete(c, raw); D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 272fbea55192..67529f0a44dd 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -26,6 +26,9 @@ struct jffs2_inodirty; struct jffs2_sb_info { struct mtd_info *mtd; + struct jffs2_raw_node_ref *refs; + int reserved_refs; + uint32_t highest_ino; uint32_t checked_ino; diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index f2473fa2fd16..3df3250314a2 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -190,7 +190,29 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) kmem_cache_free(tmp_dnode_info_slab, x); } -struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) +int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int nr) +{ + struct jffs2_raw_node_ref *p = c->refs; + + dbg_memalloc("%d\n", nr); + + while (nr && p) { + p = p->next_in_ino; + nr--; + } + while (nr) { + p = __jffs2_alloc_raw_node_ref(); + if (!p) + return -ENOMEM; + p->next_in_ino = c->refs; + c->refs = p; + nr--; + } + c->reserved_refs = nr; + return 0; +} + +struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void) { struct jffs2_raw_node_ref *ret; ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); @@ -198,7 +220,7 @@ struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) return ret; } -void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) +void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) { dbg_memalloc("%p\n", x); kmem_cache_free(raw_node_ref_slab, x); diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index d25d4919ca97..1e6eabd730f2 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -953,13 +953,19 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) for (i=0; inr_blocks; i++) { this = c->blocks[i].first_node; - while(this) { + while (this) { next = this->next_phys; - jffs2_free_raw_node_ref(this); + __jffs2_free_raw_node_ref(this); this = next; } c->blocks[i].first_node = c->blocks[i].last_node = NULL; } + this = c->refs; + while (this) { + next = this->next_in_ino; + __jffs2_free_raw_node_ref(this); + this = next; + } } struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) @@ -1047,10 +1053,27 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) } } -void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - struct jffs2_raw_node_ref *ref, uint32_t len, - struct jffs2_inode_cache *ic) +struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + uint32_t ofs, uint32_t len, + struct jffs2_inode_cache *ic) { + struct jffs2_raw_node_ref *ref; + + /* These will be preallocated _very_ shortly. */ + ref = c->refs; + if (!c->refs) { + JFFS2_WARNING("Using non-preallocated refs!\n"); + ref = __jffs2_alloc_raw_node_ref(); + BUG_ON(!ref); + WARN_ON(1); + } else { + c->refs = ref->next_in_ino; + } + + ref->next_phys = NULL; + ref->flash_offset = ofs; + if (!jeb->first_node) jeb->first_node = ref; if (jeb->last_node) { @@ -1093,15 +1116,15 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 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 + return ref; } -/* No locking. Do not use on a live file system */ +/* No locking, no reservation of 'ref'. 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) { @@ -1121,18 +1144,10 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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; -#ifdef TEST_TOTLEN - ref->__totlen = size; -#endif + uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size; + ofs |= REF_OBSOLETE; - jffs2_link_node_ref(c, jeb, ref, size, NULL); + jffs2_link_node_ref(c, jeb, ofs, size, NULL); } return 0; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 76f1b9419eea..7cc74d2ab4dc 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -318,9 +318,10 @@ 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, - struct jffs2_inode_cache *ic); +struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + uint32_t ofs, uint32_t len, + struct jffs2_inode_cache *ic); extern uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *ref); @@ -331,10 +332,9 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *len, int prio, uint32_t sumsize); int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *len, uint32_t sumsize); -int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, - struct jffs2_raw_node_ref *new, - uint32_t len, - struct jffs2_inode_cache *ic); +struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, + uint32_t ofs, uint32_t len, + struct jffs2_inode_cache *ic); 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); @@ -378,8 +378,9 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void); void jffs2_free_raw_inode(struct jffs2_raw_inode *); struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void); void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *); -struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void); -void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); +int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int nr); +struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void); +void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); 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); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 8feb8749bc75..01bf2773fe4d 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -137,6 +137,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, } } spin_unlock(&c->erase_completion_lock); + if (!ret) + ret = jffs2_prealloc_raw_node_refs(c, 1); if (ret) up(&c->alloc_sem); return ret; @@ -158,6 +160,9 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, } } spin_unlock(&c->erase_completion_lock); + if (!ret) + ret = jffs2_prealloc_raw_node_refs(c, 1); + return ret; } @@ -381,30 +386,30 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, * 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, - uint32_t len, struct jffs2_inode_cache *ic) +struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, + uint32_t ofs, uint32_t len, + struct jffs2_inode_cache *ic) { struct jffs2_eraseblock *jeb; + struct jffs2_raw_node_ref *new; - jeb = &c->blocks[new->flash_offset / c->sector_size]; -#ifdef TEST_TOTLEN - new->__totlen = len; -#endif + jeb = &c->blocks[ofs / c->sector_size]; - 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)); + D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", + ofs & ~3, ofs & 3, len)); #if 1 - /* we could get some obsolete nodes after nextblock was refiled - in wbuf.c */ - if ((c->nextblock || !ref_obsolete(new)) - &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) { + /* Allow non-obsolete nodes only to be added at the end of c->nextblock, + if c->nextblock is set. Note that wbuf.c will file obsolete nodes + even after refiling c->nextblock */ + if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) + && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { printk(KERN_WARNING "argh. node added in wrong place\n"); - jffs2_free_raw_node_ref(new); - return -EINVAL; + return ERR_PTR(-EINVAL); } #endif spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, new, len, ic); + new = jffs2_link_node_ref(c, jeb, ofs, len, ic); 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 */ @@ -425,7 +430,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r spin_unlock(&c->erase_completion_lock); - return 0; + return new; } @@ -697,7 +702,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref } spin_unlock(&c->erase_completion_lock); - jffs2_free_raw_node_ref(n); + __jffs2_free_raw_node_ref(n); } /* Also merge with the previous node in the list, if there is one @@ -722,7 +727,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref jeb->gc_node=p; } p->next_phys = ref->next_phys; - jffs2_free_raw_node_ref(ref); + __jffs2_free_raw_node_ref(ref); } spin_unlock(&c->erase_completion_lock); } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 6fce703c0543..87b0a416b6a0 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -317,7 +317,6 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc struct jffs2_summary *s) { struct jffs2_xattr_datum *xd; - struct jffs2_raw_node_ref *raw; uint32_t totlen, crc; int err; @@ -340,13 +339,8 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc 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; @@ -358,12 +352,9 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc 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; - jffs2_link_node_ref(c, jeb, raw, totlen, NULL); - /* FIXME */ raw->next_in_ino = (void *)xd; + xd->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL); + /* FIXME */ xd->node->next_in_ino = (void *)xd; if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); @@ -377,7 +368,6 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock struct jffs2_summary *s) { struct jffs2_xattr_ref *ref; - struct jffs2_raw_node_ref *raw; uint32_t crc; int err; @@ -404,12 +394,6 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock 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 @@ -418,16 +402,13 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock * 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; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen)), NULL); - /* FIXME */ raw->next_in_ino = (void *)ref; + ref->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), NULL); + /* FIXME */ ref->node->next_in_ino = (void *)ref; if (jffs2_sum_active()) jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); @@ -597,6 +578,11 @@ scan_more: jffs2_dbg_acct_paranoia_check_nolock(c, jeb); + /* Make sure there are node refs available for use */ + err = jffs2_prealloc_raw_node_refs(c, 2); + if (err) + return err; + cond_resched(); if (ofs & 3) { @@ -839,14 +825,7 @@ scan_more: return err; ofs += PAD(sizeof(struct jffs2_unknown_node)); } else { - struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); - if (!marker_ref) { - printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n"); - return -ENOMEM; - } - marker_ref->flash_offset = ofs | REF_NORMAL; - - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); + jffs2_link_node_ref(c, jeb, ofs | REF_NORMAL, c->cleanmarker_size, NULL); ofs += PAD(c->cleanmarker_size); } @@ -884,14 +863,9 @@ scan_more: break; 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)); - ref = jffs2_alloc_raw_node_ref(); - if (!ref) - return -ENOMEM; - ref->flash_offset = ofs | REF_PRISTINE; - jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)), NULL); + jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL); /* We can't summarise nodes we don't grok */ jffs2_sum_disable_collecting(s); @@ -953,7 +927,6 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s) { - struct jffs2_raw_node_ref *raw; struct jffs2_inode_cache *ic; uint32_t ino = je32_to_cpu(ri->ino); int err; @@ -969,12 +942,6 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc Which means that the _full_ amount of time to get to proper write mode with GC operational may actually be _longer_ than before. Sucks to be me. */ - raw = jffs2_alloc_raw_node_ref(); - if (!raw) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n"); - return -ENOMEM; - } - ic = jffs2_get_ino_cache(c, ino); if (!ic) { /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the @@ -988,21 +955,15 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen))))) return err; - jffs2_free_raw_node_ref(raw); return 0; } ic = jffs2_scan_make_ino_cache(c, ino); - if (!ic) { - jffs2_free_raw_node_ref(raw); + if (!ic) return -ENOMEM; - } } /* Wheee. It worked */ - - raw->flash_offset = ofs | REF_UNCHECKED; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen)), ic); + jffs2_link_node_ref(c, jeb, ofs | REF_UNCHECKED, PAD(je32_to_cpu(ri->totlen)), ic); 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), @@ -1021,7 +982,6 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s) { - struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; uint32_t crc; @@ -1063,23 +1023,14 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo return err; return 0; } - raw = jffs2_alloc_raw_node_ref(); - if (!raw) { - jffs2_free_full_dirent(fd); - printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n"); - return -ENOMEM; - } ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino)); if (!ic) { jffs2_free_full_dirent(fd); - jffs2_free_raw_node_ref(raw); return -ENOMEM; } - raw->flash_offset = ofs | REF_PRISTINE; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)), ic); + fd->raw = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rd->totlen)), ic); - fd->raw = raw; fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 351ba9f8185e..ccb6803a6e41 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -369,22 +369,18 @@ 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) +static struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + uint32_t ofs, uint32_t len, + struct jffs2_inode_cache *ic) { - 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; + if ((ofs & ~3) > c->sector_size - jeb->free_size) { + /* Ew. Summary doesn't actually tell us explicitly about dirty space */ + jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size)); } - ref = jffs2_alloc_raw_node_ref(); - if (!ref) - return NULL; - ref->flash_offset = jeb->offset + offset; - return ref; + return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic); } /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ @@ -392,7 +388,6 @@ static struct jffs2_raw_node_ref *alloc_ref_at(struct jffs2_sb_info *c, struct j static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_summary *summary, uint32_t *pseudo_random) { - struct jffs2_raw_node_ref *raw; struct jffs2_inode_cache *ic; struct jffs2_full_dirent *fd; void *sp; @@ -404,6 +399,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras for (i=0; isum_num); i++) { dbg_summary("processing summary index %d\n", i); + /* Make sure there's a spare ref for dirty space */ + err = jffs2_prealloc_raw_node_refs(c, 2); + if (err) + return err; + switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { case JFFS2_NODETYPE_INODE: { struct jffs2_sum_inode_flash *spi; @@ -415,22 +415,14 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spi->offset), jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spu->totlen)); - raw = alloc_ref_at(c, jeb, je32_to_cpu(spi->offset)); - if (!raw) { - JFFS2_NOTICE("allocation of node reference failed\n"); - return -ENOMEM; - } - ic = jffs2_scan_make_ino_cache(c, ino); if (!ic) { JFFS2_NOTICE("scan_make_ino_cache failed\n"); - jffs2_free_raw_node_ref(raw); return -ENOMEM; } - raw->flash_offset |= REF_UNCHECKED; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)), ic); + sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED, + PAD(je32_to_cpu(spi->totlen)), ic); *pseudo_random += je32_to_cpu(spi->version); @@ -455,24 +447,15 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras memcpy(&fd->name, spd->name, spd->nsize); fd->name[spd->nsize] = 0; - 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"); - return -ENOMEM; - } - ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); if (!ic) { jffs2_free_full_dirent(fd); - jffs2_free_raw_node_ref(raw); return -ENOMEM; } - raw->flash_offset |= REF_PRISTINE; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)), ic); + fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_PRISTINE, + PAD(je32_to_cpu(spd->totlen)), ic); - fd->raw = raw; fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); @@ -497,15 +480,10 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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)))) @@ -516,12 +494,10 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras JFFS2_NOTICE("allocation of xattr_datum failed\n"); return PTR_ERR(xd); } - xd->node = raw; - raw->flash_offset |= REF_UNCHECKED; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen)), NULL); - /* FIXME */ raw->next_in_ino = (void *)xd; + xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, + PAD(je32_to_cpu(spx->totlen)), NULL); + /* FIXME */ xd->node->next_in_ino = (void *)xd; *pseudo_random += je32_to_cpu(spx->xid); sp += JFFS2_SUMMARY_XATTR_SIZE; @@ -537,29 +513,21 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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; + ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, + PAD(sizeof(struct jffs2_raw_xref)), NULL); + /* FIXME */ ref->node->next_in_ino = (void *)ref; - jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref)), NULL); - /* FIXME */ raw->next_in_ino = (void *)ref; - - *pseudo_random += raw->flash_offset; + *pseudo_random += ref->node->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; break; @@ -584,7 +552,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } } } - return 0; } @@ -594,7 +561,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb uint32_t *pseudo_random) { struct jffs2_unknown_node crcnode; - struct jffs2_raw_node_ref *cache_ref; int ret, ofs; uint32_t crc; int err; @@ -650,16 +616,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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"); - return -ENOMEM; - } - - marker_ref->flash_offset = jeb->offset | REF_NORMAL; - - jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr), NULL); + jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, + je32_to_cpu(summary->cln_mkr), NULL); } } @@ -672,16 +630,11 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return ret; /* real error */ /* for PARANOIA_CHECK */ - cache_ref = alloc_ref_at(c, jeb, ofs); - - if (!cache_ref) { - JFFS2_NOTICE("Failed to allocate node ref for cache\n"); - return -ENOMEM; - } - - cache_ref->flash_offset |= REF_NORMAL; + ret = jffs2_prealloc_raw_node_refs(c, 1); + if (ret) + return ret; - jffs2_link_node_ref(c, jeb, cache_ref, sumsize, NULL); + jffs2_link_node_ref(c, jeb, (jeb->offset + ofs) | REF_NORMAL, sumsize, NULL); if (unlikely(jeb->free_size)) { JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", @@ -709,6 +662,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock union jffs2_sum_mem *temp; struct jffs2_sum_marker *sm; struct kvec vecs[2]; + uint32_t sum_ofs; void *wpage; int ret; size_t retlen; @@ -821,36 +775,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock vecs[1].iov_base = c->summary->sum_buf; vecs[1].iov_len = datasize; + sum_ofs = jeb->offset + c->sector_size - jeb->free_size; + dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n", - jeb->offset + c->sector_size - jeb->free_size); + sum_ofs); - spin_unlock(&c->erase_completion_lock); - ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - - jeb->free_size, &retlen, 0); + ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0); 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); + infosize, sum_ofs, 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; - - jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size, NULL); - } + spin_lock(&c->erase_completion_lock); + jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); + spin_unlock(&c->erase_completion_lock); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; - return 1; + return 0; } spin_lock(&c->erase_completion_lock); + jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL); + spin_unlock(&c->erase_completion_lock); return 0; } @@ -859,12 +808,15 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) { - struct jffs2_raw_node_ref *summary_ref; - int datasize, infosize, padsize, ret; + int datasize, infosize, padsize; struct jffs2_eraseblock *jeb; + int ret; dbg_summary("called\n"); + spin_unlock(&c->erase_completion_lock); + jffs2_prealloc_raw_node_refs(c, 1); + jeb = c->nextblock; if (!c->summary->sum_num || !c->summary->sum_list_head) { @@ -888,22 +840,6 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) } ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); - if (ret) - return 0; /* can't write out summary, block is marked as NOSUM_SIZE */ - - /* for ACCT_PARANOIA_CHECK */ - spin_unlock(&c->erase_completion_lock); - summary_ref = jffs2_alloc_raw_node_ref(); - - if (!summary_ref) { - JFFS2_NOTICE("Failed to allocate node ref for summary\n"); - return -ENOMEM; - } - - summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; - spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, summary_ref, infosize, NULL); - - return 0; + return ret; } diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 916c87d3393b..0d7abb260489 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -179,6 +179,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) unsigned char *buf; uint32_t start, end, ofs, len; + if (jffs2_prealloc_raw_node_refs(c, c->reserved_refs + 1)) + return; + spin_lock(&c->erase_completion_lock); jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -306,17 +309,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); kfree(buf); - if (retlen) { - struct jffs2_raw_node_ref *raw2; - - raw2 = jffs2_alloc_raw_node_ref(); - if (!raw2) - return; - - raw2->flash_offset = ofs | REF_OBSOLETE; + if (retlen) + jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, *first_raw), NULL); - jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw), NULL); - } return; } printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs); @@ -428,6 +423,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if (!c->wbuf_len) /* already checked c->wbuf above */ return 0; + if (jffs2_prealloc_raw_node_refs(c, c->reserved_refs + 1)) + return -ENOMEM; + /* claim remaining space on the page this happens, if we have a change to a new block, or if fsync forces us to flush the writebuffer. @@ -485,7 +483,6 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) /* 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]; @@ -503,15 +500,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) jeb->offset, jeb->free_size); BUG(); } - 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, NULL); + jffs2_link_node_ref(c, jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); /* FIXME: that made it count as dirty. Convert to wasted */ jeb->dirty_size -= waste; c->dirty_size -= waste; diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 0e12b7561b71..67176792e138 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -61,7 +61,6 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 uint32_t datalen, int alloc_mode) { - struct jffs2_raw_node_ref *raw; struct jffs2_full_dnode *fn; size_t retlen; uint32_t flash_ofs; @@ -83,27 +82,16 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); } - raw = jffs2_alloc_raw_node_ref(); - if (!raw) - return ERR_PTR(-ENOMEM); fn = jffs2_alloc_full_dnode(); - if (!fn) { - jffs2_free_raw_node_ref(raw); + if (!fn) return ERR_PTR(-ENOMEM); - } - - fn->ofs = je32_to_cpu(ri->offset); - fn->size = je32_to_cpu(ri->dsize); - fn->frags = 0; /* check number of valid vecs */ if (!datalen || !data) cnt = 1; retry: - fn->raw = raw; - - raw->flash_offset = flash_ofs = write_ofs(c); + flash_ofs = write_ofs(c); jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); @@ -130,14 +118,11 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 seem corrupted, in which case the scan would skip over any node we write before the original intended end of this node */ - raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), NULL); - jffs2_mark_node_obsolete(c, raw); + jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*ri)+datalen), NULL); } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); - jffs2_free_raw_node_ref(raw); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs); } - if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) { + if (!retried && alloc_mode != ALLOC_NORETRY) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; @@ -172,7 +157,6 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 goto retry; } D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); - jffs2_free_raw_node_ref(raw); } /* Release the full_dnode which is now useless, and return */ jffs2_free_full_dnode(fn); @@ -186,14 +170,17 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { - raw->flash_offset |= REF_PRISTINE; + flash_ofs |= REF_PRISTINE; } else { - raw->flash_offset |= REF_NORMAL; + flash_ofs |= REF_NORMAL; } - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), f->inocache); + fn->raw = jffs2_add_physical_node_ref(c, flash_ofs, PAD(sizeof(*ri)+datalen), f->inocache); + fn->ofs = je32_to_cpu(ri->offset); + fn->size = je32_to_cpu(ri->dsize); + fn->frags = 0; D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", - flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), + flash_ofs & ~3, flash_ofs & 3, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); @@ -208,11 +195,10 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, int alloc_mode) { - struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; size_t retlen; struct kvec vecs[2]; - uint32_t flash_ofs = write_ofs(c); + uint32_t flash_ofs; int retried = 0; int ret; @@ -223,26 +209,16 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); BUG(); - } - ); + }); vecs[0].iov_base = rd; vecs[0].iov_len = sizeof(*rd); vecs[1].iov_base = (unsigned char *)name; vecs[1].iov_len = namelen; - jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); - - raw = jffs2_alloc_raw_node_ref(); - - if (!raw) - return ERR_PTR(-ENOMEM); - fd = jffs2_alloc_full_dirent(namelen+1); - if (!fd) { - jffs2_free_raw_node_ref(raw); + if (!fd) return ERR_PTR(-ENOMEM); - } fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); @@ -252,9 +228,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff fd->name[namelen]=0; retry: - fd->raw = raw; + flash_ofs = write_ofs(c); - raw->flash_offset = flash_ofs; + jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) { BUG_ON(!retried); @@ -273,14 +249,11 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { - raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), NULL); - jffs2_mark_node_obsolete(c, raw); + jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*rd)+namelen), NULL); } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); - jffs2_free_raw_node_ref(raw); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs); } - if (!retried && (raw = jffs2_alloc_raw_node_ref())) { + if (!retried) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; @@ -313,15 +286,13 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff goto retry; } D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); - jffs2_free_raw_node_ref(raw); } /* Release the full_dnode which is now useless, and return */ jffs2_free_full_dirent(fd); return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), f->inocache); + fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | REF_PRISTINE, PAD(sizeof(*rd)+namelen), f->inocache); if (retried) { jffs2_dbg_acct_sanity_check(c,NULL); diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 008f91b1c171..2255f1367bd5 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -304,8 +304,8 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) { /* must be called under down_write(xattr_sem) */ - struct jffs2_raw_xattr rx; struct jffs2_raw_node_ref *raw; + struct jffs2_raw_xattr rx; struct kvec vecs[2]; uint32_t length; int rc, totlen; @@ -319,11 +319,6 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x vecs[1].iov_len = xd->name_len + 1 + xd->value_len; totlen = vecs[0].iov_len + vecs[1].iov_len; - raw = jffs2_alloc_raw_node_ref(); - if (!raw) - return -ENOMEM; - raw->flash_offset = phys_ofs; - /* Setup raw-xattr */ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR); @@ -343,19 +338,14 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%u, at %#08x\n", rc, totlen, length, phys_ofs); rc = rc ? rc : -EIO; - if (length) { - raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); - jffs2_mark_node_obsolete(c, raw); - } else { - jffs2_free_raw_node_ref(raw); - } + if (length) + jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(totlen), NULL); + return rc; } /* success */ - raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); + raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), NULL); /* FIXME */ raw->next_in_ino = (void *)xd; if (xd->node) @@ -563,11 +553,6 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) uint32_t phys_ofs = write_ofs(c); int ret; - raw = jffs2_alloc_raw_node_ref(); - if (!raw) - return -ENOMEM; - raw->flash_offset = phys_ofs; - rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); rr.totlen = cpu_to_je32(PAD(sizeof(rr))); @@ -582,18 +567,13 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) JFFS2_WARNING("jffs2_flash_write() returned %d, request=%u, retlen=%u, at %#08x\n", ret, sizeof(rr), length, phys_ofs); ret = ret ? ret : -EIO; - if (length) { - raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); - jffs2_mark_node_obsolete(c, raw); - } else { - jffs2_free_raw_node_ref(raw); - } + if (length) + jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(sizeof(rr)), NULL); + return ret; } - raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); + raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), NULL); /* FIXME */ raw->next_in_ino = (void *)ref; if (ref->node) delete_xattr_ref_node(c, ref); -- cgit v1.2.3 From c38c1b613d742b5fa075071568f44dc8ec9f1cb8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 01:38:27 +0100 Subject: [JFFS2] jffs2_free_all_node_refs() doesn't free them all. Rename it. ... to jffs2_free_jeb_node_refs() since that's what it does. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 4 ++-- fs/jffs2/nodelist.h | 2 +- fs/jffs2/nodemgmt.c | 2 +- fs/jffs2/summary.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index f939f908b948..aea58ee64d23 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -135,7 +135,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) c->used_size -= jeb->used_size; c->dirty_size -= jeb->dirty_size; jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0; - jffs2_free_all_node_refs(c, jeb); + jffs2_free_jeb_node_refs(c, jeb); list_add(&jeb->list, &c->erasing_list); spin_unlock(&c->erase_completion_lock); @@ -283,7 +283,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, jffs2_del_ino_cache(c, ic); } -void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +void jffs2_free_jeb_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)); diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 94d152de95eb..21b0b7b6c75f 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -417,7 +417,7 @@ 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); +void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); #ifdef CONFIG_JFFS2_FS_WRITEBUFFER /* wbuf.c */ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 8264eab2c899..bbc873e20807 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -618,7 +618,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref /* The erase_free_sem is locked, and has been since before we marked the node obsolete and potentially put its eraseblock onto the erase_pending_list. Thus, we know that the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet - by jffs2_free_all_node_refs() in erase.c. Which is nice. */ + by jffs2_free_jeb_node_refs() in erase.c. Which is nice. */ D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref))); ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index ccb6803a6e41..7bddd33f866a 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -547,7 +547,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0; jeb->free_size = c->sector_size; - jffs2_free_all_node_refs(c, jeb); + jffs2_free_jeb_node_refs(c, jeb); return -ENOTRECOVERABLE; } } -- cgit v1.2.3 From f61579c33736476e41e296a16c0d4ead4b953187 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 01:42:40 +0100 Subject: [JFFS2] Correctly handle wasted space before summary node. Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 7bddd33f866a..0c66d16eaa22 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -630,11 +630,11 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return ret; /* real error */ /* for PARANOIA_CHECK */ - ret = jffs2_prealloc_raw_node_refs(c, 1); + ret = jffs2_prealloc_raw_node_refs(c, 2); if (ret) return ret; - jffs2_link_node_ref(c, jeb, (jeb->offset + ofs) | REF_NORMAL, sumsize, NULL); + sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL); if (unlikely(jeb->free_size)) { JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", -- cgit v1.2.3 From 046b8b9808127d63326a33bc6298c90eaee90eeb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 01:50:35 +0100 Subject: [JFFS2] Add 'jeb' argument to jffs2_prealloc_raw_node_refs() Preallocation of refs is shortly going to be a per-eraseblock thing, rather than per-filesystem. Add the required argument to the function. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 2 +- fs/jffs2/malloc.c | 3 ++- fs/jffs2/nodelist.h | 3 ++- fs/jffs2/nodemgmt.c | 4 ++-- fs/jffs2/scan.c | 4 ++-- fs/jffs2/summary.c | 6 +++--- fs/jffs2/wbuf.c | 8 ++++---- 7 files changed, 16 insertions(+), 14 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index aea58ee64d23..c8386b256831 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -383,7 +383,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb .totlen = cpu_to_je32(c->cleanmarker_size) }; - jffs2_prealloc_raw_node_refs(c, 1); + jffs2_prealloc_raw_node_refs(c, jeb, 1); marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 3df3250314a2..171483ef0e4d 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -190,7 +190,8 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) kmem_cache_free(tmp_dnode_info_slab, x); } -int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int nr) +int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, int nr) { struct jffs2_raw_node_ref *p = c->refs; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 21b0b7b6c75f..6c92dc46fe9e 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -378,7 +378,8 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void); void jffs2_free_raw_inode(struct jffs2_raw_inode *); struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void); void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *); -int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int nr); +int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, int nr); struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void); void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); struct jffs2_node_frag *jffs2_alloc_node_frag(void); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index bbc873e20807..73a06d01db48 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -138,7 +138,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, } spin_unlock(&c->erase_completion_lock); if (!ret) - ret = jffs2_prealloc_raw_node_refs(c, 1); + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); if (ret) up(&c->alloc_sem); return ret; @@ -161,7 +161,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, } spin_unlock(&c->erase_completion_lock); if (!ret) - ret = jffs2_prealloc_raw_node_refs(c, 1); + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); return ret; } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index c25750aa85e3..5bbd4a36c75e 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -244,7 +244,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", skip)); - jffs2_prealloc_raw_node_refs(c, 1); + jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); jffs2_scan_dirty_space(c, c->nextblock, skip); } #endif @@ -576,7 +576,7 @@ scan_more: jffs2_dbg_acct_paranoia_check_nolock(c, jeb); /* Make sure there are node refs available for use */ - err = jffs2_prealloc_raw_node_refs(c, 2); + err = jffs2_prealloc_raw_node_refs(c, jeb, 2); if (err) return err; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 0c66d16eaa22..a60bbcea5b7f 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -400,7 +400,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras dbg_summary("processing summary index %d\n", i); /* Make sure there's a spare ref for dirty space */ - err = jffs2_prealloc_raw_node_refs(c, 2); + err = jffs2_prealloc_raw_node_refs(c, jeb, 2); if (err) return err; @@ -630,7 +630,7 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return ret; /* real error */ /* for PARANOIA_CHECK */ - ret = jffs2_prealloc_raw_node_refs(c, 2); + ret = jffs2_prealloc_raw_node_refs(c, jeb, 2); if (ret) return ret; @@ -815,9 +815,9 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) dbg_summary("called\n"); spin_unlock(&c->erase_completion_lock); - jffs2_prealloc_raw_node_refs(c, 1); jeb = c->nextblock; + jffs2_prealloc_raw_node_refs(c, jeb, 1); if (!c->summary->sum_num || !c->summary->sum_list_head) { JFFS2_WARNING("Empty summary info!!!\n"); diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 1871140e1e78..e16e45ea0474 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -179,13 +179,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) unsigned char *buf; uint32_t start, end, ofs, len; - if (jffs2_prealloc_raw_node_refs(c, c->reserved_refs + 1)) + jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; + + if (jffs2_prealloc_raw_node_refs(c, jeb, c->reserved_refs + 1)) return; spin_lock(&c->erase_completion_lock); - jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; - jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); /* Find the first node to be recovered, by skipping over every @@ -417,7 +417,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if (!c->wbuf_len) /* already checked c->wbuf above */ return 0; - if (jffs2_prealloc_raw_node_refs(c, c->reserved_refs + 1)) + if (jffs2_prealloc_raw_node_refs(c, c->nextblock, c->reserved_refs + 1)) return -ENOMEM; /* claim remaining space on the page -- cgit v1.2.3 From 8b9e9fe8c6ee354aa75dc5a33e1575b21aa52084 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 01:53:09 +0100 Subject: [JFFS2] Fix and improve debugging output during scan. Print wasted_size in scanned eraseblocks, print range correctly for summary dirent and inode entries. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 6 +++--- fs/jffs2/summary.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 5bbd4a36c75e..404ba6e48581 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -881,9 +881,9 @@ scan_more: } } - D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, - jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); - + D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n", + jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size)); + /* mark_node_obsolete can add to wasted !! */ if (jeb->wasted_size) { jeb->dirty_size += jeb->wasted_size; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index a60bbcea5b7f..523a8f330ef5 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -413,7 +413,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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)); + jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen)); ic = jffs2_scan_make_ino_cache(c, ino); if (!ic) { @@ -435,7 +435,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras struct jffs2_sum_dirent_flash *spd; spd = sp; - dbg_summary("Dirent at 0x%08x\n", + dbg_summary("Dirent at 0x%08x-0x%08x\n", jeb->offset + je32_to_cpu(spd->offset), jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); -- cgit v1.2.3 From 9bfeb691e75b21fdaa80ffae719083200b190381 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 26 May 2006 21:19:05 +0100 Subject: [JFFS2] Switch to using an array of jffs2_raw_node_refs instead of a list. This allows us to drop another pointer from the struct jffs2_raw_node_ref, shrinking it to 8 bytes on 32-bit machines (if the TEST_TOTLEN) paranoia check is turned off, which will be committed soon). Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 21 ++-- fs/jffs2/jffs2_fs_sb.h | 3 - fs/jffs2/malloc.c | 75 ++++++++----- fs/jffs2/nodelist.c | 93 ++++++++-------- fs/jffs2/nodelist.h | 31 +++++- fs/jffs2/nodemgmt.c | 51 +-------- fs/jffs2/os-linux.h | 1 + fs/jffs2/summary.c | 14 ++- fs/jffs2/wbuf.c | 287 ++++++++++++++++++++++++++++++++++--------------- 9 files changed, 351 insertions(+), 225 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index c8386b256831..1862e8bc101d 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -285,20 +285,25 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - struct jffs2_raw_node_ref *ref; + struct jffs2_raw_node_ref *block, *ref; D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset)); - while(jeb->first_node) { - ref = jeb->first_node; - jeb->first_node = ref->next_phys; - /* Remove from the inode-list */ - if (ref->next_in_ino) + block = ref = jeb->first_node; + + while (ref) { + if (ref->flash_offset == REF_LINK_NODE) { + ref = ref->next_in_ino; + jffs2_free_refblock(block); + block = ref; + continue; + } + if (ref->flash_offset != REF_EMPTY_NODE && ref->next_in_ino) jffs2_remove_node_refs_from_ino_list(c, ref, jeb); /* else it was a non-inode node or already removed, so don't bother */ - __jffs2_free_raw_node_ref(ref); + ref++; } - jeb->last_node = NULL; + jeb->first_node = jeb->last_node = NULL; } static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset) diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 67529f0a44dd..272fbea55192 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -26,9 +26,6 @@ struct jffs2_inodirty; struct jffs2_sb_info { struct mtd_info *mtd; - struct jffs2_raw_node_ref *refs; - int reserved_refs; - uint32_t highest_ino; uint32_t checked_ino; diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 171483ef0e4d..4889d0700c0e 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -57,8 +57,8 @@ int __init jffs2_create_slab_caches(void) if (!tmp_dnode_info_slab) goto err; - raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", - sizeof(struct jffs2_raw_node_ref), + raw_node_ref_slab = kmem_cache_create("jffs2_refblock", + sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), 0, 0, NULL, NULL); if (!raw_node_ref_slab) goto err; @@ -190,38 +190,65 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) kmem_cache_free(tmp_dnode_info_slab, x); } +struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) +{ + struct jffs2_raw_node_ref *ret; + + ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + if (ret) { + int i = 0; + for (i=0; i < REFS_PER_BLOCK; i++) { + ret[i].flash_offset = REF_EMPTY_NODE; + ret[i].next_in_ino = NULL; + } + ret[i].flash_offset = REF_LINK_NODE; + ret[i].next_in_ino = NULL; + } + return ret; +} + int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int nr) { - struct jffs2_raw_node_ref *p = c->refs; + struct jffs2_raw_node_ref **p, *ref; + int i = nr; dbg_memalloc("%d\n", nr); - while (nr && p) { - p = p->next_in_ino; - nr--; - } - while (nr) { - p = __jffs2_alloc_raw_node_ref(); - if (!p) - return -ENOMEM; - p->next_in_ino = c->refs; - c->refs = p; - nr--; + p = &jeb->last_node; + ref = *p; + + dbg_memalloc("Reserving %d refs for block @0x%08x\n", nr, jeb->offset); + + /* If jeb->last_node is really a valid node then skip over it */ + if (ref && ref->flash_offset != REF_EMPTY_NODE) + ref++; + + while (i) { + if (!ref) { + dbg_memalloc("Allocating new refblock linked from %p\n", p); + ref = *p = jffs2_alloc_refblock(); + if (!ref) + return -ENOMEM; + } + if (ref->flash_offset == REF_LINK_NODE) { + p = &ref->next_in_ino; + ref = *p; + continue; + } + i--; + ref++; } - c->reserved_refs = nr; - return 0; -} + jeb->allocated_refs = nr; -struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void) -{ - struct jffs2_raw_node_ref *ret; - ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); - dbg_memalloc("%p\n", ret); - return ret; + dbg_memalloc("Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p)\n", + nr, jeb->offset, jeb->last_node, jeb->last_node->flash_offset, + jeb->last_node->next_in_ino); + + return 0; } -void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) +void jffs2_free_refblock(struct jffs2_raw_node_ref *x) { dbg_memalloc("%p\n", x); kmem_cache_free(raw_node_ref_slab, x); diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 0e82979c741c..5d36e9b4d7c5 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -954,18 +954,16 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) for (i=0; inr_blocks; i++) { this = c->blocks[i].first_node; while (this) { - next = this->next_phys; - __jffs2_free_raw_node_ref(this); + if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE) + next = this[REFS_PER_BLOCK].next_in_ino; + else + next = NULL; + + jffs2_free_refblock(this); this = next; } c->blocks[i].first_node = c->blocks[i].last_node = NULL; } - this = c->refs; - while (this) { - next = this->next_in_ino; - __jffs2_free_raw_node_ref(this); - this = next; - } } struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) @@ -1060,32 +1058,37 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, { struct jffs2_raw_node_ref *ref; - /* These will be preallocated _very_ shortly. */ - ref = c->refs; - if (!c->refs) { - JFFS2_WARNING("Using non-preallocated refs!\n"); - ref = __jffs2_alloc_raw_node_ref(); - BUG_ON(!ref); - WARN_ON(1); - } else { - c->refs = ref->next_in_ino; + BUG_ON(!jeb->allocated_refs); + jeb->allocated_refs--; + + ref = jeb->last_node; + + dbg_noderef("Last node at %p is (%08x,%p)\n", ref, ref->flash_offset, + ref->next_in_ino); + + while (ref->flash_offset != REF_EMPTY_NODE) { + if (ref->flash_offset == REF_LINK_NODE) + ref = ref->next_in_ino; + else + ref++; } - ref->next_phys = NULL; + dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, + ref->flash_offset, ofs, ref->next_in_ino, len); + ref->flash_offset = ofs; - if (!jeb->first_node) + 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 + BUG_ON(ref_offset(ref) != jeb->offset); + } else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) { + uint32_t last_len = ref_totlen(c, jeb, jeb->last_node); + + JFFS2_ERROR("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)+len, + ref_offset(jeb->last_node), + ref_offset(jeb->last_node)+last_len); + BUG(); } jeb->last_node = ref; @@ -1130,12 +1133,13 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb { 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); + if (unlikely(size > jeb->free_size)) { + printk(KERN_CRIT "Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n", + size, jeb->free_size, jeb->wasted_size); BUG(); } - if (jeb->last_node && ref_obsolete(jeb->last_node)) { + /* REF_EMPTY_NODE is !obsolete, so that works OK */ + if (ref_obsolete(jeb->last_node)) { #ifdef TEST_TOTLEN jeb->last_node->__totlen += size; #endif @@ -1168,7 +1172,7 @@ static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, jeb = &c->blocks[ref->flash_offset / c->sector_size]; /* Last node in block. Use free_space */ - if (ref != jeb->last_node) { + if (unlikely(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(); @@ -1183,17 +1187,13 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je { 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) { + if (unlikely(ret != ref->__totlen)) { + if (!jeb) + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + 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); @@ -1204,13 +1204,14 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je printk(KERN_CRIT "No next ref. 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); + + ret = ref->__totlen; } #endif /* TEST_TOTLEN */ return ret; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 6c92dc46fe9e..7ad8ee043880 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -80,7 +80,6 @@ struct jffs2_raw_node_ref for this object. If this _is_ the last, it points to the inode_cache, xattr_ref or xattr_datum instead. The common part of those structures has NULL in the first word. See jffs2_raw_ref_to_ic() below */ - struct jffs2_raw_node_ref *next_phys; uint32_t flash_offset; #define TEST_TOTLEN #ifdef TEST_TOTLEN @@ -88,7 +87,29 @@ struct jffs2_raw_node_ref #endif }; -#define ref_next(r) ((r)->next_phys) +#define REF_LINK_NODE ((int32_t)-1) +#define REF_EMPTY_NODE ((int32_t)-2) + +/* Use blocks of about 256 bytes */ +#define REFS_PER_BLOCK ((255/sizeof(struct jffs2_raw_node_ref))-1) + +static inline struct jffs2_raw_node_ref *ref_next(struct jffs2_raw_node_ref *ref) +{ + ref++; + + /* Link to another block of refs */ + if (ref->flash_offset == REF_LINK_NODE) { + ref = ref->next_in_ino; + if (!ref) + return ref; + } + + /* End of chain */ + if (ref->flash_offset == REF_EMPTY_NODE) + return NULL; + + return ref; +} static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw) { @@ -234,6 +255,7 @@ struct jffs2_eraseblock uint32_t wasted_size; uint32_t free_size; /* Note that sector_size - free_size is the address of the first free space */ + uint32_t allocated_refs; struct jffs2_raw_node_ref *first_node; struct jffs2_raw_node_ref *last_node; @@ -378,10 +400,9 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void); void jffs2_free_raw_inode(struct jffs2_raw_inode *); struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void); void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *); -int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, +int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int nr); -struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void); -void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); +void jffs2_free_refblock(struct jffs2_raw_node_ref *); 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); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 73a06d01db48..71d1630609a5 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -458,14 +458,13 @@ static inline int on_list(struct list_head *obj, struct list_head *head) void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) { struct jffs2_eraseblock *jeb; - struct jffs2_raw_node_ref *next_ref; int blocknr; struct jffs2_unknown_node n; int ret, addedsize; size_t retlen; uint32_t freed_len; - if(!ref) { + if(unlikely(!ref)) { printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); return; } @@ -683,54 +682,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref spin_unlock(&c->erase_completion_lock); } - - /* Merge with the next node in the physical list, if there is one - and if it's also obsolete and if it doesn't belong to any inode */ - next_ref = ref_next(ref); - - if (next_ref && ref_obsolete(next_ref) && !next_ref->next_in_ino) { - spin_lock(&c->erase_completion_lock); - -#ifdef TEST_TOTLEN - ref->__totlen += next_ref->__totlen; -#endif - ref->next_phys = ref_next(next_ref); - if (jeb->last_node == next_ref) jeb->last_node = ref; - if (jeb->gc_node == next_ref) { - /* gc will be happy continuing gc on this node */ - jeb->gc_node=ref; - } - spin_unlock(&c->erase_completion_lock); - - __jffs2_free_raw_node_ref(next_ref); - } - - /* Also merge with the previous node in the list, if there is one - and that one is obsolete */ - if (ref != jeb->first_node ) { - struct jffs2_raw_node_ref *p = jeb->first_node; - - spin_lock(&c->erase_completion_lock); - - while ((next_ref = ref_next(ref)) != ref) - p = next_ref; - - 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; - } - if (jeb->gc_node == ref) { - /* gc will be happy continuing gc on this node */ - jeb->gc_node=p; - } - p->next_phys = ref_next(ref); - __jffs2_free_raw_node_ref(ref); - } - spin_unlock(&c->erase_completion_lock); - } out_erase_sem: up(&c->erase_free_sem); } diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 743c9e52152d..cd4021bcb944 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -95,6 +95,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_dataflash(c) (0) #define jffs2_dataflash_setup(c) (0) #define jffs2_dataflash_cleanup(c) do {} while (0) +#define jffs2_nor_wbuf_flash(c) (0) #define jffs2_nor_wbuf_flash_setup(c) (0) #define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0) diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 523a8f330ef5..00e856e4fdbe 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -511,7 +511,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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))); + jeb->offset + je32_to_cpu(spr->offset) + + (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); ref = jffs2_alloc_xattr_ref(); if (!ref) { @@ -787,10 +788,12 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", infosize, sum_ofs, ret, retlen); - /* Waste remaining space */ - spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); - spin_unlock(&c->erase_completion_lock); + if (retlen) { + /* Waste remaining space */ + spin_lock(&c->erase_completion_lock); + jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); + spin_unlock(&c->erase_completion_lock); + } c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; @@ -836,6 +839,7 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) jffs2_sum_disable_collecting(c->summary); JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); + spin_lock(&c->erase_completion_lock); return 0; } diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index e16e45ea0474..2febece89062 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -156,72 +156,126 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock jffs2_erase_pending_trigger(c); } - /* Adjust its size counts accordingly */ - c->wasted_size += jeb->free_size; - c->free_size -= jeb->free_size; - jeb->wasted_size += jeb->free_size; - jeb->free_size = 0; + if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) { + uint32_t oldfree = jeb->free_size; + + jffs2_link_node_ref(c, jeb, + (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE, + oldfree, NULL); + /* convert to wasted */ + c->wasted_size += oldfree; + jeb->wasted_size += oldfree; + c->dirty_size -= oldfree; + jeb->dirty_size -= oldfree; + } jffs2_dbg_dump_block_lists_nolock(c); jffs2_dbg_acct_sanity_check_nolock(c,jeb); jffs2_dbg_acct_paranoia_check_nolock(c, jeb); } +static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_raw_node_ref *raw, + union jffs2_node_union *node) +{ + struct jffs2_node_frag *frag; + struct jffs2_full_dirent *fd; + + dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n", + node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype)); + + BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 && + je16_to_cpu(node->u.magic) != 0); + + switch (je16_to_cpu(node->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset)); + BUG_ON(!frag); + /* Find a frag which refers to the full_dnode we want to modify */ + while (!frag->node || frag->node->raw != raw) { + frag = frag_next(frag); + BUG_ON(!frag); + } + dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node); + return &frag->node->raw; + break; + + case JFFS2_NODETYPE_DIRENT: + for (fd = f->dents; fd; fd = fd->next) { + if (fd->raw == raw) { + dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd); + return &fd->raw; + } + } + BUG(); + default: + dbg_noderef("Don't care about replacing raw for nodetype %x\n", + je16_to_cpu(node->u.nodetype)); + break; + } + return NULL; +} + /* Recover from failure to write wbuf. Recover the nodes up to the * wbuf, not the one which we were starting to try to write. */ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) { struct jffs2_eraseblock *jeb, *new_jeb; - struct jffs2_raw_node_ref **first_raw, **raw; + struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL; size_t retlen; int ret; + int nr_refile = 0; unsigned char *buf; uint32_t start, end, ofs, len; jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; - if (jffs2_prealloc_raw_node_refs(c, jeb, c->reserved_refs + 1)) - return; - spin_lock(&c->erase_completion_lock); - jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); + spin_unlock(&c->erase_completion_lock); + + BUG_ON(!ref_obsolete(jeb->last_node)); /* Find the first node to be recovered, by skipping over every node which ends before the wbuf starts, or which is obsolete. */ - first_raw = &jeb->first_node; - while (*first_raw && - (ref_obsolete(*first_raw) || - (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { - D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", - ref_offset(*first_raw), ref_flags(*first_raw), - (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)), - c->wbuf_ofs)); - first_raw = &(*first_raw)->next_phys; + for (next = raw = jeb->first_node; next; raw = next) { + next = ref_next(raw); + + if (ref_obsolete(raw) || + (next && ref_offset(next) <= c->wbuf_ofs)) { + dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", + ref_offset(raw), ref_flags(raw), + (ref_offset(raw) + ref_totlen(c, jeb, raw)), + c->wbuf_ofs); + continue; + } + dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n", + ref_offset(raw), ref_flags(raw), + (ref_offset(raw) + ref_totlen(c, jeb, raw))); + + first_raw = raw; + break; } - if (!*first_raw) { + if (!first_raw) { /* All nodes were obsolete. Nothing to recover. */ D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n")); - spin_unlock(&c->erase_completion_lock); + c->wbuf_len = 0; return; } - start = ref_offset(*first_raw); - end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw); + start = ref_offset(first_raw); + end = ref_offset(jeb->last_node); + nr_refile = 1; - /* Find the last node to be recovered */ - raw = first_raw; - while ((*raw)) { - if (!ref_obsolete(*raw)) - end = ref_offset(*raw) + ref_totlen(c, jeb, *raw); + /* Count the number of refs which need to be copied */ + while ((raw = ref_next(raw)) != jeb->last_node) + nr_refile++; - raw = &(*raw)->next_phys; - } - spin_unlock(&c->erase_completion_lock); - - D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end)); + dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n", + start, end, end - start, nr_refile); buf = NULL; if (start < c->wbuf_ofs) { @@ -248,13 +302,24 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) kfree(buf); buf = NULL; read_failed: - first_raw = &(*first_raw)->next_phys; + first_raw = ref_next(first_raw); + nr_refile--; + while (first_raw && ref_obsolete(first_raw)) { + first_raw = ref_next(first_raw); + nr_refile--; + } + /* If this was the only node to be recovered, give up */ - if (!(*first_raw)) + if (!first_raw) { + c->wbuf_len = 0; return; + } /* It wasn't. Go on and try to recover nodes complete in the wbuf */ - start = ref_offset(*first_raw); + start = ref_offset(first_raw); + dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n", + start, end, end - start, nr_refile); + } else { /* Read succeeded. Copy the remaining data from the wbuf */ memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); @@ -263,7 +328,6 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. Either 'buf' contains the data, or we find it in the wbuf */ - /* ... and get an allocation of space from a shiny new block instead */ ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); if (ret) { @@ -271,6 +335,14 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) kfree(buf); return; } + + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); + if (ret) { + printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); + kfree(buf); + return; + } + ofs = write_ofs(c); if (end-start >= c->wbuf_pagesize) { @@ -304,7 +376,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) kfree(buf); if (retlen) - jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, *first_raw), NULL); + jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL); return; } @@ -314,12 +386,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) c->wbuf_ofs = ofs + towrite; memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ - kfree(buf); } else { /* OK, now we're left with the dregs in whichever buffer we're using */ if (buf) { memcpy(c->wbuf, buf, end-start); - kfree(buf); } else { memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); } @@ -331,62 +401,111 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) new_jeb = &c->blocks[ofs / c->sector_size]; spin_lock(&c->erase_completion_lock); - if (new_jeb->first_node) { - /* Odd, but possible with ST flash later maybe */ - new_jeb->last_node->next_phys = *first_raw; - } else { - new_jeb->first_node = *first_raw; - } - - raw = first_raw; - while (*raw) { - uint32_t rawlen = ref_totlen(c, jeb, *raw); + for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) { + uint32_t rawlen = ref_totlen(c, jeb, raw); + struct jffs2_inode_cache *ic; + struct jffs2_raw_node_ref *new_ref; + struct jffs2_raw_node_ref **adjust_ref = NULL; + struct jffs2_inode_info *f = NULL; D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n", - rawlen, ref_offset(*raw), ref_flags(*raw), ofs)); + rawlen, ref_offset(raw), ref_flags(raw), ofs)); + + ic = jffs2_raw_ref_to_ic(raw); + + /* Ick. This XATTR mess should be fixed shortly... */ + if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) { + struct jffs2_xattr_datum *xd = (void *)ic; + BUG_ON(xd->node != raw); + adjust_ref = &xd->node; + raw->next_in_ino = NULL; + ic = NULL; + } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) { + struct jffs2_xattr_datum *xr = (void *)ic; + BUG_ON(xr->node != raw); + adjust_ref = &xr->node; + raw->next_in_ino = NULL; + ic = NULL; + } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) { + struct jffs2_raw_node_ref **p = &ic->nodes; + + /* Remove the old node from the per-inode list */ + while (*p && *p != (void *)ic) { + if (*p == raw) { + (*p) = (raw->next_in_ino); + raw->next_in_ino = NULL; + break; + } + p = &((*p)->next_in_ino); + } - if (ref_obsolete(*raw)) { - /* Shouldn't really happen much */ - new_jeb->dirty_size += rawlen; - new_jeb->free_size -= rawlen; - c->dirty_size += rawlen; - } else { - new_jeb->used_size += rawlen; - new_jeb->free_size -= rawlen; + if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) { + /* If it's an in-core inode, then we have to adjust any + full_dirent or full_dnode structure to point to the + new version instead of the old */ + f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink); + if (IS_ERR(f)) { + /* Should never happen; it _must_ be present */ + JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", + ic->ino, PTR_ERR(f)); + BUG(); + } + /* We don't lock f->sem. There's a number of ways we could + end up in here with it already being locked, and nobody's + going to modify it on us anyway because we hold the + alloc_sem. We're only changing one ->raw pointer too, + which we can get away with without upsetting readers. */ + adjust_ref = jffs2_incore_replace_raw(c, f, raw, + (void *)(buf?:c->wbuf) + (ref_offset(raw) - start)); + } else if (unlikely(ic->state != INO_STATE_PRESENT && + ic->state != INO_STATE_CHECKEDABSENT && + ic->state != INO_STATE_GC)) { + JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state); + BUG(); + } + } + + new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic); + + if (adjust_ref) { + BUG_ON(*adjust_ref != raw); + *adjust_ref = new_ref; + } + if (f) + jffs2_gc_release_inode(c, f); + + if (!ref_obsolete(raw)) { jeb->dirty_size += rawlen; jeb->used_size -= rawlen; c->dirty_size += rawlen; + c->used_size -= rawlen; + raw->flash_offset = ref_offset(raw) | REF_OBSOLETE; + BUG_ON(raw->next_in_ino); } - c->free_size -= rawlen; - (*raw)->flash_offset = ofs | ref_flags(*raw); ofs += rawlen; - new_jeb->last_node = *raw; - - raw = &(*raw)->next_phys; } + kfree(buf); + /* Fix up the original jeb now it's on the bad_list */ - *first_raw = NULL; - if (first_raw == &jeb->first_node) { - jeb->last_node = NULL; + if (first_raw == jeb->first_node) { D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset)); list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; jffs2_erase_pending_trigger(c); } - else - jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys); jffs2_dbg_acct_sanity_check_nolock(c, jeb); - jffs2_dbg_acct_paranoia_check_nolock(c, jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); - jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); spin_unlock(&c->erase_completion_lock); - D1(printk(KERN_DEBUG "wbuf recovery completed OK\n")); + D1(printk(KERN_DEBUG "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", c->wbuf_ofs, c->wbuf_len)); + } /* Meaning of pad argument: @@ -400,6 +519,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) { + struct jffs2_eraseblock *wbuf_jeb; int ret; size_t retlen; @@ -417,7 +537,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if (!c->wbuf_len) /* already checked c->wbuf above */ return 0; - if (jffs2_prealloc_raw_node_refs(c, c->nextblock, c->reserved_refs + 1)) + wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; + if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1)) return -ENOMEM; /* claim remaining space on the page @@ -473,32 +594,29 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) /* Adjust free size of the block if we padded. */ if (pad) { - struct jffs2_eraseblock *jeb; uint32_t waste = c->wbuf_pagesize - c->wbuf_len; - jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; - D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", - (jeb==c->nextblock)?"next":"", jeb->offset)); + (wbuf_jeb==c->nextblock)?"next":"", wbuf_jeb->offset)); /* 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 < waste) { + if (wbuf_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, 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); + wbuf_jeb->offset, wbuf_jeb->free_size); BUG(); } spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); + jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); /* FIXME: that made it count as dirty. Convert to wasted */ - jeb->dirty_size -= waste; + wbuf_jeb->dirty_size -= waste; c->dirty_size -= waste; - jeb->wasted_size += waste; + wbuf_jeb->wasted_size += waste; c->wasted_size += waste; } else spin_lock(&c->erase_completion_lock); @@ -758,7 +876,8 @@ outerr: * This is the entry for flash write. * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev */ -int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) +int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf) { struct kvec vecs[1]; @@ -953,7 +1072,7 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo } D1(if (retval == 1) { printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset); - printk(KERN_WARNING "OOB at %08x was ", offset); + printk(KERN_WARNING "OOB at %08zx was ", offset); for (i=0; i < oob_size; i++) { printk("%02x ", buf[i]); } -- cgit v1.2.3 From 098a19811b483f8e047d8292641c88e776452de0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 30 May 2006 09:00:14 +0100 Subject: [JFFS2] Preallocate node refs for cleanmarker in summary scan Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 00e856e4fdbe..51bf1654ce3b 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -564,7 +564,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb struct jffs2_unknown_node crcnode; int ret, ofs; uint32_t crc; - int err; ofs = c->sector_size - sumsize; @@ -606,16 +605,20 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb dbg_summary("Summary : CLEANMARKER node \n"); + ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); + if (ret) + return ret; + 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); - if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) - return err; + if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) + return ret; } else if (jeb->first_node) { dbg_summary("CLEANMARKER node not first node in block " "(0x%08x)\n", jeb->offset); - if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) - return err; + if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) + return ret; } else { jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, je32_to_cpu(summary->cln_mkr), NULL); -- cgit v1.2.3 From 1046d88001e7b8819f60dece2eaf1b44bf4b4460 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 18 Jun 2006 22:44:21 +0100 Subject: [JFFS2] Check CRC32 on dirent and data nodes each time they're read Also, make sure dirents are marked REF_UNCHECKED when we 'discover' them through eraseblock summary. Signed-off-by: David Woodhouse --- fs/jffs2/readinode.c | 51 +++++++++++++++++++++++++++++++++++++-------------- fs/jffs2/summary.c | 2 +- 2 files changed, 38 insertions(+), 15 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 5351b34d5419..5ea4faafa2d3 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -116,19 +116,42 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r uint32_t *latest_mctime, uint32_t *mctime_ver) { struct jffs2_full_dirent *fd; + uint32_t crc; - /* The direntry nodes are checked during the flash scanning */ - BUG_ON(ref_flags(ref) == REF_UNCHECKED); /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ BUG_ON(ref_obsolete(ref)); - /* Sanity check */ - if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { - JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", - ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); + crc = crc32(0, rd, sizeof(*rd) - 8); + if (unlikely(crc != je32_to_cpu(rd->node_crc))) { + JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n", + ref_offset(ref), je32_to_cpu(rd->node_crc), crc); return 1; } + /* If we've never checked the CRCs on this node, check them now */ + if (ref_flags(ref) == REF_UNCHECKED) { + struct jffs2_eraseblock *jeb; + int len; + + /* Sanity check */ + if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { + JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", + ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); + return 1; + } + + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + len = ref_totlen(c, jeb, ref); + + spin_lock(&c->erase_completion_lock); + jeb->used_size += len; + jeb->unchecked_size -= len; + c->used_size += len; + c->unchecked_size -= len; + ref->flash_offset = ref_offset(ref) | REF_PRISTINE; + spin_unlock(&c->erase_completion_lock); + } + fd = jffs2_alloc_full_dirent(rd->nsize + 1); if (unlikely(!fd)) return -ENOMEM; @@ -198,10 +221,18 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref struct jffs2_tmp_dnode_info *tn; uint32_t len, csize; int ret = 1; + uint32_t crc; /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ BUG_ON(ref_obsolete(ref)); + crc = crc32(0, rd, sizeof(*rd) - 8); + if (unlikely(crc != je32_to_cpu(rd->node_crc))) { + JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n", + ref_offset(ref), je32_to_cpu(rd->node_crc), crc); + return 1; + } + tn = jffs2_alloc_tmp_dnode_info(); if (!tn) { JFFS2_ERROR("failed to allocate tn (%zu bytes).\n", sizeof(*tn)); @@ -213,14 +244,6 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref /* If we've never checked the CRCs on this node, check them now */ if (ref_flags(ref) == REF_UNCHECKED) { - uint32_t crc; - - crc = crc32(0, rd, sizeof(*rd) - 8); - if (unlikely(crc != je32_to_cpu(rd->node_crc))) { - JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", - ref_offset(ref), je32_to_cpu(rd->node_crc), crc); - goto free_out; - } /* Sanity checks */ if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) || diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 51bf1654ce3b..0b02fc79e4d1 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -453,7 +453,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras return -ENOMEM; } - fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_PRISTINE, + fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_UNCHECKED, PAD(je32_to_cpu(spd->totlen)), ic); fd->next = NULL; -- cgit v1.2.3 From d6e05edc59ecd79e8badf440c0d295a979bdfa3e Mon Sep 17 00:00:00 2001 From: Andreas Mohr Date: Mon, 26 Jun 2006 18:35:02 +0200 Subject: spelling fixes acquired (aquired) contiguous (contigious) successful (succesful, succesfull) surprise (suprise) whether (weather) some other misspellings Signed-off-by: Andreas Mohr Signed-off-by: Adrian Bunk --- arch/i386/kernel/cpu/cyrix.c | 2 +- arch/i386/kernel/i8259.c | 2 +- arch/mips/momentum/ocelot_g/gt-irq.c | 4 ++-- arch/powerpc/platforms/cell/spufs/switch.c | 2 +- arch/powerpc/platforms/pseries/eeh_cache.c | 2 +- arch/s390/kernel/vtime.c | 2 +- arch/um/drivers/ubd_kern.c | 2 +- arch/x86_64/kernel/i8259.c | 2 +- block/as-iosched.c | 2 +- block/ll_rw_blk.c | 4 ++-- drivers/atm/firestream.c | 2 +- drivers/char/agp/amd-k7-agp.c | 2 +- drivers/char/agp/ati-agp.c | 2 +- drivers/char/agp/efficeon-agp.c | 2 +- drivers/char/rio/riointr.c | 2 +- drivers/hwmon/asb100.c | 2 +- drivers/hwmon/lm78.c | 2 +- drivers/hwmon/lm80.c | 2 +- drivers/hwmon/lm87.c | 2 +- drivers/hwmon/sis5595.c | 2 +- drivers/hwmon/smsc47m1.c | 2 +- drivers/hwmon/w83627hf.c | 2 +- drivers/hwmon/w83781d.c | 2 +- drivers/hwmon/w83792d.c | 2 +- drivers/ide/ide-disk.c | 2 +- drivers/ide/ide-io.c | 2 +- drivers/ieee1394/hosts.c | 2 +- drivers/ieee1394/ieee1394_core.h | 2 +- drivers/isdn/divert/isdn_divert.c | 2 +- drivers/media/video/bt8xx/bttv-cards.c | 2 +- drivers/net/3c501.c | 4 ++-- drivers/net/irda/irport.c | 2 +- drivers/net/pcmcia/smc91c92_cs.c | 2 +- drivers/net/wireless/ipw2100.c | 2 +- drivers/pci/pci.c | 2 +- drivers/s390/scsi/zfcp_erp.c | 14 +++++++------- drivers/scsi/NCR5380.c | 2 +- drivers/scsi/advansys.c | 2 +- drivers/scsi/dc395x.c | 2 +- drivers/scsi/ibmmca.c | 8 ++++---- drivers/scsi/ips.c | 4 ++-- drivers/scsi/st.c | 2 +- fs/9p/mux.c | 2 +- fs/aio.c | 2 +- fs/jffs2/summary.c | 2 +- fs/jfs/jfs_extent.c | 8 ++++---- include/asm-i386/system.h | 2 +- include/asm-m32r/system.h | 2 +- include/linux/sunrpc/gss_api.h | 2 +- lib/kernel_lock.c | 4 ++-- mm/page_alloc.c | 2 +- mm/readahead.c | 4 ++-- net/sunrpc/auth_gss/gss_krb5_mech.c | 2 +- net/sunrpc/auth_gss/gss_spkm3_mech.c | 2 +- sound/core/seq/seq_memory.h | 2 +- sound/oss/sb_ess.c | 28 ++++++++++++++-------------- sound/pci/cs5535audio/cs5535audio_pcm.c | 2 +- 57 files changed, 88 insertions(+), 88 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c index fc32c8028e24..f03b7f94c304 100644 --- a/arch/i386/kernel/cpu/cyrix.c +++ b/arch/i386/kernel/cpu/cyrix.c @@ -354,7 +354,7 @@ static void __init init_nsc(struct cpuinfo_x86 *c) * This function only handles the GX processor, and kicks every * thing else to the Cyrix init function above - that should * cover any processors that might have been branded differently - * after NSC aquired Cyrix. + * after NSC acquired Cyrix. * * If this breaks your GX1 horribly, please e-mail * info-linux@ldcmail.amd.com to tell us. diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index b7636b96e104..c1a42feba286 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -175,7 +175,7 @@ static void mask_and_ack_8259A(unsigned int irq) * Lightweight spurious IRQ detection. We do not want * to overdo spurious IRQ handling - it's usually a sign * of hardware problems, so we only do the checks we can - * do without slowing down good hardware unnecesserily. + * do without slowing down good hardware unnecessarily. * * Note that IRQ7 and IRQ15 (the two spurious IRQs * usually resulting from the 8259A-1|2 PICs) occur diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c index e5eceed1beff..8bd9b844fa9e 100644 --- a/arch/mips/momentum/ocelot_g/gt-irq.c +++ b/arch/mips/momentum/ocelot_g/gt-irq.c @@ -59,7 +59,7 @@ void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr) * bit_num - Indicates which bit number in the cause register * * Outputs : - * 1 if succesful, 0 if failure + * 1 if successful, 0 if failure */ int enable_galileo_irq(int int_cause, int bit_num) { @@ -83,7 +83,7 @@ int enable_galileo_irq(int int_cause, int bit_num) * bit_num - Indicates which bit number in the cause register * * Outputs : - * 1 if succesful, 0 if failure + * 1 if successful, 0 if failure */ int disable_galileo_irq(int int_cause, int bit_num) { diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index b30e55dab832..3068b429b031 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -2100,7 +2100,7 @@ EXPORT_SYMBOL_GPL(spu_save); * @spu: pointer to SPU iomem structure. * * Perform harvest + restore, as we may not be coming - * from a previous succesful save operation, and the + * from a previous successful save operation, and the * hardware state is unknown. */ int spu_restore(struct spu_state *new, struct spu *spu) diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index 98c23aec85be..c37a8497c60f 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -287,7 +287,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev) * find the pci device that corresponds to a given address. * This routine scans all pci busses to build the cache. * Must be run late in boot process, after the pci controllers - * have been scaned for devices (after all device resources are known). + * have been scanned for devices (after all device resources are known). */ void __init pci_addr_cache_build(void) { diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index dfe6f0856617..1f0439dc245a 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -356,7 +356,7 @@ static void internal_add_vtimer(struct vtimer_list *timer) set_vtimer(event->expires); spin_unlock_irqrestore(&vt_list->lock, flags); - /* release CPU aquired in prepare_vtimer or mod_virt_timer() */ + /* release CPU acquired in prepare_vtimer or mod_virt_timer() */ put_cpu(); } diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0897852b09a3..290cec6d69e2 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1222,7 +1222,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared, } } - /* Succesful return case! */ + /* Successful return case! */ if(backing_file_out == NULL) return(fd); diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 5ecd34ab8c2b..573990a6d668 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -278,7 +278,7 @@ static void mask_and_ack_8259A(unsigned int irq) * Lightweight spurious IRQ detection. We do not want * to overdo spurious IRQ handling - it's usually a sign * of hardware problems, so we only do the checks we can - * do without slowing down good hardware unnecesserily. + * do without slowing down good hardware unnecessarily. * * Note that IRQ7 and IRQ15 (the two spurious IRQs * usually resulting from the 8259A-1|2 PICs) occur diff --git a/block/as-iosched.c b/block/as-iosched.c index 1ec5df466708..3af31ed49a9c 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -892,7 +892,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq) } /* - * as_can_anticipate indicates weather we should either run arq + * as_can_anticipate indicates whether we should either run arq * or keep anticipating a better request. */ static int as_can_anticipate(struct as_data *ad, struct as_rq *arq) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 0603ab2f3692..c04422a502da 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -2745,7 +2745,7 @@ static int attempt_merge(request_queue_t *q, struct request *req, return 0; /* - * not contigious + * not contiguous */ if (req->sector + req->nr_sectors != next->sector) return 0; @@ -3415,7 +3415,7 @@ static struct notifier_block blk_cpu_notifier = { * * Description: * Ends all I/O on a request. It does not handle partial completions, - * unless the driver actually implements this in its completionc callback + * unless the driver actually implements this in its completion callback * through requeueing. Theh actual completion happens out-of-order, * through a softirq handler. The user must have registered a completion * callback through blk_queue_softirq_done(). diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 7f7ec288824d..f2eeaf9dc56a 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -951,7 +951,7 @@ static int fs_open(struct atm_vcc *atm_vcc) it most likely that the chip will notice it. It also prevents us from having to wait for completion. On the other hand, we may need to wait for completion anyway, to see if it completed - succesfully. */ + successfully. */ switch (atm_vcc->qos.aal) { case ATM_AAL2: diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 1f776651ac64..51d0d562d01e 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -118,7 +118,7 @@ static int amd_create_gatt_pages(int nr_tables) return retval; } -/* Since we don't need contigious memory we just try +/* Since we don't need contiguous memory we just try * to get the gatt table once */ diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 06fd10ba0c5e..160564345993 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -261,7 +261,7 @@ static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state) #endif /* - *Since we don't need contigious memory we just try + *Since we don't need contiguous memory we just try * to get the gatt table once */ diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 86a966b65236..b788b0a3bbf3 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -177,7 +177,7 @@ static int efficeon_free_gatt_table(struct agp_bridge_data *bridge) /* - * Since we don't need contigious memory we just try + * Since we don't need contiguous memory we just try * to get the gatt table once */ diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index eec1fea0cb92..0bd09040a5c0 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c @@ -546,7 +546,7 @@ static void RIOReceive(struct rio_info *p, struct Port *PortP) ** run out of space it will be set to the offset of the ** next byte to copy from the packet data area. The packet ** length field is decremented by the number of bytes that - ** we succesfully removed from the packet. When this reaches + ** we successfully removed from the packet. When this reaches ** zero, we reset the offset pointer to be zero, and free ** the packet from the front of the queue. */ diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 65b2709f750c..facc1ccb8338 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -341,7 +341,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 94be3d797e61..a6ce7abf8602 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -358,7 +358,7 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr) /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index f72120d08c4c..b4ccdfc01203 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -253,7 +253,7 @@ set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]); /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index e229daf666de..e6c1b638c971 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -421,7 +421,7 @@ static void set_fan_min(struct device *dev, const char *buf, int nr) /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan clock divider. This follows the principle - of least suprise; the user doesn't expect the fan minimum to change just + of least surprise; the user doesn't expect the fan minimum to change just because the divider changed. */ static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 6f3fda73f70c..063f71c5f07e 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -380,7 +380,7 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr) /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 7732aec54594..825e8f72698f 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -207,7 +207,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan clock divider. This follows the principle - of least suprise; the user doesn't expect the fan minimum to change just + of least surprise; the user doesn't expect the fan minimum to change just because the divider changed. */ static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 71fb7f1af8f5..79368d53c363 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -781,7 +781,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index e4c700356c44..7be469ed0f8f 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -630,7 +630,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 4ef884c216e2..e407c74bda35 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -463,7 +463,7 @@ show_fan_div(struct device *dev, struct device_attribute *attr, /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index a5017de72da5..f033d732f387 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -37,7 +37,7 @@ * Version 1.15 convert all calls to ide_raw_taskfile * since args will return register content. * Version 1.16 added suspend-resume-checkpower - * Version 1.17 do flush on standy, do flush on ATA < ATA6 + * Version 1.17 do flush on standby, do flush on ATA < ATA6 * fix wcache setup. */ diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 622a55c72f03..05ba8e01e635 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -1665,7 +1665,7 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) * Initialize a request before we fill it in and send it down to * ide_do_drive_cmd. Commands must be set up by this function. Right * now it doesn't do a lot, but if that changes abusers will have a - * nasty suprise. + * nasty surprise. */ void ide_init_drive_cmd (struct request *rq) diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c index 2d47b11777a5..ad49c040b674 100644 --- a/drivers/ieee1394/hosts.c +++ b/drivers/ieee1394/hosts.c @@ -103,7 +103,7 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data) * driver specific parts, enable the controller and make it available * to the general subsystem using hpsb_add_host(). * - * Return Value: a pointer to the &hpsb_host if succesful, %NULL if + * Return Value: a pointer to the &hpsb_host if successful, %NULL if * no memory was available. */ static DEFINE_MUTEX(host_num_alloc); diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index e7b55e895f50..0ecbf335c64f 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -139,7 +139,7 @@ int hpsb_bus_reset(struct hpsb_host *host); /* * Hand over received selfid packet to the core. Complement check (second - * quadlet is complement of first) is expected to be done and succesful. + * quadlet is complement of first) is expected to be done and successful. */ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid); diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c index f1a1f9a9b88e..1f5ebe9ee72c 100644 --- a/drivers/isdn/divert/isdn_divert.c +++ b/drivers/isdn/divert/isdn_divert.c @@ -592,7 +592,7 @@ static int put_address(char *st, u_char *p, int len) } /* put_address */ /*************************************/ -/* report a succesfull interrogation */ +/* report a successful interrogation */ /*************************************/ static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs) { char *src = ic->parm.dss1_io.data; diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 3116345c93b1..e68a6d2fff24 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -4848,7 +4848,7 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) * * The IVC120G security card has 4 i2c controlled TDA8540 matrix * swichers to provide 16 channels to MUX0. The TDA8540's have - * 4 indepedant outputs and as such the IVC120G also has the + * 4 independent outputs and as such the IVC120G also has the * optional "Monitor Out" bus. This allows the card to be looking * at one input while the monitor is looking at another. * diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index bb44509fd404..07136ec423bd 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -508,11 +508,11 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) * speak of. We simply pull the packet out of its PIO buffer (which is slow) * and queue it for the kernel. Then we reset the card for the next packet. * - * We sometimes get suprise interrupts late both because the SMP IRQ delivery + * We sometimes get surprise interrupts late both because the SMP IRQ delivery * is message passing and because the card sometimes seems to deliver late. I * think if it is part way through a receive and the mode is changed it carries * on receiving and sends us an interrupt. We have to band aid all these cases - * to get a sensible 150kbytes/second performance. Even then you want a small + * to get a sensible 150kBytes/second performance. Even then you want a small * TCP window. */ diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 98fa5319e5cc..44efd49bf4a9 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -386,7 +386,7 @@ static int __irport_change_speed(struct irda_task *task) /* Locking notes : this function may be called from irq context with * spinlock, via irport_write_wakeup(), or from non-interrupt without * spinlock (from the task timer). Yuck ! - * This is ugly, and unsafe is the spinlock is not already aquired. + * This is ugly, and unsafe is the spinlock is not already acquired. * This will be fixed when irda-task get rewritten. * Jean II */ if (!spin_is_locked(&self->lock)) { diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index e74bf5014ef6..a73d54553030 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1883,7 +1883,7 @@ static void smc_reset(struct net_device *dev) /* Set the Window 1 control, configuration and station addr registers. No point in writing the I/O base register ;-> */ SMC_SELECT_BANK(1); - /* Automatically release succesfully transmitted packets, + /* Automatically release successfully transmitted packets, Accept link errors, counter and Tx error interrupts. */ outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE, ioaddr + CONTROL); diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 72335c8eb97f..94aeb23a7729 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1485,7 +1485,7 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv) * * Sending the PREPARE_FOR_POWER_DOWN will restrict the * hardware from going into standby mode and will transition - * out of D0-standy if it is already in that state. + * out of D0-standby if it is already in that state. * * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the * driver upon completion. Once received, the driver can diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d408a3c30426..23d3b17c8cad 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -369,7 +369,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) /* * Give firmware a chance to be called, such as ACPI _PRx, _PSx - * Firmware method after natice method ? + * Firmware method after native method ? */ if (platform_pci_set_power_state) platform_pci_set_power_state(dev, state); diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 4682c8b8bd24..909731b99d26 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -167,7 +167,7 @@ zfcp_fsf_scsi_er_timeout_handler(unsigned long data) * initiates adapter recovery which is done * asynchronously * - * returns: 0 - initiated action succesfully + * returns: 0 - initiated action successfully * <0 - failed to initiate action */ int @@ -203,7 +203,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask) * purpose: Wrappper for zfcp_erp_adapter_reopen_internal * used to ensure the correct locking * - * returns: 0 - initiated action succesfully + * returns: 0 - initiated action successfully * <0 - failed to initiate action */ int @@ -469,7 +469,7 @@ zfcp_test_link(struct zfcp_port *port) * initiates Forced Reopen recovery which is done * asynchronously * - * returns: 0 - initiated action succesfully + * returns: 0 - initiated action successfully * <0 - failed to initiate action */ static int @@ -509,7 +509,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask) * purpose: Wrappper for zfcp_erp_port_forced_reopen_internal * used to ensure the correct locking * - * returns: 0 - initiated action succesfully + * returns: 0 - initiated action successfully * <0 - failed to initiate action */ int @@ -536,7 +536,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask) * initiates Reopen recovery which is done * asynchronously * - * returns: 0 - initiated action succesfully + * returns: 0 - initiated action successfully * <0 - failed to initiate action */ static int @@ -605,7 +605,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask) * initiates Reopen recovery which is done * asynchronously * - * returns: 0 - initiated action succesfully + * returns: 0 - initiated action successfully * <0 - failed to initiate action */ static int @@ -1805,7 +1805,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear) * purpose: Wrappper for zfcp_erp_port_reopen_all_internal * used to ensure the correct locking * - * returns: 0 - initiated action succesfully + * returns: 0 - initiated action successfully * <0 - failed to initiate action */ int diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index fa57e0b4a5fd..75f2f7ae2a8e 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -500,7 +500,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) /* * Function : int should_disconnect (unsigned char cmd) * - * Purpose : decide weather a command would normally disconnect or + * Purpose : decide whether a command would normally disconnect or * not, since if it won't disconnect we should go to sleep. * * Input : cmd - opcode of SCSI command diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 5ee47555a8af..dd9fb3d91000 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -12374,7 +12374,7 @@ AscInitFromEEP(ASC_DVC_VAR *asc_dvc) ASC_PRINT1( "AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i); } else { - ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM."); + ASC_PRINT("AscInitFromEEP: Successfully re-wrote EEPROM.\n"); } } return (warn_code); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 183245254931..58b0748045ee 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -3771,7 +3771,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, * @target: The target for the new device. * @lun: The lun for the new device. * - * Return the new device if succesfull or NULL on failure. + * Return the new device if successful or NULL on failure. **/ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, u8 target, u8 lun) diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 115f55471ed3..497f6642b2dc 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -760,7 +760,7 @@ static int device_inquiry(int host_index, int ldn) while (!got_interrupt(host_index)) barrier(); - /*if command succesful, break */ + /*if command successful, break */ if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) return 1; } @@ -885,7 +885,7 @@ static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, while (!got_interrupt(host_index)) barrier(); - /*if command succesful, break */ + /*if command successful, break */ if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) return 1; } @@ -921,7 +921,7 @@ static int immediate_feature(int host_index, unsigned int speed, unsigned int ti return 2; } else global_command_error_excuse = 0; - /*if command succesful, break */ + /*if command successful, break */ if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) return 1; } @@ -959,7 +959,7 @@ static int immediate_reset(int host_index, unsigned int ldn) /* did not work, finish */ return 1; } - /*if command succesful, break */ + /*if command successful, break */ if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED) return 1; } diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 5353b28b2939..78f2ff736c3e 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -6438,7 +6438,7 @@ ips_erase_bios(ips_ha_t * ha) /* VPP failure */ return (1); - /* check for succesful flash */ + /* check for successful flash */ if (status & 0x30) /* sequence error */ return (1); @@ -6550,7 +6550,7 @@ ips_erase_bios_memio(ips_ha_t * ha) /* VPP failure */ return (1); - /* check for succesful flash */ + /* check for successful flash */ if (status & 0x30) /* sequence error */ return (1); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 1272dd249af3..b5218fc0ac86 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -2818,7 +2818,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon (cmdstatp->sense_hdr.sense_key == NO_SENSE || cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && undone == 0) { - ioctl_result = 0; /* EOF written succesfully at EOM */ + ioctl_result = 0; /* EOF written successfully at EOM */ if (fileno >= 0) fileno++; STps->drv_file = fileno; diff --git a/fs/9p/mux.c b/fs/9p/mux.c index f4407eb276c7..12e1baa4508d 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -712,7 +712,7 @@ static void v9fs_read_work(void *a) * v9fs_send_request - send 9P request * The function can sleep until the request is scheduled for sending. * The function can be interrupted. Return from the function is not - * a guarantee that the request is sent succesfully. Can return errors + * a guarantee that the request is sent successfully. Can return errors * that can be retrieved by PTR_ERR macros. * * @m: mux data diff --git a/fs/aio.c b/fs/aio.c index 8c34a62df7d7..950630187acc 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -641,7 +641,7 @@ static inline int __queue_kicked_iocb(struct kiocb *iocb) * invoked both for initial i/o submission and * subsequent retries via the aio_kick_handler. * Expects to be invoked with iocb->ki_ctx->lock - * already held. The lock is released and reaquired + * already held. The lock is released and reacquired * as needed during processing. * * Calls the iocb retry method (already setup for the diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 0b02fc79e4d1..be1acc3dad97 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -43,7 +43,7 @@ int jffs2_sum_init(struct jffs2_sb_info *c) return -ENOMEM; } - dbg_summary("returned succesfully\n"); + dbg_summary("returned successfully\n"); return 0; } diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 5549378358bf..4d52593a5fc6 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -126,7 +126,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) /* allocate the disk blocks for the extent. initially, extBalloc() * will try to allocate disk blocks for the requested size (xlen). - * if this fails (xlen contigious free blocks not avaliable), it'll + * if this fails (xlen contiguous free blocks not avaliable), it'll * try to allocate a smaller number of blocks (producing a smaller * extent), with this smaller number of blocks consisting of the * requested number of blocks rounded down to the next smaller @@ -493,7 +493,7 @@ int extFill(struct inode *ip, xad_t * xp) * * initially, we will try to allocate disk blocks for the * requested size (nblocks). if this fails (nblocks - * contigious free blocks not avaliable), we'll try to allocate + * contiguous free blocks not avaliable), we'll try to allocate * a smaller number of blocks (producing a smaller extent), with * this smaller number of blocks consisting of the requested * number of blocks rounded down to the next smaller power of 2 @@ -529,7 +529,7 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) /* get the number of blocks to initially attempt to allocate. * we'll first try the number of blocks requested unless this - * number is greater than the maximum number of contigious free + * number is greater than the maximum number of contiguous free * blocks in the map. in that case, we'll start off with the * maximum free. */ @@ -586,7 +586,7 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) * in place. if this fails, we'll try to move the extent * to a new set of blocks. if moving the extent, we initially * will try to allocate disk blocks for the requested size - * (nnew). if this fails (nnew contigious free blocks not + * (nnew). if this fails (new contiguous free blocks not * avaliable), we'll try to allocate a smaller number of * blocks (producing a smaller extent), with this smaller * number of blocks consisting of the requested number of diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index 0249f912a29c..cab0180567f9 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -427,7 +427,7 @@ static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long l * does not enforce ordering, since there is no data dependency between * the read of "a" and the read of "b". Therefore, on some CPUs, such * as Alpha, "y" could be set to 3 and "x" to 0. Use rmb() - * in cases like thiswhere there are no data dependencies. + * in cases like this where there are no data dependencies. **/ #define read_barrier_depends() do { } while(0) diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h index 33567e8bfe6b..66c4742f09e7 100644 --- a/include/asm-m32r/system.h +++ b/include/asm-m32r/system.h @@ -318,7 +318,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) * does not enforce ordering, since there is no data dependency between * the read of "a" and the read of "b". Therefore, on some CPUs, such * as Alpha, "y" could be set to 3 and "x" to 0. Use rmb() - * in cases like thiswhere there are no data dependencies. + * in cases like this where there are no data dependencies. **/ #define read_barrier_depends() do { } while (0) diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 9b8bcf125c18..6e112cc5cdda 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h @@ -126,7 +126,7 @@ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); /* Just increments the mechanism's reference count and returns its input: */ struct gss_api_mech * gss_mech_get(struct gss_api_mech *); -/* For every succesful gss_mech_get or gss_mech_get_by_* call there must be a +/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a * corresponding call to gss_mech_put. */ void gss_mech_put(struct gss_api_mech *); diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c index cb5490ec00f2..e713e86811ae 100644 --- a/lib/kernel_lock.c +++ b/lib/kernel_lock.c @@ -14,7 +14,7 @@ * The 'big kernel semaphore' * * This mutex is taken and released recursively by lock_kernel() - * and unlock_kernel(). It is transparently dropped and reaquired + * and unlock_kernel(). It is transparently dropped and reacquired * over schedule(). It is used to protect legacy code that hasn't * been migrated to a proper locking design yet. * @@ -92,7 +92,7 @@ void __lockfunc unlock_kernel(void) * The 'big kernel lock' * * This spinlock is taken and released recursively by lock_kernel() - * and unlock_kernel(). It is transparently dropped and reaquired + * and unlock_kernel(). It is transparently dropped and reacquired * over schedule(). It is used to protect legacy code that hasn't * been migrated to a proper locking design yet. * diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 6c1174fcf52c..9f86191bb632 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -266,7 +266,7 @@ static inline void rmv_page_order(struct page *page) * satisfies the following equation: * P = B & ~(1 << O) * - * Assumption: *_mem_map is contigious at least up to MAX_ORDER + * Assumption: *_mem_map is contiguous at least up to MAX_ORDER */ static inline struct page * __page_find_buddy(struct page *page, unsigned long page_idx, unsigned int order) diff --git a/mm/readahead.c b/mm/readahead.c index e39e416860d7..aa7ec424656a 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -390,8 +390,8 @@ int do_page_cache_readahead(struct address_space *mapping, struct file *filp, * Read 'nr_to_read' pages starting at page 'offset'. If the flag 'block' * is set wait till the read completes. Otherwise attempt to read without * blocking. - * Returns 1 meaning 'success' if read is succesfull without switching off - * readhaead mode. Otherwise return failure. + * Returns 1 meaning 'success' if read is successful without switching off + * readahead mode. Otherwise return failure. */ static int blockable_page_cache_readahead(struct address_space *mapping, struct file *filp, diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 129e2bd36aff..b8714a87b34c 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c @@ -169,7 +169,7 @@ gss_import_sec_context_kerberos(const void *p, } ctx_id->internal_ctx_id = ctx; - dprintk("RPC: Succesfully imported new context.\n"); + dprintk("RPC: Successfully imported new context.\n"); return 0; out_err_free_key2: diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index 5bf11ccba7cd..3d0432aa45c1 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c @@ -201,7 +201,7 @@ gss_import_sec_context_spkm3(const void *p, size_t len, ctx_id->internal_ctx_id = ctx; - dprintk("Succesfully imported new spkm context.\n"); + dprintk("Successfully imported new spkm context.\n"); return 0; out_err_free_key2: diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h index 39c60d9e1efc..63e91431a29f 100644 --- a/sound/core/seq/seq_memory.h +++ b/sound/core/seq/seq_memory.h @@ -31,7 +31,7 @@ struct snd_seq_event_cell { struct snd_seq_event_cell *next; /* next cell */ }; -/* design note: the pool is a contigious block of memory, if we dynamicly +/* design note: the pool is a contiguous block of memory, if we dynamicly want to add additional cells to the pool be better store this in another pool as we need to know the base address of the pool when releasing memory. */ diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c index fae05fe3de43..180e95c87e3e 100644 --- a/sound/oss/sb_ess.c +++ b/sound/oss/sb_ess.c @@ -97,19 +97,19 @@ * * The documentation is an adventure: it's close but not fully accurate. I * found out that after a reset some registers are *NOT* reset, though the - * docs say the would be. Interresting ones are 0x7f, 0x7d and 0x7a. They are - * related to the Audio 2 channel. I also was suprised about the consequenses + * docs say the would be. Interesting ones are 0x7f, 0x7d and 0x7a. They are + * related to the Audio 2 channel. I also was surprised about the consequences * of writing 0x00 to 0x7f (which should be done by reset): The ES1887 moves * into ES1888 mode. This means that it claims IRQ 11, which happens to be my * ISDN adapter. Needless to say it no longer worked. I now understand why * after rebooting 0x7f already was 0x05, the value of my choice: the BIOS * did it. * - * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is decribed - * as if it's exactly the same as register 0xa1. This is *NOT* true. The - * description of 0x70 in ES1869 docs is accurate however. + * Oh, and this is another trap: in ES1887 docs mixer register 0x70 is + * described as if it's exactly the same as register 0xa1. This is *NOT* true. + * The description of 0x70 in ES1869 docs is accurate however. * Well, the assumption about ES1869 was wrong: register 0x70 is very much - * like register 0xa1, except that bit 7 is allways 1, whatever you want + * like register 0xa1, except that bit 7 is always 1, whatever you want * it to be. * * When using audio 2 mixer register 0x72 seems te be meaningless. Only 0xa2 @@ -117,10 +117,10 @@ * * Software reset not being able to reset all registers is great! Especially * the fact that register 0x78 isn't reset is great when you wanna change back - * to single dma operation (simplex): audio 2 is still operation, and uses the - * same dma as audio 1: your ess changes into a funny echo machine. + * to single dma operation (simplex): audio 2 is still operational, and uses + * the same dma as audio 1: your ess changes into a funny echo machine. * - * Received the new that ES1688 is detected as a ES1788. Did some thinking: + * Received the news that ES1688 is detected as a ES1788. Did some thinking: * the ES1887 detection scheme suggests in step 2 to try if bit 3 of register * 0x64 can be changed. This is inaccurate, first I inverted the * check: "If * can be modified, it's a 1688", which lead to a correct detection @@ -135,7 +135,7 @@ * About recognition of ESS chips * * The distinction of ES688, ES1688, ES1788, ES1887 and ES1888 is described in - * a (preliminary ??) datasheet on ES1887. It's aim is to identify ES1887, but + * a (preliminary ??) datasheet on ES1887. Its aim is to identify ES1887, but * during detection the text claims that "this chip may be ..." when a step * fails. This scheme is used to distinct between the above chips. * It appears however that some PnP chips like ES1868 are recognized as ES1788 @@ -156,9 +156,9 @@ * * The existing ES1688 support didn't take care of the ES1688+ recording * levels very well. Whenever a device was selected (recmask) for recording - * it's recording level was loud, and it couldn't be changed. The fact that + * its recording level was loud, and it couldn't be changed. The fact that * internal register 0xb4 could take care of RECLEV, didn't work meaning until - * it's value was restored every time the chip was reset; this reset the + * its value was restored every time the chip was reset; this reset the * value of 0xb4 too. I guess that's what 4front also had (have?) trouble with. * * About ES1887 support: @@ -169,9 +169,9 @@ * the latter case the recording volumes are 0. * Now recording levels of inputs can be controlled, by changing the playback * levels. Futhermore several devices can be recorded together (which is not - * possible with the ES1688. + * possible with the ES1688). * Besides the separate recording level control for each input, the common - * recordig level can also be controlled by RECLEV as described above. + * recording level can also be controlled by RECLEV as described above. * * Not only ES1887 have this recording mixer. I know the following from the * documentation: diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index f0a48693d687..5450a9e8f133 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -143,7 +143,7 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, if (dma->periods == periods && dma->period_bytes == period_bytes) return 0; - /* the u32 cast is okay because in snd*create we succesfully told + /* the u32 cast is okay because in snd*create we successfully told pci alloc that we're only 32 bit capable so the uppper will be 0 */ addr = (u32) substream->runtime->dma_addr; desc_addr = (u32) dma->desc_buf.addr; -- cgit v1.2.3 From c9f700f840bd481b3e01fcad1ba8da01794a6726 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sun, 11 Jun 2006 10:35:15 +0900 Subject: [JFFS2][XATTR] using 'delete marker' for xdatum/xref deletion - When xdatum is removed, a new xdatum with 'delete marker' is written. (version==0xffffffff means 'delete marker') - When xref is removed, a new xref with 'delete marker' is written. (odd-numbered xseqno means 'delete marker') - delete_xattr_(datum/xref)_delay() are new deletion functions are added. We can only use them if we can detect the target obsolete xdatum/xref as a orphan or errir one. (e.g when inode deletion, or detecting crc error) [1/3] jffs2-xattr-v6-01-delete_marker.patch Signed-off-by: KaiGai Kohei Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 19 +- fs/jffs2/gc.c | 5 +- fs/jffs2/jffs2_fs_sb.h | 3 + fs/jffs2/malloc.c | 2 + fs/jffs2/nodemgmt.c | 21 +- fs/jffs2/scan.c | 57 ++-- fs/jffs2/summary.c | 39 +-- fs/jffs2/xattr.c | 736 +++++++++++++++++++++++++++++++------------------ fs/jffs2/xattr.h | 40 ++- include/linux/jffs2.h | 1 + 10 files changed, 584 insertions(+), 339 deletions(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 1862e8bc101d..1644e3408852 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -230,7 +230,6 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, at the end of the linked list. Stash it and continue from the beginning of the list */ ic = (struct jffs2_inode_cache *)(*prev); - BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE); prev = &ic->nodes; continue; } @@ -254,7 +253,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, /* PARANOIA */ if (!ic) { - printk(KERN_WARNING "inode_cache not found in remove_node_refs()!!\n"); + JFFS2_WARNING("inode_cache/xattr_datum/xattr_ref" + " not found in remove_node_refs()!!\n"); return; } @@ -279,8 +279,19 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, printk("\n"); }); - if (ic->nodes == (void *)ic && ic->nlink == 0) - jffs2_del_ino_cache(c, ic); + switch (ic->class) { +#ifdef CONFIG_JFFS2_FS_XATTR + case RAWNODE_CLASS_XATTR_DATUM: + jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic); + break; + case RAWNODE_CLASS_XATTR_REF: + jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic); + break; +#endif + default: + if (ic->nodes == (void *)ic && ic->nlink == 0) + jffs2_del_ino_cache(c, ic); + } } void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 477c526d638b..f59b147661c9 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -275,13 +275,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) * 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); + ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw); } else { - ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic); + ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw); } goto release_sem; } diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 935fec1b1201..b98594992eed 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -119,8 +119,11 @@ struct jffs2_sb_info { #ifdef CONFIG_JFFS2_FS_XATTR #define XATTRINDEX_HASHSIZE (57) uint32_t highest_xid; + uint32_t highest_xseqno; struct list_head xattrindex[XATTRINDEX_HASHSIZE]; struct list_head xattr_unchecked; + struct list_head xattr_dead_list; + struct jffs2_xattr_ref *xref_dead_list; struct jffs2_xattr_ref *xref_temp; struct rw_semaphore xattr_sem; uint32_t xdatum_mem_usage; diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 4889d0700c0e..8310c95478e9 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -291,6 +291,7 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) memset(xd, 0, sizeof(struct jffs2_xattr_datum)); xd->class = RAWNODE_CLASS_XATTR_DATUM; + xd->node = (void *)xd; INIT_LIST_HEAD(&xd->xindex); return xd; } @@ -309,6 +310,7 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) memset(ref, 0, sizeof(struct jffs2_xattr_ref)); ref->class = RAWNODE_CLASS_XATTR_REF; + ref->node = (void *)ref; return ref; } diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 8bedfd2ff689..01594a2256eb 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -684,19 +684,26 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref spin_lock(&c->erase_completion_lock); ic = jffs2_raw_ref_to_ic(ref); - /* It seems we should never call jffs2_mark_node_obsolete() for - XATTR nodes.... yet. Make sure we notice if/when we change - that :) */ - BUG_ON(ic->class != RAWNODE_CLASS_INODE_CACHE); for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) ; *p = ref->next_in_ino; ref->next_in_ino = NULL; - if (ic->nodes == (void *)ic && ic->nlink == 0) - jffs2_del_ino_cache(c, ic); - + switch (ic->class) { +#ifdef CONFIG_JFFS2_FS_XATTR + case RAWNODE_CLASS_XATTR_DATUM: + jffs2_release_xattr_datum(c, (struct jffs2_xattr_datum *)ic); + break; + case RAWNODE_CLASS_XATTR_REF: + jffs2_release_xattr_ref(c, (struct jffs2_xattr_ref *)ic); + break; +#endif + default: + if (ic->nodes == (void *)ic && ic->nlink == 0) + jffs2_del_ino_cache(c, ic); + break; + } spin_unlock(&c->erase_completion_lock); } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 61618080b86f..79638f56c5ea 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -317,20 +317,25 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc struct jffs2_summary *s) { struct jffs2_xattr_datum *xd; - uint32_t totlen, crc; + uint32_t xid, version, 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); + 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)); + xid = je32_to_cpu(rx->xid); + version = je32_to_cpu(rx->version); + + totlen = sizeof(struct jffs2_raw_xattr); + if (version != XDATUM_DELETE_MARKER) + totlen += rx->name_len + 1 + je16_to_cpu(rx->value_len); + totlen = PAD(totlen); 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); @@ -339,22 +344,24 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc return 0; } - xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version)); - if (IS_ERR(xd)) { - if (PTR_ERR(xd) == -EEXIST) { - if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen))))) - return err; - return 0; - } + xd = jffs2_setup_xattr_datum(c, xid, version); + if (IS_ERR(xd)) 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 = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL); - /* FIXME */ xd->node->next_in_ino = (void *)xd; + if (xd->version > version) { + struct jffs2_raw_node_ref *raw + = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL); + raw->next_in_ino = xd->node->next_in_ino; + xd->node->next_in_ino = raw; + } else { + xd->version = version; + 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); + + jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, (void *)xd); + } if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); @@ -373,9 +380,8 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock 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); + 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; @@ -395,6 +401,7 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock return -ENOMEM; /* BEFORE jffs2_build_xattr_subsystem() called, + * and AFTER xattr_ref is marked as a dead xref, * 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 @@ -404,11 +411,13 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock */ ref->ino = je32_to_cpu(rr->ino); ref->xid = je32_to_cpu(rr->xid); + ref->xseqno = je32_to_cpu(rr->xseqno); + if (ref->xseqno > c->highest_xseqno) + c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER); ref->next = c->xref_temp; c->xref_temp = ref; - ref->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), NULL); - /* FIXME */ ref->node->next_in_ino = (void *)ref; + jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), (void *)ref); if (jffs2_sum_active()) jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 0b02fc79e4d1..c430f1d217e2 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -310,8 +310,6 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, #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; @@ -327,10 +325,6 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, } 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; @@ -483,22 +477,20 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); - if (IS_ERR(xd)) { - 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"); + if (IS_ERR(xd)) return PTR_ERR(xd); + if (xd->version > je32_to_cpu(spx->version)) { + /* node is not the newest one */ + struct jffs2_raw_node_ref *raw + = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, + PAD(je32_to_cpu(spx->totlen)), NULL); + raw->next_in_ino = xd->node->next_in_ino; + xd->node->next_in_ino = raw; + } else { + xd->version = je32_to_cpu(spx->version); + sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, + PAD(je32_to_cpu(spx->totlen)), (void *)xd); } - - xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, - PAD(je32_to_cpu(spx->totlen)), NULL); - /* FIXME */ xd->node->next_in_ino = (void *)xd; - *pseudo_random += je32_to_cpu(spx->xid); sp += JFFS2_SUMMARY_XATTR_SIZE; @@ -519,14 +511,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras JFFS2_NOTICE("allocation of xattr_datum failed\n"); return -ENOMEM; } - ref->ino = 0xfffffffe; - ref->xid = 0xfffffffd; ref->next = c->xref_temp; c->xref_temp = ref; - ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, - PAD(sizeof(struct jffs2_raw_xref)), NULL); - /* FIXME */ ref->node->next_in_ino = (void *)ref; + sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, + PAD(sizeof(struct jffs2_raw_xref)), (void *)ref); *pseudo_random += ref->node->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 2d82e250be34..03871ab7c26d 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -23,18 +23,15 @@ * xattr_datum_hashkey(xprefix, xname, xvalue, xsize) * is used to calcurate xdatum hashkey. The reminder of hashkey into XATTRINDEX_HASHSIZE is * the index of the xattr name/value pair cache (c->xattrindex). + * is_xattr_datum_unchecked(c, xd) + * returns 1, if xdatum contains any unchecked raw nodes. if all raw nodes are not + * unchecked, it returns 0. * unload_xattr_datum(c, xd) * is used to release xattr name/value pair and detach from c->xattrindex. * reclaim_xattr_datum(c) * is used to reclaim xattr name/value pairs on the xattr name/value pair cache when * memory usage by cache is over c->xdatum_mem_threshold. Currentry, this threshold * is hard coded as 32KiB. - * delete_xattr_datum_node(c, xd) - * is used to delete a jffs2 node is dominated by xdatum. When EBS(Erase Block Summary) is - * enabled, it overwrites the obsolete node by myself. - * delete_xattr_datum(c, xd) - * is used to delete jffs2_xattr_datum object. It must be called with 0-value of reference - * counter. (It means how many jffs2_xattr_ref object refers this xdatum.) * do_verify_xattr_datum(c, xd) * is used to load the xdatum informations without name/value pair from the medium. * It's necessary once, because those informations are not collected during mounting @@ -53,8 +50,13 @@ * is used to write xdatum to medium. xd->version will be incremented. * create_xattr_datum(c, xprefix, xname, xvalue, xsize) * is used to create new xdatum and write to medium. + * delete_xattr_datum_delay(c, xd) + * is used to delete a xdatum without 'delete marker'. It has a possibility to detect + * orphan xdatum on next mounting. + * delete_xattr_datum(c, xd) + * is used to delete a xdatum with 'delete marker'. Calling jffs2_reserve_space() is + * necessary before this function. * -------------------------------------------------- */ - static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize) { int name_len = strlen(xname); @@ -62,6 +64,22 @@ static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char * return crc32(xprefix, xname, name_len) ^ crc32(xprefix, xvalue, xsize); } +static int is_xattr_datum_unchecked(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + struct jffs2_raw_node_ref *raw; + int rc = 0; + + spin_lock(&c->erase_completion_lock); + for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) { + if (ref_flags(raw) == REF_UNCHECKED) { + rc = 1; + break; + } + } + spin_unlock(&c->erase_completion_lock); + return rc; +} + static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) { /* must be called under down_write(xattr_sem) */ @@ -107,80 +125,39 @@ static void reclaim_xattr_datum(struct jffs2_sb_info *c) before, c->xdatum_mem_usage, before - c->xdatum_mem_usage); } -static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) -{ - /* must be called under down_write(xattr_sem) */ - struct jffs2_raw_xattr rx; - size_t length; - int rc; - - if (!xd->node) { - JFFS2_WARNING("xdatum (xid=%u) is removed twice.\n", xd->xid); - return; - } - if (jffs2_sum_active()) { - memset(&rx, 0xff, sizeof(struct jffs2_raw_xattr)); - rc = jffs2_flash_read(c, ref_offset(xd->node), - sizeof(struct jffs2_unknown_node), - &length, (char *)&rx); - if (rc || length != sizeof(struct jffs2_unknown_node)) { - JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n", - rc, sizeof(struct jffs2_unknown_node), - length, ref_offset(xd->node)); - } - rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx), - &length, (char *)&rx); - if (rc || length != sizeof(struct jffs2_raw_xattr)) { - JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu ar %#08x\n", - rc, sizeof(rx), length, ref_offset(xd->node)); - } - } - spin_lock(&c->erase_completion_lock); - xd->node->next_in_ino = NULL; - spin_unlock(&c->erase_completion_lock); - jffs2_mark_node_obsolete(c, xd->node); - xd->node = NULL; -} - -static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) -{ - /* must be called under down_write(xattr_sem) */ - BUG_ON(xd->refcnt); - - unload_xattr_datum(c, xd); - if (xd->node) { - delete_xattr_datum_node(c, xd); - xd->node = NULL; - } - jffs2_free_xattr_datum(xd); -} - static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) { /* must be called under down_write(xattr_sem) */ struct jffs2_eraseblock *jeb; + struct jffs2_raw_node_ref *raw; struct jffs2_raw_xattr rx; size_t readlen; - uint32_t crc, totlen; + uint32_t crc, offset, totlen; int rc; - BUG_ON(!xd->node); - BUG_ON(ref_flags(xd->node) != REF_UNCHECKED); + spin_lock(&c->erase_completion_lock); + offset = ref_offset(xd->node); + if (ref_flags(xd->node) == REF_PRISTINE) + goto complete; + spin_unlock(&c->erase_completion_lock); - rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx); + rc = jffs2_flash_read(c, offset, sizeof(rx), &readlen, (char *)&rx); if (rc || readlen != sizeof(rx)) { JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n", - rc, sizeof(rx), readlen, ref_offset(xd->node)); + rc, sizeof(rx), readlen, offset); return rc ? rc : -EIO; } crc = crc32(0, &rx, sizeof(rx) - 4); if (crc != je32_to_cpu(rx.node_crc)) { - if (je32_to_cpu(rx.node_crc) != 0xffffffff) - JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", - ref_offset(xd->node), je32_to_cpu(rx.hdr_crc), crc); + JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + offset, je32_to_cpu(rx.hdr_crc), crc); + xd->flags |= JFFS2_XFLAGS_INVALID; return EIO; } - totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len)); + totlen = sizeof(rx); + if (xd->version != XDATUM_DELETE_MARKER) + totlen += rx.name_len + 1 + je16_to_cpu(rx.value_len); + totlen = PAD(totlen); if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR || je32_to_cpu(rx.totlen) != totlen @@ -188,11 +165,12 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat || je32_to_cpu(rx.version) != xd->version) { JFFS2_ERROR("inconsistent xdatum at %#08x, magic=%#04x/%#04x, " "nodetype=%#04x/%#04x, totlen=%u/%u, xid=%u/%u, version=%u/%u\n", - ref_offset(xd->node), je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK, + offset, je16_to_cpu(rx.magic), JFFS2_MAGIC_BITMASK, je16_to_cpu(rx.nodetype), JFFS2_NODETYPE_XATTR, je32_to_cpu(rx.totlen), totlen, je32_to_cpu(rx.xid), xd->xid, je32_to_cpu(rx.version), xd->version); + xd->flags |= JFFS2_XFLAGS_INVALID; return EIO; } xd->xprefix = rx.xprefix; @@ -200,14 +178,17 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat xd->value_len = je16_to_cpu(rx.value_len); xd->data_crc = je32_to_cpu(rx.data_crc); - /* This JFFS2_NODETYPE_XATTR node is checked */ - jeb = &c->blocks[ref_offset(xd->node) / c->sector_size]; - totlen = PAD(je32_to_cpu(rx.totlen)); - spin_lock(&c->erase_completion_lock); - c->unchecked_size -= totlen; c->used_size += totlen; - jeb->unchecked_size -= totlen; jeb->used_size += totlen; - xd->node->flash_offset = ref_offset(xd->node) | REF_PRISTINE; + complete: + for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) { + jeb = &c->blocks[ref_offset(raw) / c->sector_size]; + totlen = PAD(ref_totlen(c, jeb, raw)); + if (ref_flags(raw) == REF_UNCHECKED) { + c->unchecked_size -= totlen; c->used_size += totlen; + jeb->unchecked_size -= totlen; jeb->used_size += totlen; + } + raw->flash_offset = ref_offset(raw) | ((xd->node==raw) ? REF_PRISTINE : REF_NORMAL); + } spin_unlock(&c->erase_completion_lock); /* unchecked xdatum is chained with c->xattr_unchecked */ @@ -227,7 +208,6 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum uint32_t crc, length; int i, ret, retry = 0; - BUG_ON(!xd->node); BUG_ON(ref_flags(xd->node) != REF_PRISTINE); BUG_ON(!list_empty(&xd->xindex)); retry: @@ -253,6 +233,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum " at %#08x, read: 0x%08x calculated: 0x%08x\n", ref_offset(xd->node), xd->data_crc, crc); kfree(data); + xd->flags |= JFFS2_XFLAGS_INVALID; return EIO; } @@ -286,16 +267,13 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x * rc > 0 : Unrecoverable error, this node should be deleted. */ int rc = 0; - BUG_ON(xd->xname); - if (!xd->node) + + if (xd->xname) + return 0; + if (xd->flags & JFFS2_XFLAGS_INVALID) return EIO; - if (unlikely(ref_flags(xd->node) != REF_PRISTINE)) { + if (unlikely(is_xattr_datum_unchecked(c, xd))) rc = do_verify_xattr_datum(c, xd); - if (rc > 0) { - list_del_init(&xd->xindex); - delete_xattr_datum_node(c, xd); - } - } if (!rc) rc = do_load_xattr_datum(c, xd); return rc; @@ -304,36 +282,43 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) { /* must be called under down_write(xattr_sem) */ - struct jffs2_raw_node_ref *raw; struct jffs2_raw_xattr rx; struct kvec vecs[2]; size_t length; - int rc, totlen; + int rc, totlen, nvecs = 1; uint32_t phys_ofs = write_ofs(c); - BUG_ON(!xd->xname); + BUG_ON(is_xattr_datum_dead(xd) || (xd->flags & JFFS2_XFLAGS_INVALID) + ? !!xd->xname : !xd->xname); vecs[0].iov_base = ℞ - vecs[0].iov_len = PAD(sizeof(rx)); - vecs[1].iov_base = xd->xname; - vecs[1].iov_len = xd->name_len + 1 + xd->value_len; - totlen = vecs[0].iov_len + vecs[1].iov_len; - + vecs[0].iov_len = totlen = sizeof(rx); + if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) { + nvecs++; + vecs[1].iov_base = xd->xname; + vecs[1].iov_len = xd->name_len + 1 + xd->value_len; + totlen += vecs[1].iov_len; + } /* Setup raw-xattr */ + memset(&rx, 0, sizeof(rx)); rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR); rx.totlen = cpu_to_je32(PAD(totlen)); rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); rx.xid = cpu_to_je32(xd->xid); - rx.version = cpu_to_je32(++xd->version); - rx.xprefix = xd->xprefix; - rx.name_len = xd->name_len; - rx.value_len = cpu_to_je16(xd->value_len); - rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); + if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) { + rx.version = cpu_to_je32(++xd->version); + rx.xprefix = xd->xprefix; + rx.name_len = xd->name_len; + rx.value_len = cpu_to_je16(xd->value_len); + rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); + } else { + rx.version = cpu_to_je32(XDATUM_DELETE_MARKER); + } rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4)); - rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0); + rc = jffs2_flash_writev(c, vecs, nvecs, phys_ofs, &length, 0); if (rc || totlen != length) { JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n", rc, totlen, length, phys_ofs); @@ -343,14 +328,8 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x return rc; } - /* success */ - raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), NULL); - /* FIXME */ raw->next_in_ino = (void *)xd; - - if (xd->node) - delete_xattr_datum_node(c, xd); - xd->node = raw; + jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), (void *)xd); dbg_xattr("success on saving xdatum (xid=%u, version=%u, xprefix=%u, xname='%s')\n", xd->xid, xd->version, xd->xprefix, xd->xname); @@ -426,6 +405,39 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, return xd; } +static void delete_xattr_datum_delay(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under down_write(xattr_sem) */ + BUG_ON(xd->refcnt); + + unload_xattr_datum(c, xd); + set_xattr_datum_dead(xd); + spin_lock(&c->erase_completion_lock); + list_add(&xd->xindex, &c->xattr_dead_list); + spin_unlock(&c->erase_completion_lock); + JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. " + "An orphan xdatum may be detected on next mounting.\n", xd->xid); +} + +static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under jffs2_reserve_space() and down_write(xattr_sem) */ + int rc; + BUG_ON(xd->refcnt); + + unload_xattr_datum(c, xd); + set_xattr_datum_dead(xd); + rc = save_xattr_datum(c, xd); + if (rc) { + JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. " + "An orphan xdatum may be detected on next mounting.\n", + xd->xid); + } + spin_lock(&c->erase_completion_lock); + list_add(&xd->xindex, &c->xattr_dead_list); + spin_unlock(&c->erase_completion_lock); +} + /* -------- xref related functions ------------------ * verify_xattr_ref(c, ref) * is used to load xref information from medium. Because summary data does not @@ -450,25 +462,29 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) { struct jffs2_eraseblock *jeb; + struct jffs2_raw_node_ref *raw; struct jffs2_raw_xref rr; size_t readlen; - uint32_t crc, totlen; + uint32_t crc, offset, totlen; int rc; - BUG_ON(ref_flags(ref->node) != REF_UNCHECKED); + spin_lock(&c->erase_completion_lock); + if (ref_flags(ref->node) != REF_UNCHECKED) + goto complete; + offset = ref_offset(ref->node); + spin_unlock(&c->erase_completion_lock); - rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr); + rc = jffs2_flash_read(c, offset, sizeof(rr), &readlen, (char *)&rr); if (rc || sizeof(rr) != readlen) { JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n", - rc, sizeof(rr), readlen, ref_offset(ref->node)); + rc, sizeof(rr), readlen, offset); return rc ? rc : -EIO; } /* obsolete node */ crc = crc32(0, &rr, sizeof(rr) - 4); if (crc != je32_to_cpu(rr.node_crc)) { - if (je32_to_cpu(rr.node_crc) != 0xffffffff) - JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", - ref_offset(ref->node), je32_to_cpu(rr.node_crc), crc); + JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + offset, je32_to_cpu(rr.node_crc), crc); return EIO; } if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK @@ -476,22 +492,28 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) { JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, " "nodetype=%#04x/%#04x, totlen=%u/%zu\n", - ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, + offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF, je32_to_cpu(rr.totlen), PAD(sizeof(rr))); return EIO; } ref->ino = je32_to_cpu(rr.ino); ref->xid = je32_to_cpu(rr.xid); - - /* fixup superblock/eraseblock info */ - jeb = &c->blocks[ref_offset(ref->node) / c->sector_size]; - totlen = PAD(sizeof(rr)); + ref->xseqno = je32_to_cpu(rr.xseqno); + if (ref->xseqno > c->highest_xseqno) + c->highest_xseqno = (ref->xseqno & ~XREF_DELETE_MARKER); spin_lock(&c->erase_completion_lock); - c->unchecked_size -= totlen; c->used_size += totlen; - jeb->unchecked_size -= totlen; jeb->used_size += totlen; - ref->node->flash_offset = ref_offset(ref->node) | REF_PRISTINE; + complete: + for (raw=ref->node; raw != (void *)ref; raw=raw->next_in_ino) { + jeb = &c->blocks[ref_offset(raw) / c->sector_size]; + totlen = PAD(ref_totlen(c, jeb, raw)); + if (ref_flags(raw) == REF_UNCHECKED) { + c->unchecked_size -= totlen; c->used_size += totlen; + jeb->unchecked_size -= totlen; jeb->used_size += totlen; + } + raw->flash_offset = ref_offset(raw) | ((ref->node==raw) ? REF_PRISTINE : REF_NORMAL); + } spin_unlock(&c->erase_completion_lock); dbg_xattr("success on verifying xref (ino=%u, xid=%u) at %#08x\n", @@ -499,58 +521,12 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref return 0; } -static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) -{ - struct jffs2_raw_xref rr; - size_t length; - int rc; - - if (jffs2_sum_active()) { - memset(&rr, 0xff, sizeof(rr)); - rc = jffs2_flash_read(c, ref_offset(ref->node), - sizeof(struct jffs2_unknown_node), - &length, (char *)&rr); - if (rc || length != sizeof(struct jffs2_unknown_node)) { - JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n", - rc, sizeof(struct jffs2_unknown_node), - length, ref_offset(ref->node)); - } - rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr), - &length, (char *)&rr); - if (rc || length != sizeof(struct jffs2_raw_xref)) { - JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu at %#08x\n", - rc, sizeof(rr), length, ref_offset(ref->node)); - } - } - spin_lock(&c->erase_completion_lock); - ref->node->next_in_ino = NULL; - spin_unlock(&c->erase_completion_lock); - jffs2_mark_node_obsolete(c, ref->node); - ref->node = NULL; -} - -static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) -{ - /* must be called under down_write(xattr_sem) */ - struct jffs2_xattr_datum *xd; - - BUG_ON(!ref->node); - delete_xattr_ref_node(c, ref); - - xd = ref->xd; - xd->refcnt--; - if (!xd->refcnt) - delete_xattr_datum(c, xd); - jffs2_free_xattr_ref(ref); -} - static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) { /* must be called under down_write(xattr_sem) */ - struct jffs2_raw_node_ref *raw; struct jffs2_raw_xref rr; size_t length; - uint32_t phys_ofs = write_ofs(c); + uint32_t xseqno, phys_ofs = write_ofs(c); int ret; rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -558,8 +534,16 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) rr.totlen = cpu_to_je32(PAD(sizeof(rr))); rr.hdr_crc = cpu_to_je32(crc32(0, &rr, sizeof(struct jffs2_unknown_node) - 4)); - rr.ino = cpu_to_je32(ref->ic->ino); - rr.xid = cpu_to_je32(ref->xd->xid); + xseqno = (c->highest_xseqno += 2); + if (is_xattr_ref_dead(ref)) { + xseqno |= XREF_DELETE_MARKER; + rr.ino = cpu_to_je32(ref->ino); + rr.xid = cpu_to_je32(ref->xid); + } else { + rr.ino = cpu_to_je32(ref->ic->ino); + rr.xid = cpu_to_je32(ref->xd->xid); + } + rr.xseqno = cpu_to_je32(xseqno); rr.node_crc = cpu_to_je32(crc32(0, &rr, sizeof(rr) - 4)); ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr); @@ -572,12 +556,9 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) return ret; } - - raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), NULL); - /* FIXME */ raw->next_in_ino = (void *)ref; - if (ref->node) - delete_xattr_ref_node(c, ref); - ref->node = raw; + /* success */ + ref->xseqno = xseqno; + jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), (void *)ref); dbg_xattr("success on saving xref (ino=%u, xid=%u)\n", ref->ic->ino, ref->xd->xid); @@ -610,22 +591,116 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct return ref; /* success */ } +static void delete_xattr_ref_delay(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +{ + /* must be called under down_write(xattr_sem) */ + struct jffs2_xattr_datum *xd; + + set_xattr_ref_dead(ref); + xd = ref->xd; + ref->ino = ref->ic->ino; + ref->xid = ref->xd->xid; + spin_lock(&c->erase_completion_lock); + ref->next = c->xref_dead_list; + c->xref_dead_list = ref; + spin_unlock(&c->erase_completion_lock); + + JFFS2_NOTICE("xref(ino=%u, xid=%u) was removed without delete marker. " + "An orphan xref may be detected on next mounting.\n", + ref->ino, ref->xid); + + if (!--xd->refcnt) + delete_xattr_datum_delay(c, xd); +} + +static int delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, int enforce) +{ + /* must be called under jffs2_reserve_space() and down_write(xattr_sem) */ + struct jffs2_inode_cache *ic; + struct jffs2_xattr_datum *xd; + uint32_t length; + int rc; + + set_xattr_ref_dead(ref); + ic = ref->ic; + xd = ref->xd; + ref->ino = ic->ino; + ref->xid = xd->xid; + rc = save_xattr_ref(c, ref); + if (rc) { + if (!enforce) { + clr_xattr_ref_dead(ref); + ref->ic = ic; + ref->xd = xd; + return rc; + } + JFFS2_WARNING("could not write delete marker of xref(ino=%u, xid=%u). " + "An orphan xref may be detected on next mounting.\n", + ref->ic->ino, ref->xd->xid); + } + spin_lock(&c->erase_completion_lock); + ref->next = c->xref_dead_list; + c->xref_dead_list = ref; + spin_unlock(&c->erase_completion_lock); + + xd->refcnt--; + if (xd->refcnt) + return 0; + + /* delete xdatum */ + unload_xattr_datum(c, xd); + up_write(&c->xattr_sem); + jffs2_complete_reservation(c); + + rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xattr)), &length, + ALLOC_DELETION, JFFS2_SUMMARY_XATTR_SIZE); + if (rc) { + down(&c->alloc_sem); + down_write(&c->xattr_sem); + delete_xattr_datum_delay(c, xd); + } else { + down_write(&c->xattr_sem); + delete_xattr_datum(c, xd); + } + return 0; +} + void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) { /* It's called from jffs2_clear_inode() on inode removing. When an inode with XATTR is removed, those XATTRs must be removed. */ - struct jffs2_xattr_ref *ref, *_ref; + struct jffs2_xattr_ref *ref; + uint32_t length; + int rc, retry; if (!ic || ic->nlink > 0) return; + down_read(&c->xattr_sem); + if (!ic->xref) { + up_read(&c->xattr_sem); + return; + } + up_read(&c->xattr_sem); + retry: + rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xref)), &length, + ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE); down_write(&c->xattr_sem); - for (ref = ic->xref; ref; ref = _ref) { - _ref = ref->next; - delete_xattr_ref(c, ref); + if (ic->xref) { + ref = ic->xref; + ic->xref = ref->next; + if (rc) { + delete_xattr_ref_delay(c, ref); + } else { + delete_xattr_ref(c, ref, 1); + } } - ic->xref = NULL; + retry = ic->xref ? 1 : 0; up_write(&c->xattr_sem); + if (!rc) + jffs2_complete_reservation(c); + if (retry) + goto retry; } void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) @@ -655,7 +730,7 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac * duplicate name/value pairs. If duplicate name/value pair would be found, * one will be removed. */ - struct jffs2_xattr_ref *ref, *cmp, **pref; + struct jffs2_xattr_ref *ref, *cmp, **pref, **pcmp; int rc = 0; if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED)) @@ -668,27 +743,32 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac rc = load_xattr_datum(c, ref->xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref(c, ref); + delete_xattr_ref_delay(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; } - for (cmp=ref->next, pref=&ref->next; cmp; pref=&cmp->next, cmp=cmp->next) { + for (cmp=ref->next, pcmp=&ref->next; cmp; pcmp=&cmp->next, cmp=cmp->next) { if (!cmp->xd->xname) { ref->xd->flags |= JFFS2_XFLAGS_BIND; rc = load_xattr_datum(c, cmp->xd); ref->xd->flags &= ~JFFS2_XFLAGS_BIND; if (unlikely(rc > 0)) { - *pref = cmp->next; - delete_xattr_ref(c, cmp); + *pcmp = cmp->next; + delete_xattr_ref_delay(c, cmp); goto retry; } else if (unlikely(rc < 0)) goto out; } if (ref->xd->xprefix == cmp->xd->xprefix && !strcmp(ref->xd->xname, cmp->xd->xname)) { - *pref = cmp->next; - delete_xattr_ref(c, cmp); + if (ref->xseqno > cmp->xseqno) { + *pcmp = cmp->next; + delete_xattr_ref_delay(c, cmp); + } else { + *pref = ref->next; + delete_xattr_ref_delay(c, ref); + } goto retry; } } @@ -719,9 +799,13 @@ void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c) for (i=0; i < XATTRINDEX_HASHSIZE; i++) INIT_LIST_HEAD(&c->xattrindex[i]); INIT_LIST_HEAD(&c->xattr_unchecked); + INIT_LIST_HEAD(&c->xattr_dead_list); + c->xref_dead_list = NULL; c->xref_temp = NULL; init_rwsem(&c->xattr_sem); + c->highest_xid = 0; + c->highest_xseqno = 0; c->xdatum_mem_usage = 0; c->xdatum_mem_threshold = 32 * 1024; /* Default 32KB */ } @@ -751,7 +835,11 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c) _ref = ref->next; jffs2_free_xattr_ref(ref); } - c->xref_temp = NULL; + + for (ref=c->xref_dead_list; ref; ref = _ref) { + _ref = ref->next; + jffs2_free_xattr_ref(ref); + } for (i=0; i < XATTRINDEX_HASHSIZE; i++) { list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { @@ -761,64 +849,120 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c) jffs2_free_xattr_datum(xd); } } + + list_for_each_entry_safe(xd, _xd, &c->xattr_dead_list, xindex) { + list_del(&xd->xindex); + jffs2_free_xattr_datum(xd); + } } +#define XREF_TMPHASH_SIZE (128) void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) { struct jffs2_xattr_ref *ref, *_ref; + struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE]; struct jffs2_xattr_datum *xd, *_xd; struct jffs2_inode_cache *ic; - int i, xdatum_count =0, xdatum_unchecked_count = 0, xref_count = 0; + struct jffs2_raw_node_ref *raw; + int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0; BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); + /* Phase.1 : Drop dead xdatum */ + for (i=0; i < XATTRINDEX_HASHSIZE; i++) { + list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { + BUG_ON(xd->node == (void *)xd); + if (is_xattr_datum_dead(xd)) { + list_del_init(&xd->xindex); + list_add(&xd->xindex, &c->xattr_unchecked); + } + } + } - /* Phase.1 */ + /* Phase.2 : Merge same xref */ + for (i=0; i < XREF_TMPHASH_SIZE; i++) + xref_tmphash[i] = NULL; for (ref=c->xref_temp; ref; ref=_ref) { + struct jffs2_xattr_ref *tmp; + _ref = ref->next; - /* checking REF_UNCHECKED nodes */ if (ref_flags(ref->node) != REF_PRISTINE) { if (verify_xattr_ref(c, ref)) { - delete_xattr_ref_node(c, ref); + BUG_ON(ref->node->next_in_ino != (void *)ref); + ref->node->next_in_ino = NULL; + jffs2_mark_node_obsolete(c, ref->node); jffs2_free_xattr_ref(ref); continue; } } - /* At this point, ref->xid and ref->ino contain XID and inode number. - ref->xd and ref->ic are not valid yet. */ - xd = jffs2_find_xattr_datum(c, ref->xid); - ic = jffs2_get_ino_cache(c, ref->ino); - if (!xd || !ic) { - if (ref_flags(ref->node) != REF_UNCHECKED) - JFFS2_WARNING("xref(ino=%u, xid=%u) is orphan. \n", - ref->ino, ref->xid); - delete_xattr_ref_node(c, ref); + + i = (ref->ino ^ ref->xid) % XREF_TMPHASH_SIZE; + for (tmp=xref_tmphash[i]; tmp; tmp=tmp->next) { + if (tmp->ino == ref->ino && tmp->xid == ref->xid) + break; + } + if (tmp) { + raw = ref->node; + if (ref->xseqno > tmp->xseqno) { + tmp->xseqno = ref->xseqno; + raw->next_in_ino = tmp->node; + tmp->node = raw; + } else { + raw->next_in_ino = tmp->node->next_in_ino; + tmp->node->next_in_ino = raw; + } jffs2_free_xattr_ref(ref); continue; + } else { + ref->next = xref_tmphash[i]; + xref_tmphash[i] = ref; } - ref->xd = xd; - ref->ic = ic; - xd->refcnt++; - ref->next = ic->xref; - ic->xref = ref; - xref_count++; } c->xref_temp = NULL; - /* After this, ref->xid/ino are NEVER used. */ - /* Phase.2 */ + /* Phase.3 : Bind xref with inode_cache and xattr_datum */ + for (i=0; i < XREF_TMPHASH_SIZE; i++) { + for (ref=xref_tmphash[i]; ref; ref=_ref) { + _ref = ref->next; + if (is_xattr_ref_dead(ref)) { + ref->next = c->xref_dead_list; + c->xref_dead_list = ref; + continue; + } + /* At this point, ref->xid and ref->ino contain XID and inode number. + ref->xd and ref->ic are not valid yet. */ + xd = jffs2_find_xattr_datum(c, ref->xid); + ic = jffs2_get_ino_cache(c, ref->ino); + if (!xd || !ic) { + JFFS2_WARNING("xref(ino=%u, xid=%u, xseqno=%u) is orphan. \n", + ref->ino, ref->xid, ref->xseqno); + set_xattr_ref_dead(ref); + ref->next = c->xref_dead_list; + c->xref_dead_list = ref; + continue; + } + ref->xd = xd; + ref->ic = ic; + xd->refcnt++; + ref->next = ic->xref; + ic->xref = ref; + xref_count++; + } + } + + /* Phase.4 : Link unchecked xdatum to xattr_unchecked list */ for (i=0; i < XATTRINDEX_HASHSIZE; i++) { list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { list_del_init(&xd->xindex); if (!xd->refcnt) { - if (ref_flags(xd->node) != REF_UNCHECKED) - JFFS2_WARNING("orphan xdatum(xid=%u, version=%u) at %#08x\n", - xd->xid, xd->version, ref_offset(xd->node)); - delete_xattr_datum(c, xd); + JFFS2_WARNING("orphan xdatum(xid=%u, version=%u)\n", + xd->xid, xd->version); + set_xattr_datum_dead(xd); + list_add(&xd->xindex, &c->xattr_unchecked); continue; } - if (ref_flags(xd->node) != REF_PRISTINE) { - dbg_xattr("unchecked xdatum(xid=%u) at %#08x\n", - xd->xid, ref_offset(xd->node)); + if (is_xattr_datum_unchecked(c, xd)) { + dbg_xattr("unchecked xdatum(xid=%u, version=%u)\n", + xd->xid, xd->version); list_add(&xd->xindex, &c->xattr_unchecked); xdatum_unchecked_count++; } @@ -833,28 +977,18 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, uint32_t xid, uint32_t version) { - struct jffs2_xattr_datum *xd, *_xd; + struct jffs2_xattr_datum *xd; - _xd = jffs2_find_xattr_datum(c, xid); - if (_xd) { - dbg_xattr("duplicate xdatum (xid=%u, version=%u/%u) at %#08x\n", - xid, version, _xd->version, ref_offset(_xd->node)); - if (version < _xd->version) - return ERR_PTR(-EEXIST); - } - xd = jffs2_alloc_xattr_datum(); - if (!xd) - return ERR_PTR(-ENOMEM); - xd->xid = xid; - xd->version = version; - if (xd->xid > c->highest_xid) - c->highest_xid = xd->xid; - list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]); - - if (_xd) { - list_del_init(&_xd->xindex); - delete_xattr_datum_node(c, _xd); - jffs2_free_xattr_datum(_xd); + xd = jffs2_find_xattr_datum(c, xid); + if (!xd) { + xd = jffs2_alloc_xattr_datum(); + if (!xd) + return ERR_PTR(-ENOMEM); + xd->xid = xid; + xd->version = version; + if (xd->xid > c->highest_xid) + c->highest_xid = xd->xid; + list_add_tail(&xd->xindex, &c->xattrindex[xid % XATTRINDEX_HASHSIZE]); } return xd; } @@ -945,7 +1079,7 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref(c, ref); + delete_xattr_ref_delay(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; @@ -1006,7 +1140,7 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref(c, ref); + delete_xattr_ref_delay(c, ref); goto retry; } else if (unlikely(rc < 0)) { goto out; @@ -1069,7 +1203,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref(c, ref); + delete_xattr_ref_delay(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; @@ -1081,8 +1215,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, } if (!buffer) { *pref = ref->next; - delete_xattr_ref(c, ref); - rc = 0; + rc = delete_xattr_ref(c, ref, 0); goto out; } goto found; @@ -1094,7 +1227,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, goto out; } if (!buffer) { - rc = -EINVAL; + rc = -ENODATA; goto out; } found: @@ -1110,16 +1243,15 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, request = PAD(sizeof(struct jffs2_raw_xref)); rc = jffs2_reserve_space(c, request, &length, ALLOC_NORMAL, JFFS2_SUMMARY_XREF_SIZE); + down_write(&c->xattr_sem); if (rc) { JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); - down_write(&c->xattr_sem); xd->refcnt--; if (!xd->refcnt) - delete_xattr_datum(c, xd); + delete_xattr_datum_delay(c, xd); up_write(&c->xattr_sem); return rc; } - down_write(&c->xattr_sem); if (ref) *pref = ref->next; newref = create_xattr_ref(c, ic, xd); @@ -1131,9 +1263,21 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, rc = PTR_ERR(newref); xd->refcnt--; if (!xd->refcnt) - delete_xattr_datum(c, xd); + delete_xattr_datum_delay(c, xd); } else if (ref) { - delete_xattr_ref(c, ref); + up_write(&c->xattr_sem); + jffs2_complete_reservation(c); + + rc = jffs2_reserve_space(c, request, &length, + ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE); + down_write(&c->xattr_sem); + if (rc) { + JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); + delete_xattr_ref_delay(c, ref); + up_write(&c->xattr_sem); + return 0; + } + delete_xattr_ref(c, ref, 1); } out: up_write(&c->xattr_sem); @@ -1142,38 +1286,37 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, } /* -------- garbage collector functions ------------- - * jffs2_garbage_collect_xattr_datum(c, xd) + * jffs2_garbage_collect_xattr_datum(c, xd, raw) * is used to move xdatum into new node. - * jffs2_garbage_collect_xattr_ref(c, ref) + * jffs2_garbage_collect_xattr_ref(c, ref, raw) * is used to move xref into new node. * jffs2_verify_xattr(c) * is used to call do_verify_xattr_datum() before garbage collecting. * -------------------------------------------------- */ -int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, + struct jffs2_raw_node_ref *raw) { uint32_t totlen, length, old_ofs; - int rc = -EINVAL; + int rc = 0; down_write(&c->xattr_sem); - BUG_ON(!xd->node); + if (xd->node != raw) + goto out; + if (is_xattr_datum_dead(xd) && (raw->next_in_ino == (void *)xd)) + goto out; old_ofs = ref_offset(xd->node); totlen = ref_totlen(c, c->gcblock, xd->node); - if (totlen < sizeof(struct jffs2_raw_xattr)) - goto out; - if (!xd->xname) { + if (!is_xattr_datum_dead(xd)) { rc = load_xattr_datum(c, xd); - if (unlikely(rc > 0)) { - delete_xattr_datum_node(c, xd); - rc = 0; - goto out; - } else if (unlikely(rc < 0)) + if (unlikely(rc < 0)) goto out; } + rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE); - if (rc || length < totlen) { - JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, totlen); + if (rc) { + JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen); rc = rc ? rc : -EBADFD; goto out; } @@ -1182,27 +1325,33 @@ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xatt dbg_xattr("xdatum (xid=%u, version=%u) GC'ed from %#08x to %08x\n", xd->xid, xd->version, old_ofs, ref_offset(xd->node)); out: + if (!rc) + jffs2_mark_node_obsolete(c, raw); up_write(&c->xattr_sem); return rc; } -int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, + struct jffs2_raw_node_ref *raw) { uint32_t totlen, length, old_ofs; - int rc = -EINVAL; + int rc = 0; down_write(&c->xattr_sem); BUG_ON(!ref->node); + if (ref->node != raw) + goto out; + if (is_xattr_ref_dead(ref) && (raw->next_in_ino == (void *)ref)) + goto out; + old_ofs = ref_offset(ref->node); totlen = ref_totlen(c, c->gcblock, ref->node); - if (totlen != sizeof(struct jffs2_raw_xref)) - goto out; rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE); - if (rc || length < totlen) { - JFFS2_WARNING("%s: jffs2_reserve_space() = %d, request = %u\n", + if (rc) { + JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n", __FUNCTION__, rc, totlen); rc = rc ? rc : -EBADFD; goto out; @@ -1212,6 +1361,8 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ dbg_xattr("xref (ino=%u, xid=%u) GC'ed from %#08x to %08x\n", ref->ic->ino, ref->xd->xid, old_ofs, ref_offset(ref->node)); out: + if (!rc) + jffs2_mark_node_obsolete(c, raw); up_write(&c->xattr_sem); return rc; } @@ -1219,20 +1370,59 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ int jffs2_verify_xattr(struct jffs2_sb_info *c) { struct jffs2_xattr_datum *xd, *_xd; + struct jffs2_eraseblock *jeb; + struct jffs2_raw_node_ref *raw; + uint32_t totlen; int rc; down_write(&c->xattr_sem); list_for_each_entry_safe(xd, _xd, &c->xattr_unchecked, xindex) { rc = do_verify_xattr_datum(c, xd); - if (rc == 0) { - list_del_init(&xd->xindex); - break; - } else if (rc > 0) { - list_del_init(&xd->xindex); - delete_xattr_datum_node(c, xd); + if (rc < 0) + continue; + list_del_init(&xd->xindex); + spin_lock(&c->erase_completion_lock); + for (raw=xd->node; raw != (void *)xd; raw=raw->next_in_ino) { + if (ref_flags(raw) != REF_UNCHECKED) + continue; + jeb = &c->blocks[ref_offset(raw) / c->sector_size]; + totlen = PAD(ref_totlen(c, jeb, raw)); + c->unchecked_size -= totlen; c->used_size += totlen; + jeb->unchecked_size -= totlen; jeb->used_size += totlen; + raw->flash_offset = ref_offset(raw) + | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL); } + if (is_xattr_datum_dead(xd)) + list_add(&xd->xindex, &c->xattr_dead_list); + spin_unlock(&c->erase_completion_lock); } up_write(&c->xattr_sem); - return list_empty(&c->xattr_unchecked) ? 1 : 0; } + +void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +{ + /* must be called under spin_lock(&c->erase_completion_lock) */ + if (xd->node != (void *)xd) + return; + + list_del(&xd->xindex); + jffs2_free_xattr_datum(xd); +} + +void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +{ + /* must be called under spin_lock(&c->erase_completion_lock) */ + struct jffs2_xattr_ref *tmp, **ptmp; + + if (ref->node != (void *)ref) + return; + + for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) { + if (ref == tmp) { + *ptmp = tmp->next; + jffs2_free_xattr_ref(ref); + break; + } + } +} diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 2c199856c582..06ab7b880212 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -16,6 +16,7 @@ #define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */ #define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */ +#define JFFS2_XFLAGS_INVALID (0x80) /* This datum contains crc error */ struct jffs2_xattr_datum { @@ -23,7 +24,7 @@ struct jffs2_xattr_datum struct jffs2_raw_node_ref *node; uint8_t class; uint8_t flags; - uint16_t xprefix; /* see JFFS2_XATTR_PREFIX_* */ + uint16_t xprefix; /* see JFFS2_XATTR_PREFIX_* */ struct list_head xindex; /* chained from c->xattrindex[n] */ uint32_t refcnt; /* # of xattr_ref refers this */ @@ -47,6 +48,7 @@ struct jffs2_xattr_ref uint8_t flags; /* Currently unused */ u16 unused; + uint32_t xseqno; union { struct jffs2_inode_cache *ic; /* reference to jffs2_inode_cache */ uint32_t ino; /* only used in scanning/building */ @@ -58,6 +60,34 @@ struct jffs2_xattr_ref struct jffs2_xattr_ref *next; /* chained from ic->xref_list */ }; +#define XDATUM_DELETE_MARKER (0xffffffff) +#define XREF_DELETE_MARKER (0x00000001) +static inline int is_xattr_datum_dead(struct jffs2_xattr_datum *xd) +{ + return (xd->version == XDATUM_DELETE_MARKER); +} + +static inline void set_xattr_datum_dead(struct jffs2_xattr_datum *xd) +{ + xd->version = XDATUM_DELETE_MARKER; +} + +static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref) +{ + return ((ref->xseqno & XREF_DELETE_MARKER) != 0); +} + +static inline void set_xattr_ref_dead(struct jffs2_xattr_ref *ref) +{ + ref->xseqno |= XREF_DELETE_MARKER; +} + +static inline void clr_xattr_ref_dead(struct jffs2_xattr_ref *ref) +{ + ref->xseqno &= ~XREF_DELETE_MARKER; +} + + #ifdef CONFIG_JFFS2_FS_XATTR extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c); @@ -70,9 +100,13 @@ extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c 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_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, + struct jffs2_raw_node_ref *raw); +extern int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, + struct jffs2_raw_node_ref *raw); extern int jffs2_verify_xattr(struct jffs2_sb_info *c); +extern void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd); +extern void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref); extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, char *buffer, size_t size); diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h index c6f70660b371..c9c760700bc3 100644 --- a/include/linux/jffs2.h +++ b/include/linux/jffs2.h @@ -186,6 +186,7 @@ struct jffs2_raw_xref jint32_t hdr_crc; jint32_t ino; /* inode number */ jint32_t xid; /* XATTR identifier number */ + jint32_t xseqno; /* xref sequencial number */ jint32_t node_crc; } __attribute__((packed)); -- cgit v1.2.3 From 332a6b99c587161a972eaa1b00ae0e0dc49fbbfd Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 24 Jun 2006 09:17:42 +0900 Subject: [JFFS2][XATTR] Fix wrong copyright summary.c was modified at 2006. Signed-off-by: KaiGai Kohei Signed-off-by: David Woodhouse --- fs/jffs2/summary.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index c430f1d217e2..1deb92acd2bb 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -5,7 +5,7 @@ * Zoltan Sogor , * Patrik Kluba , * University of Szeged, Hungary - * 2005 KaiGai Kohei + * 2006 KaiGai Kohei * * For licensing information, see the file 'LICENCE' in this directory. * -- cgit v1.2.3