X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_yaffs2.c;fp=yaffs_yaffs2.c;h=6d4681726a60b3ae63adc3456661a8652790194a;hp=688211e1ae6a48e3ee9e0bc1bb93cc8067ff7c2c;hb=21b2dedaa32ab309f6d1daec966528b7586bd207;hpb=bf0323aab4b4a577fcb2dafc573b443aabcedc02 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 {