mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
e631ddba58
The goal of summary is to speed up the mount time. Erase block summary (EBS) stores summary information at the end of every (closed) erase block. It is no longer necessary to scan all nodes separetly (and read all pages of them) just read this "small" summary, where every information is stored which is needed at mount time. This summary information is stored in a JFFS2_FEATURE_RWCOMPAT_DELETE. During the mount process if there is no summary info the orignal scan process will be executed. EBS works with NAND and NOR flashes, too. There is a user space tool called sumtool to generate this summary information for a JFFS2 image. Signed-off-by: Ferenc Havasi <havasi@inf.u-szeged.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
730 lines
19 KiB
C
730 lines
19 KiB
C
/*
|
|
* JFFS2 -- Journalling Flash File System, Version 2.
|
|
*
|
|
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
|
|
* Zoltan Sogor <weth@inf.u-szeged.hu>,
|
|
* Patrik Kluba <pajko@halom.u-szeged.hu>,
|
|
* University of Szeged, Hungary
|
|
*
|
|
* For licensing information, see the file 'LICENCE' in this directory.
|
|
*
|
|
* $Id: summary.c,v 1.1 2005/09/07 08:34:54 havasi Exp $
|
|
*
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/mtd/mtd.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/crc32.h>
|
|
#include <linux/compiler.h>
|
|
#include <linux/vmalloc.h>
|
|
#include "nodelist.h"
|
|
#include "debug.h"
|
|
|
|
int jffs2_sum_init(struct jffs2_sb_info *c)
|
|
{
|
|
c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
|
|
|
|
if (!c->summary) {
|
|
JFFS2_WARNING("Can't allocate memory for summary information!\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memset(c->summary, 0, sizeof(struct jffs2_summary));
|
|
|
|
c->summary->sum_buf = vmalloc(c->sector_size);
|
|
|
|
if (!c->summary->sum_buf) {
|
|
JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
JFFS2_DBG_SUMMARY("returned succesfully\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
void jffs2_sum_exit(struct jffs2_sb_info *c)
|
|
{
|
|
JFFS2_DBG_SUMMARY("called\n");
|
|
|
|
jffs2_sum_disable_collecting(c->summary);
|
|
|
|
vfree(c->summary->sum_buf);
|
|
c->summary->sum_buf = NULL;
|
|
|
|
kfree(c->summary);
|
|
c->summary = NULL;
|
|
}
|
|
|
|
static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
|
|
{
|
|
if (!s->sum_list_head)
|
|
s->sum_list_head = (union jffs2_sum_mem *) item;
|
|
if (s->sum_list_tail)
|
|
s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
|
|
s->sum_list_tail = (union jffs2_sum_mem *) item;
|
|
|
|
switch (je16_to_cpu(item->u.nodetype)) {
|
|
case JFFS2_NODETYPE_INODE:
|
|
s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
|
|
s->sum_num++;
|
|
JFFS2_DBG_SUMMARY("inode (%u) added to summary\n",
|
|
je32_to_cpu(item->i.inode));
|
|
break;
|
|
case JFFS2_NODETYPE_DIRENT:
|
|
s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
|
|
s->sum_num++;
|
|
JFFS2_DBG_SUMMARY("dirent (%u) added to summary\n",
|
|
je32_to_cpu(item->d.ino));
|
|
break;
|
|
default:
|
|
JFFS2_WARNING("UNKNOWN node type %u\n",
|
|
je16_to_cpu(item->u.nodetype));
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
|
|
|
|
int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
|
|
{
|
|
JFFS2_DBG_SUMMARY("called with %u\n", size);
|
|
s->sum_padded += size;
|
|
return 0;
|
|
}
|
|
|
|
int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri,
|
|
uint32_t ofs)
|
|
{
|
|
struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
|
|
|
|
if (!temp)
|
|
return -ENOMEM;
|
|
|
|
temp->nodetype = ri->nodetype;
|
|
temp->inode = ri->ino;
|
|
temp->version = ri->version;
|
|
temp->offset = cpu_to_je32(ofs); /* relative offset from the begining of the jeb */
|
|
temp->totlen = ri->totlen;
|
|
temp->next = NULL;
|
|
|
|
return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
|
|
}
|
|
|
|
int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd,
|
|
uint32_t ofs)
|
|
{
|
|
struct jffs2_sum_dirent_mem *temp =
|
|
kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
|
|
|
|
if (!temp)
|
|
return -ENOMEM;
|
|
|
|
temp->nodetype = rd->nodetype;
|
|
temp->totlen = rd->totlen;
|
|
temp->offset = cpu_to_je32(ofs); /* relative from the begining of the jeb */
|
|
temp->pino = rd->pino;
|
|
temp->version = rd->version;
|
|
temp->ino = rd->ino;
|
|
temp->nsize = rd->nsize;
|
|
temp->type = rd->type;
|
|
temp->next = NULL;
|
|
|
|
memcpy(temp->name, rd->name, rd->nsize);
|
|
|
|
return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
|
|
}
|
|
|
|
/* Cleanup every collected summary information */
|
|
|
|
static void jffs2_sum_clean_collected(struct jffs2_summary *s)
|
|
{
|
|
union jffs2_sum_mem *temp;
|
|
|
|
if (!s->sum_list_head) {
|
|
JFFS2_DBG_SUMMARY("already empty\n");
|
|
}
|
|
while (s->sum_list_head) {
|
|
temp = s->sum_list_head;
|
|
s->sum_list_head = s->sum_list_head->u.next;
|
|
kfree(temp);
|
|
}
|
|
s->sum_list_tail = NULL;
|
|
s->sum_padded = 0;
|
|
s->sum_num = 0;
|
|
}
|
|
|
|
void jffs2_sum_reset_collected(struct jffs2_summary *s)
|
|
{
|
|
JFFS2_DBG_SUMMARY("called\n");
|
|
jffs2_sum_clean_collected(s);
|
|
s->sum_size = 0;
|
|
}
|
|
|
|
void jffs2_sum_disable_collecting(struct jffs2_summary *s)
|
|
{
|
|
JFFS2_DBG_SUMMARY("called\n");
|
|
jffs2_sum_clean_collected(s);
|
|
s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
|
|
}
|
|
|
|
int jffs2_sum_is_disabled(struct jffs2_summary *s)
|
|
{
|
|
return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE);
|
|
}
|
|
|
|
/* Move the collected summary information into sb (called from scan.c) */
|
|
|
|
void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s)
|
|
{
|
|
JFFS2_DBG_SUMMARY("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n",
|
|
c->summary->sum_size, c->summary->sum_num,
|
|
s->sum_size, s->sum_num);
|
|
|
|
c->summary->sum_size = s->sum_size;
|
|
c->summary->sum_num = s->sum_num;
|
|
c->summary->sum_padded = s->sum_padded;
|
|
c->summary->sum_list_head = s->sum_list_head;
|
|
c->summary->sum_list_tail = s->sum_list_tail;
|
|
|
|
s->sum_list_head = s->sum_list_tail = NULL;
|
|
}
|
|
|
|
/* Called from wbuf.c to collect writed node info */
|
|
|
|
int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
|
|
unsigned long count, uint32_t ofs)
|
|
{
|
|
union jffs2_node_union *node;
|
|
struct jffs2_eraseblock *jeb;
|
|
|
|
node = invecs[0].iov_base;
|
|
jeb = &c->blocks[ofs / c->sector_size];
|
|
ofs -= jeb->offset;
|
|
|
|
switch (je16_to_cpu(node->u.nodetype)) {
|
|
case JFFS2_NODETYPE_INODE: {
|
|
struct jffs2_sum_inode_mem *temp =
|
|
kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
|
|
|
|
if (!temp)
|
|
goto no_mem;
|
|
|
|
temp->nodetype = node->i.nodetype;
|
|
temp->inode = node->i.ino;
|
|
temp->version = node->i.version;
|
|
temp->offset = cpu_to_je32(ofs);
|
|
temp->totlen = node->i.totlen;
|
|
temp->next = NULL;
|
|
|
|
return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
|
|
}
|
|
|
|
case JFFS2_NODETYPE_DIRENT: {
|
|
struct jffs2_sum_dirent_mem *temp =
|
|
kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
|
|
|
|
if (!temp)
|
|
goto no_mem;
|
|
|
|
temp->nodetype = node->d.nodetype;
|
|
temp->totlen = node->d.totlen;
|
|
temp->offset = cpu_to_je32(ofs);
|
|
temp->pino = node->d.pino;
|
|
temp->version = node->d.version;
|
|
temp->ino = node->d.ino;
|
|
temp->nsize = node->d.nsize;
|
|
temp->type = node->d.type;
|
|
temp->next = NULL;
|
|
|
|
switch (count) {
|
|
case 1:
|
|
memcpy(temp->name,node->d.name,node->d.nsize);
|
|
break;
|
|
|
|
case 2:
|
|
memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
|
|
break;
|
|
|
|
default:
|
|
BUG(); /* impossible count value */
|
|
break;
|
|
}
|
|
|
|
return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
|
|
}
|
|
|
|
case JFFS2_NODETYPE_PADDING:
|
|
JFFS2_DBG_SUMMARY("node PADDING\n");
|
|
c->summary->sum_padded += je32_to_cpu(node->u.totlen);
|
|
break;
|
|
|
|
case JFFS2_NODETYPE_CLEANMARKER:
|
|
JFFS2_DBG_SUMMARY("node CLEANMARKER\n");
|
|
break;
|
|
|
|
case JFFS2_NODETYPE_SUMMARY:
|
|
JFFS2_DBG_SUMMARY("node SUMMARY\n");
|
|
break;
|
|
|
|
default:
|
|
/* If you implement a new node type you should also implement
|
|
summary support for it or disable summary.
|
|
*/
|
|
BUG();
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
|
|
no_mem:
|
|
JFFS2_WARNING("MEMORY ALLOCATION ERROR!");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
|
|
/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
|
|
|
|
static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
|
struct jffs2_summary_node *summary, uint32_t *pseudo_random)
|
|
{
|
|
struct jffs2_raw_node_ref *raw;
|
|
struct jffs2_inode_cache *ic;
|
|
struct jffs2_full_dirent *fd;
|
|
void *sp;
|
|
int i, ino;
|
|
|
|
sp = summary->sum;
|
|
|
|
for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
|
|
JFFS2_DBG_SUMMARY("processing summary index %d\n", i);
|
|
|
|
switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
|
|
case JFFS2_NODETYPE_INODE: {
|
|
struct jffs2_sum_inode_flash *spi;
|
|
spi = sp;
|
|
|
|
ino = je32_to_cpu(spi->inode);
|
|
|
|
JFFS2_DBG_SUMMARY("Inode at 0x%08x\n",
|
|
jeb->offset + je32_to_cpu(spi->offset));
|
|
|
|
raw = jffs2_alloc_raw_node_ref();
|
|
if (!raw) {
|
|
JFFS2_NOTICE("allocation of node reference failed\n");
|
|
kfree(summary);
|
|
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);
|
|
kfree(summary);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
|
|
raw->__totlen = PAD(je32_to_cpu(spi->totlen));
|
|
raw->next_phys = NULL;
|
|
raw->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)));
|
|
|
|
sp += JFFS2_SUMMARY_INODE_SIZE;
|
|
|
|
break;
|
|
}
|
|
|
|
case JFFS2_NODETYPE_DIRENT: {
|
|
struct jffs2_sum_dirent_flash *spd;
|
|
spd = sp;
|
|
|
|
JFFS2_DBG_SUMMARY("Dirent at 0x%08x\n",
|
|
jeb->offset + je32_to_cpu(spd->offset));
|
|
|
|
fd = jffs2_alloc_full_dirent(spd->nsize+1);
|
|
if (!fd) {
|
|
kfree(summary);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(&fd->name, spd->name, spd->nsize);
|
|
fd->name[spd->nsize] = 0;
|
|
|
|
raw = jffs2_alloc_raw_node_ref();
|
|
if (!raw) {
|
|
jffs2_free_full_dirent(fd);
|
|
JFFS2_NOTICE("allocation of node reference failed\n");
|
|
kfree(summary);
|
|
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);
|
|
kfree(summary);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
raw->__totlen = PAD(je32_to_cpu(spd->totlen));
|
|
raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
|
|
raw->next_phys = NULL;
|
|
raw->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;
|
|
|
|
fd->raw = raw;
|
|
fd->next = NULL;
|
|
fd->version = je32_to_cpu(spd->version);
|
|
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);
|
|
|
|
sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
|
|
|
|
break;
|
|
}
|
|
|
|
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_unknown_node crcnode;
|
|
struct jffs2_raw_node_ref *cache_ref;
|
|
struct jffs2_summary_node *summary;
|
|
int ret, sumsize;
|
|
uint32_t crc;
|
|
|
|
sumsize = c->sector_size - ofs;
|
|
ofs += jeb->offset;
|
|
|
|
JFFS2_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;
|
|
}
|
|
|
|
/* OK, now check for node validity and CRC */
|
|
crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
|
crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
|
|
crcnode.totlen = summary->totlen;
|
|
crc = crc32(0, &crcnode, sizeof(crcnode)-4);
|
|
|
|
if (je32_to_cpu(summary->hdr_crc) != crc) {
|
|
JFFS2_DBG_SUMMARY("Summary node header is corrupt (bad CRC or "
|
|
"no summary at all)\n");
|
|
goto crc_err;
|
|
}
|
|
|
|
if (je32_to_cpu(summary->totlen) != sumsize) {
|
|
JFFS2_DBG_SUMMARY("Summary node is corrupt (wrong erasesize?)\n");
|
|
goto crc_err;
|
|
}
|
|
|
|
crc = crc32(0, summary, sizeof(struct jffs2_summary_node)-8);
|
|
|
|
if (je32_to_cpu(summary->node_crc) != crc) {
|
|
JFFS2_DBG_SUMMARY("Summary node is corrupt (bad CRC)\n");
|
|
goto crc_err;
|
|
}
|
|
|
|
crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_summary_node));
|
|
|
|
if (je32_to_cpu(summary->sum_crc) != crc) {
|
|
JFFS2_DBG_SUMMARY("Summary node data is corrupt (bad CRC)\n");
|
|
goto crc_err;
|
|
}
|
|
|
|
if ( je32_to_cpu(summary->cln_mkr) ) {
|
|
|
|
JFFS2_DBG_SUMMARY("Summary : CLEANMARKER node \n");
|
|
|
|
if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
|
|
JFFS2_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)));
|
|
} else if (jeb->first_node) {
|
|
JFFS2_DBG_SUMMARY("CLEANMARKER node not first node in block "
|
|
"(0x%08x)\n", jeb->offset);
|
|
UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
|
|
} else {
|
|
struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
|
|
|
|
if (!marker_ref) {
|
|
JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
|
|
kfree(summary);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
marker_ref->next_in_ino = NULL;
|
|
marker_ref->next_phys = NULL;
|
|
marker_ref->flash_offset = jeb->offset | REF_NORMAL;
|
|
marker_ref->__totlen = je32_to_cpu(summary->cln_mkr);
|
|
jeb->first_node = jeb->last_node = marker_ref;
|
|
|
|
USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) );
|
|
}
|
|
}
|
|
|
|
if (je32_to_cpu(summary->padded)) {
|
|
DIRTY_SPACE(je32_to_cpu(summary->padded));
|
|
}
|
|
|
|
ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* for PARANOIA_CHECK */
|
|
cache_ref = jffs2_alloc_raw_node_ref();
|
|
|
|
if (!cache_ref) {
|
|
JFFS2_NOTICE("Failed to allocate node ref for cache\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
crc_err:
|
|
JFFS2_WARNING("Summary node crc error, skipping summary information.\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
|
|
|
|
static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
|
uint32_t infosize, uint32_t datasize, int padsize)
|
|
{
|
|
struct jffs2_summary_node isum;
|
|
union jffs2_sum_mem *temp;
|
|
struct jffs2_sum_marker *sm;
|
|
struct kvec vecs[2];
|
|
void *wpage;
|
|
int ret;
|
|
size_t retlen;
|
|
|
|
memset(c->summary->sum_buf, 0xff, datasize);
|
|
memset(&isum, 0, sizeof(isum));
|
|
|
|
isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
|
isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
|
|
isum.totlen = cpu_to_je32(infosize);
|
|
isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
|
|
isum.padded = cpu_to_je32(c->summary->sum_padded);
|
|
isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
|
|
isum.sum_num = cpu_to_je32(c->summary->sum_num);
|
|
wpage = c->summary->sum_buf;
|
|
|
|
while (c->summary->sum_num) {
|
|
|
|
switch (je16_to_cpu(c->summary->sum_list_head->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;
|
|
|
|
wpage += JFFS2_SUMMARY_INODE_SIZE;
|
|
|
|
break;
|
|
}
|
|
|
|
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;
|
|
|
|
memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name,
|
|
c->summary->sum_list_head->d.nsize);
|
|
|
|
wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize);
|
|
|
|
break;
|
|
}
|
|
|
|
default : {
|
|
BUG(); /* unknown node in summary information */
|
|
}
|
|
}
|
|
|
|
temp = c->summary->sum_list_head;
|
|
c->summary->sum_list_head = c->summary->sum_list_head->u.next;
|
|
kfree(temp);
|
|
|
|
c->summary->sum_num--;
|
|
}
|
|
|
|
jffs2_sum_reset_collected(c->summary);
|
|
|
|
wpage += padsize;
|
|
|
|
sm = wpage;
|
|
sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
|
|
sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
|
|
|
|
isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
|
|
isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
|
|
|
|
vecs[0].iov_base = &isum;
|
|
vecs[0].iov_len = sizeof(isum);
|
|
vecs[1].iov_base = c->summary->sum_buf;
|
|
vecs[1].iov_len = datasize;
|
|
|
|
JFFS2_DBG_SUMMARY("JFFS2: writing out data to flash to pos : 0x%08x\n",
|
|
jeb->offset + c->sector_size - jeb->free_size);
|
|
|
|
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)) {
|
|
JFFS2_WARNING("Write of %zd 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;
|
|
WASTED_SPACE(infosize);
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Write out summary information - called from jffs2_do_reserve_space */
|
|
|
|
int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
|
|
{
|
|
struct jffs2_raw_node_ref *summary_ref;
|
|
int datasize, infosize, padsize, ret;
|
|
struct jffs2_eraseblock *jeb;
|
|
|
|
JFFS2_DBG_SUMMARY("called\n");
|
|
|
|
jeb = c->nextblock;
|
|
|
|
if (!c->summary->sum_num || !c->summary->sum_list_head) {
|
|
JFFS2_WARNING("Empty summary info!!!\n");
|
|
BUG();
|
|
}
|
|
|
|
datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
|
|
infosize = sizeof(struct jffs2_summary_node) + datasize;
|
|
padsize = jeb->free_size - infosize;
|
|
infosize += padsize;
|
|
datasize += padsize;
|
|
|
|
/* Is there enough space for summary? */
|
|
if (padsize < 0) {
|
|
/* don't try to write out summary for this jeb */
|
|
jffs2_sum_disable_collecting(c->summary);
|
|
|
|
JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize);
|
|
return 0;
|
|
}
|
|
|
|
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();
|
|
spin_lock(&c->erase_completion_lock);
|
|
|
|
if (!summary_ref) {
|
|
JFFS2_NOTICE("Failed to allocate node ref for summary\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
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);
|
|
|
|
return 0;
|
|
}
|