From 33308768bd24abe4e1f59c5025a3dd824119ae1d Mon Sep 17 00:00:00 2001 From: Charles Manning Date: Tue, 8 Mar 2016 08:03:06 +1300 Subject: [PATCH] Write object headers with stored file extents Previously file object headers were being written with file extents rather than stored extents. This could lead to situations where the data in the cache was not yet written to flash but had been accounted for in the object header file size. Under power fail this could cause zero-filled blobs at the end of a file. This change tracks the stored file size and only write object headers reflecting the extents of the file that has actually been stored to flash, thus avoiding the holes. Signed-off-by: Charles Manning --- yaffs_guts.c | 24 ++++++++++++++++++------ yaffs_guts.h | 12 +++++++++++- yaffs_yaffs1.c | 6 +++--- yaffs_yaffs2.c | 15 ++++++++------- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/yaffs_guts.c b/yaffs_guts.c index 4e679bf..bf58eca 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -2001,7 +2001,7 @@ static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number, switch (type) { case YAFFS_OBJECT_TYPE_FILE: the_obj->variant.file_variant.file_size = 0; - the_obj->variant.file_variant.scanned_size = 0; + the_obj->variant.file_variant.stored_size = 0; the_obj->variant.file_variant.shrink_size = yaffs_max_file_size(dev); the_obj->variant.file_variant.top_level = 0; @@ -2547,9 +2547,9 @@ 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.file_size); + object->variant.file_variant.stored_size); tags.extra_file_size = - object->variant.file_variant.file_size; + object->variant.file_variant.stored_size; } yaffs_verify_oh(object, oh, &tags, 1); @@ -3050,6 +3050,7 @@ static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, int new_chunk_id; struct yaffs_ext_tags new_tags; struct yaffs_dev *dev = in->my_dev; + loff_t endpos; yaffs_check_gc(dev, 0); @@ -3071,13 +3072,24 @@ static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1; new_tags.n_bytes = n_bytes; - if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) { + if (n_bytes < 1 || n_bytes > dev->data_bytes_per_chunk) { yaffs_trace(YAFFS_TRACE_ERROR, "Writing %d bytes to chunk!!!!!!!!!", n_bytes); BUG(); } + /* + * If this is a data chunk and the write goes past the end of the stored + * size then update the stored_size. + */ + if (inode_chunk > 0) { + endpos = (inode_chunk - 1) * dev->data_bytes_per_chunk + + n_bytes; + if (in->variant.file_variant.stored_size < endpos) + in->variant.file_variant.stored_size = endpos; + } + new_chunk_id = yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve); @@ -3090,7 +3102,6 @@ static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, yaffs_verify_file_sane(in); } return new_chunk_id; - } @@ -3319,7 +3330,7 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, case YAFFS_OBJECT_TYPE_FILE: if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED && oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED) - file_size = in->variant.file_variant.file_size; + file_size = in->variant.file_variant.stored_size; yaffs_oh_size_load(oh, file_size); break; case YAFFS_OBJECT_TYPE_HARDLINK: @@ -3740,6 +3751,7 @@ void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size) } obj->variant.file_variant.file_size = new_size; + obj->variant.file_variant.stored_size = new_size; yaffs_prune_tree(dev, &obj->variant.file_variant); } diff --git a/yaffs_guts.h b/yaffs_guts.h index c2f7ac4..e2b2fb9 100644 --- a/yaffs_guts.h +++ b/yaffs_guts.h @@ -374,9 +374,19 @@ struct yaffs_tnode { * - a hard link */ +/* The file variant has three file sizes: + * - file_size : size of file as written into Yaffs - including data in cache. + * - stored_size - size of file as stored on media. + * - shrink_size - size of file that has been shrunk back to. + * + * The stored_size and file_size might be different because the data written + * into the cache will increase the file_size but the stored_size will only + * change when the data is actually stored. + * + */ struct yaffs_file_var { loff_t file_size; - loff_t scanned_size; + loff_t stored_size; loff_t shrink_size; int top_level; struct yaffs_tnode *top; diff --git a/yaffs_yaffs1.c b/yaffs_yaffs1.c index d277e20..4f2e768 100644 --- a/yaffs_yaffs1.c +++ b/yaffs_yaffs1.c @@ -162,15 +162,15 @@ int yaffs1_scan(struct yaffs_dev *dev) if (in && in->variant_type == YAFFS_OBJECT_TYPE_FILE && - in->variant.file_variant.scanned_size < + in->variant.file_variant.stored_size < endpos) { - in->variant.file_variant.scanned_size = + in->variant.file_variant.stored_size = endpos; if (!dev->param.use_header_file_size) { in->variant. file_variant.file_size = in->variant. - file_variant.scanned_size; + file_variant.stored_size; } } diff --git a/yaffs_yaffs2.c b/yaffs_yaffs2.c index 9fb7c94..f2f98a4 100644 --- a/yaffs_yaffs2.c +++ b/yaffs_yaffs2.c @@ -432,11 +432,12 @@ static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, obj->serial = cp->serial; obj->n_data_chunks = cp->n_data_chunks; - if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) { obj->variant.file_variant.file_size = cp->size_or_equiv_obj; - else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) + obj->variant.file_variant.stored_size = cp->size_or_equiv_obj; + } else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; - + } if (obj->hdr_chunk > 0) obj->lazy_loaded = 1; return 1; @@ -1068,9 +1069,9 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, endpos = chunk_base + tags.n_bytes; if (!in->valid && - in->variant.file_variant.scanned_size < endpos) { + in->variant.file_variant.stored_size < endpos) { in->variant.file_variant. - scanned_size = endpos; + stored_size = endpos; in->variant.file_variant. file_size = endpos; } @@ -1299,7 +1300,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, break; case YAFFS_OBJECT_TYPE_FILE: file_var = &in->variant.file_variant; - if (file_var->scanned_size < file_size) { + if (file_var->stored_size < file_size) { /* This covers the case where the file * size is greater than the data held. * This will happen if the file is @@ -1307,7 +1308,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, * current data extents. */ file_var->file_size = file_size; - file_var->scanned_size = file_size; + file_var->stored_size = file_size; } if (file_var->shrink_size > file_size) -- 2.30.2