X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_yaffs2.c;h=9eb42f7ff54d9e4a93036e9a2ad75e53f1147707;hp=688211e1ae6a48e3ee9e0bc1bb93cc8067ff7c2c;hb=b19d3c9f0ada46534e44308f72d7e70ab1e301ee;hpb=bf0323aab4b4a577fcb2dafc573b443aabcedc02 diff --git a/yaffs_yaffs2.c b/yaffs_yaffs2.c index 688211e..9eb42f7 100644 --- a/yaffs_yaffs2.c +++ b/yaffs_yaffs2.c @@ -1,8 +1,7 @@ /* * 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 + * Copyright (C) 2002-2018 Aleph One Ltd. * * Created by Charles Manning * @@ -21,6 +20,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. @@ -41,7 +41,7 @@ */ void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) { - int i; + u32 i; unsigned seq; unsigned block_no = 0; struct yaffs_block_info *b; @@ -54,7 +54,7 @@ void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) b = dev->block_info; for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { if (b->block_state == YAFFS_BLOCK_STATE_FULL && - (b->pages_in_use - b->soft_del_pages) < + (u32)(b->pages_in_use - b->soft_del_pages) < dev->param.chunks_per_block && b->seq_number < seq) { seq = b->seq_number; @@ -248,6 +248,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 +271,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 +282,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 +295,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,30 +323,67 @@ 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; + u32 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) == + (int)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_wr(dev, dev->chunk_bits, n_bytes) == + (int)n_bytes); return ok ? 1 : 0; } @@ -345,6 +399,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; @@ -353,14 +408,27 @@ static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) n_bytes = n_blocks * sizeof(struct yaffs_block_info); - ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == + (int)n_bytes); 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); + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == + (int)n_bytes); + return ok ? 1 : 0; } @@ -473,6 +541,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 +595,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); - + (int)dev->tnode_size); + } return ok; } @@ -540,14 +643,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); + (int)dev->tnode_size); + yaffs2_do_endian_tnode(dev, tn); + } else ok = 0; @@ -556,10 +663,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 +679,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 +720,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 +735,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 +755,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", @@ -642,7 +771,7 @@ static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) cp.obj_id, cp.parent_id, cp_variant_type, cp.hdr_chunk); - if (ok && cp.obj_id == ~0) { + if (ok && cp.obj_id == (u32)(~0)) { done = 1; } else if (ok) { obj = @@ -678,6 +807,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 +831,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 +996,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. @@ -917,7 +1053,7 @@ int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) while (increase > 0 && small_increase_ok) { this_write = increase; - if (this_write > dev->data_bytes_per_chunk) + if (this_write > (int)dev->data_bytes_per_chunk) this_write = dev->data_bytes_per_chunk; written = yaffs_do_file_wr(obj, local_buffer, pos, this_write, @@ -948,6 +1084,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; @@ -1001,6 +1139,9 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, dev->summary_used++; } + if (result == YAFFS_FAIL) + yaffs_trace(YAFFS_TRACE_SCAN, + "Could not get tags for chunk %d\n", chunk); /* Let's have a good look at this chunk... */ if (!tags.chunk_used) { @@ -1157,6 +1298,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,10 +1337,10 @@ 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 : + (u32)oh->parent_obj_id : tags.extra_parent_id; is_shrink = (oh) ? @@ -1271,7 +1414,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 { @@ -1380,7 +1523,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, int yaffs2_scan_backwards(struct yaffs_dev *dev) { - int blk; + u32 blk; int block_iter; int start_iter; int end_iter;