X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=72555d53ed08a6ec7864ddb5c598768fb140eda8;hp=1c0ae71320a52fc5645e09fd76e5203c348ab8c7;hb=21b2dedaa32ab309f6d1daec966528b7586bd207;hpb=319d4f76f0e10d1d6427120221237950e373d74b diff --git a/yaffs_guts.c b/yaffs_guts.c index 1c0ae71..72555d5 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -15,6 +15,7 @@ #include "yaffs_trace.h" #include "yaffs_guts.h" +#include "yaffs_endian.h" #include "yaffs_getblockinfo.h" #include "yaffs_tagscompat.h" #include "yaffs_tagsmarshall.h" @@ -755,7 +756,7 @@ void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, 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; @@ -1922,21 +1923,18 @@ static int yaffs_new_obj_id(struct yaffs_dev *dev) struct list_head *i; u32 n = (u32) bucket; - /* Now find an object value that has not already been taken - * by scanning the list. + /* + * Now find an object value that has not already been taken + * by scanning the list, incrementing each time by number of buckets. */ - while (!found) { found = 1; n += YAFFS_NOBJECT_BUCKETS; - if (1 || dev->obj_bucket[bucket].count > 0) { - list_for_each(i, &dev->obj_bucket[bucket].list) { - /* If there is already one in the list */ - if (i && list_entry(i, struct yaffs_obj, - hash_link)->obj_id == n) { - found = 0; - } - } + list_for_each(i, &dev->obj_bucket[bucket].list) { + /* Check if this value is already taken. */ + if (i && list_entry(i, struct yaffs_obj, + hash_link)->obj_id == n) + found = 0; } } return n; @@ -2004,7 +2002,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; @@ -2532,12 +2530,14 @@ static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, 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; @@ -2549,10 +2549,10 @@ 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); + 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); @@ -3053,6 +3053,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); @@ -3074,13 +3075,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); @@ -3093,7 +3105,6 @@ static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, yaffs_verify_file_sane(in); } return new_chunk_id; - } @@ -3131,12 +3142,12 @@ static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, 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; @@ -3181,14 +3192,15 @@ static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name, 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; @@ -3235,6 +3247,8 @@ static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) 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); @@ -3250,7 +3264,18 @@ static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) /* 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) { @@ -3283,12 +3308,18 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, 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); } @@ -3322,8 +3353,8 @@ 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; - 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; @@ -3362,6 +3393,10 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, 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 */ @@ -3743,6 +3778,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); } @@ -4083,7 +4119,7 @@ static int yaffs_unlink_worker(struct yaffs_obj *obj) } } -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); @@ -4626,8 +4662,11 @@ static int yaffs_check_dev_fns(struct yaffs_dev *dev) 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 = @@ -4639,9 +4678,15 @@ static int yaffs_create_initial_dir(struct yaffs_dev *dev) 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; @@ -4854,12 +4899,14 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) 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; @@ -5022,8 +5069,15 @@ void yaffs_deinitialise(struct yaffs_dev *dev) 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; @@ -5091,26 +5145,47 @@ int yaffs_get_n_free_chunks(struct yaffs_dev *dev) } - /* * 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; }