summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
03e4ccd)
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 <cdhmanning@gmail.com>
switch (type) {
case YAFFS_OBJECT_TYPE_FILE:
the_obj->variant.file_variant.file_size = 0;
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;
the_obj->variant.file_variant.shrink_size =
yaffs_max_file_size(dev);
the_obj->variant.file_variant.top_level = 0;
/* Update file size */
if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
yaffs_oh_size_load(oh,
/* 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);
- object->variant.file_variant.file_size;
+ object->variant.file_variant.stored_size;
}
yaffs_verify_oh(object, oh, &tags, 1);
}
yaffs_verify_oh(object, oh, &tags, 1);
int new_chunk_id;
struct yaffs_ext_tags new_tags;
struct yaffs_dev *dev = in->my_dev;
int new_chunk_id;
struct yaffs_ext_tags new_tags;
struct yaffs_dev *dev = in->my_dev;
(prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
new_tags.n_bytes = n_bytes;
(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();
}
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);
new_chunk_id =
yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
yaffs_verify_file_sane(in);
}
return new_chunk_id;
yaffs_verify_file_sane(in);
}
return new_chunk_id;
case YAFFS_OBJECT_TYPE_FILE:
if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
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:
yaffs_oh_size_load(oh, file_size);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
}
obj->variant.file_variant.file_size = 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);
}
yaffs_prune_tree(dev, &obj->variant.file_variant);
}
+/* 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;
struct yaffs_file_var {
loff_t file_size;
loff_t shrink_size;
int top_level;
struct yaffs_tnode *top;
loff_t shrink_size;
int top_level;
struct yaffs_tnode *top;
if (in &&
in->variant_type ==
YAFFS_OBJECT_TYPE_FILE &&
if (in &&
in->variant_type ==
YAFFS_OBJECT_TYPE_FILE &&
- in->variant.file_variant.scanned_size <
+ in->variant.file_variant.stored_size <
- 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.
endpos;
if (!dev->param.use_header_file_size) {
in->variant.
file_variant.file_size =
in->variant.
- file_variant.scanned_size;
+ file_variant.stored_size;
obj->serial = cp->serial;
obj->n_data_chunks = cp->n_data_chunks;
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;
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;
obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
if (obj->hdr_chunk > 0)
obj->lazy_loaded = 1;
return 1;
if (obj->hdr_chunk > 0)
obj->lazy_loaded = 1;
return 1;
endpos = chunk_base + tags.n_bytes;
if (!in->valid &&
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.
in->variant.file_variant.
in->variant.file_variant.
file_size = endpos;
}
in->variant.file_variant.
file_size = endpos;
}
break;
case YAFFS_OBJECT_TYPE_FILE:
file_var = &in->variant.file_variant;
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
/* This covers the case where the file
* size is greater than the data held.
* This will happen if the file is
* current data extents.
*/
file_var->file_size = file_size;
* 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)
}
if (file_var->shrink_size > file_size)