18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
58c2ecf20Sopenharmony_ci *		     Zoltan Sogor <weth@inf.u-szeged.hu>,
68c2ecf20Sopenharmony_ci *		     Patrik Kluba <pajko@halom.u-szeged.hu>,
78c2ecf20Sopenharmony_ci *		     University of Szeged, Hungary
88c2ecf20Sopenharmony_ci *	       2006  KaiGai Kohei <kaigai@ak.jp.nec.com>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h>
198c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
208c2ecf20Sopenharmony_ci#include <linux/crc32.h>
218c2ecf20Sopenharmony_ci#include <linux/compiler.h>
228c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
238c2ecf20Sopenharmony_ci#include "nodelist.h"
248c2ecf20Sopenharmony_ci#include "debug.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciint jffs2_sum_init(struct jffs2_sb_info *c)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	uint32_t sum_size = min_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (!c->summary) {
338c2ecf20Sopenharmony_ci		JFFS2_WARNING("Can't allocate memory for summary information!\n");
348c2ecf20Sopenharmony_ci		return -ENOMEM;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	c->summary->sum_buf = kmalloc(sum_size, GFP_KERNEL);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!c->summary->sum_buf) {
408c2ecf20Sopenharmony_ci		JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n");
418c2ecf20Sopenharmony_ci		kfree(c->summary);
428c2ecf20Sopenharmony_ci		return -ENOMEM;
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	dbg_summary("returned successfully\n");
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	return 0;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_civoid jffs2_sum_exit(struct jffs2_sb_info *c)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	dbg_summary("called\n");
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	jffs2_sum_disable_collecting(c->summary);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	kfree(c->summary->sum_buf);
578c2ecf20Sopenharmony_ci	c->summary->sum_buf = NULL;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	kfree(c->summary);
608c2ecf20Sopenharmony_ci	c->summary = NULL;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	if (!s->sum_list_head)
668c2ecf20Sopenharmony_ci		s->sum_list_head = (union jffs2_sum_mem *) item;
678c2ecf20Sopenharmony_ci	if (s->sum_list_tail)
688c2ecf20Sopenharmony_ci		s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
698c2ecf20Sopenharmony_ci	s->sum_list_tail = (union jffs2_sum_mem *) item;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	switch (je16_to_cpu(item->u.nodetype)) {
728c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_INODE:
738c2ecf20Sopenharmony_ci			s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
748c2ecf20Sopenharmony_ci			s->sum_num++;
758c2ecf20Sopenharmony_ci			dbg_summary("inode (%u) added to summary\n",
768c2ecf20Sopenharmony_ci						je32_to_cpu(item->i.inode));
778c2ecf20Sopenharmony_ci			break;
788c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_DIRENT:
798c2ecf20Sopenharmony_ci			s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
808c2ecf20Sopenharmony_ci			s->sum_num++;
818c2ecf20Sopenharmony_ci			dbg_summary("dirent (%u) added to summary\n",
828c2ecf20Sopenharmony_ci						je32_to_cpu(item->d.ino));
838c2ecf20Sopenharmony_ci			break;
848c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR
858c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_XATTR:
868c2ecf20Sopenharmony_ci			s->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
878c2ecf20Sopenharmony_ci			s->sum_num++;
888c2ecf20Sopenharmony_ci			dbg_summary("xattr (xid=%u, version=%u) added to summary\n",
898c2ecf20Sopenharmony_ci				    je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version));
908c2ecf20Sopenharmony_ci			break;
918c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_XREF:
928c2ecf20Sopenharmony_ci			s->sum_size += JFFS2_SUMMARY_XREF_SIZE;
938c2ecf20Sopenharmony_ci			s->sum_num++;
948c2ecf20Sopenharmony_ci			dbg_summary("xref added to summary\n");
958c2ecf20Sopenharmony_ci			break;
968c2ecf20Sopenharmony_ci#endif
978c2ecf20Sopenharmony_ci		default:
988c2ecf20Sopenharmony_ci			JFFS2_WARNING("UNKNOWN node type %u\n",
998c2ecf20Sopenharmony_ci					    je16_to_cpu(item->u.nodetype));
1008c2ecf20Sopenharmony_ci			return 1;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ciint jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	dbg_summary("called with %u\n", size);
1118c2ecf20Sopenharmony_ci	s->sum_padded += size;
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciint jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri,
1168c2ecf20Sopenharmony_ci				uint32_t ofs)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (!temp)
1218c2ecf20Sopenharmony_ci		return -ENOMEM;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	temp->nodetype = ri->nodetype;
1248c2ecf20Sopenharmony_ci	temp->inode = ri->ino;
1258c2ecf20Sopenharmony_ci	temp->version = ri->version;
1268c2ecf20Sopenharmony_ci	temp->offset = cpu_to_je32(ofs); /* relative offset from the beginning of the jeb */
1278c2ecf20Sopenharmony_ci	temp->totlen = ri->totlen;
1288c2ecf20Sopenharmony_ci	temp->next = NULL;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ciint jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd,
1348c2ecf20Sopenharmony_ci				uint32_t ofs)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct jffs2_sum_dirent_mem *temp =
1378c2ecf20Sopenharmony_ci		kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (!temp)
1408c2ecf20Sopenharmony_ci		return -ENOMEM;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	temp->nodetype = rd->nodetype;
1438c2ecf20Sopenharmony_ci	temp->totlen = rd->totlen;
1448c2ecf20Sopenharmony_ci	temp->offset = cpu_to_je32(ofs);	/* relative from the beginning of the jeb */
1458c2ecf20Sopenharmony_ci	temp->pino = rd->pino;
1468c2ecf20Sopenharmony_ci	temp->version = rd->version;
1478c2ecf20Sopenharmony_ci	temp->ino = rd->ino;
1488c2ecf20Sopenharmony_ci	temp->nsize = rd->nsize;
1498c2ecf20Sopenharmony_ci	temp->type = rd->type;
1508c2ecf20Sopenharmony_ci	temp->next = NULL;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	memcpy(temp->name, rd->name, rd->nsize);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR
1588c2ecf20Sopenharmony_ciint jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct jffs2_sum_xattr_mem *temp;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
1638c2ecf20Sopenharmony_ci	if (!temp)
1648c2ecf20Sopenharmony_ci		return -ENOMEM;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	temp->nodetype = rx->nodetype;
1678c2ecf20Sopenharmony_ci	temp->xid = rx->xid;
1688c2ecf20Sopenharmony_ci	temp->version = rx->version;
1698c2ecf20Sopenharmony_ci	temp->offset = cpu_to_je32(ofs);
1708c2ecf20Sopenharmony_ci	temp->totlen = rx->totlen;
1718c2ecf20Sopenharmony_ci	temp->next = NULL;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ciint jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct jffs2_sum_xref_mem *temp;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
1818c2ecf20Sopenharmony_ci	if (!temp)
1828c2ecf20Sopenharmony_ci		return -ENOMEM;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	temp->nodetype = rr->nodetype;
1858c2ecf20Sopenharmony_ci	temp->offset = cpu_to_je32(ofs);
1868c2ecf20Sopenharmony_ci	temp->next = NULL;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci#endif
1918c2ecf20Sopenharmony_ci/* Cleanup every collected summary information */
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic void jffs2_sum_clean_collected(struct jffs2_summary *s)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	union jffs2_sum_mem *temp;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (!s->sum_list_head) {
1988c2ecf20Sopenharmony_ci		dbg_summary("already empty\n");
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci	while (s->sum_list_head) {
2018c2ecf20Sopenharmony_ci		temp = s->sum_list_head;
2028c2ecf20Sopenharmony_ci		s->sum_list_head = s->sum_list_head->u.next;
2038c2ecf20Sopenharmony_ci		kfree(temp);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci	s->sum_list_tail = NULL;
2068c2ecf20Sopenharmony_ci	s->sum_padded = 0;
2078c2ecf20Sopenharmony_ci	s->sum_num = 0;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_civoid jffs2_sum_reset_collected(struct jffs2_summary *s)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	dbg_summary("called\n");
2138c2ecf20Sopenharmony_ci	jffs2_sum_clean_collected(s);
2148c2ecf20Sopenharmony_ci	s->sum_size = 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_civoid jffs2_sum_disable_collecting(struct jffs2_summary *s)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	dbg_summary("called\n");
2208c2ecf20Sopenharmony_ci	jffs2_sum_clean_collected(s);
2218c2ecf20Sopenharmony_ci	s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ciint jffs2_sum_is_disabled(struct jffs2_summary *s)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE);
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/* Move the collected summary information into sb (called from scan.c) */
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_civoid jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	dbg_summary("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n",
2348c2ecf20Sopenharmony_ci				c->summary->sum_size, c->summary->sum_num,
2358c2ecf20Sopenharmony_ci				s->sum_size, s->sum_num);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	c->summary->sum_size = s->sum_size;
2388c2ecf20Sopenharmony_ci	c->summary->sum_num = s->sum_num;
2398c2ecf20Sopenharmony_ci	c->summary->sum_padded = s->sum_padded;
2408c2ecf20Sopenharmony_ci	c->summary->sum_list_head = s->sum_list_head;
2418c2ecf20Sopenharmony_ci	c->summary->sum_list_tail = s->sum_list_tail;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	s->sum_list_head = s->sum_list_tail = NULL;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci/* Called from wbuf.c to collect writed node info */
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ciint jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
2498c2ecf20Sopenharmony_ci				unsigned long count, uint32_t ofs)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	union jffs2_node_union *node;
2528c2ecf20Sopenharmony_ci	struct jffs2_eraseblock *jeb;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (c->summary->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) {
2558c2ecf20Sopenharmony_ci		dbg_summary("Summary is disabled for this jeb! Skipping summary info!\n");
2568c2ecf20Sopenharmony_ci		return 0;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	node = invecs[0].iov_base;
2608c2ecf20Sopenharmony_ci	jeb = &c->blocks[ofs / c->sector_size];
2618c2ecf20Sopenharmony_ci	ofs -= jeb->offset;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	switch (je16_to_cpu(node->u.nodetype)) {
2648c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_INODE: {
2658c2ecf20Sopenharmony_ci			struct jffs2_sum_inode_mem *temp =
2668c2ecf20Sopenharmony_ci				kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci			if (!temp)
2698c2ecf20Sopenharmony_ci				goto no_mem;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci			temp->nodetype = node->i.nodetype;
2728c2ecf20Sopenharmony_ci			temp->inode = node->i.ino;
2738c2ecf20Sopenharmony_ci			temp->version = node->i.version;
2748c2ecf20Sopenharmony_ci			temp->offset = cpu_to_je32(ofs);
2758c2ecf20Sopenharmony_ci			temp->totlen = node->i.totlen;
2768c2ecf20Sopenharmony_ci			temp->next = NULL;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci			return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
2798c2ecf20Sopenharmony_ci		}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_DIRENT: {
2828c2ecf20Sopenharmony_ci			struct jffs2_sum_dirent_mem *temp =
2838c2ecf20Sopenharmony_ci				kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci			if (!temp)
2868c2ecf20Sopenharmony_ci				goto no_mem;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci			temp->nodetype = node->d.nodetype;
2898c2ecf20Sopenharmony_ci			temp->totlen = node->d.totlen;
2908c2ecf20Sopenharmony_ci			temp->offset = cpu_to_je32(ofs);
2918c2ecf20Sopenharmony_ci			temp->pino = node->d.pino;
2928c2ecf20Sopenharmony_ci			temp->version = node->d.version;
2938c2ecf20Sopenharmony_ci			temp->ino = node->d.ino;
2948c2ecf20Sopenharmony_ci			temp->nsize = node->d.nsize;
2958c2ecf20Sopenharmony_ci			temp->type = node->d.type;
2968c2ecf20Sopenharmony_ci			temp->next = NULL;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci			switch (count) {
2998c2ecf20Sopenharmony_ci				case 1:
3008c2ecf20Sopenharmony_ci					memcpy(temp->name,node->d.name,node->d.nsize);
3018c2ecf20Sopenharmony_ci					break;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci				case 2:
3048c2ecf20Sopenharmony_ci					memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
3058c2ecf20Sopenharmony_ci					break;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci				default:
3088c2ecf20Sopenharmony_ci					BUG();	/* impossible count value */
3098c2ecf20Sopenharmony_ci					break;
3108c2ecf20Sopenharmony_ci			}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci			return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR
3158c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_XATTR: {
3168c2ecf20Sopenharmony_ci			struct jffs2_sum_xattr_mem *temp;
3178c2ecf20Sopenharmony_ci			temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
3188c2ecf20Sopenharmony_ci			if (!temp)
3198c2ecf20Sopenharmony_ci				goto no_mem;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci			temp->nodetype = node->x.nodetype;
3228c2ecf20Sopenharmony_ci			temp->xid = node->x.xid;
3238c2ecf20Sopenharmony_ci			temp->version = node->x.version;
3248c2ecf20Sopenharmony_ci			temp->totlen = node->x.totlen;
3258c2ecf20Sopenharmony_ci			temp->offset = cpu_to_je32(ofs);
3268c2ecf20Sopenharmony_ci			temp->next = NULL;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci			return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
3298c2ecf20Sopenharmony_ci		}
3308c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_XREF: {
3318c2ecf20Sopenharmony_ci			struct jffs2_sum_xref_mem *temp;
3328c2ecf20Sopenharmony_ci			temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
3338c2ecf20Sopenharmony_ci			if (!temp)
3348c2ecf20Sopenharmony_ci				goto no_mem;
3358c2ecf20Sopenharmony_ci			temp->nodetype = node->r.nodetype;
3368c2ecf20Sopenharmony_ci			temp->offset = cpu_to_je32(ofs);
3378c2ecf20Sopenharmony_ci			temp->next = NULL;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci			return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci#endif
3428c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_PADDING:
3438c2ecf20Sopenharmony_ci			dbg_summary("node PADDING\n");
3448c2ecf20Sopenharmony_ci			c->summary->sum_padded += je32_to_cpu(node->u.totlen);
3458c2ecf20Sopenharmony_ci			break;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_CLEANMARKER:
3488c2ecf20Sopenharmony_ci			dbg_summary("node CLEANMARKER\n");
3498c2ecf20Sopenharmony_ci			break;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		case JFFS2_NODETYPE_SUMMARY:
3528c2ecf20Sopenharmony_ci			dbg_summary("node SUMMARY\n");
3538c2ecf20Sopenharmony_ci			break;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		default:
3568c2ecf20Sopenharmony_ci			/* If you implement a new node type you should also implement
3578c2ecf20Sopenharmony_ci			   summary support for it or disable summary.
3588c2ecf20Sopenharmony_ci			*/
3598c2ecf20Sopenharmony_ci			BUG();
3608c2ecf20Sopenharmony_ci			break;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cino_mem:
3668c2ecf20Sopenharmony_ci	JFFS2_WARNING("MEMORY ALLOCATION ERROR!");
3678c2ecf20Sopenharmony_ci	return -ENOMEM;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c,
3718c2ecf20Sopenharmony_ci						    struct jffs2_eraseblock *jeb,
3728c2ecf20Sopenharmony_ci						    uint32_t ofs, uint32_t len,
3738c2ecf20Sopenharmony_ci						    struct jffs2_inode_cache *ic)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	/* If there was a gap, mark it dirty */
3768c2ecf20Sopenharmony_ci	if ((ofs & ~3) > c->sector_size - jeb->free_size) {
3778c2ecf20Sopenharmony_ci		/* Ew. Summary doesn't actually tell us explicitly about dirty space */
3788c2ecf20Sopenharmony_ci		jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size));
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
3878c2ecf20Sopenharmony_ci				struct jffs2_raw_summary *summary, uint32_t *pseudo_random)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct jffs2_inode_cache *ic;
3908c2ecf20Sopenharmony_ci	struct jffs2_full_dirent *fd;
3918c2ecf20Sopenharmony_ci	void *sp;
3928c2ecf20Sopenharmony_ci	int i, ino;
3938c2ecf20Sopenharmony_ci	int err;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	sp = summary->sum;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
3988c2ecf20Sopenharmony_ci		dbg_summary("processing summary index %d\n", i);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		cond_resched();
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		/* Make sure there's a spare ref for dirty space */
4038c2ecf20Sopenharmony_ci		err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
4048c2ecf20Sopenharmony_ci		if (err)
4058c2ecf20Sopenharmony_ci			return err;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
4088c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_INODE: {
4098c2ecf20Sopenharmony_ci				struct jffs2_sum_inode_flash *spi;
4108c2ecf20Sopenharmony_ci				spi = sp;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci				ino = je32_to_cpu(spi->inode);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci				dbg_summary("Inode at 0x%08x-0x%08x\n",
4158c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spi->offset),
4168c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen));
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci				ic = jffs2_scan_make_ino_cache(c, ino);
4198c2ecf20Sopenharmony_ci				if (!ic) {
4208c2ecf20Sopenharmony_ci					JFFS2_NOTICE("scan_make_ino_cache failed\n");
4218c2ecf20Sopenharmony_ci					return -ENOMEM;
4228c2ecf20Sopenharmony_ci				}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci				sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED,
4258c2ecf20Sopenharmony_ci						  PAD(je32_to_cpu(spi->totlen)), ic);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci				*pseudo_random += je32_to_cpu(spi->version);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci				sp += JFFS2_SUMMARY_INODE_SIZE;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci				break;
4328c2ecf20Sopenharmony_ci			}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_DIRENT: {
4358c2ecf20Sopenharmony_ci				struct jffs2_sum_dirent_flash *spd;
4368c2ecf20Sopenharmony_ci				int checkedlen;
4378c2ecf20Sopenharmony_ci				spd = sp;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci				dbg_summary("Dirent at 0x%08x-0x%08x\n",
4408c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spd->offset),
4418c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen));
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci				/* This should never happen, but https://dev.laptop.org/ticket/4184 */
4458c2ecf20Sopenharmony_ci				checkedlen = strnlen(spd->name, spd->nsize);
4468c2ecf20Sopenharmony_ci				if (!checkedlen) {
4478c2ecf20Sopenharmony_ci					pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n",
4488c2ecf20Sopenharmony_ci					       jeb->offset +
4498c2ecf20Sopenharmony_ci					       je32_to_cpu(spd->offset));
4508c2ecf20Sopenharmony_ci					return -EIO;
4518c2ecf20Sopenharmony_ci				}
4528c2ecf20Sopenharmony_ci				if (checkedlen < spd->nsize) {
4538c2ecf20Sopenharmony_ci					pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n",
4548c2ecf20Sopenharmony_ci					       jeb->offset +
4558c2ecf20Sopenharmony_ci					       je32_to_cpu(spd->offset),
4568c2ecf20Sopenharmony_ci					       checkedlen);
4578c2ecf20Sopenharmony_ci				}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci				fd = jffs2_alloc_full_dirent(checkedlen+1);
4618c2ecf20Sopenharmony_ci				if (!fd)
4628c2ecf20Sopenharmony_ci					return -ENOMEM;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci				memcpy(&fd->name, spd->name, checkedlen);
4658c2ecf20Sopenharmony_ci				fd->name[checkedlen] = 0;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci				ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
4688c2ecf20Sopenharmony_ci				if (!ic) {
4698c2ecf20Sopenharmony_ci					jffs2_free_full_dirent(fd);
4708c2ecf20Sopenharmony_ci					return -ENOMEM;
4718c2ecf20Sopenharmony_ci				}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci				fd->raw = sum_link_node_ref(c, jeb,  je32_to_cpu(spd->offset) | REF_UNCHECKED,
4748c2ecf20Sopenharmony_ci							    PAD(je32_to_cpu(spd->totlen)), ic);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci				fd->next = NULL;
4778c2ecf20Sopenharmony_ci				fd->version = je32_to_cpu(spd->version);
4788c2ecf20Sopenharmony_ci				fd->ino = je32_to_cpu(spd->ino);
4798c2ecf20Sopenharmony_ci				fd->nhash = full_name_hash(NULL, fd->name, checkedlen);
4808c2ecf20Sopenharmony_ci				fd->type = spd->type;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci				jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci				*pseudo_random += je32_to_cpu(spd->version);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci				sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci				break;
4898c2ecf20Sopenharmony_ci			}
4908c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR
4918c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_XATTR: {
4928c2ecf20Sopenharmony_ci				struct jffs2_xattr_datum *xd;
4938c2ecf20Sopenharmony_ci				struct jffs2_sum_xattr_flash *spx;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci				spx = (struct jffs2_sum_xattr_flash *)sp;
4968c2ecf20Sopenharmony_ci				dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n",
4978c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spx->offset),
4988c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen),
4998c2ecf20Sopenharmony_ci					    je32_to_cpu(spx->xid), je32_to_cpu(spx->version));
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci				xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
5028c2ecf20Sopenharmony_ci								je32_to_cpu(spx->version));
5038c2ecf20Sopenharmony_ci				if (IS_ERR(xd))
5048c2ecf20Sopenharmony_ci					return PTR_ERR(xd);
5058c2ecf20Sopenharmony_ci				if (xd->version > je32_to_cpu(spx->version)) {
5068c2ecf20Sopenharmony_ci					/* node is not the newest one */
5078c2ecf20Sopenharmony_ci					struct jffs2_raw_node_ref *raw
5088c2ecf20Sopenharmony_ci						= sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
5098c2ecf20Sopenharmony_ci								    PAD(je32_to_cpu(spx->totlen)), NULL);
5108c2ecf20Sopenharmony_ci					raw->next_in_ino = xd->node->next_in_ino;
5118c2ecf20Sopenharmony_ci					xd->node->next_in_ino = raw;
5128c2ecf20Sopenharmony_ci				} else {
5138c2ecf20Sopenharmony_ci					xd->version = je32_to_cpu(spx->version);
5148c2ecf20Sopenharmony_ci					sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
5158c2ecf20Sopenharmony_ci							  PAD(je32_to_cpu(spx->totlen)), (void *)xd);
5168c2ecf20Sopenharmony_ci				}
5178c2ecf20Sopenharmony_ci				*pseudo_random += je32_to_cpu(spx->xid);
5188c2ecf20Sopenharmony_ci				sp += JFFS2_SUMMARY_XATTR_SIZE;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci				break;
5218c2ecf20Sopenharmony_ci			}
5228c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_XREF: {
5238c2ecf20Sopenharmony_ci				struct jffs2_xattr_ref *ref;
5248c2ecf20Sopenharmony_ci				struct jffs2_sum_xref_flash *spr;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci				spr = (struct jffs2_sum_xref_flash *)sp;
5278c2ecf20Sopenharmony_ci				dbg_summary("xref at %#08x-%#08x\n",
5288c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spr->offset),
5298c2ecf20Sopenharmony_ci					    jeb->offset + je32_to_cpu(spr->offset) +
5308c2ecf20Sopenharmony_ci					    (uint32_t)PAD(sizeof(struct jffs2_raw_xref)));
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci				ref = jffs2_alloc_xattr_ref();
5338c2ecf20Sopenharmony_ci				if (!ref) {
5348c2ecf20Sopenharmony_ci					JFFS2_NOTICE("allocation of xattr_datum failed\n");
5358c2ecf20Sopenharmony_ci					return -ENOMEM;
5368c2ecf20Sopenharmony_ci				}
5378c2ecf20Sopenharmony_ci				ref->next = c->xref_temp;
5388c2ecf20Sopenharmony_ci				c->xref_temp = ref;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci				sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
5418c2ecf20Sopenharmony_ci						  PAD(sizeof(struct jffs2_raw_xref)), (void *)ref);
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci				*pseudo_random += ref->node->flash_offset;
5448c2ecf20Sopenharmony_ci				sp += JFFS2_SUMMARY_XREF_SIZE;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci				break;
5478c2ecf20Sopenharmony_ci			}
5488c2ecf20Sopenharmony_ci#endif
5498c2ecf20Sopenharmony_ci			default : {
5508c2ecf20Sopenharmony_ci				uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype);
5518c2ecf20Sopenharmony_ci				JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype);
5528c2ecf20Sopenharmony_ci				if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT)
5538c2ecf20Sopenharmony_ci					return -EIO;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci				/* For compatible node types, just fall back to the full scan */
5568c2ecf20Sopenharmony_ci				c->wasted_size -= jeb->wasted_size;
5578c2ecf20Sopenharmony_ci				c->free_size += c->sector_size - jeb->free_size;
5588c2ecf20Sopenharmony_ci				c->used_size -= jeb->used_size;
5598c2ecf20Sopenharmony_ci				c->dirty_size -= jeb->dirty_size;
5608c2ecf20Sopenharmony_ci				jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0;
5618c2ecf20Sopenharmony_ci				jeb->free_size = c->sector_size;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci				jffs2_free_jeb_node_refs(c, jeb);
5648c2ecf20Sopenharmony_ci				return -ENOTRECOVERABLE;
5658c2ecf20Sopenharmony_ci			}
5668c2ecf20Sopenharmony_ci		}
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci	return 0;
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci/* Process the summary node - called from jffs2_scan_eraseblock() */
5728c2ecf20Sopenharmony_ciint jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
5738c2ecf20Sopenharmony_ci			   struct jffs2_raw_summary *summary, uint32_t sumsize,
5748c2ecf20Sopenharmony_ci			   uint32_t *pseudo_random)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct jffs2_unknown_node crcnode;
5778c2ecf20Sopenharmony_ci	int ret, ofs;
5788c2ecf20Sopenharmony_ci	uint32_t crc;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	ofs = c->sector_size - sumsize;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
5838c2ecf20Sopenharmony_ci		    jeb->offset, jeb->offset + ofs, sumsize);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* OK, now check for node validity and CRC */
5868c2ecf20Sopenharmony_ci	crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
5878c2ecf20Sopenharmony_ci	crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
5888c2ecf20Sopenharmony_ci	crcnode.totlen = summary->totlen;
5898c2ecf20Sopenharmony_ci	crc = crc32(0, &crcnode, sizeof(crcnode)-4);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (je32_to_cpu(summary->hdr_crc) != crc) {
5928c2ecf20Sopenharmony_ci		dbg_summary("Summary node header is corrupt (bad CRC or "
5938c2ecf20Sopenharmony_ci				"no summary at all)\n");
5948c2ecf20Sopenharmony_ci		goto crc_err;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	if (je32_to_cpu(summary->totlen) != sumsize) {
5988c2ecf20Sopenharmony_ci		dbg_summary("Summary node is corrupt (wrong erasesize?)\n");
5998c2ecf20Sopenharmony_ci		goto crc_err;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	if (je32_to_cpu(summary->node_crc) != crc) {
6058c2ecf20Sopenharmony_ci		dbg_summary("Summary node is corrupt (bad CRC)\n");
6068c2ecf20Sopenharmony_ci		goto crc_err;
6078c2ecf20Sopenharmony_ci	}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary));
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (je32_to_cpu(summary->sum_crc) != crc) {
6128c2ecf20Sopenharmony_ci		dbg_summary("Summary node data is corrupt (bad CRC)\n");
6138c2ecf20Sopenharmony_ci		goto crc_err;
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if ( je32_to_cpu(summary->cln_mkr) ) {
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		dbg_summary("Summary : CLEANMARKER node \n");
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
6218c2ecf20Sopenharmony_ci		if (ret)
6228c2ecf20Sopenharmony_ci			return ret;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
6258c2ecf20Sopenharmony_ci			dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
6268c2ecf20Sopenharmony_ci				je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
6278c2ecf20Sopenharmony_ci			if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
6288c2ecf20Sopenharmony_ci				return ret;
6298c2ecf20Sopenharmony_ci		} else if (jeb->first_node) {
6308c2ecf20Sopenharmony_ci			dbg_summary("CLEANMARKER node not first node in block "
6318c2ecf20Sopenharmony_ci					"(0x%08x)\n", jeb->offset);
6328c2ecf20Sopenharmony_ci			if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
6338c2ecf20Sopenharmony_ci				return ret;
6348c2ecf20Sopenharmony_ci		} else {
6358c2ecf20Sopenharmony_ci			jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL,
6368c2ecf20Sopenharmony_ci					    je32_to_cpu(summary->cln_mkr), NULL);
6378c2ecf20Sopenharmony_ci		}
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
6418c2ecf20Sopenharmony_ci	/* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full
6428c2ecf20Sopenharmony_ci	   scan of this eraseblock. So return zero */
6438c2ecf20Sopenharmony_ci	if (ret == -ENOTRECOVERABLE)
6448c2ecf20Sopenharmony_ci		return 0;
6458c2ecf20Sopenharmony_ci	if (ret)
6468c2ecf20Sopenharmony_ci		return ret;		/* real error */
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/* for PARANOIA_CHECK */
6498c2ecf20Sopenharmony_ci	ret = jffs2_prealloc_raw_node_refs(c, jeb, 2);
6508c2ecf20Sopenharmony_ci	if (ret)
6518c2ecf20Sopenharmony_ci		return ret;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	if (unlikely(jeb->free_size)) {
6568c2ecf20Sopenharmony_ci		JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n",
6578c2ecf20Sopenharmony_ci			      jeb->free_size, jeb->offset);
6588c2ecf20Sopenharmony_ci		jeb->wasted_size += jeb->free_size;
6598c2ecf20Sopenharmony_ci		c->wasted_size += jeb->free_size;
6608c2ecf20Sopenharmony_ci		c->free_size -= jeb->free_size;
6618c2ecf20Sopenharmony_ci		jeb->free_size = 0;
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	return jffs2_scan_classify_jeb(c, jeb);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cicrc_err:
6678c2ecf20Sopenharmony_ci	JFFS2_WARNING("Summary node crc error, skipping summary information.\n");
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	return 0;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
6758c2ecf20Sopenharmony_ci				uint32_t infosize, uint32_t datasize, int padsize)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	struct jffs2_raw_summary isum;
6788c2ecf20Sopenharmony_ci	union jffs2_sum_mem *temp;
6798c2ecf20Sopenharmony_ci	struct jffs2_sum_marker *sm;
6808c2ecf20Sopenharmony_ci	struct kvec vecs[2];
6818c2ecf20Sopenharmony_ci	uint32_t sum_ofs;
6828c2ecf20Sopenharmony_ci	void *wpage;
6838c2ecf20Sopenharmony_ci	int ret;
6848c2ecf20Sopenharmony_ci	size_t retlen;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (padsize + datasize > MAX_SUMMARY_SIZE) {
6878c2ecf20Sopenharmony_ci		/* It won't fit in the buffer. Abort summary for this jeb */
6888c2ecf20Sopenharmony_ci		jffs2_sum_disable_collecting(c->summary);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci		JFFS2_WARNING("Summary too big (%d data, %d pad) in eraseblock at %08x\n",
6918c2ecf20Sopenharmony_ci			      datasize, padsize, jeb->offset);
6928c2ecf20Sopenharmony_ci		/* Non-fatal */
6938c2ecf20Sopenharmony_ci		return 0;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci	/* Is there enough space for summary? */
6968c2ecf20Sopenharmony_ci	if (padsize < 0) {
6978c2ecf20Sopenharmony_ci		/* don't try to write out summary for this jeb */
6988c2ecf20Sopenharmony_ci		jffs2_sum_disable_collecting(c->summary);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		JFFS2_WARNING("Not enough space for summary, padsize = %d\n",
7018c2ecf20Sopenharmony_ci			      padsize);
7028c2ecf20Sopenharmony_ci		/* Non-fatal */
7038c2ecf20Sopenharmony_ci		return 0;
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	memset(c->summary->sum_buf, 0xff, datasize);
7078c2ecf20Sopenharmony_ci	memset(&isum, 0, sizeof(isum));
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
7108c2ecf20Sopenharmony_ci	isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
7118c2ecf20Sopenharmony_ci	isum.totlen = cpu_to_je32(infosize);
7128c2ecf20Sopenharmony_ci	isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
7138c2ecf20Sopenharmony_ci	isum.padded = cpu_to_je32(c->summary->sum_padded);
7148c2ecf20Sopenharmony_ci	isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
7158c2ecf20Sopenharmony_ci	isum.sum_num = cpu_to_je32(c->summary->sum_num);
7168c2ecf20Sopenharmony_ci	wpage = c->summary->sum_buf;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	while (c->summary->sum_num) {
7198c2ecf20Sopenharmony_ci		temp = c->summary->sum_list_head;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci		switch (je16_to_cpu(temp->u.nodetype)) {
7228c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_INODE: {
7238c2ecf20Sopenharmony_ci				struct jffs2_sum_inode_flash *sino_ptr = wpage;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci				sino_ptr->nodetype = temp->i.nodetype;
7268c2ecf20Sopenharmony_ci				sino_ptr->inode = temp->i.inode;
7278c2ecf20Sopenharmony_ci				sino_ptr->version = temp->i.version;
7288c2ecf20Sopenharmony_ci				sino_ptr->offset = temp->i.offset;
7298c2ecf20Sopenharmony_ci				sino_ptr->totlen = temp->i.totlen;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci				wpage += JFFS2_SUMMARY_INODE_SIZE;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci				break;
7348c2ecf20Sopenharmony_ci			}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_DIRENT: {
7378c2ecf20Sopenharmony_ci				struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci				sdrnt_ptr->nodetype = temp->d.nodetype;
7408c2ecf20Sopenharmony_ci				sdrnt_ptr->totlen = temp->d.totlen;
7418c2ecf20Sopenharmony_ci				sdrnt_ptr->offset = temp->d.offset;
7428c2ecf20Sopenharmony_ci				sdrnt_ptr->pino = temp->d.pino;
7438c2ecf20Sopenharmony_ci				sdrnt_ptr->version = temp->d.version;
7448c2ecf20Sopenharmony_ci				sdrnt_ptr->ino = temp->d.ino;
7458c2ecf20Sopenharmony_ci				sdrnt_ptr->nsize = temp->d.nsize;
7468c2ecf20Sopenharmony_ci				sdrnt_ptr->type = temp->d.type;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci				memcpy(sdrnt_ptr->name, temp->d.name,
7498c2ecf20Sopenharmony_ci							temp->d.nsize);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci				wpage += JFFS2_SUMMARY_DIRENT_SIZE(temp->d.nsize);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci				break;
7548c2ecf20Sopenharmony_ci			}
7558c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR
7568c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_XATTR: {
7578c2ecf20Sopenharmony_ci				struct jffs2_sum_xattr_flash *sxattr_ptr = wpage;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci				temp = c->summary->sum_list_head;
7608c2ecf20Sopenharmony_ci				sxattr_ptr->nodetype = temp->x.nodetype;
7618c2ecf20Sopenharmony_ci				sxattr_ptr->xid = temp->x.xid;
7628c2ecf20Sopenharmony_ci				sxattr_ptr->version = temp->x.version;
7638c2ecf20Sopenharmony_ci				sxattr_ptr->offset = temp->x.offset;
7648c2ecf20Sopenharmony_ci				sxattr_ptr->totlen = temp->x.totlen;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci				wpage += JFFS2_SUMMARY_XATTR_SIZE;
7678c2ecf20Sopenharmony_ci				break;
7688c2ecf20Sopenharmony_ci			}
7698c2ecf20Sopenharmony_ci			case JFFS2_NODETYPE_XREF: {
7708c2ecf20Sopenharmony_ci				struct jffs2_sum_xref_flash *sxref_ptr = wpage;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci				temp = c->summary->sum_list_head;
7738c2ecf20Sopenharmony_ci				sxref_ptr->nodetype = temp->r.nodetype;
7748c2ecf20Sopenharmony_ci				sxref_ptr->offset = temp->r.offset;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci				wpage += JFFS2_SUMMARY_XREF_SIZE;
7778c2ecf20Sopenharmony_ci				break;
7788c2ecf20Sopenharmony_ci			}
7798c2ecf20Sopenharmony_ci#endif
7808c2ecf20Sopenharmony_ci			default : {
7818c2ecf20Sopenharmony_ci				if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK)
7828c2ecf20Sopenharmony_ci				    == JFFS2_FEATURE_RWCOMPAT_COPY) {
7838c2ecf20Sopenharmony_ci					dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n",
7848c2ecf20Sopenharmony_ci						    je16_to_cpu(temp->u.nodetype));
7858c2ecf20Sopenharmony_ci					jffs2_sum_disable_collecting(c->summary);
7868c2ecf20Sopenharmony_ci					/* The above call removes the list, nothing more to do */
7878c2ecf20Sopenharmony_ci					goto bail_rwcompat;
7888c2ecf20Sopenharmony_ci				} else {
7898c2ecf20Sopenharmony_ci					BUG();	/* unknown node in summary information */
7908c2ecf20Sopenharmony_ci				}
7918c2ecf20Sopenharmony_ci			}
7928c2ecf20Sopenharmony_ci		}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci		c->summary->sum_list_head = temp->u.next;
7958c2ecf20Sopenharmony_ci		kfree(temp);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		c->summary->sum_num--;
7988c2ecf20Sopenharmony_ci	}
7998c2ecf20Sopenharmony_ci bail_rwcompat:
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	jffs2_sum_reset_collected(c->summary);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	wpage += padsize;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	sm = wpage;
8068c2ecf20Sopenharmony_ci	sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
8078c2ecf20Sopenharmony_ci	sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
8108c2ecf20Sopenharmony_ci	isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	vecs[0].iov_base = &isum;
8138c2ecf20Sopenharmony_ci	vecs[0].iov_len = sizeof(isum);
8148c2ecf20Sopenharmony_ci	vecs[1].iov_base = c->summary->sum_buf;
8158c2ecf20Sopenharmony_ci	vecs[1].iov_len = datasize;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	sum_ofs = jeb->offset + c->sector_size - jeb->free_size;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	dbg_summary("writing out data to flash to pos : 0x%08x\n", sum_ofs);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (ret || (retlen != infosize)) {
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci		JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n",
8268c2ecf20Sopenharmony_ci			      infosize, sum_ofs, ret, retlen);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		if (retlen) {
8298c2ecf20Sopenharmony_ci			/* Waste remaining space */
8308c2ecf20Sopenharmony_ci			spin_lock(&c->erase_completion_lock);
8318c2ecf20Sopenharmony_ci			jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL);
8328c2ecf20Sopenharmony_ci			spin_unlock(&c->erase_completion_lock);
8338c2ecf20Sopenharmony_ci		}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci		c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		return 0;
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	spin_lock(&c->erase_completion_lock);
8418c2ecf20Sopenharmony_ci	jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL);
8428c2ecf20Sopenharmony_ci	spin_unlock(&c->erase_completion_lock);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	return 0;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci/* Write out summary information - called from jffs2_do_reserve_space */
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ciint jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
8508c2ecf20Sopenharmony_ci	__must_hold(&c->erase_completion_block)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	int datasize, infosize, padsize;
8538c2ecf20Sopenharmony_ci	struct jffs2_eraseblock *jeb;
8548c2ecf20Sopenharmony_ci	int ret = 0;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	dbg_summary("called\n");
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	spin_unlock(&c->erase_completion_lock);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	jeb = c->nextblock;
8618c2ecf20Sopenharmony_ci	jffs2_prealloc_raw_node_refs(c, jeb, 1);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if (!c->summary->sum_num || !c->summary->sum_list_head) {
8648c2ecf20Sopenharmony_ci		JFFS2_WARNING("Empty summary info!!!\n");
8658c2ecf20Sopenharmony_ci		BUG();
8668c2ecf20Sopenharmony_ci	}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
8698c2ecf20Sopenharmony_ci	infosize = sizeof(struct jffs2_raw_summary) + datasize;
8708c2ecf20Sopenharmony_ci	padsize = jeb->free_size - infosize;
8718c2ecf20Sopenharmony_ci	infosize += padsize;
8728c2ecf20Sopenharmony_ci	datasize += padsize;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
8758c2ecf20Sopenharmony_ci	spin_lock(&c->erase_completion_lock);
8768c2ecf20Sopenharmony_ci	return ret;
8778c2ecf20Sopenharmony_ci}
878