#include "yaffs_guts.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_tagscompat.h"
+#include "yaffs_tagsmarshall.h"
#include "yaffs_nand.h"
#include "yaffs_yaffs1.h"
#include "yaffs_yaffs2.h"
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 */
if (buffer) {
/* assume it is an unmanaged one. */
- yaffs_trace(YAFFS_TRACE_BUFFERS, "Releasing unmanaged temp buffer");
+ yaffs_trace(YAFFS_TRACE_BUFFERS,
+ "Releasing unmanaged temp buffer");
kfree(buffer);
dev->unmanaged_buffer_deallocs++;
}
}
-/*
- * Determine if we have a managed buffer.
- */
-int yaffs_is_managed_tmp_buffer(struct yaffs_dev *dev, const u8 *buffer)
-{
- int i;
-
- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
- if (dev->temp_buffer[i].buffer == buffer)
- return 1;
- }
-
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].data == buffer)
- return 1;
- }
-
- if (buffer == dev->checkpt_buffer)
- return 1;
-
- yaffs_trace(YAFFS_TRACE_ALWAYS,
- "yaffs: unmaged buffer detected.");
- return 0;
-}
-
/*
* Functions for robustisizing TODO
*
const u8 *data,
const struct yaffs_ext_tags *tags)
{
- dev = dev;
- nand_chunk = nand_chunk;
- data = data;
- tags = tags;
+ (void) dev;
+ (void) nand_chunk;
+ (void) data;
+ (void) tags;
}
static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
const struct yaffs_ext_tags *tags)
{
- dev = dev;
- nand_chunk = nand_chunk;
- tags = tags;
+ (void) dev;
+ (void) nand_chunk;
+ (void) tags;
}
void yaffs_handle_chunk_error(struct yaffs_dev *dev,
static inline int yaffs_hash_fn(int n)
{
- n = abs(n);
+ if (n < 0)
+ n = -n;
return n % YAFFS_NOBJECT_BUCKETS;
}
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);
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);
}
loff_t yaffs_max_file_size(struct yaffs_dev *dev)
{
- return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
+ if(sizeof(loff_t) < 8)
+ return YAFFS_MAX_FILE_SIZE_32;
+ else
+ return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
}
/*-------------------- TNODES -------------------
dev->n_tnodes = 0;
}
-void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
+static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
unsigned pos, unsigned val)
{
u32 *map = (u32 *) tn;
int required_depth;
int level = file_struct->top_level;
- dev = dev;
+ (void) dev;
/* Check sane level and chunk Id */
if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
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 */
return NULL;
}
-struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
+static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
enum yaffs_obj_type type)
{
struct yaffs_obj *the_obj = NULL;
bi->has_shrink_hdr = 0;
bi->skip_erased_check = 1; /* Clean, so no need to check */
bi->gc_prioritise = 0;
- bi->has_summary=0;
+ bi->has_summary = 0;
yaffs_clear_chunk_bits(dev, block_no);
/* Update file size */
if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
- yaffs_oh_size_load( oh,
+ yaffs_oh_size_load(oh,
object->variant.file_variant.file_size);
tags.extra_file_size =
object->variant.file_variant.file_size;
int erased_chunks;
int checkpt_block_adjust;
- if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0)
+ if (dev->param.gc_control_fn &&
+ (dev->param.gc_control_fn(dev) & 1) == 0)
return YAFFS_OK;
if (dev->gc_disable)
}
} else {
#else
- dev = dev;
+ (void) dev;
{
#endif
strncpy(name, oh_name, buff_size - 1);
break;
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;
+ oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
+ file_size = in->variant.file_variant.file_size;
yaffs_oh_size_load(oh, file_size);
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
while (n > 0 && chunk_written >= 0) {
yaffs_addr_to_chunk(dev, offset, &chunk, &start);
- if (((loff_t)chunk) * dev->data_bytes_per_chunk + start != offset ||
+ if (((loff_t)chunk) *
+ dev->data_bytes_per_chunk + start != offset ||
start >= dev->data_bytes_per_chunk) {
yaffs_trace(YAFFS_TRACE_ERROR,
"AddrToChunk of offset %lld gives chunk %d start %d",
* before.
*/
- chunk_start = (((loff_t)(chunk - 1)) * dev->data_bytes_per_chunk);
+ chunk_start = (((loff_t)(chunk - 1)) *
+ dev->data_bytes_per_chunk);
if (chunk_start > in->variant.file_variant.file_size)
n_bytes_read = 0; /* Past end of file */
}
if (n_copy != dev->data_bytes_per_chunk ||
+ !dev->param.cache_bypass_aligned ||
dev->param.inband_tags) {
/* An incomplete start or end chunk (or maybe both
* start and end chunk), or we're using inband tags,
+ * or we're forcing writes through the cache,
* so we want to use the cache buffers.
*/
if (dev->param.n_caches > 0) {
/* ---------------------- File resizing stuff ------------------ */
-static void yaffs_prune_chunks(struct yaffs_obj *in, int new_size)
+static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
{
struct yaffs_dev *dev = in->my_dev;
- int old_size = in->variant.file_variant.file_size;
+ loff_t old_size = in->variant.file_variant.file_size;
int i;
int chunk_id;
- int last_del = 1 + (old_size - 1) / dev->data_bytes_per_chunk;
- int start_del = 1 + (new_size + dev->data_bytes_per_chunk - 1) /
- dev->data_bytes_per_chunk;
+ u32 dummy;
+ int last_del;
+ int start_del;
+
+ if (old_size > 0)
+ yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
+ else
+ last_del = 0;
+ yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
+ &start_del, &dummy);
+ last_del++;
+ start_del++;
/* Delete backwards so that we don't end up with holes if
* power is lost part-way through the operation.
return ret_val;
}
-int yaffs_del_file(struct yaffs_obj *in)
+static int yaffs_del_file(struct yaffs_obj *in)
{
int ret_val = YAFFS_OK;
int deleted; /* Need to cache value on stack if in is freed */
*/
yaffs_get_obj_name(l, buffer,
YAFFS_MAX_NAME_LENGTH + 1);
- if (strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
+ if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
return l;
}
}
/*--------------------------- Initialisation code -------------------------- */
-static int yaffs_check_dev_fns(const struct yaffs_dev *dev)
+static int yaffs_check_dev_fns(struct yaffs_dev *dev)
{
+ struct yaffs_driver *drv = &dev->drv;
+ struct yaffs_tags_handler *tagger = &dev->tagger;
+
/* Common functions, gotta have */
- if (!dev->param.erase_fn || !dev->param.initialise_flash_fn)
+ if (!drv->drv_read_chunk_fn ||
+ !drv->drv_write_chunk_fn ||
+ !drv->drv_erase_fn)
return 0;
- /* Can use the "with tags" style interface for yaffs1 or yaffs2 */
- if (dev->param.write_chunk_tags_fn &&
- dev->param.read_chunk_tags_fn &&
- !dev->param.write_chunk_fn &&
- !dev->param.read_chunk_fn &&
- dev->param.bad_block_fn && dev->param.query_block_fn)
- return 1;
+ if (dev->param.is_yaffs2 &&
+ (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
+ return 0;
- /* Can use the "spare" style interface for yaffs1 */
- if (!dev->param.is_yaffs2 &&
- !dev->param.write_chunk_tags_fn &&
- !dev->param.read_chunk_tags_fn &&
- dev->param.write_chunk_fn &&
- dev->param.read_chunk_fn &&
- !dev->param.bad_block_fn && !dev->param.query_block_fn)
- return 1;
+ /* Install the default tags marshalling functions if needed. */
+ yaffs_tags_compat_install(dev);
+ yaffs_tags_marshall_install(dev);
- return 0; /* bad */
+ /* Check we now have the marshalling functions required. */
+ if (!tagger->write_chunk_tags_fn ||
+ !tagger->read_chunk_tags_fn ||
+ !tagger->query_block_fn ||
+ !tagger->mark_bad_fn)
+ return 0;
+
+ return 1;
}
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()");
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 =
return YAFFS_FAIL;
}
- /* Finished with most checks. Further checks happen later on too. */
+ 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 (yaffs_init_nand(dev) != YAFFS_OK) {
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
+ return YAFFS_FAIL;
+ }
dev->is_mounted = 1;
if (!init_failed && !yaffs_create_initial_dir(dev))
init_failed = 1;
- if(!init_failed && dev->param.is_yaffs2 &&
+ if (!init_failed && dev->param.is_yaffs2 &&
!dev->param.disable_summary &&
!yaffs_summary_init(dev))
init_failed = 1;
dev->is_mounted = 0;
- if (dev->param.deinitialise_flash_fn)
- dev->param.deinitialise_flash_fn(dev);
+ yaffs_deinit_nand(dev);
}
}
return n_free;
}
-/*\
- * Marshalling functions to get loff_t file sizes into aand out of
+
+int yaffs_format_dev(struct yaffs_dev *dev)
+{
+ int i;
+ enum yaffs_block_state state;
+ u32 dummy;
+
+ if(dev->is_mounted)
+ return YAFFS_FAIL;
+
+ /*
+ * The runtime variables might not have been set up,
+ * so set up what we need.
+ */
+ dev->internal_start_block = dev->param.start_block;
+ dev->internal_end_block = dev->param.end_block;
+ dev->block_offset = 0;
+ dev->chunk_offset = 0;
+
+ if (dev->param.start_block == 0) {
+ dev->internal_start_block = dev->param.start_block + 1;
+ dev->internal_end_block = dev->param.end_block + 1;
+ dev->block_offset = 1;
+ dev->chunk_offset = dev->param.chunks_per_block;
+ }
+
+ 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;
+}
+
+
+/*
+ * 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)
{
loff_t retval;
- if(~(oh->file_size_high))
+ 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
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]++;
+ }
+}