162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, 562306a36Sopenharmony_ci * Zoltan Sogor <weth@inf.u-szeged.hu>, 662306a36Sopenharmony_ci * Patrik Kluba <pajko@halom.u-szeged.hu>, 762306a36Sopenharmony_ci * University of Szeged, Hungary 862306a36Sopenharmony_ci * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 1962306a36Sopenharmony_ci#include <linux/pagemap.h> 2062306a36Sopenharmony_ci#include <linux/crc32.h> 2162306a36Sopenharmony_ci#include <linux/compiler.h> 2262306a36Sopenharmony_ci#include <linux/vmalloc.h> 2362306a36Sopenharmony_ci#include "nodelist.h" 2462306a36Sopenharmony_ci#include "debug.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciint jffs2_sum_init(struct jffs2_sb_info *c) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci uint32_t sum_size = min_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (!c->summary) { 3362306a36Sopenharmony_ci JFFS2_WARNING("Can't allocate memory for summary information!\n"); 3462306a36Sopenharmony_ci return -ENOMEM; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci c->summary->sum_buf = kmalloc(sum_size, GFP_KERNEL); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (!c->summary->sum_buf) { 4062306a36Sopenharmony_ci JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n"); 4162306a36Sopenharmony_ci kfree(c->summary); 4262306a36Sopenharmony_ci return -ENOMEM; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci dbg_summary("returned successfully\n"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid jffs2_sum_exit(struct jffs2_sb_info *c) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci dbg_summary("called\n"); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci jffs2_sum_disable_collecting(c->summary); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci kfree(c->summary->sum_buf); 5762306a36Sopenharmony_ci c->summary->sum_buf = NULL; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci kfree(c->summary); 6062306a36Sopenharmony_ci c->summary = NULL; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci if (!s->sum_list_head) 6662306a36Sopenharmony_ci s->sum_list_head = (union jffs2_sum_mem *) item; 6762306a36Sopenharmony_ci if (s->sum_list_tail) 6862306a36Sopenharmony_ci s->sum_list_tail->u.next = (union jffs2_sum_mem *) item; 6962306a36Sopenharmony_ci s->sum_list_tail = (union jffs2_sum_mem *) item; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci switch (je16_to_cpu(item->u.nodetype)) { 7262306a36Sopenharmony_ci case JFFS2_NODETYPE_INODE: 7362306a36Sopenharmony_ci s->sum_size += JFFS2_SUMMARY_INODE_SIZE; 7462306a36Sopenharmony_ci s->sum_num++; 7562306a36Sopenharmony_ci dbg_summary("inode (%u) added to summary\n", 7662306a36Sopenharmony_ci je32_to_cpu(item->i.inode)); 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci case JFFS2_NODETYPE_DIRENT: 7962306a36Sopenharmony_ci s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize); 8062306a36Sopenharmony_ci s->sum_num++; 8162306a36Sopenharmony_ci dbg_summary("dirent (%u) added to summary\n", 8262306a36Sopenharmony_ci je32_to_cpu(item->d.ino)); 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 8562306a36Sopenharmony_ci case JFFS2_NODETYPE_XATTR: 8662306a36Sopenharmony_ci s->sum_size += JFFS2_SUMMARY_XATTR_SIZE; 8762306a36Sopenharmony_ci s->sum_num++; 8862306a36Sopenharmony_ci dbg_summary("xattr (xid=%u, version=%u) added to summary\n", 8962306a36Sopenharmony_ci je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version)); 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci case JFFS2_NODETYPE_XREF: 9262306a36Sopenharmony_ci s->sum_size += JFFS2_SUMMARY_XREF_SIZE; 9362306a36Sopenharmony_ci s->sum_num++; 9462306a36Sopenharmony_ci dbg_summary("xref added to summary\n"); 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci#endif 9762306a36Sopenharmony_ci default: 9862306a36Sopenharmony_ci JFFS2_WARNING("UNKNOWN node type %u\n", 9962306a36Sopenharmony_ci je16_to_cpu(item->u.nodetype)); 10062306a36Sopenharmony_ci return 1; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciint jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci dbg_summary("called with %u\n", size); 11162306a36Sopenharmony_ci s->sum_padded += size; 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciint jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, 11662306a36Sopenharmony_ci uint32_t ofs) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (!temp) 12162306a36Sopenharmony_ci return -ENOMEM; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci temp->nodetype = ri->nodetype; 12462306a36Sopenharmony_ci temp->inode = ri->ino; 12562306a36Sopenharmony_ci temp->version = ri->version; 12662306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); /* relative offset from the beginning of the jeb */ 12762306a36Sopenharmony_ci temp->totlen = ri->totlen; 12862306a36Sopenharmony_ci temp->next = NULL; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ciint jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, 13462306a36Sopenharmony_ci uint32_t ofs) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct jffs2_sum_dirent_mem *temp = 13762306a36Sopenharmony_ci kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!temp) 14062306a36Sopenharmony_ci return -ENOMEM; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci temp->nodetype = rd->nodetype; 14362306a36Sopenharmony_ci temp->totlen = rd->totlen; 14462306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); /* relative from the beginning of the jeb */ 14562306a36Sopenharmony_ci temp->pino = rd->pino; 14662306a36Sopenharmony_ci temp->version = rd->version; 14762306a36Sopenharmony_ci temp->ino = rd->ino; 14862306a36Sopenharmony_ci temp->nsize = rd->nsize; 14962306a36Sopenharmony_ci temp->type = rd->type; 15062306a36Sopenharmony_ci temp->next = NULL; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci memcpy(temp->name, rd->name, rd->nsize); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 15862306a36Sopenharmony_ciint jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct jffs2_sum_xattr_mem *temp; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); 16362306a36Sopenharmony_ci if (!temp) 16462306a36Sopenharmony_ci return -ENOMEM; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci temp->nodetype = rx->nodetype; 16762306a36Sopenharmony_ci temp->xid = rx->xid; 16862306a36Sopenharmony_ci temp->version = rx->version; 16962306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); 17062306a36Sopenharmony_ci temp->totlen = rx->totlen; 17162306a36Sopenharmony_ci temp->next = NULL; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct jffs2_sum_xref_mem *temp; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); 18162306a36Sopenharmony_ci if (!temp) 18262306a36Sopenharmony_ci return -ENOMEM; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci temp->nodetype = rr->nodetype; 18562306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); 18662306a36Sopenharmony_ci temp->next = NULL; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci#endif 19162306a36Sopenharmony_ci/* Cleanup every collected summary information */ 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void jffs2_sum_clean_collected(struct jffs2_summary *s) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci union jffs2_sum_mem *temp; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (!s->sum_list_head) { 19862306a36Sopenharmony_ci dbg_summary("already empty\n"); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci while (s->sum_list_head) { 20162306a36Sopenharmony_ci temp = s->sum_list_head; 20262306a36Sopenharmony_ci s->sum_list_head = s->sum_list_head->u.next; 20362306a36Sopenharmony_ci kfree(temp); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci s->sum_list_tail = NULL; 20662306a36Sopenharmony_ci s->sum_padded = 0; 20762306a36Sopenharmony_ci s->sum_num = 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_civoid jffs2_sum_reset_collected(struct jffs2_summary *s) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci dbg_summary("called\n"); 21362306a36Sopenharmony_ci jffs2_sum_clean_collected(s); 21462306a36Sopenharmony_ci s->sum_size = 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_civoid jffs2_sum_disable_collecting(struct jffs2_summary *s) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci dbg_summary("called\n"); 22062306a36Sopenharmony_ci jffs2_sum_clean_collected(s); 22162306a36Sopenharmony_ci s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ciint jffs2_sum_is_disabled(struct jffs2_summary *s) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* Move the collected summary information into sb (called from scan.c) */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_civoid jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci dbg_summary("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n", 23462306a36Sopenharmony_ci c->summary->sum_size, c->summary->sum_num, 23562306a36Sopenharmony_ci s->sum_size, s->sum_num); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci c->summary->sum_size = s->sum_size; 23862306a36Sopenharmony_ci c->summary->sum_num = s->sum_num; 23962306a36Sopenharmony_ci c->summary->sum_padded = s->sum_padded; 24062306a36Sopenharmony_ci c->summary->sum_list_head = s->sum_list_head; 24162306a36Sopenharmony_ci c->summary->sum_list_tail = s->sum_list_tail; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci s->sum_list_head = s->sum_list_tail = NULL; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* Called from wbuf.c to collect writed node info */ 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ciint jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, 24962306a36Sopenharmony_ci unsigned long count, uint32_t ofs) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci union jffs2_node_union *node; 25262306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (c->summary->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) { 25562306a36Sopenharmony_ci dbg_summary("Summary is disabled for this jeb! Skipping summary info!\n"); 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci node = invecs[0].iov_base; 26062306a36Sopenharmony_ci jeb = &c->blocks[ofs / c->sector_size]; 26162306a36Sopenharmony_ci ofs -= jeb->offset; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci switch (je16_to_cpu(node->u.nodetype)) { 26462306a36Sopenharmony_ci case JFFS2_NODETYPE_INODE: { 26562306a36Sopenharmony_ci struct jffs2_sum_inode_mem *temp = 26662306a36Sopenharmony_ci kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!temp) 26962306a36Sopenharmony_ci goto no_mem; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci temp->nodetype = node->i.nodetype; 27262306a36Sopenharmony_ci temp->inode = node->i.ino; 27362306a36Sopenharmony_ci temp->version = node->i.version; 27462306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); 27562306a36Sopenharmony_ci temp->totlen = node->i.totlen; 27662306a36Sopenharmony_ci temp->next = NULL; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci case JFFS2_NODETYPE_DIRENT: { 28262306a36Sopenharmony_ci struct jffs2_sum_dirent_mem *temp = 28362306a36Sopenharmony_ci kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!temp) 28662306a36Sopenharmony_ci goto no_mem; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci temp->nodetype = node->d.nodetype; 28962306a36Sopenharmony_ci temp->totlen = node->d.totlen; 29062306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); 29162306a36Sopenharmony_ci temp->pino = node->d.pino; 29262306a36Sopenharmony_ci temp->version = node->d.version; 29362306a36Sopenharmony_ci temp->ino = node->d.ino; 29462306a36Sopenharmony_ci temp->nsize = node->d.nsize; 29562306a36Sopenharmony_ci temp->type = node->d.type; 29662306a36Sopenharmony_ci temp->next = NULL; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci switch (count) { 29962306a36Sopenharmony_ci case 1: 30062306a36Sopenharmony_ci memcpy(temp->name,node->d.name,node->d.nsize); 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci case 2: 30462306a36Sopenharmony_ci memcpy(temp->name,invecs[1].iov_base,node->d.nsize); 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci default: 30862306a36Sopenharmony_ci BUG(); /* impossible count value */ 30962306a36Sopenharmony_ci break; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 31562306a36Sopenharmony_ci case JFFS2_NODETYPE_XATTR: { 31662306a36Sopenharmony_ci struct jffs2_sum_xattr_mem *temp; 31762306a36Sopenharmony_ci temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); 31862306a36Sopenharmony_ci if (!temp) 31962306a36Sopenharmony_ci goto no_mem; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci temp->nodetype = node->x.nodetype; 32262306a36Sopenharmony_ci temp->xid = node->x.xid; 32362306a36Sopenharmony_ci temp->version = node->x.version; 32462306a36Sopenharmony_ci temp->totlen = node->x.totlen; 32562306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); 32662306a36Sopenharmony_ci temp->next = NULL; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci case JFFS2_NODETYPE_XREF: { 33162306a36Sopenharmony_ci struct jffs2_sum_xref_mem *temp; 33262306a36Sopenharmony_ci temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); 33362306a36Sopenharmony_ci if (!temp) 33462306a36Sopenharmony_ci goto no_mem; 33562306a36Sopenharmony_ci temp->nodetype = node->r.nodetype; 33662306a36Sopenharmony_ci temp->offset = cpu_to_je32(ofs); 33762306a36Sopenharmony_ci temp->next = NULL; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci#endif 34262306a36Sopenharmony_ci case JFFS2_NODETYPE_PADDING: 34362306a36Sopenharmony_ci dbg_summary("node PADDING\n"); 34462306a36Sopenharmony_ci c->summary->sum_padded += je32_to_cpu(node->u.totlen); 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci case JFFS2_NODETYPE_CLEANMARKER: 34862306a36Sopenharmony_ci dbg_summary("node CLEANMARKER\n"); 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci case JFFS2_NODETYPE_SUMMARY: 35262306a36Sopenharmony_ci dbg_summary("node SUMMARY\n"); 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci default: 35662306a36Sopenharmony_ci /* If you implement a new node type you should also implement 35762306a36Sopenharmony_ci summary support for it or disable summary. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci BUG(); 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cino_mem: 36662306a36Sopenharmony_ci JFFS2_WARNING("MEMORY ALLOCATION ERROR!"); 36762306a36Sopenharmony_ci return -ENOMEM; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c, 37162306a36Sopenharmony_ci struct jffs2_eraseblock *jeb, 37262306a36Sopenharmony_ci uint32_t ofs, uint32_t len, 37362306a36Sopenharmony_ci struct jffs2_inode_cache *ic) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci /* If there was a gap, mark it dirty */ 37662306a36Sopenharmony_ci if ((ofs & ~3) > c->sector_size - jeb->free_size) { 37762306a36Sopenharmony_ci /* Ew. Summary doesn't actually tell us explicitly about dirty space */ 37862306a36Sopenharmony_ci jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size)); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 38762306a36Sopenharmony_ci struct jffs2_raw_summary *summary, uint32_t *pseudo_random) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct jffs2_inode_cache *ic; 39062306a36Sopenharmony_ci struct jffs2_full_dirent *fd; 39162306a36Sopenharmony_ci void *sp; 39262306a36Sopenharmony_ci int i, ino; 39362306a36Sopenharmony_ci int err; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci sp = summary->sum; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci for (i=0; i<je32_to_cpu(summary->sum_num); i++) { 39862306a36Sopenharmony_ci dbg_summary("processing summary index %d\n", i); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci cond_resched(); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* Make sure there's a spare ref for dirty space */ 40362306a36Sopenharmony_ci err = jffs2_prealloc_raw_node_refs(c, jeb, 2); 40462306a36Sopenharmony_ci if (err) 40562306a36Sopenharmony_ci return err; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { 40862306a36Sopenharmony_ci case JFFS2_NODETYPE_INODE: { 40962306a36Sopenharmony_ci struct jffs2_sum_inode_flash *spi; 41062306a36Sopenharmony_ci spi = sp; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ino = je32_to_cpu(spi->inode); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci dbg_summary("Inode at 0x%08x-0x%08x\n", 41562306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spi->offset), 41662306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen)); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ic = jffs2_scan_make_ino_cache(c, ino); 41962306a36Sopenharmony_ci if (!ic) { 42062306a36Sopenharmony_ci JFFS2_NOTICE("scan_make_ino_cache failed\n"); 42162306a36Sopenharmony_ci return -ENOMEM; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED, 42562306a36Sopenharmony_ci PAD(je32_to_cpu(spi->totlen)), ic); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci *pseudo_random += je32_to_cpu(spi->version); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci sp += JFFS2_SUMMARY_INODE_SIZE; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci case JFFS2_NODETYPE_DIRENT: { 43562306a36Sopenharmony_ci struct jffs2_sum_dirent_flash *spd; 43662306a36Sopenharmony_ci int checkedlen; 43762306a36Sopenharmony_ci spd = sp; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci dbg_summary("Dirent at 0x%08x-0x%08x\n", 44062306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spd->offset), 44162306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* This should never happen, but https://dev.laptop.org/ticket/4184 */ 44562306a36Sopenharmony_ci checkedlen = strnlen(spd->name, spd->nsize); 44662306a36Sopenharmony_ci if (!checkedlen) { 44762306a36Sopenharmony_ci pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n", 44862306a36Sopenharmony_ci jeb->offset + 44962306a36Sopenharmony_ci je32_to_cpu(spd->offset)); 45062306a36Sopenharmony_ci return -EIO; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci if (checkedlen < spd->nsize) { 45362306a36Sopenharmony_ci pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n", 45462306a36Sopenharmony_ci jeb->offset + 45562306a36Sopenharmony_ci je32_to_cpu(spd->offset), 45662306a36Sopenharmony_ci checkedlen); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci fd = jffs2_alloc_full_dirent(checkedlen+1); 46162306a36Sopenharmony_ci if (!fd) 46262306a36Sopenharmony_ci return -ENOMEM; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci memcpy(&fd->name, spd->name, checkedlen); 46562306a36Sopenharmony_ci fd->name[checkedlen] = 0; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); 46862306a36Sopenharmony_ci if (!ic) { 46962306a36Sopenharmony_ci jffs2_free_full_dirent(fd); 47062306a36Sopenharmony_ci return -ENOMEM; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_UNCHECKED, 47462306a36Sopenharmony_ci PAD(je32_to_cpu(spd->totlen)), ic); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci fd->next = NULL; 47762306a36Sopenharmony_ci fd->version = je32_to_cpu(spd->version); 47862306a36Sopenharmony_ci fd->ino = je32_to_cpu(spd->ino); 47962306a36Sopenharmony_ci fd->nhash = full_name_hash(NULL, fd->name, checkedlen); 48062306a36Sopenharmony_ci fd->type = spd->type; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci jffs2_add_fd_to_list(c, fd, &ic->scan_dents); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci *pseudo_random += je32_to_cpu(spd->version); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci break; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 49162306a36Sopenharmony_ci case JFFS2_NODETYPE_XATTR: { 49262306a36Sopenharmony_ci struct jffs2_xattr_datum *xd; 49362306a36Sopenharmony_ci struct jffs2_sum_xattr_flash *spx; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci spx = (struct jffs2_sum_xattr_flash *)sp; 49662306a36Sopenharmony_ci dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", 49762306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spx->offset), 49862306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), 49962306a36Sopenharmony_ci je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), 50262306a36Sopenharmony_ci je32_to_cpu(spx->version)); 50362306a36Sopenharmony_ci if (IS_ERR(xd)) 50462306a36Sopenharmony_ci return PTR_ERR(xd); 50562306a36Sopenharmony_ci if (xd->version > je32_to_cpu(spx->version)) { 50662306a36Sopenharmony_ci /* node is not the newest one */ 50762306a36Sopenharmony_ci struct jffs2_raw_node_ref *raw 50862306a36Sopenharmony_ci = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, 50962306a36Sopenharmony_ci PAD(je32_to_cpu(spx->totlen)), NULL); 51062306a36Sopenharmony_ci raw->next_in_ino = xd->node->next_in_ino; 51162306a36Sopenharmony_ci xd->node->next_in_ino = raw; 51262306a36Sopenharmony_ci } else { 51362306a36Sopenharmony_ci xd->version = je32_to_cpu(spx->version); 51462306a36Sopenharmony_ci sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, 51562306a36Sopenharmony_ci PAD(je32_to_cpu(spx->totlen)), (void *)xd); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci *pseudo_random += je32_to_cpu(spx->xid); 51862306a36Sopenharmony_ci sp += JFFS2_SUMMARY_XATTR_SIZE; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci case JFFS2_NODETYPE_XREF: { 52362306a36Sopenharmony_ci struct jffs2_xattr_ref *ref; 52462306a36Sopenharmony_ci struct jffs2_sum_xref_flash *spr; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci spr = (struct jffs2_sum_xref_flash *)sp; 52762306a36Sopenharmony_ci dbg_summary("xref at %#08x-%#08x\n", 52862306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spr->offset), 52962306a36Sopenharmony_ci jeb->offset + je32_to_cpu(spr->offset) + 53062306a36Sopenharmony_ci (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ref = jffs2_alloc_xattr_ref(); 53362306a36Sopenharmony_ci if (!ref) { 53462306a36Sopenharmony_ci JFFS2_NOTICE("allocation of xattr_datum failed\n"); 53562306a36Sopenharmony_ci return -ENOMEM; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci ref->next = c->xref_temp; 53862306a36Sopenharmony_ci c->xref_temp = ref; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, 54162306a36Sopenharmony_ci PAD(sizeof(struct jffs2_raw_xref)), (void *)ref); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci *pseudo_random += ref->node->flash_offset; 54462306a36Sopenharmony_ci sp += JFFS2_SUMMARY_XREF_SIZE; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci#endif 54962306a36Sopenharmony_ci default : { 55062306a36Sopenharmony_ci uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype); 55162306a36Sopenharmony_ci JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype); 55262306a36Sopenharmony_ci if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT) 55362306a36Sopenharmony_ci return -EIO; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* For compatible node types, just fall back to the full scan */ 55662306a36Sopenharmony_ci c->wasted_size -= jeb->wasted_size; 55762306a36Sopenharmony_ci c->free_size += c->sector_size - jeb->free_size; 55862306a36Sopenharmony_ci c->used_size -= jeb->used_size; 55962306a36Sopenharmony_ci c->dirty_size -= jeb->dirty_size; 56062306a36Sopenharmony_ci jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0; 56162306a36Sopenharmony_ci jeb->free_size = c->sector_size; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci jffs2_free_jeb_node_refs(c, jeb); 56462306a36Sopenharmony_ci return -ENOTRECOVERABLE; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/* Process the summary node - called from jffs2_scan_eraseblock() */ 57262306a36Sopenharmony_ciint jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 57362306a36Sopenharmony_ci struct jffs2_raw_summary *summary, uint32_t sumsize, 57462306a36Sopenharmony_ci uint32_t *pseudo_random) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct jffs2_unknown_node crcnode; 57762306a36Sopenharmony_ci int ret, ofs; 57862306a36Sopenharmony_ci uint32_t crc; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci ofs = c->sector_size - sumsize; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", 58362306a36Sopenharmony_ci jeb->offset, jeb->offset + ofs, sumsize); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* OK, now check for node validity and CRC */ 58662306a36Sopenharmony_ci crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 58762306a36Sopenharmony_ci crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); 58862306a36Sopenharmony_ci crcnode.totlen = summary->totlen; 58962306a36Sopenharmony_ci crc = crc32(0, &crcnode, sizeof(crcnode)-4); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (je32_to_cpu(summary->hdr_crc) != crc) { 59262306a36Sopenharmony_ci dbg_summary("Summary node header is corrupt (bad CRC or " 59362306a36Sopenharmony_ci "no summary at all)\n"); 59462306a36Sopenharmony_ci goto crc_err; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (je32_to_cpu(summary->totlen) != sumsize) { 59862306a36Sopenharmony_ci dbg_summary("Summary node is corrupt (wrong erasesize?)\n"); 59962306a36Sopenharmony_ci goto crc_err; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (je32_to_cpu(summary->node_crc) != crc) { 60562306a36Sopenharmony_ci dbg_summary("Summary node is corrupt (bad CRC)\n"); 60662306a36Sopenharmony_ci goto crc_err; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary)); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (je32_to_cpu(summary->sum_crc) != crc) { 61262306a36Sopenharmony_ci dbg_summary("Summary node data is corrupt (bad CRC)\n"); 61362306a36Sopenharmony_ci goto crc_err; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if ( je32_to_cpu(summary->cln_mkr) ) { 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci dbg_summary("Summary : CLEANMARKER node \n"); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); 62162306a36Sopenharmony_ci if (ret) 62262306a36Sopenharmony_ci return ret; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { 62562306a36Sopenharmony_ci dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", 62662306a36Sopenharmony_ci je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); 62762306a36Sopenharmony_ci if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) 62862306a36Sopenharmony_ci return ret; 62962306a36Sopenharmony_ci } else if (jeb->first_node) { 63062306a36Sopenharmony_ci dbg_summary("CLEANMARKER node not first node in block " 63162306a36Sopenharmony_ci "(0x%08x)\n", jeb->offset); 63262306a36Sopenharmony_ci if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) 63362306a36Sopenharmony_ci return ret; 63462306a36Sopenharmony_ci } else { 63562306a36Sopenharmony_ci jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, 63662306a36Sopenharmony_ci je32_to_cpu(summary->cln_mkr), NULL); 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); 64162306a36Sopenharmony_ci /* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full 64262306a36Sopenharmony_ci scan of this eraseblock. So return zero */ 64362306a36Sopenharmony_ci if (ret == -ENOTRECOVERABLE) 64462306a36Sopenharmony_ci return 0; 64562306a36Sopenharmony_ci if (ret) 64662306a36Sopenharmony_ci return ret; /* real error */ 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* for PARANOIA_CHECK */ 64962306a36Sopenharmony_ci ret = jffs2_prealloc_raw_node_refs(c, jeb, 2); 65062306a36Sopenharmony_ci if (ret) 65162306a36Sopenharmony_ci return ret; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (unlikely(jeb->free_size)) { 65662306a36Sopenharmony_ci JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", 65762306a36Sopenharmony_ci jeb->free_size, jeb->offset); 65862306a36Sopenharmony_ci jeb->wasted_size += jeb->free_size; 65962306a36Sopenharmony_ci c->wasted_size += jeb->free_size; 66062306a36Sopenharmony_ci c->free_size -= jeb->free_size; 66162306a36Sopenharmony_ci jeb->free_size = 0; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return jffs2_scan_classify_jeb(c, jeb); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cicrc_err: 66762306a36Sopenharmony_ci JFFS2_WARNING("Summary node crc error, skipping summary information.\n"); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return 0; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */ 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 67562306a36Sopenharmony_ci uint32_t infosize, uint32_t datasize, int padsize) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct jffs2_raw_summary isum; 67862306a36Sopenharmony_ci union jffs2_sum_mem *temp; 67962306a36Sopenharmony_ci struct jffs2_sum_marker *sm; 68062306a36Sopenharmony_ci struct kvec vecs[2]; 68162306a36Sopenharmony_ci uint32_t sum_ofs; 68262306a36Sopenharmony_ci void *wpage; 68362306a36Sopenharmony_ci int ret; 68462306a36Sopenharmony_ci size_t retlen; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (padsize + datasize > MAX_SUMMARY_SIZE) { 68762306a36Sopenharmony_ci /* It won't fit in the buffer. Abort summary for this jeb */ 68862306a36Sopenharmony_ci jffs2_sum_disable_collecting(c->summary); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci JFFS2_WARNING("Summary too big (%d data, %d pad) in eraseblock at %08x\n", 69162306a36Sopenharmony_ci datasize, padsize, jeb->offset); 69262306a36Sopenharmony_ci /* Non-fatal */ 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci /* Is there enough space for summary? */ 69662306a36Sopenharmony_ci if (padsize < 0) { 69762306a36Sopenharmony_ci /* don't try to write out summary for this jeb */ 69862306a36Sopenharmony_ci jffs2_sum_disable_collecting(c->summary); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci JFFS2_WARNING("Not enough space for summary, padsize = %d\n", 70162306a36Sopenharmony_ci padsize); 70262306a36Sopenharmony_ci /* Non-fatal */ 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci memset(c->summary->sum_buf, 0xff, datasize); 70762306a36Sopenharmony_ci memset(&isum, 0, sizeof(isum)); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 71062306a36Sopenharmony_ci isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); 71162306a36Sopenharmony_ci isum.totlen = cpu_to_je32(infosize); 71262306a36Sopenharmony_ci isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4)); 71362306a36Sopenharmony_ci isum.padded = cpu_to_je32(c->summary->sum_padded); 71462306a36Sopenharmony_ci isum.cln_mkr = cpu_to_je32(c->cleanmarker_size); 71562306a36Sopenharmony_ci isum.sum_num = cpu_to_je32(c->summary->sum_num); 71662306a36Sopenharmony_ci wpage = c->summary->sum_buf; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci while (c->summary->sum_num) { 71962306a36Sopenharmony_ci temp = c->summary->sum_list_head; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci switch (je16_to_cpu(temp->u.nodetype)) { 72262306a36Sopenharmony_ci case JFFS2_NODETYPE_INODE: { 72362306a36Sopenharmony_ci struct jffs2_sum_inode_flash *sino_ptr = wpage; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci sino_ptr->nodetype = temp->i.nodetype; 72662306a36Sopenharmony_ci sino_ptr->inode = temp->i.inode; 72762306a36Sopenharmony_ci sino_ptr->version = temp->i.version; 72862306a36Sopenharmony_ci sino_ptr->offset = temp->i.offset; 72962306a36Sopenharmony_ci sino_ptr->totlen = temp->i.totlen; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci wpage += JFFS2_SUMMARY_INODE_SIZE; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci case JFFS2_NODETYPE_DIRENT: { 73762306a36Sopenharmony_ci struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci sdrnt_ptr->nodetype = temp->d.nodetype; 74062306a36Sopenharmony_ci sdrnt_ptr->totlen = temp->d.totlen; 74162306a36Sopenharmony_ci sdrnt_ptr->offset = temp->d.offset; 74262306a36Sopenharmony_ci sdrnt_ptr->pino = temp->d.pino; 74362306a36Sopenharmony_ci sdrnt_ptr->version = temp->d.version; 74462306a36Sopenharmony_ci sdrnt_ptr->ino = temp->d.ino; 74562306a36Sopenharmony_ci sdrnt_ptr->nsize = temp->d.nsize; 74662306a36Sopenharmony_ci sdrnt_ptr->type = temp->d.type; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci memcpy(sdrnt_ptr->name, temp->d.name, 74962306a36Sopenharmony_ci temp->d.nsize); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci wpage += JFFS2_SUMMARY_DIRENT_SIZE(temp->d.nsize); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 75662306a36Sopenharmony_ci case JFFS2_NODETYPE_XATTR: { 75762306a36Sopenharmony_ci struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci temp = c->summary->sum_list_head; 76062306a36Sopenharmony_ci sxattr_ptr->nodetype = temp->x.nodetype; 76162306a36Sopenharmony_ci sxattr_ptr->xid = temp->x.xid; 76262306a36Sopenharmony_ci sxattr_ptr->version = temp->x.version; 76362306a36Sopenharmony_ci sxattr_ptr->offset = temp->x.offset; 76462306a36Sopenharmony_ci sxattr_ptr->totlen = temp->x.totlen; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci wpage += JFFS2_SUMMARY_XATTR_SIZE; 76762306a36Sopenharmony_ci break; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci case JFFS2_NODETYPE_XREF: { 77062306a36Sopenharmony_ci struct jffs2_sum_xref_flash *sxref_ptr = wpage; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci temp = c->summary->sum_list_head; 77362306a36Sopenharmony_ci sxref_ptr->nodetype = temp->r.nodetype; 77462306a36Sopenharmony_ci sxref_ptr->offset = temp->r.offset; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci wpage += JFFS2_SUMMARY_XREF_SIZE; 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci#endif 78062306a36Sopenharmony_ci default : { 78162306a36Sopenharmony_ci if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK) 78262306a36Sopenharmony_ci == JFFS2_FEATURE_RWCOMPAT_COPY) { 78362306a36Sopenharmony_ci dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n", 78462306a36Sopenharmony_ci je16_to_cpu(temp->u.nodetype)); 78562306a36Sopenharmony_ci jffs2_sum_disable_collecting(c->summary); 78662306a36Sopenharmony_ci /* The above call removes the list, nothing more to do */ 78762306a36Sopenharmony_ci goto bail_rwcompat; 78862306a36Sopenharmony_ci } else { 78962306a36Sopenharmony_ci BUG(); /* unknown node in summary information */ 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci c->summary->sum_list_head = temp->u.next; 79562306a36Sopenharmony_ci kfree(temp); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci c->summary->sum_num--; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci bail_rwcompat: 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci jffs2_sum_reset_collected(c->summary); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci wpage += padsize; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci sm = wpage; 80662306a36Sopenharmony_ci sm->offset = cpu_to_je32(c->sector_size - jeb->free_size); 80762306a36Sopenharmony_ci sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize)); 81062306a36Sopenharmony_ci isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8)); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci vecs[0].iov_base = &isum; 81362306a36Sopenharmony_ci vecs[0].iov_len = sizeof(isum); 81462306a36Sopenharmony_ci vecs[1].iov_base = c->summary->sum_buf; 81562306a36Sopenharmony_ci vecs[1].iov_len = datasize; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci sum_ofs = jeb->offset + c->sector_size - jeb->free_size; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci dbg_summary("writing out data to flash to pos : 0x%08x\n", sum_ofs); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (ret || (retlen != infosize)) { 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", 82662306a36Sopenharmony_ci infosize, sum_ofs, ret, retlen); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (retlen) { 82962306a36Sopenharmony_ci /* Waste remaining space */ 83062306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 83162306a36Sopenharmony_ci jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); 83262306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci return 0; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 84162306a36Sopenharmony_ci jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL); 84262306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/* Write out summary information - called from jffs2_do_reserve_space */ 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ciint jffs2_sum_write_sumnode(struct jffs2_sb_info *c) 85062306a36Sopenharmony_ci __must_hold(&c->erase_completion_block) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci int datasize, infosize, padsize; 85362306a36Sopenharmony_ci struct jffs2_eraseblock *jeb; 85462306a36Sopenharmony_ci int ret = 0; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci dbg_summary("called\n"); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci spin_unlock(&c->erase_completion_lock); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci jeb = c->nextblock; 86162306a36Sopenharmony_ci jffs2_prealloc_raw_node_refs(c, jeb, 1); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (!c->summary->sum_num || !c->summary->sum_list_head) { 86462306a36Sopenharmony_ci JFFS2_WARNING("Empty summary info!!!\n"); 86562306a36Sopenharmony_ci BUG(); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker); 86962306a36Sopenharmony_ci infosize = sizeof(struct jffs2_raw_summary) + datasize; 87062306a36Sopenharmony_ci padsize = jeb->free_size - infosize; 87162306a36Sopenharmony_ci infosize += padsize; 87262306a36Sopenharmony_ci datasize += padsize; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); 87562306a36Sopenharmony_ci spin_lock(&c->erase_completion_lock); 87662306a36Sopenharmony_ci return ret; 87762306a36Sopenharmony_ci} 878