summaryrefslogtreecommitdiff
path: root/target/linux/generic/files/fs/yaffs2
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/files/fs/yaffs2')
-rw-r--r--target/linux/generic/files/fs/yaffs2/NOTE.openwrt2
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_attribs.c16
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_guts.c342
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_guts.h35
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c4
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h14
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_summary.c1
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_vfs.c218
-rw-r--r--target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c8
9 files changed, 438 insertions, 202 deletions
diff --git a/target/linux/generic/files/fs/yaffs2/NOTE.openwrt b/target/linux/generic/files/fs/yaffs2/NOTE.openwrt
index 0be479d..ad807bd 100644
--- a/target/linux/generic/files/fs/yaffs2/NOTE.openwrt
+++ b/target/linux/generic/files/fs/yaffs2/NOTE.openwrt
@@ -1,4 +1,4 @@
The yaffs2 source has been fetched from the yaffs2 GIT tree.
URL: git://www.aleph1.co.uk/yaffs2
-Version: bc76682d93955cfb33051beb503ad9f8a5450578 (2013-12-03)
+Version: 7e5cf0fa1b694f835cdc184a8395b229fa29f9ae (2014-08-07)
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
index 3d778f2..711941f 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_attribs.c
@@ -14,6 +14,14 @@
#include "yaffs_guts.h"
#include "yaffs_attribs.h"
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+#define IATTR_UID ia_uid
+#define IATTR_GID ia_gid
+#else
+#define IATTR_UID ia_uid.val
+#define IATTR_GID ia_gid.val
+#endif
+
void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
{
obj->yst_uid = oh->yst_uid;
@@ -77,9 +85,9 @@ int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
if (valid & ATTR_MODE)
obj->yst_mode = attr->ia_mode;
if (valid & ATTR_UID)
- obj->yst_uid = attr->ia_uid;
+ obj->yst_uid = attr->IATTR_UID;
if (valid & ATTR_GID)
- obj->yst_gid = attr->ia_gid;
+ obj->yst_gid = attr->IATTR_GID;
if (valid & ATTR_ATIME)
obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
@@ -103,9 +111,9 @@ int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
attr->ia_mode = obj->yst_mode;
valid |= ATTR_MODE;
- attr->ia_uid = obj->yst_uid;
+ attr->IATTR_UID = obj->yst_uid;
valid |= ATTR_UID;
- attr->ia_gid = obj->yst_gid;
+ attr->IATTR_GID = obj->yst_gid;
valid |= ATTR_GID;
Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.c b/target/linux/generic/files/fs/yaffs2/yaffs_guts.c
index 1fd464d..1c0ae71 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;
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.h b/target/linux/generic/files/fs/yaffs2/yaffs_guts.h
index 0578536..231f8ac 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_guts.h
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_guts.h
@@ -144,12 +144,12 @@ struct yaffs_cache {
*/
struct yaffs_tags {
- unsigned chunk_id:20;
- unsigned serial_number:2;
- unsigned n_bytes_lsb:10;
- unsigned obj_id:18;
- unsigned ecc:12;
- unsigned n_bytes_msb:2;
+ u32 chunk_id:20;
+ u32 serial_number:2;
+ u32 n_bytes_lsb:10;
+ u32 obj_id:18;
+ u32 ecc:12;
+ u32 n_bytes_msb:2;
};
union yaffs_tags_union {
@@ -287,9 +287,9 @@ enum yaffs_block_state {
struct yaffs_block_info {
- int soft_del_pages:10; /* number of soft deleted pages */
- int pages_in_use:10; /* number of pages in use */
- unsigned block_state:4; /* One of the above block states. */
+ s32 soft_del_pages:10; /* number of soft deleted pages */
+ s32 pages_in_use:10; /* number of pages in use */
+ u32 block_state:4; /* One of the above block states. */
/* NB use unsigned because enum is sometimes
* an int */
u32 needs_retiring:1; /* Data has failed on this block, */
@@ -688,8 +688,8 @@ struct yaffs_dev {
/* Block Info */
struct yaffs_block_info *block_info;
u8 *chunk_bits; /* bitmap of chunks in use */
- unsigned block_info_alt:1; /* allocated using alternative alloc */
- unsigned chunk_bits_alt:1; /* allocated using alternative alloc */
+ u8 block_info_alt:1; /* allocated using alternative alloc */
+ u8 chunk_bits_alt:1; /* allocated using alternative alloc */
int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
* Must be consistent with chunks_per_block.
*/
@@ -776,6 +776,7 @@ struct yaffs_dev {
u32 n_page_writes;
u32 n_page_reads;
u32 n_erasures;
+ u32 n_bad_queries;
u32 n_bad_markings;
u32 n_erase_failures;
u32 n_gc_copies;
@@ -854,6 +855,9 @@ int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
int yaffs_del_obj(struct yaffs_obj *obj);
+struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
+ enum yaffs_obj_type type);
+
int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
@@ -872,10 +876,13 @@ struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
const YCHAR *name, u32 mode, u32 uid,
u32 gid);
-int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);
+int yaffs_flush_file(struct yaffs_obj *in,
+ int update_time,
+ int data_sync,
+ int discard_cache);
/* Flushing and checkpointing */
-void yaffs_flush_whole_cache(struct yaffs_dev *dev);
+void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard);
int yaffs_checkpoint_save(struct yaffs_dev *dev);
int yaffs_checkpoint_restore(struct yaffs_dev *dev);
@@ -978,7 +985,7 @@ u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
-int yaffs_format_dev(struct yaffs_dev *dev);
+int yaffs_guts_format_dev(struct yaffs_dev *dev);
void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
int *chunk_out, u32 *offset_out);
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c
index 7ae63c5..7c01461 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_mtdif.c
@@ -22,12 +22,14 @@
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+#include "uapi/linux/major.h"
+#endif
#include "yaffs_trace.h"
#include "yaffs_guts.h"
#include "yaffs_linux.h"
-
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
#endif
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h
index b80f0a5..3015d58 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_packedtags1.h
@@ -21,13 +21,13 @@
#include "yaffs_guts.h"
struct yaffs_packed_tags1 {
- unsigned chunk_id:20;
- unsigned serial_number:2;
- unsigned n_bytes:10;
- unsigned obj_id:18;
- unsigned ecc:12;
- unsigned deleted:1;
- unsigned unused_stuff:1;
+ u32 chunk_id:20;
+ u32 serial_number:2;
+ u32 n_bytes:10;
+ u32 obj_id:18;
+ u32 ecc:12;
+ u32 deleted:1;
+ u32 unused_stuff:1;
unsigned should_be_ff;
};
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_summary.c b/target/linux/generic/files/fs/yaffs2/yaffs_summary.c
index 6f3c783..3c9e723 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_summary.c
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_summary.c
@@ -235,7 +235,6 @@ int yaffs_summary_read(struct yaffs_dev *dev,
if (result == YAFFS_OK) {
/* Verify header */
if (hdr.version != YAFFS_SUMMARY_VERSION ||
- hdr.block != blk ||
hdr.seq != bi->seq_number ||
hdr.sum != yaffs_summary_sum(dev))
result = YAFFS_FAIL;
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c b/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c
index 67050d4..76bc1db 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_vfs.c
@@ -236,6 +236,15 @@ MODULE_PARM(yaffs_gc_control, "i");
#define Y_CLEAR_INODE(i) end_writeback(i)
#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+#define YAFFS_USE_DIR_ITERATE
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0))
+#define YAFFS_NEW_PROCFS
+#include <linux/seq_file.h>
+#endif
+
#define update_dir_time(dir) do {\
(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
@@ -1023,7 +1032,11 @@ static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
if (!alias)
return -ENOMEM;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
ret = vfs_readlink(dentry, buffer, buflen, alias);
+#else
+ ret = readlink_copy(buffer, buflen, alias);
+#endif
kfree(alias);
return ret;
}
@@ -1206,6 +1219,23 @@ struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
#define YCRED(x) (x->cred)
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#define YPROC_uid(p) (YCRED(p)->fsuid)
+#define YPROC_gid(p) (YCRED(p)->fsgid)
+#define EXTRACT_gid(x) x
+#define EXTRACT_uid(x) x
+#define MAKE_gid(x) x
+#define MAKE_uid(x) x
+#else
+#define YPROC_uid(p) from_kuid(&init_user_ns, YCRED(p)->fsuid)
+#define YPROC_gid(p) from_kgid(&init_user_ns, YCRED(p)->fsgid)
+#define EXTRACT_gid(x) from_kgid(&init_user_ns, x)
+#define EXTRACT_uid(x) from_kuid(&init_user_ns, x)
+#define MAKE_gid(x) make_kgid(&init_user_ns, x)
+#define MAKE_uid(x) make_kuid(&init_user_ns, x)
+#endif
+
+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
dev_t rdev)
@@ -1225,9 +1255,9 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
int error = -ENOSPC;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YPROC_uid(current);
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
mode |= S_ISGID;
@@ -1424,9 +1454,9 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
{
struct yaffs_obj *obj;
struct yaffs_dev *dev;
- uid_t uid = YCRED(current)->fsuid;
+ uid_t uid = YPROC_uid(current);
gid_t gid =
- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+ (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
@@ -1674,6 +1704,77 @@ static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
/*-----------------------------------------------------------------*/
+#ifdef YAFFS_USE_DIR_ITERATE
+static int yaffs_iterate(struct file *f, struct dir_context *dc)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+ struct yaffs_search_context *sc;
+ unsigned long curoffs;
+ struct yaffs_obj *l;
+ int ret_val = 0;
+
+ char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+ obj = yaffs_dentry_to_obj(f->f_dentry);
+ dev = obj->my_dev;
+
+ yaffs_gross_lock(dev);
+
+ yaffs_dev_to_lc(dev)->readdir_process = current;
+
+ sc = yaffs_new_search(obj);
+ if (!sc) {
+ ret_val = -ENOMEM;
+ goto out;
+ }
+
+ if (!dir_emit_dots(f, dc))
+ return 0;
+
+ curoffs = 1;
+
+ while (sc->next_return) {
+ curoffs++;
+ l = sc->next_return;
+ if (curoffs >= dc->pos) {
+ int this_inode = yaffs_get_obj_inode(l);
+ int this_type = yaffs_get_obj_type(l);
+
+ yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
+ yaffs_trace(YAFFS_TRACE_OS,
+ "yaffs_readdir: %s inode %d",
+ name, yaffs_get_obj_inode(l));
+
+ yaffs_gross_unlock(dev);
+
+ if (!dir_emit(dc,
+ name,
+ strlen(name),
+ this_inode,
+ this_type)) {
+ yaffs_gross_lock(dev);
+ goto out;
+ }
+
+ yaffs_gross_lock(dev);
+
+ dc->pos++;
+ f->f_pos++;
+ }
+ yaffs_search_advance(sc);
+ }
+
+out:
+ yaffs_search_end(sc);
+ yaffs_dev_to_lc(dev)->readdir_process = NULL;
+ yaffs_gross_unlock(dev);
+
+ return ret_val;
+}
+
+#else
+
static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
{
struct yaffs_obj *obj;
@@ -1781,9 +1882,15 @@ out:
return ret_val;
}
+#endif
+
static const struct file_operations yaffs_dir_operations = {
.read = generic_read_dir,
+#ifdef YAFFS_USE_DIR_ITERATE
+ .iterate = yaffs_iterate,
+#else
.readdir = yaffs_readdir,
+#endif
.fsync = yaffs_sync_object,
.llseek = generic_file_llseek,
};
@@ -1829,8 +1936,8 @@ static void yaffs_fill_inode_from_obj(struct inode *inode,
inode->i_ino = obj->obj_id;
inode->i_mode = obj->yst_mode;
- inode->i_uid = obj->yst_uid;
- inode->i_gid = obj->yst_gid;
+ inode->i_uid = MAKE_uid(obj->yst_uid);
+ inode->i_gid = MAKE_gid(obj->yst_gid);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
inode->i_blksize = inode->i_sb->s_blocksize;
#endif
@@ -1856,7 +1963,7 @@ static void yaffs_fill_inode_from_obj(struct inode *inode,
yaffs_trace(YAFFS_TRACE_OS,
"yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
- inode->i_mode, inode->i_uid, inode->i_gid,
+ inode->i_mode, obj->yst_uid, obj->yst_gid,
inode->i_size, atomic_read(&inode->i_count));
switch (obj->yst_mode & S_IFMT) {
@@ -2670,7 +2777,7 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
/* Get the device */
mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
- if (!mtd) {
+ if (IS_ERR(mtd)) {
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs: MTD device %u either not valid or unavailable",
MINOR(sb->s_dev));
@@ -2713,15 +2820,11 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version,
context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
if (!dev || !context) {
- if (dev)
- kfree(dev);
- if (context)
- kfree(context);
+ kfree(dev);
+ kfree(context);
dev = NULL;
context = NULL;
- }
- if (!dev) {
/* Deep shit could not allocate device structure */
yaffs_trace(YAFFS_TRACE_ALWAYS,
"yaffs_read_super: Failed trying to allocate struct yaffs_dev."
@@ -3188,7 +3291,7 @@ static struct {
#define MAX_MASK_NAME_LENGTH 40
static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
- unsigned long count, void *data)
+ unsigned long count)
{
unsigned rg = 0, mask_bitfield;
char *end;
@@ -3289,7 +3392,7 @@ static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
*/
static int yaffs_proc_debug_write(struct file *file, const char *buf,
- unsigned long count, void *data)
+ unsigned long count)
{
char str[100];
@@ -3301,7 +3404,7 @@ static int yaffs_proc_debug_write(struct file *file, const char *buf,
struct list_head *item;
memset(str, 0, sizeof(str));
- memcpy(str, buf, min(count, sizeof(str) -1));
+ memcpy(str, buf, min((size_t)count, sizeof(str) -1));
cmd = str[1];
@@ -3364,12 +3467,18 @@ static int yaffs_proc_debug_write(struct file *file, const char *buf,
return count;
}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
static int yaffs_proc_write(struct file *file, const char *buf,
- unsigned long count, void *data)
+ unsigned long count, void *ppos)
+#else
+static ssize_t yaffs_proc_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+#endif
{
if (buf[0] == '.')
- return yaffs_proc_debug_write(file, buf, count, data);
- return yaffs_proc_write_trace_options(file, buf, count, data);
+ return yaffs_proc_debug_write(file, buf, count);
+ return yaffs_proc_write_trace_options(file, buf, count);
}
/* Stuff to handle installation of file systems */
@@ -3384,16 +3493,52 @@ static struct file_system_to_install fs_to_install[] = {
{NULL, 0}
};
-static int __init init_yaffs_fs(void)
+
+#ifdef YAFFS_NEW_PROCFS
+static int yaffs_proc_show(struct seq_file *m, void *v)
{
- int error = 0;
- struct file_system_to_install *fsinst;
+ /* FIXME: Unify in a better way? */
+ char buffer[512];
+ char *start;
+ int len;
- yaffs_trace(YAFFS_TRACE_ALWAYS,
- "yaffs built " __DATE__ " " __TIME__ " Installing.");
+ len = yaffs_proc_read(buffer, &start, 0, sizeof(buffer), NULL, NULL);
+ seq_puts(m, buffer);
+ return 0;
+}
+
+static int yaffs_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, yaffs_proc_show, NULL);
+}
+
+static struct file_operations procfs_ops = {
+ .owner = THIS_MODULE,
+ .open = yaffs_proc_open,
+ .read = seq_read,
+ .write = yaffs_proc_write,
+};
+
+static int yaffs_procfs_init(void)
+{
+ /* Install the proc_fs entries */
+ my_proc_entry = proc_create("yaffs",
+ S_IRUGO | S_IFREG,
+ YPROC_ROOT,
+ &procfs_ops);
+
+ if (my_proc_entry) {
+ return 0;
+ } else {
+ return -ENOMEM;
+ }
+}
+
+#else
- mutex_init(&yaffs_context_lock);
+static int yaffs_procfs_init(void)
+{
/* Install the proc_fs entries */
my_proc_entry = create_proc_entry("yaffs",
S_IRUGO | S_IFREG, YPROC_ROOT);
@@ -3402,9 +3547,28 @@ static int __init init_yaffs_fs(void)
my_proc_entry->write_proc = yaffs_proc_write;
my_proc_entry->read_proc = yaffs_proc_read;
my_proc_entry->data = NULL;
+ return 0;
} else {
return -ENOMEM;
- }
+ }
+}
+
+#endif
+
+
+static int __init init_yaffs_fs(void)
+{
+ int error = 0;
+ struct file_system_to_install *fsinst;
+
+ yaffs_trace(YAFFS_TRACE_ALWAYS,
+ "yaffs built " __DATE__ " " __TIME__ " Installing.");
+
+ mutex_init(&yaffs_context_lock);
+
+ error = yaffs_procfs_init();
+ if (error)
+ return error;
/* Now add the file system entries */
diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c
index f1dc972..8c31a66 100644
--- a/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c
+++ b/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c
@@ -1193,12 +1193,14 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
}
if (!in->valid && in->variant_type !=
- (oh ? oh->type : tags.extra_obj_type))
+ (oh ? oh->type : tags.extra_obj_type)) {
yaffs_trace(YAFFS_TRACE_ERROR,
- "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan",
+ "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
oh ? oh->type : tags.extra_obj_type,
in->variant_type, tags.obj_id,
chunk);
+ in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
+ }
if (!in->valid &&
(tags.obj_id == YAFFS_OBJECTID_ROOT ||
@@ -1439,7 +1441,7 @@ int yaffs2_scan_backwards(struct yaffs_dev *dev)
bi++;
}
- yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan);
+ yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
cond_resched();