Write object headers with stored file extents charles_experiment
authorCharles Manning <cdhmanning@gmail.com>
Mon, 7 Mar 2016 19:03:06 +0000 (08:03 +1300)
committerCharles Manning <cdhmanning@gmail.com>
Mon, 7 Mar 2016 19:03:06 +0000 (08:03 +1300)
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>
yaffs_guts.c
yaffs_guts.h
yaffs_yaffs1.c
yaffs_yaffs2.c

index 4e679bf2cf97efabcfcc6eddfaa81c36c748238c..bf58eca1da0b3ceaf0316adbb7ed055b6519733b 100644 (file)
@@ -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;
        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;
@@ -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,
                        /* 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 =
                                tags.extra_file_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);
@@ -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;
        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);
 
 
        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;
 
            (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);
 
@@ -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;
                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)
        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:
@@ -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.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);
 }
index c2f7ac46ef6c7e9ca4f2f57a5616b4c92c615a3c..e2b2fb9378afe615beba22b0eb86f3d65a992b99 100644 (file)
@@ -374,9 +374,19 @@ struct yaffs_tnode {
  * - a hard link
  */
 
  * - 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;
 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;
        loff_t shrink_size;
        int top_level;
        struct yaffs_tnode *top;
index d277e20e2a554cee97d28e91430ea24e839d4775..4f2e76878ceab34c27d5bba7162d9042234e9880 100644 (file)
@@ -162,15 +162,15 @@ int yaffs1_scan(struct yaffs_dev *dev)
                                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 <
                                      endpos) {
                                      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.
                                            endpos;
                                        if (!dev->param.use_header_file_size) {
                                                in->variant.
                                                    file_variant.file_size =
                                                    in->variant.
-                                                   file_variant.scanned_size;
+                                                   file_variant.stored_size;
                                        }
 
                                }
                                        }
 
                                }
index 9fb7c944caca02acbf511e55dbe71d9cf88f573f..f2f98a4c08770e8d3542de0f24a4f40fa6c51072 100644 (file)
@@ -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;
 
        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;
@@ -1068,9 +1069,9 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
                        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.
-                                   scanned_size = endpos;
+                                   stored_size = endpos;
                                in->variant.file_variant.
                                    file_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;
                                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
@@ -1307,7 +1308,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
                                         * 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)