/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
- * Copyright (C) 2002-2011 Aleph One Ltd.
- * for Toby Churchill Ltd and Brightstar Engineering
+ * Copyright (C) 2002-2018 Aleph One Ltd.
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
#include "yaffs_trace.h"
#include "yaffs_guts.h"
+
+#include "yaffs_cache.h"
+#include "yaffs_endian.h"
#include "yaffs_getblockinfo.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsmarshall.h"
/* Forward declarations */
-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);
result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
- if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
+ if (result == YAFFS_FAIL ||
+ tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
retval = YAFFS_FAIL;
if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
int result;
result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
- if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
+ if (result == YAFFS_FAIL ||
+ memcmp(buffer, data, dev->data_bytes_per_chunk) ||
temp_tags.obj_id != tags->obj_id ||
temp_tags.chunk_id != tags->chunk_id ||
temp_tags.n_bytes != tags->n_bytes)
static int yaffs_find_alloc_block(struct yaffs_dev *dev)
{
- int i;
+ u32 i;
struct yaffs_block_info *bi;
if (dev->n_erased_blocks < 1) {
for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
dev->alloc_block_finder++;
- if (dev->alloc_block_finder < dev->internal_start_block
- || dev->alloc_block_finder > dev->internal_end_block) {
+ if (dev->alloc_block_finder < (int)dev->internal_start_block
+ || dev->alloc_block_finder > (int)dev->internal_end_block) {
dev->alloc_block_finder = dev->internal_start_block;
}
return -1;
}
- if (dev->n_erased_blocks < dev->param.n_reserved_blocks
+ if (dev->n_erased_blocks < (int)dev->param.n_reserved_blocks
&& dev->alloc_page == 0)
yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
const u8 *data,
struct yaffs_ext_tags *tags, int use_reserver)
{
- int attempts = 0;
+ u32 attempts = 0;
int write_ok = 0;
int chunk;
yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
} while (write_ok != YAFFS_OK &&
- (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
+ (yaffs_wr_attempts == 0 || attempts <= yaffs_wr_attempts));
if (!write_ok)
chunk = -1;
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;
static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
int chunk_obj)
{
- return (tags->chunk_id == chunk_obj &&
- tags->obj_id == obj_id &&
+ return (tags->chunk_id == (u32)chunk_obj &&
+ tags->obj_id == (u32)obj_id &&
!tags->is_deleted) ? 1 : 0;
}
return YAFFS_FAIL;
}
-/*------------------------ Short Operations Cache ------------------------------
- * In many situations where there is no high level buffering a lot of
- * reads might be short sequential reads, and a lot of writes may be short
- * sequential writes. eg. scanning/writing a jpeg file.
- * In these cases, a short read/write cache can provide a huge perfomance
- * benefit with dumb-as-a-rock code.
- * In Linux, the page cache provides read buffering and the short op cache
- * provides write buffering.
- *
- * There are a small number (~10) of cache chunks per device so that we don't
- * need a very intelligent search.
- */
-
-static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
-{
- struct yaffs_dev *dev = obj->my_dev;
- int i;
- struct yaffs_cache *cache;
- int n_caches = obj->my_dev->param.n_caches;
-
- for (i = 0; i < n_caches; i++) {
- cache = &dev->cache[i];
- if (cache->object == obj && cache->dirty)
- return 1;
- }
-
- return 0;
-}
-
-static void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard)
-{
-
- if (!cache || cache->locked)
- return;
-
- /* Write it out and free it up if need be.*/
- if (cache->dirty) {
- yaffs_wr_data_obj(cache->object,
- cache->chunk_id,
- cache->data,
- cache->n_bytes,
- 1);
-
- cache->dirty = 0;
- }
-
- if (discard)
- cache->object = NULL;
-}
-
-static void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard)
-{
- struct yaffs_dev *dev = obj->my_dev;
- int i;
- struct yaffs_cache *cache;
- int n_caches = obj->my_dev->param.n_caches;
-
- if (n_caches < 1)
- return;
-
-
- /* Find the chunks for this object and flush them. */
- for (i = 0; i < n_caches; i++) {
- cache = &dev->cache[i];
- if (cache->object == obj)
- yaffs_flush_single_cache(cache, discard);
- }
-
-}
-
-
-void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard)
-{
- struct yaffs_obj *obj;
- int n_caches = dev->param.n_caches;
- int i;
-
- /* Find a dirty object in the cache and flush it...
- * until there are no further dirty objects.
- */
- do {
- obj = NULL;
- for (i = 0; i < n_caches && !obj; i++) {
- if (dev->cache[i].object && dev->cache[i].dirty)
- obj = dev->cache[i].object;
- }
- if (obj)
- yaffs_flush_file_cache(obj, discard);
- } while (obj);
-
-}
-
-/* Grab us an unused cache chunk for use.
- * First look for an empty one.
- * Then look for the least recently used non-dirty one.
- * Then look for the least recently used dirty one...., flush and look again.
- */
-static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
-{
- int i;
-
- if (dev->param.n_caches > 0) {
- for (i = 0; i < dev->param.n_caches; i++) {
- if (!dev->cache[i].object)
- return &dev->cache[i];
- }
- }
-
- return NULL;
-}
-
-static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
-{
- struct yaffs_cache *cache;
- int usage;
- int i;
-
- if (dev->param.n_caches < 1)
- return NULL;
-
- /* First look for an unused cache */
-
- cache = yaffs_grab_chunk_worker(dev);
-
- if (cache)
- return cache;
-
- /*
- * Thery were all in use.
- * Find the LRU cache and flush it if it is dirty.
- */
-
- usage = -1;
- cache = NULL;
-
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].object &&
- !dev->cache[i].locked &&
- (dev->cache[i].last_use < usage || !cache)) {
- usage = dev->cache[i].last_use;
- cache = &dev->cache[i];
- }
- }
-
-#if 1
- yaffs_flush_single_cache(cache, 1);
-#else
- yaffs_flush_file_cache(cache->object, 1);
- cache = yaffs_grab_chunk_worker(dev);
-#endif
-
- return cache;
-}
-
-/* Find a cached chunk */
-static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
- int chunk_id)
-{
- struct yaffs_dev *dev = obj->my_dev;
- int i;
-
- if (dev->param.n_caches < 1)
- return NULL;
-
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].object == obj &&
- dev->cache[i].chunk_id == chunk_id) {
- dev->cache_hits++;
-
- return &dev->cache[i];
- }
- }
- return NULL;
-}
-
-/* Mark the chunk for the least recently used algorithym */
-static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
- int is_write)
-{
- int i;
-
- if (dev->param.n_caches < 1)
- return;
-
- if (dev->cache_last_use < 0 ||
- dev->cache_last_use > 100000000) {
- /* Reset the cache usages */
- for (i = 1; i < dev->param.n_caches; i++)
- dev->cache[i].last_use = 0;
-
- dev->cache_last_use = 0;
- }
- dev->cache_last_use++;
- cache->last_use = dev->cache_last_use;
-
- if (is_write)
- cache->dirty = 1;
-}
-
-/* Invalidate a single cache page.
- * Do this when a whole page gets written,
- * ie the short cache for this page is no longer valid.
- */
-static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
-{
- struct yaffs_cache *cache;
-
- if (object->my_dev->param.n_caches > 0) {
- cache = yaffs_find_chunk_cache(object, chunk_id);
-
- if (cache)
- cache->object = NULL;
- }
-}
-
-/* Invalidate all the cache pages associated with this object
- * Do this whenever ther file is deleted or resized.
- */
-static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
-{
- int i;
- struct yaffs_dev *dev = in->my_dev;
-
- if (dev->param.n_caches > 0) {
- /* Invalidate it. */
- for (i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].object == in)
- dev->cache[i].object = NULL;
- }
- }
-}
static void yaffs_unhash_obj(struct yaffs_obj *obj)
{
static int yaffs_generic_obj_del(struct yaffs_obj *in)
{
/* Iinvalidate the file's data in the cache, without flushing. */
- yaffs_invalidate_whole_cache(in);
+ yaffs_invalidate_file_cache(in);
if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
/* Move to unlinked directory so we have a deletion record */
{
struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
int erased_ok = 0;
- int i;
+ u32 i;
/* If the block is still healthy erase it and mark as clean.
* If the block has had a data failure, then retire it.
bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
/* If this is the block being garbage collected then stop gc'ing */
- if (block_no == dev->gc_block)
+ if (block_no == (int)dev->gc_block)
dev->gc_block = 0;
/* If this block is currently the best candidate for gc
* then drop as a candidate */
- if (block_no == dev->gc_dirtiest) {
+ if (block_no == (int)dev->gc_dirtiest) {
dev->gc_dirtiest = 0;
dev->gc_pages_in_use = 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.stored_size);
+ yaffs_oh_size_load(dev, oh,
+ object->variant.file_variant.stored_size, 1);
tags.extra_file_size =
object->variant.file_variant.stored_size;
}
{
int old_chunk;
int ret_val = YAFFS_OK;
- int i;
+ u32 i;
int is_checkpt_block;
int max_copies;
int chunks_before = yaffs_get_erased_chunks(dev);
static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
int aggressive, int background)
{
- int i;
- int iterations;
- unsigned selected = 0;
+ u32 i;
+ u32 iterations;
+ u32 selected = 0;
int prioritised = 0;
int prioritised_exist = 0;
struct yaffs_block_info *bi;
- int threshold;
+ u32 threshold = dev->param.chunks_per_block;
+
+ (void) prioritised;
/* First let's see if we need to grab a prioritised block */
if (dev->has_pending_prioritised_gc && !aggressive) {
*/
if (!selected) {
- int pages_used;
+ u32 pages_used;
int n_blocks =
dev->internal_end_block - dev->internal_start_block + 1;
if (aggressive) {
threshold = dev->param.chunks_per_block;
iterations = n_blocks;
} else {
- int max_threshold;
+ u32 max_threshold;
if (background)
max_threshold = dev->param.chunks_per_block / 2;
gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
}
- if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
+ if (dev->n_erased_blocks < (int)dev->param.n_reserved_blocks &&
dev->gc_block > 0) {
yaffs_trace(YAFFS_TRACE_GC,
"yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
dev->n_erased_blocks, max_tries,
dev->gc_block);
}
- } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
+ } while ((dev->n_erased_blocks < (int)dev->param.n_reserved_blocks) &&
(dev->gc_block > 0) && (max_tries < 2));
return aggressive ? gc_ok : YAFFS_OK;
{
int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
+ (void) urgency;
yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
yaffs_check_gc(dev, 1);
struct yaffs_ext_tags tags;
struct yaffs_block_info *bi;
+ (void) lyn;
if (chunk_id <= 0)
return;
}
}
-static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
- const u8 *buffer, int n_bytes, int use_reserve)
+int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
+ const u8 *buffer, int n_bytes, int use_reserve)
{
/* Find old chunk Need to do this to get serial number
* Write new one and patch into tree.
(prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
new_tags.n_bytes = n_bytes;
- if (n_bytes < 1 || n_bytes > dev->data_bytes_per_chunk) {
+ if (n_bytes < 1 || n_bytes > (int)dev->data_bytes_per_chunk) {
yaffs_trace(YAFFS_TRACE_ERROR,
"Writing %d bytes to chunk!!!!!!!!!",
n_bytes);
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;
struct yaffs_dev *dev;
struct yaffs_ext_tags tags;
int result;
- int alloc_failed = 0;
if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
return;
dev = in->my_dev;
- in->lazy_loaded = 0;
buf = yaffs_get_temp_buffer(dev);
result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
+
+ if (result == YAFFS_FAIL) {
+ yaffs_release_temp_buffer(dev, buf);
+ return;
+ }
+
oh = (struct yaffs_obj_hdr *)buf;
+ yaffs_do_endian_oh(dev, oh);
+
+ in->lazy_loaded = 0;
in->yst_mode = oh->yst_mode;
yaffs_load_attribs(in, oh);
yaffs_set_obj_name_from_oh(in, oh);
- if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
+ if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
in->variant.symlink_variant.alias =
yaffs_clone_str(oh->alias);
- if (!in->variant.symlink_variant.alias)
- alloc_failed = 1; /* Not returned */
- }
yaffs_release_temp_buffer(dev, buf);
}
/* 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));
+ if (result == YAFFS_OK) {
+ yaffs_verify_oh(in, oh, &old_tags, 0);
+ memcpy(old_name, oh->name, sizeof(oh->name));
+
+ /*
+ * 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);
}
if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
file_size = in->variant.file_variant.stored_size;
- yaffs_oh_size_load(oh, file_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 */
bi->has_shrink_hdr = 1;
}
-
return new_chunk_id;
}
* a whole chunk or we're using inband tags then use the cache
* (if there is caching) else bypass the cache.
*/
- if (cache || n_copy != dev->data_bytes_per_chunk ||
+ if (cache || n_copy != (int)dev->data_bytes_per_chunk ||
dev->param.inband_tags) {
if (dev->param.n_caches > 0) {
start >= dev->data_bytes_per_chunk) {
yaffs_trace(YAFFS_TRACE_ERROR,
"AddrToChunk of offset %lld gives chunk %d start %d",
- offset, chunk, start);
+ (long long)offset, chunk, start);
}
chunk++; /* File pos to chunk in file offset */
(start + n)) ? n_bytes_read : (start + n);
if (n_writeback < 0 ||
- n_writeback > dev->data_bytes_per_chunk)
+ n_writeback > (int)dev->data_bytes_per_chunk)
BUG();
} else {
n_writeback = dev->data_bytes_per_chunk;
}
- if (n_copy != dev->data_bytes_per_chunk ||
+ if (n_copy != (int)dev->data_bytes_per_chunk ||
!dev->param.cache_bypass_aligned ||
dev->param.inband_tags) {
/* An incomplete start or end chunk (or maybe both
if (chunk_id < 1)
continue;
- if (chunk_id <
+ if ((u32)chunk_id <
(dev->internal_start_block * dev->param.chunks_per_block) ||
- chunk_id >=
+ (u32)chunk_id >=
((dev->internal_end_block + 1) *
dev->param.chunks_per_block)) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
loff_t old_size = in->variant.file_variant.file_size;
yaffs_flush_file_cache(in, 1);
- yaffs_invalidate_whole_cache(in);
+ yaffs_invalidate_file_cache(in);
yaffs_check_gc(dev, 0);
if (obj->hdr_chunk > 0) {
result = yaffs_rd_chunk_tags_nand(obj->my_dev,
- obj->hdr_chunk,
- buffer, NULL);
+ obj->hdr_chunk, buffer, NULL);
+ if (result == YAFFS_OK)
+ yaffs_load_name_from_oh(obj->my_dev, name,
+ oh->name, buffer_size);
}
- yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
- buffer_size);
-
yaffs_release_temp_buffer(obj->my_dev, buffer);
}
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;
return YAFFS_FAIL;
}
+ if (!yaffs_init_tmp_buffers(dev))
+ return YAFFS_FAIL;
+
if (yaffs_init_nand(dev) != YAFFS_OK) {
yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
return YAFFS_FAIL;
}
+ dev->ll_init = 1;
+
return YAFFS_OK;
}
int yaffs_guts_format_dev(struct yaffs_dev *dev)
{
- int i;
+ u32 i;
enum yaffs_block_state state;
u32 dummy;
return YAFFS_OK;
}
+/*
+ * If the dev is mounted r/w then the cleanup will happen during
+ * yaffs_guts_initialise. However if the dev is mounted ro then
+ * the cleanup will be dfered until yaffs is remounted r/w.
+ */
+void yaffs_guts_cleanup(struct yaffs_dev *dev)
+{
+ yaffs_strip_deleted_objs(dev);
+ yaffs_fix_hanging_objs(dev);
+ if (dev->param.empty_lost_n_found)
+ yaffs_empty_l_n_f(dev);
+}
int yaffs_guts_initialise(struct yaffs_dev *dev)
{
int init_failed = 0;
- unsigned x;
- int bits;
+ u32 x;
+ u32 bits;
if(yaffs_guts_ll_init(dev) != 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;
- /* Initialise temporary buffers and caches. */
- if (!yaffs_init_tmp_buffers(dev))
- init_failed = 1;
+ yaffs_endian_config(dev);
- dev->cache = NULL;
+ /* Initialise temporary caches. */
dev->gc_cleanup_list = NULL;
- if (!init_failed && dev->param.n_caches > 0) {
- int i;
- void *buf;
- int cache_bytes =
- dev->param.n_caches * sizeof(struct yaffs_cache);
-
- if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
- dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
-
- dev->cache = kmalloc(cache_bytes, GFP_NOFS);
-
- buf = (u8 *) dev->cache;
-
- if (dev->cache)
- memset(dev->cache, 0, cache_bytes);
-
- for (i = 0; i < dev->param.n_caches && buf; i++) {
- dev->cache[i].object = NULL;
- dev->cache[i].last_use = 0;
- dev->cache[i].dirty = 0;
- dev->cache[i].data = buf =
- kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
- }
- if (!buf)
- init_failed = 1;
-
- dev->cache_last_use = 0;
- }
+ if (!init_failed)
+ init_failed = yaffs_cache_init(dev) < 0;
dev->cache_hits = 0;
init_failed = 1;
}
- yaffs_strip_deleted_objs(dev);
- yaffs_fix_hanging_objs(dev);
- if (dev->param.empty_lost_n_found)
- yaffs_empty_l_n_f(dev);
+ yaffs_guts_cleanup(dev);
}
if (init_failed) {
void yaffs_deinitialise(struct yaffs_dev *dev)
{
if (dev->is_mounted) {
- int i;
+ u32 i;
yaffs_deinit_blocks(dev);
yaffs_deinit_tnodes_and_objs(dev);
yaffs_summary_deinit(dev);
-
- if (dev->param.n_caches > 0 && dev->cache) {
-
- for (i = 0; i < dev->param.n_caches; i++) {
- kfree(dev->cache[i].data);
- dev->cache[i].data = NULL;
- }
-
- kfree(dev->cache);
- dev->cache = NULL;
- }
+ yaffs_cache_deinit(dev);
kfree(dev->gc_cleanup_list);
int yaffs_count_free_chunks(struct yaffs_dev *dev)
{
int n_free = 0;
- int b;
+ u32 b;
struct yaffs_block_info *blk;
blk = dev->block_info;
int n_free;
int n_dirty_caches;
int blocks_for_checkpt;
- int i;
n_free = dev->n_free_chunks;
n_free += dev->n_deleted_files;
/* Now count and subtract the number of dirty chunks in the cache. */
-
- for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
- if (dev->cache[i].dirty)
- n_dirty_caches++;
- }
-
+ n_dirty_caches = yaffs_count_dirty_caches(dev);
n_free -= n_dirty_caches;
n_free -=
}
-
/*
* 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);
+ oh->file_size_low = FSIZE_LOW(fsize);
+
+ oh->file_size_high = FSIZE_HIGH(fsize);
+
+ 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 = FSIZE_COMBINE(high, low);
+ } else {
+ u32 low = oh->file_size_low;
+
+ if (do_endian)
+ yaffs_do_endian_u32(dev, &low);
+ retval = (loff_t)low;
+ }
return retval;
}
void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
{
- int i;
+ u32 i;
struct yaffs_block_info *bi;
int s;