#include "yaffs_trace.h"
#include "yaffs_guts.h"
+#include "yaffs_endian.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsmarshall.h"
loff_t yaffs_max_file_size(struct yaffs_dev *dev)
{
- if(sizeof(loff_t) < 8)
+ if (sizeof(loff_t) < 8)
return YAFFS_MAX_FILE_SIZE_32;
else
return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
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;
if (tags.chunk_id == 0) {
/* It is an object Id,
- * We need to nuke the
- * shrinkheader flags since its
+ * We need to nuke the shrinkheader flags since its
* work is done.
- * Also need to clean up
- * shadowing.
+ * Also need to clean up shadowing.
+ * NB We don't want to do all the work of translating
+ * object header endianism back and forth so we leave
+ * the oh endian in its stored order.
*/
+
struct yaffs_obj_hdr *oh;
oh = (struct yaffs_obj_hdr *) buffer;
/* Update file size */
if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
- yaffs_oh_size_load(oh,
- object->variant.file_variant.file_size);
+ yaffs_oh_size_load(dev, oh,
+ object->variant.file_variant.stored_size, 1);
tags.extra_file_size =
- object->variant.file_variant.file_size;
+ object->variant.file_variant.stored_size;
}
yaffs_verify_oh(object, oh, &tags, 1);
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);
(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);
yaffs_verify_file_sane(in);
}
return new_chunk_id;
-
}
if (xmod->set)
retval =
- nval_set(x_buffer, x_size, xmod->name, xmod->data,
+ nval_set(dev, x_buffer, x_size, xmod->name, xmod->data,
xmod->size, xmod->flags);
else
- retval = nval_del(x_buffer, x_size, xmod->name);
+ retval = nval_del(dev, x_buffer, x_size, xmod->name);
- obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+ obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size);
obj->xattr_known = 1;
xmod->result = retval;
x_buffer = buffer + x_offs;
if (!obj->xattr_known) {
- obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+ obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size);
obj->xattr_known = 1;
}
if (name)
- retval = nval_get(x_buffer, x_size, name, value, size);
+ retval = nval_get(dev, x_buffer, x_size,
+ name, value, size);
else
- retval = nval_list(x_buffer, x_size, value, size);
+ retval = nval_list(dev, x_buffer, x_size, value, size);
}
yaffs_release_temp_buffer(dev, (u8 *) buffer);
return retval;
result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
oh = (struct yaffs_obj_hdr *)buf;
+ yaffs_do_endian_oh(dev, oh);
+
in->yst_mode = oh->yst_mode;
yaffs_load_attribs(in, oh);
yaffs_set_obj_name_from_oh(in, oh);
/* UpdateObjectHeader updates the header on NAND for an object.
* If name is not NULL, then that new name is used.
+ *
+ * We're always creating the obj header from scratch (except reading
+ * the old name) so first set up in cpu endianness then run it through
+ * endian fixing at the end.
+ *
+ * However, a twist: If there are xattribs we leave them as they were.
+ *
+ * Careful! The buffer holds the whole chunk. Part of the chunk holds the
+ * object header and the rest holds the xattribs, therefore we use a buffer
+ * pointer and an oh pointer to point to the same memory.
*/
+
int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
{
prev_chunk_id = in->hdr_chunk;
if (prev_chunk_id > 0) {
+ /* Access the old obj header just to read the name. */
result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
buffer, &old_tags);
yaffs_verify_oh(in, oh, &old_tags, 0);
memcpy(old_name, oh->name, sizeof(oh->name));
- memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
+
+ /*
+ * NB We only wipe the object header area because the rest of
+ * the buffer might contain xattribs.
+ */
+ memset(oh, 0xff, sizeof(*oh));
} else {
memset(buffer, 0xff, dev->data_bytes_per_chunk);
}
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;
- yaffs_oh_size_load(oh, file_size);
+ file_size = in->variant.file_variant.stored_size;
+ yaffs_oh_size_load(dev, oh, file_size, 0);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
oh->equiv_id = in->variant.hardlink_variant.equiv_id;
new_tags.extra_equiv_id = oh->equiv_id;
new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
new_tags.extra_obj_type = in->variant_type;
+
+ /* Now endian swizzle the oh if needed. */
+ yaffs_do_endian_oh(dev, oh);
+
yaffs_verify_oh(in, oh, &new_tags, 1);
/* Create new chunk in NAND */
}
obj->variant.file_variant.file_size = new_size;
+ obj->variant.file_variant.stored_size = new_size;
yaffs_prune_tree(dev, &obj->variant.file_variant);
}
}
}
-static int yaffs_unlink_obj(struct yaffs_obj *obj)
+int yaffs_unlink_obj(struct yaffs_obj *obj)
{
if (obj && obj->unlink_allowed)
return yaffs_unlink_worker(obj);
static int yaffs_create_initial_dir(struct yaffs_dev *dev)
{
/* Initialise the unlinked, deleted, root and lost+found directories */
- dev->lost_n_found = dev->root_dir = NULL;
- dev->unlinked_dir = dev->del_dir = NULL;
+ dev->lost_n_found = NULL;
+ dev->root_dir = NULL;
+ dev->unlinked_dir = NULL;
+ dev->del_dir = NULL;
+
dev->unlinked_dir =
yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
dev->del_dir =
yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
YAFFS_LOSTNFOUND_MODE | S_IFDIR);
- if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
- && dev->del_dir) {
- yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
+ if (dev->lost_n_found &&
+ dev->root_dir &&
+ dev->unlinked_dir &&
+ dev->del_dir) {
+ /* If lost-n-found is hidden then yank it out of the directory tree. */
+ if (dev->param.hide_lost_n_found)
+ list_del_init(&dev->lost_n_found->siblings);
+ else
+ yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
return YAFFS_OK;
}
return YAFFS_FAIL;
dev->n_erase_failures = 0;
dev->n_erased_blocks = 0;
dev->gc_disable = 0;
- dev->has_pending_prioritised_gc = 1;
- /* Assume the worst for now, will get fixed on first GC */
+ dev->has_pending_prioritised_gc = 1; /* Assume the worst for now,
+ * will get fixed on first GC */
INIT_LIST_HEAD(&dev->dirty_dirs);
dev->oldest_dirty_seq = 0;
dev->oldest_dirty_block = 0;
+ yaffs_endian_config(dev);
+
/* Initialise temporary buffers and caches. */
if (!yaffs_init_tmp_buffers(dev))
init_failed = 1;
kfree(dev->gc_cleanup_list);
- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
kfree(dev->temp_buffer[i].buffer);
+ dev->temp_buffer[i].buffer = NULL;
+ }
+
+ kfree(dev->checkpt_buffer);
+ dev->checkpt_buffer = NULL;
+ kfree(dev->checkpt_block_list);
+ dev->checkpt_block_list = NULL;
dev->is_mounted = 0;
}
-
/*
* Marshalling functions to get loff_t file sizes into and out of
* object headers.
*/
-void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
+void yaffs_oh_size_load(struct yaffs_dev *dev,
+ struct yaffs_obj_hdr *oh,
+ loff_t fsize,
+ int do_endian)
{
oh->file_size_low = (fsize & 0xFFFFFFFF);
oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
+
+ if (do_endian) {
+ yaffs_do_endian_u32(dev, &oh->file_size_low);
+ yaffs_do_endian_u32(dev, &oh->file_size_high);
+ }
}
-loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
+loff_t yaffs_oh_to_size(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh,
+ int do_endian)
{
loff_t retval;
- if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
- retval = (((loff_t) oh->file_size_high) << 32) |
- (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
- else
- retval = (loff_t) oh->file_size_low;
+
+ if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) {
+ u32 low = oh->file_size_low;
+ u32 high = oh->file_size_high;
+
+ if (do_endian) {
+ yaffs_do_endian_u32 (dev, &low);
+ yaffs_do_endian_u32 (dev, &high);
+ }
+ retval = (((loff_t) high) << 32) |
+ (((loff_t) low) & 0xFFFFFFFF);
+ } else {
+ u32 low = oh->file_size_low;
+
+ if (do_endian)
+ yaffs_do_endian_u32(dev, &low);
+ retval = (loff_t)low;
+ }
return retval;
}