summaryrefslogtreecommitdiffstats
path: root/target/linux/generic/files/fs/yaffs2/yaffs_guts.c
diff options
context:
space:
mode:
authorGabor Juhos <juhosg@openwrt.org>2015-03-31 15:31:57 +0000
committerGabor Juhos <juhosg@openwrt.org>2015-03-31 15:31:57 +0000
commit82f0308be91d572df10dadfe59f196e14760dc3d (patch)
tree06f81e98d755d3b1d9a199b9b78a277ce3577b03 /target/linux/generic/files/fs/yaffs2/yaffs_guts.c
parent640318e62090821c1778dc9e3dfc5608bdcd7f0b (diff)
downloadmaster-31e0f0ae-82f0308be91d572df10dadfe59f196e14760dc3d.tar.gz
master-31e0f0ae-82f0308be91d572df10dadfe59f196e14760dc3d.tar.bz2
master-31e0f0ae-82f0308be91d572df10dadfe59f196e14760dc3d.zip
kernel: update yaffs code to the latest version
Use the latest version of the yaffs code. Fetched from the yaffs2 git tree and it is based on the following commit: commit 7e5cf0fa1b694f835cdc184a8395b229fa29f9ae Author: Charles Manning <cdhmanning@gmail.com> Date: Thu Aug 7 11:25:05 2014 +1200 yaffs-direct: Basic tests. Add lpthread flag for background gc support Signed-off-by: Charles Manning <cdhmanning@gmail.com> Signed-off-by: Gabor Juhos <juhosg@openwrt.org> SVN-Revision: 45188
Diffstat (limited to 'target/linux/generic/files/fs/yaffs2/yaffs_guts.c')
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_guts.c342
1 files changed, 198 insertions, 144 deletions
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.c b/target/linux/generic/files/fs/yaffs2/yaffs_guts.c
index 1fd464d68a..1c0ae71320 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_guts.c
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_guts.c
@@ -631,6 +631,78 @@ static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
/*---------------- Name handling functions ------------*/
+static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
+ const YCHAR *oh_name, int buff_size)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ if (dev->param.auto_unicode) {
+ if (*oh_name) {
+ /* It is an ASCII name, do an ASCII to
+ * unicode conversion */
+ const char *ascii_oh_name = (const char *)oh_name;
+ int n = buff_size - 1;
+ while (n > 0 && *ascii_oh_name) {
+ *name = *ascii_oh_name;
+ name++;
+ ascii_oh_name++;
+ n--;
+ }
+ } else {
+ strncpy(name, oh_name + 1, buff_size - 1);
+ }
+ } else {
+#else
+ (void) dev;
+ {
+#endif
+ strncpy(name, oh_name, buff_size - 1);
+ }
+}
+
+static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
+ const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+
+ int is_ascii;
+ const YCHAR *w;
+
+ if (dev->param.auto_unicode) {
+
+ is_ascii = 1;
+ w = name;
+
+ /* Figure out if the name will fit in ascii character set */
+ while (is_ascii && *w) {
+ if ((*w) & 0xff00)
+ is_ascii = 0;
+ w++;
+ }
+
+ if (is_ascii) {
+ /* It is an ASCII name, so convert unicode to ascii */
+ char *ascii_oh_name = (char *)oh_name;
+ int n = YAFFS_MAX_NAME_LENGTH - 1;
+ while (n > 0 && *name) {
+ *ascii_oh_name = *name;
+ name++;
+ ascii_oh_name++;
+ n--;
+ }
+ } else {
+ /* Unicode name, so save starting at the second YCHAR */
+ *oh_name = 0;
+ strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
+ }
+ } else {
+#else
+ dev = dev;
+ {
+#endif
+ strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
+ }
+}
+
static u16 yaffs_calc_name_sum(const YCHAR *name)
{
u16 sum = 0;
@@ -1377,56 +1449,49 @@ static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
return 0;
}
-static void yaffs_flush_file_cache(struct yaffs_obj *obj)
+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 lowest = -99; /* Stop compiler whining. */
int i;
struct yaffs_cache *cache;
- int chunk_written = 0;
int n_caches = obj->my_dev->param.n_caches;
if (n_caches < 1)
return;
- do {
- cache = NULL;
-
- /* Find the lowest dirty chunk for this object */
- for (i = 0; i < n_caches; i++) {
- if (dev->cache[i].object == obj &&
- dev->cache[i].dirty) {
- if (!cache ||
- dev->cache[i].chunk_id < lowest) {
- cache = &dev->cache[i];
- lowest = cache->chunk_id;
- }
- }
- }
- if (cache && !cache->locked) {
- /* Write it out and free it up */
- chunk_written =
- yaffs_wr_data_obj(cache->object,
- cache->chunk_id,
- cache->data,
- cache->n_bytes, 1);
- cache->dirty = 0;
- cache->object = NULL;
- }
- } while (cache && chunk_written > 0);
- if (cache)
- /* Hoosterman, disk full while writing cache out. */
- yaffs_trace(YAFFS_TRACE_ERROR,
- "yaffs tragedy: no space during cache write");
+ /* 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);
+ }
+
}
-/*yaffs_flush_whole_cache(dev)
- *
- *
- */
-void yaffs_flush_whole_cache(struct yaffs_dev *dev)
+void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard)
{
struct yaffs_obj *obj;
int n_caches = dev->param.n_caches;
@@ -1442,12 +1507,12 @@ void yaffs_flush_whole_cache(struct yaffs_dev *dev)
obj = dev->cache[i].object;
}
if (obj)
- yaffs_flush_file_cache(obj);
+ yaffs_flush_file_cache(obj, discard);
} while (obj);
}
-/* Grab us a cache chunk for use.
+/* 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.
@@ -1462,56 +1527,50 @@ static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
return &dev->cache[i];
}
}
+
return NULL;
}
static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
{
struct yaffs_cache *cache;
- struct yaffs_obj *the_obj;
int usage;
int i;
- int pushout;
if (dev->param.n_caches < 1)
return NULL;
- /* Try find a non-dirty one... */
+ /* First look for an unused cache */
cache = yaffs_grab_chunk_worker(dev);
- if (!cache) {
- /* They were all dirty, find the LRU object and flush
- * its cache, then find again.
- * NB what's here is not very accurate,
- * we actually flush the object with the LRU chunk.
- */
+ if (cache)
+ return cache;
- /* With locking we can't assume we can use entry zero,
- * Set the_obj to a valid pointer for Coverity. */
- the_obj = dev->cache[0].object;
- usage = -1;
- cache = NULL;
- pushout = -1;
+ /*
+ * Thery were all in use.
+ * Find the LRU cache and flush it if it is dirty.
+ */
- 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 = -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;
- the_obj = dev->cache[i].object;
cache = &dev->cache[i];
- pushout = i;
- }
- }
-
- if (!cache || cache->dirty) {
- /* Flush and try again */
- yaffs_flush_file_cache(the_obj);
- cache = yaffs_grab_chunk_worker(dev);
}
}
+
+#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;
}
@@ -3189,78 +3248,6 @@ static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
yaffs_release_temp_buffer(dev, buf);
}
-static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
- const YCHAR *oh_name, int buff_size)
-{
-#ifdef CONFIG_YAFFS_AUTO_UNICODE
- if (dev->param.auto_unicode) {
- if (*oh_name) {
- /* It is an ASCII name, do an ASCII to
- * unicode conversion */
- const char *ascii_oh_name = (const char *)oh_name;
- int n = buff_size - 1;
- while (n > 0 && *ascii_oh_name) {
- *name = *ascii_oh_name;
- name++;
- ascii_oh_name++;
- n--;
- }
- } else {
- strncpy(name, oh_name + 1, buff_size - 1);
- }
- } else {
-#else
- (void) dev;
- {
-#endif
- strncpy(name, oh_name, buff_size - 1);
- }
-}
-
-static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
- const YCHAR *name)
-{
-#ifdef CONFIG_YAFFS_AUTO_UNICODE
-
- int is_ascii;
- YCHAR *w;
-
- if (dev->param.auto_unicode) {
-
- is_ascii = 1;
- w = name;
-
- /* Figure out if the name will fit in ascii character set */
- while (is_ascii && *w) {
- if ((*w) & 0xff00)
- is_ascii = 0;
- w++;
- }
-
- if (is_ascii) {
- /* It is an ASCII name, so convert unicode to ascii */
- char *ascii_oh_name = (char *)oh_name;
- int n = YAFFS_MAX_NAME_LENGTH - 1;
- while (n > 0 && *name) {
- *ascii_oh_name = *name;
- name++;
- ascii_oh_name++;
- n--;
- }
- } else {
- /* Unicode name, so save starting at the second YCHAR */
- *oh_name = 0;
- strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
- }
- } else {
-#else
- dev = dev;
- {
-#endif
- strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
- }
-}
-
/* UpdateObjectHeader updates the header on NAND for an object.
* If name is not NULL, then that new name is used.
*/
@@ -3765,7 +3752,7 @@ int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
struct yaffs_dev *dev = in->my_dev;
loff_t old_size = in->variant.file_variant.file_size;
- yaffs_flush_file_cache(in);
+ yaffs_flush_file_cache(in, 1);
yaffs_invalidate_whole_cache(in);
yaffs_check_gc(dev, 0);
@@ -3798,12 +3785,15 @@ int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
return YAFFS_OK;
}
-int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync)
+int yaffs_flush_file(struct yaffs_obj *in,
+ int update_time,
+ int data_sync,
+ int discard_cache)
{
if (!in->dirty)
return YAFFS_OK;
- yaffs_flush_file_cache(in);
+ yaffs_flush_file_cache(in, discard_cache);
if (data_sync)
return YAFFS_OK;
@@ -3950,6 +3940,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;
@@ -4678,7 +4732,7 @@ int yaffs_guts_ll_init(struct yaffs_dev *dev)
}
-int yaffs_format_dev(struct yaffs_dev *dev)
+int yaffs_guts_format_dev(struct yaffs_dev *dev)
{
int i;
enum yaffs_block_state state;