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
This commit is contained in:
Gabor Juhos
2015-03-31 15:31:57 +00:00
parent 640318e620
commit 82f0308be9
32 changed files with 654 additions and 1301 deletions

View File

@@ -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);
/* 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);
}
if (cache)
/* Hoosterman, disk full while writing cache out. */
yaffs_trace(YAFFS_TRACE_ERROR,
"yaffs tragedy: no space during cache write");
}
/*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;