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
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
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 \
"
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 \
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 \
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;
#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?
typedef struct
{
nandemul_Page *page[PAGES_PER_BLOCK];
- int damaged;
+ int damaged;
} nandemul_Block;
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));
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 <nBlocks; i++)
{
-
+
nandemul_Block *blk;
-
+
if(!(blk = ned.block[i] = malloc(sizeof(nandemul_Block))))
{
fail = 1;
- }
+ }
else
{
for(j = 0; j < PAGES_PER_BLOCK; j++)
nAllocated++;
}
}
-
+
if(fail)
{
//Todo thump pages
-
+
for(i = 0; i < nAllocated; i++)
{
kfree(ned.block[i]);
}
kfree(ned.block);
-
+
yaffs_trace(YAFFS_TRACE_ALWAYS,
"Allocation failed, could only allocate %dMB of %dMB requested.\n",
nAllocated/64,sizeInMB);
return 0;
}
-
+
ned.nBlocks = nBlocks;
-
+
initialised = 1;
-
+
return 1;
}
int blk;
int pg;
int i;
-
+
u8 *x;
-
+
blk = nand_chunk/PAGES_PER_BLOCK;
pg = nand_chunk%PAGES_PER_BLOCK;
-
-
+
+
if(data)
{
x = ned.block[blk]->page[pg]->data;
-
+
for(i = 0; i < PAGE_DATA_SIZE; i++)
{
x[i] &=data[i];
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);
{
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;
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)
int nandemul2k_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
{
-
-
+
+
if(blockNumber < 0 || blockNumber >= ned.nBlocks)
{
yaffs_trace(YAFFS_TRACE_ALWAYS,
{
nandemul_ReallyEraseBlock(blockNumber);
}
-
+
return YAFFS_OK;
}
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)
int chunkNo;
*seq_number = 0;
-
+
chunkNo = block_no * dev->param.chunks_per_block;
-
+
nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
if(tags.block_bad)
{
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
+typedef unsigned long long u64;
typedef signed int s32;
#endif
#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;
#include "yaffs_checkptrw.h"
#include "yaffs_getblockinfo.h"
+#include "yaffs_endian.h"
struct yaffs_checkpt_chunk_hdr {
int version;
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;
dev->checkpt_byte_offs = sizeof(hdr);
+ yaffs2_do_endian_hdr(dev, &hdr);
memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
}
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);
--- /dev/null
+/*
+ * 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 <charles@aleph1.co.uk>
+ *
+ * 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);
+}
--- /dev/null
+/*
+ * 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 <charles@aleph1.co.uk>
+ *
+ * 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
#include "yaffs_trace.h"
#include "yaffs_guts.h"
+#include "yaffs_endian.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsmarshall.h"
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;
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;
/* 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;
}
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;
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;
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);
/* 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)
{
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);
}
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;
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 */
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;
}
-
/*
* 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;
}
union yaffs_tags_union {
struct yaffs_tags as_tags;
- u8 as_bytes[8];
+ u8 as_bytes[8];
+ u32 as_u32[2];
};
};
+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 */
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.
*/
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;
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;
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);
/*
* 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.
* ----------
*/
#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)
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) {
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));
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;
}
#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
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)
#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
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;
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,
&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;
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;
};
/* 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
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;
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;
* 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"
#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 */
/********** 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,
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)
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);
}
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;
* 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"
(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,
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)
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.
#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.
/*--------------------- 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;
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;
}
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)) &&
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;
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);
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;
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;
}
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; i<tnode_size_u32; i++)
+ as_u32[i] = swap_u32(as_u32[i]);
+}
+
+struct yaffs_tnode *yaffs2_do_endian_tnode_copy(struct yaffs_dev *dev,
+ struct yaffs_tnode *tn)
+{
+ if (!dev->swap_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)
/* 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;
}
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;
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,
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;
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));
/* 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));
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",
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));
if (!ok)
return 0;
+ yaffs_do_endian_u32(dev, &checkpt_sum1);
if (checkpt_sum0 != checkpt_sum1)
return 0;
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.
return result;
}
+/* Yaffs2 scanning */
+
struct yaffs_block_index {
int seq;
int block;
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 */
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 :
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 {