X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=d3e877fe3d1275e0c072e649ae1da1227376f9f6;hp=14ab47219674ff8f5abf3fd4cb3e3228f0a5a4d8;hb=6014fce5c65757724aef9033f2a710da324f2523;hpb=6c0b1f629b813db703ceac9e35822380d7f73f1f diff --git a/yaffs_guts.c b/yaffs_guts.c index 14ab472..d3e877f 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -41,7 +41,8 @@ static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, const u8 *buffer, int n_bytes, int use_reserve); - +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, + int buffer_size); /* Function to calculate chunk and offset */ @@ -609,10 +610,10 @@ static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block) memset(buffer, 0xff, dev->data_bytes_per_chunk); memset(&tags, 0, sizeof(tags)); tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; - if (dev->param.write_chunk_tags_fn(dev, chunk_id - - dev->chunk_offset, - buffer, - &tags) != YAFFS_OK) + if (dev->tagger.write_chunk_tags_fn(dev, chunk_id - + dev->chunk_offset, + buffer, + &tags) != YAFFS_OK) yaffs_trace(YAFFS_TRACE_ALWAYS, "yaffs: Failed to write bad block marker to block %d", flash_block); @@ -648,15 +649,21 @@ static u16 yaffs_calc_name_sum(const YCHAR *name) return sum; } + void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) { memset(obj->short_name, 0, sizeof(obj->short_name)); - if (name && + + if (name && !name[0]) { + yaffs_fix_null_name(obj, obj->short_name, + YAFFS_SHORT_NAME_LENGTH); + name = obj->short_name; + } else if (name && strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= - YAFFS_SHORT_NAME_LENGTH) + YAFFS_SHORT_NAME_LENGTH) { strcpy(obj->short_name, name); - else - obj->short_name[0] = _Y('\0'); + } + obj->sum = yaffs_calc_name_sum(name); } @@ -973,7 +980,7 @@ static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, return -1; } -static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, +int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, struct yaffs_ext_tags *tags) { /*Get the Tnode, then get the level 0 offset chunk offset */ @@ -3943,6 +3950,70 @@ int yaffs_del_obj(struct yaffs_obj *obj) return ret_val; } + +static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir, + struct yaffs_obj *to_dir) +{ + struct yaffs_obj *obj; + struct list_head *lh; + struct list_head *n; + + list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) { + obj = list_entry(lh, struct yaffs_obj, siblings); + yaffs_add_obj_to_dir(to_dir, obj); + } +} + +struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj, + enum yaffs_obj_type type) +{ + /* Tear down the old variant */ + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + /* Nuke file data */ + yaffs_resize_file(obj, 0); + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); + obj->variant.file_variant.top = NULL; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Put the children in lost and found. */ + yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found); + if (!list_empty(&obj->variant.dir_variant.dirty)) + list_del_init(&obj->variant.dir_variant.dirty); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + /* Nuke symplink data */ + kfree(obj->variant.symlink_variant.alias); + obj->variant.symlink_variant.alias = NULL; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + list_del_init(&obj->hard_links); + break; + default: + break; + } + + memset(&obj->variant, 0, sizeof(obj->variant)); + + /*Set up new variant if the memset is not enough. */ + switch (type) { + case YAFFS_OBJECT_TYPE_DIRECTORY: + INIT_LIST_HEAD(&obj->variant.dir_variant.children); + INIT_LIST_HEAD(&obj->variant.dir_variant.dirty); + break; + case YAFFS_OBJECT_TYPE_FILE: + case YAFFS_OBJECT_TYPE_SYMLINK: + case YAFFS_OBJECT_TYPE_HARDLINK: + default: + break; + } + + obj->variant_type = type; + + return obj; + +} + static int yaffs_unlink_worker(struct yaffs_obj *obj) { int del_now = 0; @@ -4535,16 +4606,17 @@ YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj) static int yaffs_check_dev_fns(struct yaffs_dev *dev) { - struct yaffs_param *param = &dev->param; + struct yaffs_driver *drv = &dev->drv; + struct yaffs_tags_handler *tagger = &dev->tagger; /* Common functions, gotta have */ - if (!param->drv_read_chunk_fn || - !param->drv_write_chunk_fn || - !param->drv_erase_fn) + if (!drv->drv_read_chunk_fn || + !drv->drv_write_chunk_fn || + !drv->drv_erase_fn) return 0; - if (param->is_yaffs2 && - (!param->drv_mark_bad_fn || !param->drv_check_bad_fn)) + if (dev->param.is_yaffs2 && + (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn)) return 0; /* Install the default tags marshalling functions if needed. */ @@ -4552,10 +4624,10 @@ static int yaffs_check_dev_fns(struct yaffs_dev *dev) yaffs_tags_marshall_install(dev); /* Check we now have the marshalling functions required. */ - if (!param->write_chunk_tags_fn || - !param->read_chunk_tags_fn || - !param->query_block_fn || - !param->mark_bad_fn) + if (!tagger->write_chunk_tags_fn || + !tagger->read_chunk_tags_fn || + !tagger->query_block_fn || + !tagger->mark_bad_fn) return 0; return 1; @@ -4585,15 +4657,16 @@ static int yaffs_create_initial_dir(struct yaffs_dev *dev) return YAFFS_FAIL; } -int yaffs_guts_initialise(struct yaffs_dev *dev) +/* Low level init. + * Typically only used by yaffs_guts_initialise, but also used by the + * Low level yaffs driver tests. + */ + +int yaffs_guts_ll_init(struct yaffs_dev *dev) { - int init_failed = 0; - unsigned x; - int bits; - yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()"); - /* Check stuff that must be set */ + yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()"); if (!dev) { yaffs_trace(YAFFS_TRACE_ALWAYS, @@ -4602,10 +4675,8 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) return YAFFS_FAIL; } - if (dev->is_mounted) { - yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); - return YAFFS_FAIL; - } + if (dev->ll_init) + return YAFFS_OK; dev->internal_start_block = dev->param.start_block; dev->internal_end_block = dev->param.end_block; @@ -4645,11 +4716,6 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) return YAFFS_FAIL; } - if (yaffs_init_nand(dev) != YAFFS_OK) { - yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); - return YAFFS_FAIL; - } - /* Sort out space for inband tags, if required */ if (dev->param.inband_tags) dev->data_bytes_per_chunk = @@ -4667,7 +4733,50 @@ int yaffs_guts_initialise(struct yaffs_dev *dev) return YAFFS_FAIL; } - /* Finished with most checks. Further checks happen later on too. */ + if (yaffs_init_nand(dev) != YAFFS_OK) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); + return YAFFS_FAIL; + } + + return YAFFS_OK; +} + + +int yaffs_format_dev(struct yaffs_dev *dev) +{ + int i; + enum yaffs_block_state state; + u32 dummy; + + if(yaffs_guts_ll_init(dev) != YAFFS_OK) + return YAFFS_FAIL; + + if(dev->is_mounted) + return YAFFS_FAIL; + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + yaffs_query_init_block_state(dev, i, &state, &dummy); + if (state != YAFFS_BLOCK_STATE_DEAD) + yaffs_erase_block(dev, i); + } + + return YAFFS_OK; +} + + +int yaffs_guts_initialise(struct yaffs_dev *dev) +{ + int init_failed = 0; + unsigned x; + int bits; + + if(yaffs_guts_ll_init(dev) != YAFFS_OK) + return YAFFS_FAIL; + + if (dev->is_mounted) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); + return YAFFS_FAIL; + } dev->is_mounted = 1; @@ -4991,6 +5100,8 @@ int yaffs_get_n_free_chunks(struct yaffs_dev *dev) return n_free; } + + /* * Marshalling functions to get loff_t file sizes into and out of * object headers. @@ -5013,3 +5124,23 @@ loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh) return retval; } + + +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]) +{ + int i; + struct yaffs_block_info *bi; + int s; + + for(i = 0; i < 10; i++) + bs[i] = 0; + + for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + bi = yaffs_get_block_info(dev, i); + s = bi->block_state; + if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN) + bs[0]++; + else + bs[s]++; + } +}