From 21b2dedaa32ab309f6d1daec966528b7586bd207 Mon Sep 17 00:00:00 2001 From: Charles Manning Date: Sat, 2 Jul 2016 12:11:34 +1200 Subject: [PATCH] yaffs2: Yaffs endian support Allow the forcing of endians so that Yaffs can be used on mixed endian machines, or a flash image can be extracted and used elsewhere. Signed-off-by: Charles Manning --- Makefile | 2 + direct/handle_common.sh | 1 + direct/test-framework/FrameworkRules.mk | 2 + direct/test-framework/yaffs_nandsim_file.c | 2 +- direct/test-framework/yaffs_ramem2k.c | 128 ++++++++--------- direct/yportenv.h | 1 + yaffs_attribs.c | 4 + yaffs_checkptrw.c | 15 ++ yaffs_endian.c | 106 ++++++++++++++ yaffs_endian.h | 52 +++++++ yaffs_guts.c | 100 +++++++++---- yaffs_guts.h | 21 ++- yaffs_nameval.c | 111 ++++++++------ yaffs_nameval.h | 13 +- yaffs_packedtags1.c | 1 - yaffs_packedtags2.c | 51 ++++--- yaffs_packedtags2.h | 12 +- yaffs_summary.c | 5 +- yaffs_tagscompat.c | 65 ++++++--- yaffs_tagsmarshall.c | 12 +- yaffs_yaffs1.c | 2 +- yaffs_yaffs2.c | 159 +++++++++++++++++++-- 22 files changed, 655 insertions(+), 210 deletions(-) create mode 100644 yaffs_endian.c create mode 100644 yaffs_endian.h diff --git a/Makefile b/Makefile index a346458..c82fdbd 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ ifneq ($(KERNELRELEASE),) yaffs2-objs += yaffs_yaffs1.o yaffs2-objs += yaffs_yaffs2.o yaffs2-objs += yaffs_verify.o + yaffs2-objs += yaffs_endian.o yaffs2-objs += yaffs_summary.o yaffs2multi-objs := yaffs_mtdif_multi.o @@ -53,6 +54,7 @@ ifneq ($(KERNELRELEASE),) yaffs2multi-objs += yaffs_yaffs1.o yaffs2multi-objs += yaffs_yaffs2.o yaffs2multi-objs += yaffs_verify.o + yaffs2multi-objs += yaffs_endian.o yaffs2multi-objs += yaffs_summary.o else diff --git a/direct/handle_common.sh b/direct/handle_common.sh index 2b5a043..1da0c75 100755 --- a/direct/handle_common.sh +++ b/direct/handle_common.sh @@ -14,6 +14,7 @@ YAFFS_COMMON_SOURCES="\ yaffs_yaffs1.c yaffs_yaffs1.h \ yaffs_yaffs2.c yaffs_yaffs2.h \ yaffs_bitmap.c yaffs_bitmap.h \ + yaffs_endian.c yaffs_endian.h \ yaffs_verify.c yaffs_verify.h \ yaffs_summary.c yaffs_summary.h \ " diff --git a/direct/test-framework/FrameworkRules.mk b/direct/test-framework/FrameworkRules.mk index 5f77f99..e33cde5 100644 --- a/direct/test-framework/FrameworkRules.mk +++ b/direct/test-framework/FrameworkRules.mk @@ -35,6 +35,7 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o yaffs_error.o\ yaffs_tagscompat.o yaffs_tagsmarshall.o \ yaffs_packedtags2.o yaffs_nand.o \ yaffs_checkptrw.o \ + yaffs_endian.o \ yaffs_nameval.o yaffs_attribs.o \ yaffs_m18_drv.o yaffs_nor_drv.o ynorsim.o \ yaffs_nand_drv.o \ @@ -59,6 +60,7 @@ YAFFSDIRECTSYMLINKS = \ yaffs_attribs.c \ yportenv.h \ yaffs_hweight.c yaffs_hweight.h \ + yaffs_endian.c yaffs_endian.h \ yaffs_error.c \ yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h \ yaffs_tagscompat.c yaffs_tagscompat.h \ diff --git a/direct/test-framework/yaffs_nandsim_file.c b/direct/test-framework/yaffs_nandsim_file.c index 3beac5a..16e69a0 100644 --- a/direct/test-framework/yaffs_nandsim_file.c +++ b/direct/test-framework/yaffs_nandsim_file.c @@ -54,7 +54,7 @@ struct yaffs_dev *yaffs_nandsim_install_drv(const char *dev_name, param->is_yaffs2 = 1; param->use_nand_ecc = 1; param->n_caches = 10; - /* param->hide_lost_n_found = 1; */ + param->stored_endian = 2; if(yaffs_nand_install_drv(dev, chip) != YAFFS_OK) goto fail; diff --git a/direct/test-framework/yaffs_ramem2k.c b/direct/test-framework/yaffs_ramem2k.c index 715ae77..cfb0f4f 100644 --- a/direct/test-framework/yaffs_ramem2k.c +++ b/direct/test-framework/yaffs_ramem2k.c @@ -49,7 +49,7 @@ #define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE)) -typedef struct +typedef struct { u8 data[PAGE_TOTAL_SIZE]; // Data + spare int empty; // is this empty? @@ -59,7 +59,7 @@ typedef struct typedef struct { nandemul_Page *page[PAGES_PER_BLOCK]; - int damaged; + int damaged; } nandemul_Block; @@ -87,16 +87,16 @@ static void nandemul_yield(int n) static void nandemul_ReallyEraseBlock(int blockNumber) { int i; - + nandemul_Block *blk; - + if(blockNumber < 0 || blockNumber >= ned.nBlocks) { return; } - + blk = ned.block[blockNumber]; - + for(i = 0; i < PAGES_PER_BLOCK; i++) { memset(blk->page[i],0xff,sizeof(nandemul_Page)); @@ -116,40 +116,40 @@ static int nandemul2k_CalcNBlocks(void) static int CheckInit(void) { static int initialised = 0; - + int i,j; - + int fail = 0; - int nBlocks; + int nBlocks; int nAllocated = 0; - - if(initialised) + + if(initialised) { return YAFFS_OK; } - - + + ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks(); - + ned.block = malloc(sizeof(nandemul_Block*) * nBlocks ); - + if(!ned.block) return YAFFS_FAIL; - - - - + + + + for(i=fail=0; i page[pg]->data; - + for(i = 0; i < PAGE_DATA_SIZE; i++) { x[i] &=data[i]; @@ -212,16 +212,16 @@ int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev *dev,int nand_chunk,con ned.block[blk]->page[pg]->empty = 0; } - - + + if(tags) { x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; - - yaffs_pack_tags2((struct yaffs_packed_tags2 *)x,tags, !dev->param.no_tags_ecc); - + + yaffs_pack_tags2(dev, (struct yaffs_packed_tags2 *)x,tags, !dev->param.no_tags_ecc); + } - + if(tags || data) { nandemul_yield(1); @@ -235,26 +235,26 @@ int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev,int nand_chunk, u { int blk; int pg; - + u8 *x; - - + + blk = nand_chunk/PAGES_PER_BLOCK; pg = nand_chunk%PAGES_PER_BLOCK; - - + + if(data) { memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE); } - - + + if(tags) { x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE]; - - yaffs_unpack_tags2(tags,(struct yaffs_packed_tags2 *)x, !dev->param.no_tags_ecc); + + yaffs_unpack_tags2(dev, tags,(struct yaffs_packed_tags2 *)x, !dev->param.no_tags_ecc); } return YAFFS_OK; @@ -267,12 +267,12 @@ static int nandemul2k_CheckChunkErased(struct yaffs_dev *dev,int nand_chunk) int pg; int i; - - + + blk = nand_chunk/PAGES_PER_BLOCK; pg = nand_chunk%PAGES_PER_BLOCK; - - + + for(i = 0; i < PAGE_TOTAL_SIZE; i++) { if(ned.block[blk]->page[pg]->data[i] != 0xFF) @@ -287,8 +287,8 @@ static int nandemul2k_CheckChunkErased(struct yaffs_dev *dev,int nand_chunk) int nandemul2k_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber) { - - + + if(blockNumber < 0 || blockNumber >= ned.nBlocks) { yaffs_trace(YAFFS_TRACE_ALWAYS, @@ -305,7 +305,7 @@ int nandemul2k_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber) { nandemul_ReallyEraseBlock(blockNumber); } - + return YAFFS_OK; } @@ -314,19 +314,19 @@ int nandemul2k_InitialiseNAND(struct yaffs_dev *dev) CheckInit(); return YAFFS_OK; } - + int nandemul2k_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no) { - + u8 *x; - + x = &ned.block[block_no]->page[0]->data[PAGE_DATA_SIZE]; - + memset(x,0,sizeof(struct yaffs_packed_tags2)); - - + + return YAFFS_OK; - + } int nandemul2k_QueryNANDBlock(struct yaffs_dev *dev, int block_no, enum yaffs_block_state *state, u32 *seq_number) @@ -335,9 +335,9 @@ int nandemul2k_QueryNANDBlock(struct yaffs_dev *dev, int block_no, enum yaffs_bl int chunkNo; *seq_number = 0; - + chunkNo = block_no * dev->param.chunks_per_block; - + nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags); if(tags.block_bad) { diff --git a/direct/yportenv.h b/direct/yportenv.h index 5b7d188..81da08e 100644 --- a/direct/yportenv.h +++ b/direct/yportenv.h @@ -23,6 +23,7 @@ typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; +typedef unsigned long long u64; typedef signed int s32; #endif diff --git a/yaffs_attribs.c b/yaffs_attribs.c index 711941f..5eb7c5a 100644 --- a/yaffs_attribs.c +++ b/yaffs_attribs.c @@ -22,6 +22,10 @@ #define IATTR_GID ia_gid.val #endif +/* + * Loading attibs from/to object header assumes the object header + * is in cpu endian. + */ void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) { obj->yst_uid = oh->yst_uid; diff --git a/yaffs_checkptrw.c b/yaffs_checkptrw.c index 16ee1e0..59ca34a 100644 --- a/yaffs_checkptrw.c +++ b/yaffs_checkptrw.c @@ -13,6 +13,7 @@ #include "yaffs_checkptrw.h" #include "yaffs_getblockinfo.h" +#include "yaffs_endian.h" struct yaffs_checkpt_chunk_hdr { int version; @@ -32,6 +33,18 @@ static int apply_block_offset(struct yaffs_dev *dev, int block) return block - dev->block_offset; } + +static void yaffs2_do_endian_hdr(struct yaffs_dev *dev, + struct yaffs_checkpt_chunk_hdr *hdr) +{ + if (!dev->swap_endian) + return; + hdr->version = swap_s32(hdr->version); + hdr->seq = swap_s32(hdr->seq); + hdr->sum = swap_u32(hdr->sum); + hdr->xor = swap_u32(hdr->xor); +} + static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) { struct yaffs_checkpt_chunk_hdr hdr; @@ -43,6 +56,7 @@ static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) dev->checkpt_byte_offs = sizeof(hdr); + yaffs2_do_endian_hdr(dev, &hdr); memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr)); } @@ -51,6 +65,7 @@ static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev) struct yaffs_checkpt_chunk_hdr hdr; memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr)); + yaffs2_do_endian_hdr(dev, &hdr); dev->checkpt_byte_offs = sizeof(hdr); diff --git a/yaffs_endian.c b/yaffs_endian.c new file mode 100644 index 0000000..0bc67fe --- /dev/null +++ b/yaffs_endian.c @@ -0,0 +1,106 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Endian processing functions. + */ + +#include "yaffs_endian.h" +#include "yaffs_guts.h" + + +void yaffs_do_endian_u32(struct yaffs_dev *dev, u32 *val) +{ + if (!dev->swap_endian) + return; + *val = swap_u32(*val); +} + +void yaffs_do_endian_s32(struct yaffs_dev *dev, s32 *val) +{ + if (!dev->swap_endian) + return; + *val = swap_s32(*val); +} + +void yaffs_do_endian_oh(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh) +{ + if (!dev->swap_endian) + return; + /* Change every field */ + oh->type = swap_u32(oh->type); + oh->parent_obj_id = swap_s32(oh->parent_obj_id); + + oh->yst_mode = swap_u32(oh->yst_mode); + + oh->yst_uid = swap_u32(oh->yst_uid); + oh->yst_gid = swap_u32(oh->yst_gid); + oh->yst_atime = swap_u32(oh->yst_atime); + oh->yst_mtime = swap_u32(oh->yst_mtime); + oh->yst_ctime = swap_u32(oh->yst_ctime); + + oh->file_size_low = swap_u32(oh->file_size_low); + + oh->equiv_id = swap_u32(oh->equiv_id); + + oh->yst_rdev = swap_u32(oh->yst_rdev); + + oh->win_ctime[0] = swap_u32(oh->win_ctime[0]); + oh->win_ctime[1] = swap_u32(oh->win_ctime[1]); + oh->win_atime[0] = swap_u32(oh->win_atime[0]); + oh->win_atime[1] = swap_u32(oh->win_atime[1]); + oh->win_mtime[0] = swap_u32(oh->win_mtime[0]); + oh->win_mtime[1] = swap_u32(oh->win_mtime[1]); + + oh->inband_shadowed_obj_id = swap_u32(oh->inband_shadowed_obj_id); + oh->inband_is_shrink = swap_u32(oh->inband_is_shrink); + + oh->file_size_high = swap_u32(oh->file_size_high); + oh->reserved[0] = swap_u32(oh->reserved[0]); + oh->shadows_obj = swap_s32(oh->shadows_obj); + + oh->is_shrink = swap_u32(oh->is_shrink); +} + + +void yaffs_do_endian_packed_tags2(struct yaffs_dev *dev, + struct yaffs_packed_tags2_tags_only *ptt) +{ + if (!dev->swap_endian) + return; + ptt->seq_number = swap_u32(ptt->seq_number); + ptt->obj_id = swap_u32(ptt->obj_id); + ptt->chunk_id = swap_u32(ptt->chunk_id); + ptt->n_bytes = swap_u32(ptt->n_bytes); +} + +void yaffs_endian_config(struct yaffs_dev *dev) +{ + u32 x = 1; + + if (dev->tnode_size < 1) + BUG(); + + dev->swap_endian = 0; + + if (((char *)&x)[0] == 1) { + /* Little Endian. */ + if (dev->param.stored_endian == 2 /* big endian */) + dev->swap_endian = 1; + } else { + /* Big Endian. */ + if (dev->param.stored_endian == 1 /* little endian */) + dev->swap_endian = 1; + } + + if (dev->swap_endian) + dev->tn_swap_buffer = kmalloc(dev->tnode_size, GFP_NOFS); +} diff --git a/yaffs_endian.h b/yaffs_endian.h new file mode 100644 index 0000000..d37bc50 --- /dev/null +++ b/yaffs_endian.h @@ -0,0 +1,52 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_ENDIAN_H__ +#define __YAFFS_ENDIAN_H__ +#include "yaffs_guts.h" +#include "yaffs_packedtags2.h" + +static inline u32 swap_u32(u32 val) +{ + return ((val >>24) & 0x000000ff) | + ((val >> 8) & 0x0000ff00) | + ((val << 8) & 0x00ff0000) | + ((val <<24) & 0xff000000); +} + +#define swap_s32(val) \ + (s32)(swap_u32((u32)(val))) + +static inline Y_LOFF_T swap_loff_t(Y_LOFF_T lval) +{ + u32 vall = swap_u32((u32) (lval & 0xffffffff)); + u32 valh; + + if (sizeof(Y_LOFF_T) == sizeof(u32)) + return (Y_LOFF_T) vall; + + valh = swap_u32((u32) ((lval >> 32) & 0xffffffff)); + + return (Y_LOFF_T)((((u64)vall) << 32) | valh); +} + +void yaffs_do_endian_s32(struct yaffs_dev *dev, s32 *val); +void yaffs_do_endian_u32(struct yaffs_dev *dev, u32 *val); +void yaffs_do_endian_oh(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh); +void yaffs_do_endian_packed_tags2(struct yaffs_dev *dev, + struct yaffs_packed_tags2_tags_only *ptt); +void yaffs_endian_config(struct yaffs_dev *dev); + +#endif diff --git a/yaffs_guts.c b/yaffs_guts.c index c89b29c..72555d5 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -15,6 +15,7 @@ #include "yaffs_trace.h" #include "yaffs_guts.h" +#include "yaffs_endian.h" #include "yaffs_getblockinfo.h" #include "yaffs_tagscompat.h" #include "yaffs_tagsmarshall.h" @@ -755,7 +756,7 @@ void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, loff_t yaffs_max_file_size(struct yaffs_dev *dev) { - if(sizeof(loff_t) < 8) + if (sizeof(loff_t) < 8) return YAFFS_MAX_FILE_SIZE_32; else return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk; @@ -2529,12 +2530,14 @@ static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, if (tags.chunk_id == 0) { /* It is an object Id, - * We need to nuke the - * shrinkheader flags since its + * We need to nuke the shrinkheader flags since its * work is done. - * Also need to clean up - * shadowing. + * Also need to clean up shadowing. + * NB We don't want to do all the work of translating + * object header endianism back and forth so we leave + * the oh endian in its stored order. */ + struct yaffs_obj_hdr *oh; oh = (struct yaffs_obj_hdr *) buffer; @@ -2546,8 +2549,8 @@ static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, /* Update file size */ if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) { - yaffs_oh_size_load(oh, - object->variant.file_variant.stored_size); + yaffs_oh_size_load(dev, oh, + object->variant.file_variant.stored_size, 1); tags.extra_file_size = object->variant.file_variant.stored_size; } @@ -3139,12 +3142,12 @@ static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, if (xmod->set) retval = - nval_set(x_buffer, x_size, xmod->name, xmod->data, + nval_set(dev, x_buffer, x_size, xmod->name, xmod->data, xmod->size, xmod->flags); else - retval = nval_del(x_buffer, x_size, xmod->name); + retval = nval_del(dev, x_buffer, x_size, xmod->name); - obj->has_xattr = nval_hasvalues(x_buffer, x_size); + obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size); obj->xattr_known = 1; xmod->result = retval; @@ -3189,14 +3192,15 @@ static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name, x_buffer = buffer + x_offs; if (!obj->xattr_known) { - obj->has_xattr = nval_hasvalues(x_buffer, x_size); + obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size); obj->xattr_known = 1; } if (name) - retval = nval_get(x_buffer, x_size, name, value, size); + retval = nval_get(dev, x_buffer, x_size, + name, value, size); else - retval = nval_list(x_buffer, x_size, value, size); + retval = nval_list(dev, x_buffer, x_size, value, size); } yaffs_release_temp_buffer(dev, (u8 *) buffer); return retval; @@ -3243,6 +3247,8 @@ static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags); oh = (struct yaffs_obj_hdr *)buf; + yaffs_do_endian_oh(dev, oh); + in->yst_mode = oh->yst_mode; yaffs_load_attribs(in, oh); yaffs_set_obj_name_from_oh(in, oh); @@ -3258,7 +3264,18 @@ static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) /* UpdateObjectHeader updates the header on NAND for an object. * If name is not NULL, then that new name is used. + * + * We're always creating the obj header from scratch (except reading + * the old name) so first set up in cpu endianness then run it through + * endian fixing at the end. + * + * However, a twist: If there are xattribs we leave them as they were. + * + * Careful! The buffer holds the whole chunk. Part of the chunk holds the + * object header and the rest holds the xattribs, therefore we use a buffer + * pointer and an oh pointer to point to the same memory. */ + int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, int is_shrink, int shadows, struct yaffs_xattr_mod *xmod) { @@ -3291,12 +3308,18 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, prev_chunk_id = in->hdr_chunk; if (prev_chunk_id > 0) { + /* Access the old obj header just to read the name. */ result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id, buffer, &old_tags); yaffs_verify_oh(in, oh, &old_tags, 0); memcpy(old_name, oh->name, sizeof(oh->name)); - memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr)); + + /* + * NB We only wipe the object header area because the rest of + * the buffer might contain xattribs. + */ + memset(oh, 0xff, sizeof(*oh)); } else { memset(buffer, 0xff, dev->data_bytes_per_chunk); } @@ -3331,7 +3354,7 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED && oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED) file_size = in->variant.file_variant.stored_size; - yaffs_oh_size_load(oh, file_size); + yaffs_oh_size_load(dev, oh, file_size, 0); break; case YAFFS_OBJECT_TYPE_HARDLINK: oh->equiv_id = in->variant.hardlink_variant.equiv_id; @@ -3370,6 +3393,10 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, new_tags.extra_equiv_id = oh->equiv_id; new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; new_tags.extra_obj_type = in->variant_type; + + /* Now endian swizzle the oh if needed. */ + yaffs_do_endian_oh(dev, oh); + yaffs_verify_oh(in, oh, &new_tags, 1); /* Create new chunk in NAND */ @@ -4872,12 +4899,14 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) dev->n_erase_failures = 0; dev->n_erased_blocks = 0; dev->gc_disable = 0; - dev->has_pending_prioritised_gc = 1; - /* Assume the worst for now, will get fixed on first GC */ + dev->has_pending_prioritised_gc = 1; /* Assume the worst for now, + * will get fixed on first GC */ INIT_LIST_HEAD(&dev->dirty_dirs); dev->oldest_dirty_seq = 0; dev->oldest_dirty_block = 0; + yaffs_endian_config(dev); + /* Initialise temporary buffers and caches. */ if (!yaffs_init_tmp_buffers(dev)) init_failed = 1; @@ -5116,26 +5145,47 @@ int yaffs_get_n_free_chunks(struct yaffs_dev *dev) } - /* * Marshalling functions to get loff_t file sizes into and out of * object headers. */ -void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize) +void yaffs_oh_size_load(struct yaffs_dev *dev, + struct yaffs_obj_hdr *oh, + loff_t fsize, + int do_endian) { oh->file_size_low = (fsize & 0xFFFFFFFF); oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF); + + if (do_endian) { + yaffs_do_endian_u32(dev, &oh->file_size_low); + yaffs_do_endian_u32(dev, &oh->file_size_high); + } } -loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh) +loff_t yaffs_oh_to_size(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh, + int do_endian) { loff_t retval; - if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) - retval = (((loff_t) oh->file_size_high) << 32) | - (((loff_t) oh->file_size_low) & 0xFFFFFFFF); - else - retval = (loff_t) oh->file_size_low; + + if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) { + u32 low = oh->file_size_low; + u32 high = oh->file_size_high; + + if (do_endian) { + yaffs_do_endian_u32 (dev, &low); + yaffs_do_endian_u32 (dev, &high); + } + retval = (((loff_t) high) << 32) | + (((loff_t) low) & 0xFFFFFFFF); + } else { + u32 low = oh->file_size_low; + + if (do_endian) + yaffs_do_endian_u32(dev, &low); + retval = (loff_t)low; + } return retval; } diff --git a/yaffs_guts.h b/yaffs_guts.h index b0aca33..c7e201c 100644 --- a/yaffs_guts.h +++ b/yaffs_guts.h @@ -153,7 +153,8 @@ struct yaffs_tags { union yaffs_tags_union { struct yaffs_tags as_tags; - u8 as_bytes[8]; + u8 as_bytes[8]; + u32 as_u32[2]; }; @@ -311,6 +312,11 @@ struct yaffs_block_info { }; +union yaffs_block_info_union { + struct yaffs_block_info bi; + u32 as_u32[2]; +}; + /* -------------------------- Object structure -------------------------------*/ /* This is the object structure as stored on NAND */ @@ -560,6 +566,8 @@ struct yaffs_param { int hide_lost_n_found; /* Set non-zero to hide the lost-n-found dir. */ + int stored_endian; /* 0=cpu endian, 1=little endian, 2=big endian */ + /* The remove_obj_fn function must be supplied by OS flavours that * need it. * yaffs direct uses it to implement the faster readdir. @@ -644,6 +652,8 @@ struct yaffs_dev { */ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ + struct yaffs_tnode *tn_swap_buffer; + /* Stuff to support wide tnodes */ u32 tnode_width; u32 tnode_mask; @@ -657,6 +667,7 @@ struct yaffs_dev { int is_mounted; int read_only; int is_checkpointed; + int swap_endian; /* Stored endian needs endian swap. */ /* Stuff to support block offsetting to support start block zero */ int internal_start_block; @@ -1018,11 +1029,13 @@ int yaffs_guts_format_dev(struct yaffs_dev *dev); void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, int *chunk_out, u32 *offset_out); /* - * Marshalling functions to get loff_t file sizes into aand out of + * Marshalling functions to get loff_t file sizes into and out of * object headers. */ -void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize); -loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh); +void yaffs_oh_size_load(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh, + loff_t fsize, int do_endian); +loff_t yaffs_oh_to_size(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh, + int do_endian); loff_t yaffs_max_file_size(struct yaffs_dev *dev); /* diff --git a/yaffs_nameval.c b/yaffs_nameval.c index 4bdf4ed..478248e 100644 --- a/yaffs_nameval.c +++ b/yaffs_nameval.c @@ -16,7 +16,7 @@ * values and fits into a small finite buffer. * * Each attribute is stored as a record: - * sizeof(int) bytes record size. + * sizeof(size) bytes record size. * strnlen+1 bytes name null terminated. * nbytes value. * ---------- @@ -26,27 +26,32 @@ */ #include "yaffs_nameval.h" - +#include "yaffs_guts.h" #include "yportenv.h" -static int nval_find(const char *xb, int xb_size, const YCHAR *name, +static int nval_find(struct yaffs_dev *dev, + const char *xb, int xb_size, const YCHAR *name, int *exist_size) { int pos = 0; - int size; + s32 size; + + memcpy(&size, xb, sizeof(size)); + yaffs_do_endian_s32(dev, &size); - memcpy(&size, xb, sizeof(int)); while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { - if (!strncmp((YCHAR *) (xb + pos + sizeof(int)), + if (!strncmp((YCHAR *) (xb + pos + sizeof(size)), name, size)) { if (exist_size) *exist_size = size; return pos; } pos += size; - if (pos < xb_size - sizeof(int)) - memcpy(&size, xb + pos, sizeof(int)); - else + if (pos < xb_size - sizeof(size)) { + memcpy(&size, xb + pos, sizeof(size)); + yaffs_do_endian_s32(dev, &size); + + } else size = 0; } if (exist_size) @@ -54,89 +59,101 @@ static int nval_find(const char *xb, int xb_size, const YCHAR *name, return -ENODATA; } -static int nval_used(const char *xb, int xb_size) +static int nval_used(struct yaffs_dev *dev, const char *xb, int xb_size) { int pos = 0; - int size; + s32 size; + + memcpy(&size, xb + pos, sizeof(size)); + yaffs_do_endian_s32(dev, &size); - memcpy(&size, xb + pos, sizeof(int)); while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { pos += size; - if (pos < xb_size - sizeof(int)) - memcpy(&size, xb + pos, sizeof(int)); - else + if (pos < xb_size - sizeof(size)) { + memcpy(&size, xb + pos, sizeof(size)); + yaffs_do_endian_s32(dev, &size); + } else size = 0; } return pos; } -int nval_del(char *xb, int xb_size, const YCHAR *name) +int nval_del(struct yaffs_dev *dev, char *xb, int xb_size, const YCHAR *name) { - int pos = nval_find(xb, xb_size, name, NULL); - int size; + int pos = nval_find(dev, xb, xb_size, name, NULL); + s32 size; if (pos < 0 || pos >= xb_size) return -ENODATA; /* Find size, shift rest over this record, * then zero out the rest of buffer */ - memcpy(&size, xb + pos, sizeof(int)); + memcpy(&size, xb + pos, sizeof(size)); + yaffs_do_endian_s32(dev, &size); + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); memset(xb + (xb_size - size), 0, size); return 0; } -int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, - int bsize, int flags) +int nval_set(struct yaffs_dev *dev, + char *xb, int xb_size, const YCHAR *name, const char *buf, + int bsize, int flags) { int pos; int namelen = strnlen(name, xb_size); - int reclen; int size_exist = 0; int space; int start; + s32 reclen; + s32 reclen_endianised; - pos = nval_find(xb, xb_size, name, &size_exist); + pos = nval_find(dev, xb, xb_size, name, &size_exist); if (flags & XATTR_CREATE && pos >= 0) return -EEXIST; if (flags & XATTR_REPLACE && pos < 0) return -ENODATA; - start = nval_used(xb, xb_size); + start = nval_used(dev, xb, xb_size); space = xb_size - start + size_exist; - reclen = (sizeof(int) + namelen + 1 + bsize); + reclen = (sizeof(reclen) + namelen + 1 + bsize); if (reclen > space) return -ENOSPC; if (pos >= 0) { - nval_del(xb, xb_size, name); - start = nval_used(xb, xb_size); + /* Exists, so delete it. */ + nval_del(dev, xb, xb_size, name); + start = nval_used(dev, xb, xb_size); } pos = start; - memcpy(xb + pos, &reclen, sizeof(int)); - pos += sizeof(int); + reclen_endianised = reclen; + yaffs_do_endian_s32(dev, &reclen_endianised); + memcpy(xb + pos, &reclen_endianised, sizeof(reclen_endianised)); + pos += sizeof(reclen_endianised); strncpy((YCHAR *) (xb + pos), name, reclen); pos += (namelen + 1); memcpy(xb + pos, buf, bsize); return 0; } -int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, +int nval_get(struct yaffs_dev *dev, + const char *xb, int xb_size, const YCHAR * name, char *buf, int bsize) { - int pos = nval_find(xb, xb_size, name, NULL); - int size; + int pos = nval_find(dev, xb, xb_size, name, NULL); + s32 size; if (pos >= 0 && pos < xb_size) { - memcpy(&size, xb + pos, sizeof(int)); - pos += sizeof(int); /* advance past record length */ - size -= sizeof(int); + memcpy(&size, xb + pos, sizeof(size)); + yaffs_do_endian_s32(dev, &size); + pos += sizeof(size); /* advance past record length */ + size -= sizeof(size); /* Advance over name string */ while (xb[pos] && size > 0 && pos < xb_size) { @@ -164,21 +181,23 @@ int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, return -ENODATA; } -int nval_list(const char *xb, int xb_size, char *buf, int bsize) +int nval_list(struct yaffs_dev *dev, const char *xb, int xb_size, char *buf, int bsize) { int pos = 0; - int size; + s32 size; int name_len; int ncopied = 0; int filled = 0; - memcpy(&size, xb + pos, sizeof(int)); - while (size > sizeof(int) && + memcpy(&size, xb + pos, sizeof(size)); + yaffs_do_endian_s32(dev, &size); + + while (size > sizeof(size) && size <= xb_size && (pos + size) < xb_size && !filled) { - pos += sizeof(int); - size -= sizeof(int); + pos += sizeof(size); + size -= sizeof(size); name_len = strnlen((YCHAR *) (xb + pos), size); if (ncopied + name_len + 1 < bsize) { memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); @@ -194,15 +213,17 @@ int nval_list(const char *xb, int xb_size, char *buf, int bsize) filled = 1; } pos += size; - if (pos < xb_size - sizeof(int)) - memcpy(&size, xb + pos, sizeof(int)); + if (pos < xb_size - sizeof(size)) { + memcpy(&size, xb + pos, sizeof(size)); + yaffs_do_endian_s32(dev, &size); + } else size = 0; } return ncopied; } -int nval_hasvalues(const char *xb, int xb_size) +int nval_hasvalues(struct yaffs_dev *dev, const char *xb, int xb_size) { - return nval_used(xb, xb_size) > 0; + return nval_used(dev, xb, xb_size) > 0; } diff --git a/yaffs_nameval.h b/yaffs_nameval.h index 951e64f..b0bd81c 100644 --- a/yaffs_nameval.h +++ b/yaffs_nameval.h @@ -18,11 +18,14 @@ #include "yportenv.h" -int nval_del(char *xb, int xb_size, const YCHAR * name); -int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf, +int nval_del(struct yaffs_dev *dev, char *xb, int xb_size, const YCHAR * name); +int nval_set(struct yaffs_dev *dev, + char *xb, int xb_size, const YCHAR * name, const char *buf, int bsize, int flags); -int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, +int nval_get(struct yaffs_dev *dev, + const char *xb, int xb_size, const YCHAR * name, char *buf, int bsize); -int nval_list(const char *xb, int xb_size, char *buf, int bsize); -int nval_hasvalues(const char *xb, int xb_size); +int nval_list(struct yaffs_dev *dev, + const char *xb, int xb_size, char *buf, int bsize); +int nval_hasvalues(struct yaffs_dev *dev, const char *xb, int xb_size); #endif diff --git a/yaffs_packedtags1.c b/yaffs_packedtags1.c index dd9a331..0928b8e 100644 --- a/yaffs_packedtags1.c +++ b/yaffs_packedtags1.c @@ -38,7 +38,6 @@ void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt, void yaffs_unpack_tags1(struct yaffs_ext_tags *t, const struct yaffs_packed_tags1 *pt) { - if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) { t->block_bad = 0; if (pt->should_be_ff != 0xffffffff) diff --git a/yaffs_packedtags2.c b/yaffs_packedtags2.c index e1d18cc..d5291fc 100644 --- a/yaffs_packedtags2.c +++ b/yaffs_packedtags2.c @@ -14,6 +14,7 @@ #include "yaffs_packedtags2.h" #include "yportenv.h" #include "yaffs_trace.h" +#include "yaffs_endian.h" /* This code packs a set of extended tags into a binary structure for * NAND storage @@ -72,7 +73,8 @@ static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t) return 1; } -void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt, +void yaffs_pack_tags2_tags_only(struct yaffs_dev *dev, + struct yaffs_packed_tags2_tags_only *ptt, const struct yaffs_ext_tags *t) { ptt->chunk_id = t->chunk_id; @@ -106,12 +108,14 @@ void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt, yaffs_dump_packed_tags2_tags_only(ptt); yaffs_dump_tags2(t); + yaffs_do_endian_packed_tags2(dev, ptt); } -void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, +void yaffs_pack_tags2(struct yaffs_dev *dev, + struct yaffs_packed_tags2 *pt, const struct yaffs_ext_tags *t, int tags_ecc) { - yaffs_pack_tags2_tags_only(&pt->t, t); + yaffs_pack_tags2_tags_only(dev, &pt->t, t); if (tags_ecc) yaffs_ecc_calc_other((unsigned char *)&pt->t, @@ -119,45 +123,52 @@ void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, &pt->ecc); } -void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, - struct yaffs_packed_tags2_tags_only *ptt) +void yaffs_unpack_tags2_tags_only(struct yaffs_dev *dev, + struct yaffs_ext_tags *t, + struct yaffs_packed_tags2_tags_only *ptt_ptr) { + struct yaffs_packed_tags2_tags_only ptt_copy = *ptt_ptr; + memset(t, 0, sizeof(struct yaffs_ext_tags)); - if (ptt->seq_number == 0xffffffff) + if (ptt_copy.seq_number == 0xffffffff) return; + yaffs_do_endian_packed_tags2(dev, &ptt_copy); + t->block_bad = 0; t->chunk_used = 1; - t->obj_id = ptt->obj_id; - t->chunk_id = ptt->chunk_id; - t->n_bytes = ptt->n_bytes; + t->obj_id = ptt_copy.obj_id; + t->chunk_id = ptt_copy.chunk_id; + t->n_bytes = ptt_copy.n_bytes; t->is_deleted = 0; t->serial_number = 0; - t->seq_number = ptt->seq_number; + t->seq_number = ptt_copy.seq_number; /* Do extra header info stuff */ - if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { + if (ptt_copy.chunk_id & EXTRA_HEADER_INFO_FLAG) { t->chunk_id = 0; t->n_bytes = 0; t->extra_available = 1; - t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); - t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0; - t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0; - t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; + t->extra_parent_id = ptt_copy.chunk_id & (~(ALL_EXTRA_FLAGS)); + t->extra_is_shrink = ptt_copy.chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0; + t->extra_shadows = ptt_copy.chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0; + t->extra_obj_type = ptt_copy.obj_id >> EXTRA_OBJECT_TYPE_SHIFT; t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) - t->extra_equiv_id = ptt->n_bytes; + t->extra_equiv_id = ptt_copy.n_bytes; else - t->extra_file_size = ptt->n_bytes; + t->extra_file_size = ptt_copy.n_bytes; } - yaffs_dump_packed_tags2_tags_only(ptt); + yaffs_dump_packed_tags2_tags_only(ptt_ptr); yaffs_dump_tags2(t); } -void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, +void yaffs_unpack_tags2(struct yaffs_dev *dev, + struct yaffs_ext_tags *t, + struct yaffs_packed_tags2 *pt, int tags_ecc) { enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; @@ -188,7 +199,7 @@ void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, ecc_result = YAFFS_ECC_RESULT_UNKNOWN; } } - yaffs_unpack_tags2_tags_only(t, &pt->t); + yaffs_unpack_tags2_tags_only(dev, t, &pt->t); t->ecc_result = ecc_result; diff --git a/yaffs_packedtags2.h b/yaffs_packedtags2.h index 675e719..9cafe0e 100644 --- a/yaffs_packedtags2.h +++ b/yaffs_packedtags2.h @@ -34,14 +34,18 @@ struct yaffs_packed_tags2 { }; /* Full packed tags with ECC, used for oob tags */ -void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, +void yaffs_pack_tags2(struct yaffs_dev *dev, + struct yaffs_packed_tags2 *pt, const struct yaffs_ext_tags *t, int tags_ecc); -void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, +void yaffs_unpack_tags2(struct yaffs_dev *dev, + struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, int tags_ecc); /* Only the tags part (no ECC for use with inband tags */ -void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt, +void yaffs_pack_tags2_tags_only(struct yaffs_dev *dev, + struct yaffs_packed_tags2_tags_only *pt, const struct yaffs_ext_tags *t); -void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, +void yaffs_unpack_tags2_tags_only(struct yaffs_dev *dev, + struct yaffs_ext_tags *t, struct yaffs_packed_tags2_tags_only *pt); #endif diff --git a/yaffs_summary.c b/yaffs_summary.c index 3c9e723..0250963 100644 --- a/yaffs_summary.c +++ b/yaffs_summary.c @@ -259,8 +259,9 @@ int yaffs_summary_add(struct yaffs_dev *dev, return YAFFS_OK; if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { - yaffs_pack_tags2_tags_only(&tags_only, tags); + yaffs_pack_tags2_tags_only(dev, &tags_only, tags); sum_tags = &dev->sum_tags[chunk_in_block]; + sum_tags->chunk_id = tags_only.chunk_id; sum_tags->n_bytes = tags_only.n_bytes; sum_tags->obj_id = tags_only.obj_id; @@ -286,7 +287,7 @@ int yaffs_summary_fetch(struct yaffs_dev *dev, tags_only.chunk_id = sum_tags->chunk_id; tags_only.n_bytes = sum_tags->n_bytes; tags_only.obj_id = sum_tags->obj_id; - yaffs_unpack_tags2_tags_only(tags, &tags_only); + yaffs_unpack_tags2_tags_only(dev, tags, &tags_only); return YAFFS_OK; } return YAFFS_FAIL; diff --git a/yaffs_tagscompat.c b/yaffs_tagscompat.c index 092430b..e57c2d3 100644 --- a/yaffs_tagscompat.c +++ b/yaffs_tagscompat.c @@ -9,6 +9,9 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * This file handles yaffs1-style tags to allow compatibility with Yaffs1 style + * flash layouts. */ #include "yaffs_guts.h" @@ -16,13 +19,13 @@ #include "yaffs_ecc.h" #include "yaffs_getblockinfo.h" #include "yaffs_trace.h" +#include "yaffs_endian.h" static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); /********** Tags ECC calculations *********/ - void yaffs_calc_tags_ecc(struct yaffs_tags *tags) { /* Calculate an ecc */ @@ -73,21 +76,30 @@ int yaffs_check_tags_ecc(struct yaffs_tags *tags) /********** Tags **********/ -static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +/* + * During tags storing/retireval we use a copy of the tags so that + * we can modify the endian etc without damaging the previous structure. + */ +static void yaffs_load_tags_to_spare(struct yaffs_dev *dev, + struct yaffs_spare *spare_ptr, struct yaffs_tags *tags_ptr) { - union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; - - yaffs_calc_tags_ecc(tags_ptr); - - spare_ptr->tb0 = tu->as_bytes[0]; - spare_ptr->tb1 = tu->as_bytes[1]; - spare_ptr->tb2 = tu->as_bytes[2]; - spare_ptr->tb3 = tu->as_bytes[3]; - spare_ptr->tb4 = tu->as_bytes[4]; - spare_ptr->tb5 = tu->as_bytes[5]; - spare_ptr->tb6 = tu->as_bytes[6]; - spare_ptr->tb7 = tu->as_bytes[7]; + union yaffs_tags_union *tu_ptr = (union yaffs_tags_union *)tags_ptr; + union yaffs_tags_union tags_stored = *tu_ptr; + + yaffs_calc_tags_ecc(&tags_stored.as_tags); + + yaffs_do_endian_u32(dev, &tags_stored.as_u32[0]); + yaffs_do_endian_u32(dev, &tags_stored.as_u32[1]); + + spare_ptr->tb0 = tags_stored.as_bytes[0]; + spare_ptr->tb1 = tags_stored.as_bytes[1]; + spare_ptr->tb2 = tags_stored.as_bytes[2]; + spare_ptr->tb3 = tags_stored.as_bytes[3]; + spare_ptr->tb4 = tags_stored.as_bytes[4]; + spare_ptr->tb5 = tags_stored.as_bytes[5]; + spare_ptr->tb6 = tags_stored.as_bytes[6]; + spare_ptr->tb7 = tags_stored.as_bytes[7]; } static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, @@ -95,16 +107,22 @@ static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, struct yaffs_tags *tags_ptr) { union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; + union yaffs_tags_union tags_stored; int result; - tu->as_bytes[0] = spare_ptr->tb0; - tu->as_bytes[1] = spare_ptr->tb1; - tu->as_bytes[2] = spare_ptr->tb2; - tu->as_bytes[3] = spare_ptr->tb3; - tu->as_bytes[4] = spare_ptr->tb4; - tu->as_bytes[5] = spare_ptr->tb5; - tu->as_bytes[6] = spare_ptr->tb6; - tu->as_bytes[7] = spare_ptr->tb7; + tags_stored.as_bytes[0] = spare_ptr->tb0; + tags_stored.as_bytes[1] = spare_ptr->tb1; + tags_stored.as_bytes[2] = spare_ptr->tb2; + tags_stored.as_bytes[3] = spare_ptr->tb3; + tags_stored.as_bytes[4] = spare_ptr->tb4; + tags_stored.as_bytes[5] = spare_ptr->tb5; + tags_stored.as_bytes[6] = spare_ptr->tb6; + tags_stored.as_bytes[7] = spare_ptr->tb7; + + yaffs_do_endian_u32(dev, &tags_stored.as_u32[0]); + yaffs_do_endian_u32(dev, &tags_stored.as_u32[1]); + + *tu = tags_stored; result = yaffs_check_tags_ecc(tags_ptr); if (result > 0) @@ -263,7 +281,7 @@ static int yaffs_tags_compat_wr(struct yaffs_dev *dev, yaffs_ecc_calc(&data[256], spare.ecc2); } - yaffs_load_tags_to_spare(&spare, &tags); + yaffs_load_tags_to_spare(dev, &spare, &tags); } return yaffs_wr_nand(dev, nand_chunk, data, &spare); } @@ -303,6 +321,7 @@ static int yaffs_tags_compat_rd(struct yaffs_dev *dev, if (ext_tags->chunk_used) { yaffs_get_tags_from_spare(dev, &spare, &tags); + ext_tags->obj_id = tags.obj_id; ext_tags->chunk_id = tags.chunk_id; ext_tags->n_bytes = tags.n_bytes_lsb; diff --git a/yaffs_tagsmarshall.c b/yaffs_tagsmarshall.c index 44a83b1..c2e2369 100644 --- a/yaffs_tagsmarshall.c +++ b/yaffs_tagsmarshall.c @@ -9,6 +9,10 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * This file handles the marshalling (ie internal<-->external structure + * translation between the internal tags and the stored tags in Yaffs2-style + * tags storage. */ #include "yaffs_guts.h" @@ -43,9 +47,9 @@ static int yaffs_tags_marshall_write(struct yaffs_dev *dev, (struct yaffs_packed_tags2_tags_only *)(data + dev-> data_bytes_per_chunk); - yaffs_pack_tags2_tags_only(pt2tp, tags); + yaffs_pack_tags2_tags_only(dev, pt2tp, tags); } else { - yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc); + yaffs_pack_tags2(dev, &pt, tags, !dev->param.no_tags_ecc); } retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, @@ -103,11 +107,11 @@ static int yaffs_tags_marshall_read(struct yaffs_dev *dev, pt2tp = (struct yaffs_packed_tags2_tags_only *) &data[dev->data_bytes_per_chunk]; - yaffs_unpack_tags2_tags_only(tags, pt2tp); + yaffs_unpack_tags2_tags_only(dev, tags, pt2tp); } } else if (tags) { memcpy(packed_tags_ptr, spare_buffer, packed_tags_size); - yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc); + yaffs_unpack_tags2(dev, tags, &pt, !dev->param.no_tags_ecc); } if (local_data) diff --git a/yaffs_yaffs1.c b/yaffs_yaffs1.c index 4f2e768..e98d04d 100644 --- a/yaffs_yaffs1.c +++ b/yaffs_yaffs1.c @@ -325,7 +325,7 @@ int yaffs1_scan(struct yaffs_dev *dev) use_header_file_size) in->variant. file_variant.file_size - = yaffs_oh_to_size(oh); + = yaffs_oh_to_size(dev, oh, 0); break; case YAFFS_OBJECT_TYPE_HARDLINK: in->variant. diff --git a/yaffs_yaffs2.c b/yaffs_yaffs2.c index 688211e..6d46817 100644 --- a/yaffs_yaffs2.c +++ b/yaffs_yaffs2.c @@ -21,6 +21,7 @@ #include "yaffs_verify.h" #include "yaffs_attribs.h" #include "yaffs_summary.h" +#include "yaffs_endian.h" /* * Checkpoints are really no benefit on very small partitions. @@ -248,6 +249,18 @@ int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev) /*--------------------- Checkpointing --------------------*/ +static void yaffs2_do_endian_validity_marker(struct yaffs_dev *dev, + struct yaffs_checkpt_validity *v) +{ + + if (!dev->swap_endian) + return; + v->struct_type = swap_s32(v->struct_type); + v->magic = swap_u32(v->magic); + v->version = swap_u32(v->version); + v->head = swap_u32(v->head); +} + static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) { struct yaffs_checkpt_validity cp; @@ -259,6 +272,8 @@ static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) cp.version = YAFFS_CHECKPOINT_VERSION; cp.head = (head) ? 1 : 0; + yaffs2_do_endian_validity_marker(dev, &cp); + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0; } @@ -268,6 +283,7 @@ static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) int ok; ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + yaffs2_do_endian_validity_marker(dev, &cp); if (ok) ok = (cp.struct_type == sizeof(cp)) && @@ -280,6 +296,8 @@ static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp, struct yaffs_dev *dev) { + cp->struct_type = sizeof(*cp); + cp->n_erased_blocks = dev->n_erased_blocks; cp->alloc_block = dev->alloc_block; cp->alloc_page = dev->alloc_page; @@ -306,28 +324,63 @@ static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev, dev->seq_number = cp->seq_number; } +static void yaffs2_do_endian_checkpt_dev(struct yaffs_dev *dev, + struct yaffs_checkpt_dev *cp) +{ + if (!dev->swap_endian) + return; + cp->struct_type = swap_s32(cp->struct_type); + cp->n_erased_blocks = swap_s32(cp->n_erased_blocks); + cp->alloc_block = swap_s32(cp->alloc_block); + cp->alloc_page = swap_u32(cp->alloc_page); + cp->n_free_chunks = swap_s32(cp->n_free_chunks); + cp->n_deleted_files = swap_s32(cp->n_deleted_files); + cp->n_unlinked_files = swap_s32(cp->n_unlinked_files); + cp->n_bg_deletions = swap_s32(cp->n_bg_deletions); +} + static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev) { struct yaffs_checkpt_dev cp; u32 n_bytes; u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1; int ok; + int i; + union yaffs_block_info_union bu; /* Write device runtime values */ yaffs2_dev_to_checkpt_dev(&cp, dev); - cp.struct_type = sizeof(cp); + yaffs2_do_endian_checkpt_dev(dev, &cp); ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); if (!ok) return 0; - /* Write block info */ - n_bytes = n_blocks * sizeof(struct yaffs_block_info); - ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); + /* Write block info. */ + if (!dev->swap_endian) { + n_bytes = n_blocks * sizeof(struct yaffs_block_info); + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); + } else { + /* + * Need to swap the endianisms. We can't do this in place + * since that would damage live data, + * so write one block info at a time using a copy. + */ + for (i = 0; i < n_blocks && ok; i++) { + bu.bi = dev->block_info[i]; + bu.as_u32[0] = swap_u32(bu.as_u32[0]); + bu.as_u32[1] = swap_u32(bu.as_u32[1]); + ok = (yaffs2_checkpt_wr(dev, &bu, sizeof(bu)) == sizeof(bu)); + } + } + if (!ok) return 0; - /* Write chunk bits */ + /* + * Write chunk bits. Chunk bits are in bytes so + * no endian conversion is needed. + */ n_bytes = n_blocks * dev->chunk_bit_stride; ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes); @@ -345,6 +398,7 @@ static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); if (!ok) return 0; + yaffs2_do_endian_checkpt_dev(dev, &cp); if (cp.struct_type != sizeof(cp)) return 0; @@ -358,10 +412,21 @@ static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) if (!ok) return 0; + if (dev->swap_endian) { + /* The block info can just be handled as a list of u32s. */ + u32 *as_u32 = (u32 *) dev->block_info; + u32 n_u32s = n_bytes/sizeof(u32); + u32 i; + + for (i=0; i < n_u32s; i++) + as_u32[i] = swap_u32(as_u32[i]); + } + n_bytes = n_blocks * dev->chunk_bit_stride; ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); + return ok ? 1 : 0; } @@ -473,6 +538,33 @@ static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, return 1; } +static void yaffs2_do_endian_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +{ + int i; + u32 *as_u32 = (u32 *)tn; + int tnode_size_u32 = dev->tnode_size / sizeof(u32); + + if (!dev->swap_endian) + return; + /* Swap all the tnode data as u32s to fix endianisms. */ + for (i = 0; iswap_endian) + return tn; + + memcpy(dev->tn_swap_buffer, tn, dev->tnode_size); + tn = dev->tn_swap_buffer; + + yaffs2_do_endian_tnode(dev, tn); + + return tn; +} + static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, struct yaffs_tnode *tn, u32 level, int chunk_offset) @@ -500,12 +592,20 @@ static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, /* Level 0 tnode */ base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; + yaffs_do_endian_u32(dev, &base_offset); + ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) == sizeof(base_offset)); - if (ok) + if (ok) { + /* + * NB Can't do an in-place endian swizzle since that would + * damage current tnode data. + * If a tnode endian conversion is required we do a copy. + */ + tn = yaffs2_do_endian_tnode_copy(dev, tn); ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size); - + } return ok; } @@ -540,14 +640,18 @@ static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) == sizeof(base_chunk)); + yaffs_do_endian_u32(dev, &base_chunk); + while (ok && (~base_chunk)) { nread++; /* Read level 0 tnode */ tn = yaffs_get_tnode(dev); - if (tn) + if (tn) { ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size); + yaffs2_do_endian_tnode(dev, tn); + } else ok = 0; @@ -556,10 +660,13 @@ static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) file_stuct_ptr, base_chunk, tn) ? 1 : 0; - if (ok) + if (ok) { ok = (yaffs2_checkpt_rd (dev, &base_chunk, sizeof(base_chunk)) == sizeof(base_chunk)); + yaffs_do_endian_u32(dev, &base_chunk); + } + } yaffs_trace(YAFFS_TRACE_CHECKPOINT, @@ -569,6 +676,21 @@ static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) return ok ? 1 : 0; } + +static void yaffs2_do_endian_checkpt_obj(struct yaffs_dev *dev, + struct yaffs_checkpt_obj *cp) +{ + if (!dev->swap_endian) + return; + cp->struct_type = swap_s32(cp->struct_type); + cp->obj_id = swap_u32(cp->obj_id); + cp->parent_id = swap_u32(cp->parent_id); + cp->hdr_chunk = swap_s32(cp->hdr_chunk); + cp->bit_field = swap_u32(cp->bit_field); + cp->n_data_chunks = swap_s32(cp->n_data_chunks); + cp->size_or_equiv_obj = swap_loff_t(cp->size_or_equiv_obj); +} + static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) { struct yaffs_obj *obj; @@ -595,6 +717,7 @@ static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) cp.obj_id, cp.parent_id, cp_variant_type, cp.hdr_chunk, obj); + yaffs2_do_endian_checkpt_obj (dev, &cp); ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); @@ -609,6 +732,7 @@ static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) /* Dump end of list */ memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj)); cp.struct_type = sizeof(cp); + yaffs2_do_endian_checkpt_obj (dev, &cp); if (ok) ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); @@ -628,6 +752,8 @@ static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) while (ok && !done) { ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + yaffs2_do_endian_checkpt_obj (dev, &cp); + if (cp.struct_type != sizeof(cp)) { yaffs_trace(YAFFS_TRACE_CHECKPOINT, "struct size %d instead of %d ok %d", @@ -678,6 +804,8 @@ static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev) yaffs2_get_checkpt_sum(dev, &checkpt_sum); + yaffs_do_endian_u32(dev, &checkpt_sum); + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum)); @@ -700,6 +828,7 @@ static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev) if (!ok) return 0; + yaffs_do_endian_u32(dev, &checkpt_sum1); if (checkpt_sum0 != checkpt_sum1) return 0; @@ -864,6 +993,10 @@ int yaffs2_checkpt_restore(struct yaffs_dev *dev) return retval; } +/* End of checkpointing */ + +/* Hole handling logic for truncate past end of file */ + int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) { /* if new_size > old_file_size. @@ -948,6 +1081,8 @@ int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) return result; } +/* Yaffs2 scanning */ + struct yaffs_block_index { int seq; int block; @@ -1157,6 +1292,8 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, oh = (struct yaffs_obj_hdr *)chunk_data; + yaffs_do_endian_oh(dev, oh); + if (dev->param.inband_tags) { /* Fix up the header if they got * corrupted by inband tags */ @@ -1194,7 +1331,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE) )) { loff_t this_size = (oh) ? - yaffs_oh_to_size(oh) : + yaffs_oh_to_size(dev, oh, 0) : tags.extra_file_size; u32 parent_obj_id = (oh) ? oh->parent_obj_id : @@ -1271,7 +1408,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, parent = yaffs_find_or_create_by_number(dev, oh->parent_obj_id, YAFFS_OBJECT_TYPE_DIRECTORY); - file_size = yaffs_oh_to_size(oh); + file_size = yaffs_oh_to_size(dev, oh, 0); is_shrink = oh->is_shrink; equiv_id = oh->equiv_id; } else { -- 2.30.2