From: Gabor Juhos Date: Tue, 31 Mar 2015 15:31:57 +0000 (+0000) Subject: kernel: update yaffs code to the latest version X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=82f0308be91d572df10dadfe59f196e14760dc3d;p=openwrt%2Fstaging%2Fyousong.git 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 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 Signed-off-by: Gabor Juhos SVN-Revision: 45188 --- diff --git a/target/linux/generic/files/fs/yaffs2/NOTE.openwrt b/target/linux/generic/files/fs/yaffs2/NOTE.openwrt index 0be479d66c..ad807bdc09 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 3d778f2266..711941f137 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 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; diff --git a/target/linux/generic/files/fs/yaffs2/yaffs_guts.h b/target/linux/generic/files/fs/yaffs2/yaffs_guts.h index 05785367cb..231f8ac567 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 7ae63c54a9..7c01461ab9 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 b80f0a5b15..3015d58a07 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 6f3c7839fa..3c9e72321e 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 67050d4e3d..76bc1db59f 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 +#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 f1dc972276..8c31a661ff 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(); diff --git a/target/linux/generic/patches-3.14/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch b/target/linux/generic/patches-3.14/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch deleted file mode 100644 index c1f7367dd8..0000000000 --- a/target/linux/generic/patches-3.14/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch +++ /dev/null @@ -1,155 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -329,6 +329,33 @@ static int yaffs_readpage(struct file *f - return ret; - } - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid()) -+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid()) -+#else -+#define YCRED_FSUID() YCRED(current)->fsuid -+#define YCRED_FSGID() YCRED(current)->fsgid -+ -+static inline uid_t i_uid_read(const struct inode *inode) -+{ -+ return inode->i_uid; -+} -+ -+static inline gid_t i_gid_read(const struct inode *inode) -+{ -+ return inode->i_gid; -+} -+ -+static inline void i_uid_write(struct inode *inode, uid_t uid) -+{ -+ inode->i_uid = uid; -+} -+ -+static inline void i_gid_write(struct inode *inode, gid_t gid) -+{ -+ inode->i_gid = gid; -+} -+#endif - - static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val) - { -@@ -1225,9 +1252,9 @@ static int yaffs_mknod(struct inode *dir - struct yaffs_obj *parent = yaffs_inode_to_obj(dir); - - int error = -ENOSPC; -- uid_t uid = YCRED(current)->fsuid; -+ uid_t uid = YCRED_FSUID(); - gid_t gid = -- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; -+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID(); - - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) - mode |= S_ISGID; -@@ -1424,9 +1451,9 @@ static int yaffs_symlink(struct inode *d - { - struct yaffs_obj *obj; - struct yaffs_dev *dev; -- uid_t uid = YCRED(current)->fsuid; -+ uid_t uid = YCRED_FSUID(); - gid_t gid = -- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; -+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID(); - - yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); - -@@ -1829,8 +1856,8 @@ static void yaffs_fill_inode_from_obj(st - - inode->i_ino = obj->obj_id; - inode->i_mode = obj->yst_mode; -- inode->i_uid = obj->yst_uid; -- inode->i_gid = obj->yst_gid; -+ i_uid_write(inode, obj->yst_uid); -+ i_gid_write(inode, obj->yst_gid); - #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) - inode->i_blksize = inode->i_sb->s_blocksize; - #endif -@@ -1856,7 +1883,7 @@ static void yaffs_fill_inode_from_obj(st - - 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, i_uid_read(inode), i_gid_read(inode), - inode->i_size, atomic_read(&inode->i_count)); - - switch (obj->yst_mode & S_IFMT) { ---- a/fs/yaffs2/yaffs_attribs.c -+++ b/fs/yaffs2/yaffs_attribs.c -@@ -14,6 +14,48 @@ - #include "yaffs_guts.h" - #include "yaffs_attribs.h" - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+static inline uid_t ia_uid_read(const struct iattr *iattr) -+{ -+ return from_kuid(&init_user_ns, iattr->ia_uid); -+} -+ -+static inline gid_t ia_gid_read(const struct iattr *iattr) -+{ -+ return from_kgid(&init_user_ns, iattr->ia_gid); -+} -+ -+static inline void ia_uid_write(struct iattr *iattr, uid_t uid) -+{ -+ iattr->ia_uid = make_kuid(&init_user_ns, uid); -+} -+ -+static inline void ia_gid_write(struct iattr *iattr, gid_t gid) -+{ -+ iattr->ia_gid = make_kgid(&init_user_ns, gid); -+} -+#else -+static inline uid_t ia_uid_read(const struct iattr *iattr) -+{ -+ return iattr->ia_uid; -+} -+ -+static inline gid_t ia_gid_read(const struct iattr *inode) -+{ -+ return iattr->ia_gid; -+} -+ -+static inline void ia_uid_write(struct iattr *iattr, uid_t uid) -+{ -+ iattr->ia_uid = uid; -+} -+ -+static inline void ia_gid_write(struct iattr *iattr, gid_t gid) -+{ -+ iattr->ia_gid = gid; -+} -+#endif -+ - void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) - { - obj->yst_uid = oh->yst_uid; -@@ -77,9 +119,9 @@ int yaffs_set_attribs(struct yaffs_obj * - if (valid & ATTR_MODE) - obj->yst_mode = attr->ia_mode; - if (valid & ATTR_UID) -- obj->yst_uid = attr->ia_uid; -+ obj->yst_uid = ia_uid_read(attr); - if (valid & ATTR_GID) -- obj->yst_gid = attr->ia_gid; -+ obj->yst_gid = ia_gid_read(attr); - - if (valid & ATTR_ATIME) - obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); -@@ -103,9 +145,9 @@ int yaffs_get_attribs(struct yaffs_obj * - - attr->ia_mode = obj->yst_mode; - valid |= ATTR_MODE; -- attr->ia_uid = obj->yst_uid; -+ ia_uid_write(attr, obj->yst_uid); - valid |= ATTR_UID; -- attr->ia_gid = obj->yst_gid; -+ ia_gid_write(attr, obj->yst_gid); - valid |= ATTR_GID; - - Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; diff --git a/target/linux/generic/patches-3.14/501-yaffs-add-missing-flush-arguments.patch b/target/linux/generic/patches-3.14/501-yaffs-add-missing-flush-arguments.patch new file mode 100644 index 0000000000..d5ccc3e81e --- /dev/null +++ b/target/linux/generic/patches-3.14/501-yaffs-add-missing-flush-arguments.patch @@ -0,0 +1,38 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -738,7 +738,7 @@ static int yaffs_file_flush(struct file + + yaffs_gross_lock(dev); + +- yaffs_flush_file(obj, 1, 0); ++ yaffs_flush_file(obj, 1, 0, 1); + + yaffs_gross_unlock(dev); + +@@ -768,7 +768,7 @@ static int yaffs_sync_object(struct file + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + "yaffs_sync_object"); + yaffs_gross_lock(dev); +- yaffs_flush_file(obj, 1, datasync); ++ yaffs_flush_file(obj, 1, datasync, 1); + yaffs_gross_unlock(dev); + return 0; + } +@@ -2187,7 +2187,7 @@ static void yaffs_flush_inodes(struct su + yaffs_trace(YAFFS_TRACE_OS, + "flushing obj %d", + obj->obj_id); +- yaffs_flush_file(obj, 1, 0); ++ yaffs_flush_file(obj, 1, 0, 1); + } + } + } +@@ -2200,7 +2200,7 @@ static void yaffs_flush_super(struct sup + + yaffs_flush_inodes(sb); + yaffs_update_dirty_dirs(dev); +- yaffs_flush_whole_cache(dev); ++ yaffs_flush_whole_cache(dev, 1); + if (do_checkpoint) + yaffs_checkpoint_save(dev); + } diff --git a/target/linux/generic/patches-3.14/502-yaffs-3.10-disable-proc-entry.patch b/target/linux/generic/patches-3.14/502-yaffs-3.10-disable-proc-entry.patch deleted file mode 100644 index 5b73d3898b..0000000000 --- a/target/linux/generic/patches-3.14/502-yaffs-3.10-disable-proc-entry.patch +++ /dev/null @@ -1,44 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -3025,6 +3025,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "y - #endif - - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - static struct proc_dir_entry *my_proc_entry; - - static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) -@@ -3398,6 +3399,7 @@ static int yaffs_proc_write(struct file - return yaffs_proc_debug_write(file, buf, count, data); - return yaffs_proc_write_trace_options(file, buf, count, data); - } -+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */ - - /* Stuff to handle installation of file systems */ - struct file_system_to_install { -@@ -3421,6 +3423,7 @@ static int __init init_yaffs_fs(void) - - mutex_init(&yaffs_context_lock); - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - /* Install the proc_fs entries */ - my_proc_entry = create_proc_entry("yaffs", - S_IRUGO | S_IFREG, YPROC_ROOT); -@@ -3432,6 +3435,7 @@ static int __init init_yaffs_fs(void) - } else { - return -ENOMEM; - } -+#endif - - /* Now add the file system entries */ - -@@ -3468,7 +3472,9 @@ static void __exit exit_yaffs_fs(void) - yaffs_trace(YAFFS_TRACE_ALWAYS, - "yaffs built " __DATE__ " " __TIME__ " removing."); - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - remove_proc_entry("yaffs", YPROC_ROOT); -+#endif - - fsinst = fs_to_install; - diff --git a/target/linux/generic/patches-3.14/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-3.14/502-yaffs-fix-compat-tags-handling.patch new file mode 100644 index 0000000000..a18cf6fd7b --- /dev/null +++ b/target/linux/generic/patches-3.14/502-yaffs-fix-compat-tags-handling.patch @@ -0,0 +1,239 @@ +Subject: yaffs: fix compat tags handling + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -17,7 +17,9 @@ + #include "yaffs_getblockinfo.h" + #include "yaffs_trace.h" + ++#if 0 + static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++#endif + + + /********** Tags ECC calculations *********/ +@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta + return 0; + } + ++#if 0 + /********** Tags **********/ + + static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; + } ++#else ++ ++#include "yaffs_packedtags1.h" ++ ++static int yaffs_tags_compat_write(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ u8 tag_buf[9]; ++ int retval; ++ ++ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ ++ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); ++ compile_time_assertion(sizeof(struct yaffs_tags) == 8); ++ ++ yaffs_pack_tags1(&pt1, tags); ++ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * tags, one with is_deleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++ if (!dev->param.tags_9bytes) { ++ if (tags->is_deleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++ memcpy(tag_buf, &pt1, 8); ++ } else { ++ if (tags->is_deleted) { ++ memset(tag_buf, 0xff, 8); ++ tag_buf[8] = 0; ++ } else { ++ memcpy(tag_buf, &pt1, 8); ++ tag_buf[8] = 0xff; ++ } ++ } ++ ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, ++ (data) ? dev->data_bytes_per_chunk : 0, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8); ++ ++ return retval; ++} ++ ++/* Return with empty extended tags but add ecc_result. ++ */ ++static int return_empty_tags(struct yaffs_ext_tags *tags, ++ enum yaffs_ecc_result ecc_result, ++ int retval) ++{ ++ if (tags) { ++ memset(tags, 0, sizeof(*tags)); ++ tags->ecc_result = ecc_result; ++ } ++ ++ return retval; ++} ++ ++static int yaffs_tags_compat_read(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ enum yaffs_ecc_result ecc_result; ++ int retval; ++ int deleted; ++ u8 tag_buf[9]; ++ ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8, ++ &ecc_result); ++ ++ switch (ecc_result) { ++ case YAFFS_ECC_RESULT_NO_ERROR: ++ case YAFFS_ECC_RESULT_FIXED: ++ break; ++ ++ case YAFFS_ECC_RESULT_UNFIXED: ++ default: ++ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. */ ++ if (yaffs_check_ff(tag_buf, 8)) { ++ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_OK); ++ } ++ ++ memcpy(&pt1, tag_buf, 8); ++ ++ if (!dev->param.tags_9bytes) { ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++ } else { ++ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; ++ } ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. */ ++ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->n_tags_ecc_fixed++; ++ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->n_tags_ecc_unfixed++; ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, ++ YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] ++ */ ++ pt1.should_be_ff = 0xffffffff; ++ yaffs_unpack_tags1(tags, &pt1); ++ tags->ecc_result = ecc_result; ++ ++ /* Set deleted state */ ++ tags->is_deleted = deleted; ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_ext_tags tags; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); ++ ++ *seq_number = 0; ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ if (retval == YAFFS_FAIL) { ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ goto out; ++ } ++ ++ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, ++ NULL, &tags); ++ ++ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", ++ block_no); ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else if (tags.chunk_used) { ++ *seq_number = tags.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ retval = YAFFS_OK; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %u state %d", ++ *seq_number, *state); ++ ++ return retval; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if (dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} ++#endif diff --git a/target/linux/generic/patches-3.14/503-yaffs-3.12-convert-readdir-to-iterate.patch b/target/linux/generic/patches-3.14/503-yaffs-3.12-convert-readdir-to-iterate.patch deleted file mode 100644 index 586c141e0a..0000000000 --- a/target/linux/generic/patches-3.14/503-yaffs-3.12-convert-readdir-to-iterate.patch +++ /dev/null @@ -1,129 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -1701,6 +1701,110 @@ static void yaffs_remove_obj_callback(st - - /*-----------------------------------------------------------------*/ - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) -+static int yaffs_readdir(struct file *file, struct dir_context *ctx) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ struct yaffs_search_context *sc; -+ struct inode *inode = file->f_dentry->d_inode; -+ unsigned long offset, curoffs; -+ struct yaffs_obj *l; -+ int ret_val = 0; -+ -+ char name[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ obj = yaffs_dentry_to_obj(file->f_dentry); -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ yaffs_dev_to_lc(dev)->readdir_process = current; -+ -+ offset = ctx->pos; -+ -+ sc = yaffs_new_search(obj); -+ if (!sc) { -+ ret_val = -ENOMEM; -+ goto out; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: starting at %d", (int)offset); -+ -+ if (offset == 0) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry . ino %d", -+ (int)inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (!dir_emit_dot(file, ctx)) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ ctx->pos++; -+ } -+ if (offset == 1) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry .. ino %d", -+ (int)file->f_dentry->d_parent->d_inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (!dir_emit_dotdot(file, ctx)) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ ctx->pos++; -+ } -+ -+ curoffs = 1; -+ -+ /* If the directory has changed since the open or last call to -+ readdir, rewind to after the 2 canned entries. */ -+ if (file->f_version != inode->i_version) { -+ offset = 2; -+ ctx->pos = offset; -+ file->f_version = inode->i_version; -+ } -+ -+ while (sc->next_return) { -+ curoffs++; -+ l = sc->next_return; -+ if (curoffs >= offset) { -+ 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(ctx, name, strlen(name), -+ this_inode, this_type) < 0) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ -+ yaffs_gross_lock(dev); -+ -+ offset++; -+ ctx->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; -@@ -1807,10 +1911,15 @@ out: - - return ret_val; - } -+#endif - - static const struct file_operations yaffs_dir_operations = { - .read = generic_read_dir, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) -+ .iterate = yaffs_readdir, -+#else - .readdir = yaffs_readdir, -+#endif - .fsync = yaffs_sync_object, - .llseek = generic_file_llseek, - }; diff --git a/target/linux/generic/patches-3.14/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-3.14/503-yaffs-add-tags-9bytes-mount-option.patch index 4858519ca1..9ecaa72832 100644 --- a/target/linux/generic/patches-3.14/503-yaffs-add-tags-9bytes-mount-option.patch +++ b/target/linux/generic/patches-3.14/503-yaffs-add-tags-9bytes-mount-option.patch @@ -4,7 +4,7 @@ Signed-off-by: Gabor Juhos --- --- a/fs/yaffs2/yaffs_vfs.c +++ b/fs/yaffs2/yaffs_vfs.c -@@ -2634,6 +2634,7 @@ static const struct super_operations yaf +@@ -2605,6 +2605,7 @@ static const struct super_operations yaf struct yaffs_options { int inband_tags; @@ -12,7 +12,7 @@ Signed-off-by: Gabor Juhos int skip_checkpoint_read; int skip_checkpoint_write; int no_cache; -@@ -2673,6 +2674,8 @@ static int yaffs_parse_options(struct ya +@@ -2644,6 +2645,8 @@ static int yaffs_parse_options(struct ya if (!strcmp(cur_opt, "inband-tags")) { options->inband_tags = 1; @@ -21,7 +21,7 @@ Signed-off-by: Gabor Juhos } else if (!strcmp(cur_opt, "tags-ecc-off")) { options->tags_ecc_on = 0; options->tags_ecc_overridden = 1; -@@ -2746,7 +2749,6 @@ static struct super_block *yaffs_interna +@@ -2717,7 +2720,6 @@ static struct super_block *yaffs_interna struct yaffs_param *param; int read_only = 0; @@ -29,7 +29,7 @@ Signed-off-by: Gabor Juhos struct yaffs_options options; -@@ -2786,6 +2788,9 @@ static struct super_block *yaffs_interna +@@ -2757,6 +2759,9 @@ static struct super_block *yaffs_interna memset(&options, 0, sizeof(options)); @@ -39,7 +39,7 @@ Signed-off-by: Gabor Juhos if (yaffs_parse_options(&options, data_str)) { /* Option parsing failed */ return NULL; -@@ -2819,17 +2824,22 @@ static struct super_block *yaffs_interna +@@ -2790,17 +2795,22 @@ static struct super_block *yaffs_interna } /* Added NCB 26/5/2006 for completeness */ @@ -68,7 +68,7 @@ Signed-off-by: Gabor Juhos return NULL; /* OK, so if we got here, we have an MTD that's NAND and looks -@@ -2890,7 +2900,8 @@ static struct super_block *yaffs_interna +@@ -2857,7 +2867,8 @@ static struct super_block *yaffs_interna param->n_reserved_blocks = 5; param->n_caches = (options.no_cache) ? 0 : 10; @@ -80,15 +80,7 @@ Signed-off-by: Gabor Juhos if (options.lazy_loading_overridden) --- a/fs/yaffs2/yaffs_mtdif.c +++ b/fs/yaffs2/yaffs_mtdif.c -@@ -16,6 +16,7 @@ - #include "yaffs_mtdif.h" - - #include "linux/mtd/mtd.h" -+#include "uapi/linux/major.h" - #include "linux/types.h" - #include "linux/time.h" - #include "linux/mtd/nand.h" -@@ -276,7 +277,8 @@ struct mtd_info * yaffs_get_mtd_device(d +@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d return mtd; } @@ -98,7 +90,7 @@ Signed-off-by: Gabor Juhos { if (yaffs_version == 2) { if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || -@@ -295,6 +297,12 @@ int yaffs_verify_mtd(struct mtd_info *mt +@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt ); return -1; } diff --git a/target/linux/generic/patches-3.14/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-3.14/504-yaffs-3.16-new-fops.patch new file mode 100644 index 0000000000..11c6da0516 --- /dev/null +++ b/target/linux/generic/patches-3.14/504-yaffs-3.16-new-fops.patch @@ -0,0 +1,25 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -774,7 +774,21 @@ static int yaffs_sync_object(struct file + } + + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) ++static const struct file_operations yaffs_file_operations = { ++ .read = new_sync_read, ++ .read_iter = generic_file_read_iter, ++ .write = new_sync_write, ++ .write_iter = generic_file_write_iter, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = iter_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) + static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, diff --git a/target/linux/generic/patches-3.14/504-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-3.14/504-yaffs-fix-compat-tags-handling.patch deleted file mode 100644 index a18cf6fd7b..0000000000 --- a/target/linux/generic/patches-3.14/504-yaffs-fix-compat-tags-handling.patch +++ /dev/null @@ -1,239 +0,0 @@ -Subject: yaffs: fix compat tags handling - -Signed-off-by: Gabor Juhos ---- ---- a/fs/yaffs2/yaffs_tagscompat.c -+++ b/fs/yaffs2/yaffs_tagscompat.c -@@ -17,7 +17,9 @@ - #include "yaffs_getblockinfo.h" - #include "yaffs_trace.h" - -+#if 0 - static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); -+#endif - - - /********** Tags ECC calculations *********/ -@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta - return 0; - } - -+#if 0 - /********** Tags **********/ - - static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, -@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya - if(!dev->tagger.mark_bad_fn) - dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; - } -+#else -+ -+#include "yaffs_packedtags1.h" -+ -+static int yaffs_tags_compat_write(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 *data, -+ const struct yaffs_ext_tags *tags) -+{ -+ struct yaffs_packed_tags1 pt1; -+ u8 tag_buf[9]; -+ int retval; -+ -+ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ -+ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); -+ compile_time_assertion(sizeof(struct yaffs_tags) == 8); -+ -+ yaffs_pack_tags1(&pt1, tags); -+ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); -+ -+ /* When deleting a chunk, the upper layer provides only skeletal -+ * tags, one with is_deleted set. However, we need to update the -+ * tags, not erase them completely. So we use the NAND write property -+ * that only zeroed-bits stick and set tag bytes to all-ones and -+ * zero just the (not) deleted bit. -+ */ -+ if (!dev->param.tags_9bytes) { -+ if (tags->is_deleted) { -+ memset(&pt1, 0xff, 8); -+ /* clear delete status bit to indicate deleted */ -+ pt1.deleted = 0; -+ } -+ memcpy(tag_buf, &pt1, 8); -+ } else { -+ if (tags->is_deleted) { -+ memset(tag_buf, 0xff, 8); -+ tag_buf[8] = 0; -+ } else { -+ memcpy(tag_buf, &pt1, 8); -+ tag_buf[8] = 0xff; -+ } -+ } -+ -+ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, -+ data, -+ (data) ? dev->data_bytes_per_chunk : 0, -+ tag_buf, -+ (dev->param.tags_9bytes) ? 9 : 8); -+ -+ return retval; -+} -+ -+/* Return with empty extended tags but add ecc_result. -+ */ -+static int return_empty_tags(struct yaffs_ext_tags *tags, -+ enum yaffs_ecc_result ecc_result, -+ int retval) -+{ -+ if (tags) { -+ memset(tags, 0, sizeof(*tags)); -+ tags->ecc_result = ecc_result; -+ } -+ -+ return retval; -+} -+ -+static int yaffs_tags_compat_read(struct yaffs_dev *dev, -+ int nand_chunk, -+ u8 *data, -+ struct yaffs_ext_tags *tags) -+{ -+ struct yaffs_packed_tags1 pt1; -+ enum yaffs_ecc_result ecc_result; -+ int retval; -+ int deleted; -+ u8 tag_buf[9]; -+ -+ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, -+ data, dev->param.total_bytes_per_chunk, -+ tag_buf, -+ (dev->param.tags_9bytes) ? 9 : 8, -+ &ecc_result); -+ -+ switch (ecc_result) { -+ case YAFFS_ECC_RESULT_NO_ERROR: -+ case YAFFS_ECC_RESULT_FIXED: -+ break; -+ -+ case YAFFS_ECC_RESULT_UNFIXED: -+ default: -+ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); -+ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); -+ return YAFFS_FAIL; -+ } -+ -+ /* Check for a blank/erased chunk. */ -+ if (yaffs_check_ff(tag_buf, 8)) { -+ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ -+ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, -+ YAFFS_OK); -+ } -+ -+ memcpy(&pt1, tag_buf, 8); -+ -+ if (!dev->param.tags_9bytes) { -+ /* Read deleted status (bit) then return it to it's non-deleted -+ * state before performing tags mini-ECC check. pt1.deleted is -+ * inverted. -+ */ -+ deleted = !pt1.deleted; -+ pt1.deleted = 1; -+ } else { -+ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; -+ } -+ -+ /* Check the packed tags mini-ECC and correct if necessary/possible. */ -+ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); -+ switch (retval) { -+ case 0: -+ /* no tags error, use MTD result */ -+ break; -+ case 1: -+ /* recovered tags-ECC error */ -+ dev->n_tags_ecc_fixed++; -+ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) -+ ecc_result = YAFFS_ECC_RESULT_FIXED; -+ break; -+ default: -+ /* unrecovered tags-ECC error */ -+ dev->n_tags_ecc_unfixed++; -+ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, -+ YAFFS_FAIL); -+ } -+ -+ /* Unpack the tags to extended form and set ECC result. -+ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] -+ */ -+ pt1.should_be_ff = 0xffffffff; -+ yaffs_unpack_tags1(tags, &pt1); -+ tags->ecc_result = ecc_result; -+ -+ /* Set deleted state */ -+ tags->is_deleted = deleted; -+ return YAFFS_OK; -+} -+ -+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) -+{ -+ return dev->drv.drv_mark_bad_fn(dev, block_no); -+} -+ -+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, -+ int block_no, -+ enum yaffs_block_state *state, -+ u32 *seq_number) -+{ -+ struct yaffs_ext_tags tags; -+ int retval; -+ -+ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); -+ -+ *seq_number = 0; -+ -+ retval = dev->drv.drv_check_bad_fn(dev, block_no); -+ if (retval == YAFFS_FAIL) { -+ *state = YAFFS_BLOCK_STATE_DEAD; -+ goto out; -+ } -+ -+ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, -+ NULL, &tags); -+ -+ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { -+ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", -+ block_no); -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; -+ } else if (tags.chunk_used) { -+ *seq_number = tags.seq_number; -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; -+ } else { -+ *state = YAFFS_BLOCK_STATE_EMPTY; -+ } -+ -+ retval = YAFFS_OK; -+ -+out: -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "block query returns seq %u state %d", -+ *seq_number, *state); -+ -+ return retval; -+} -+ -+void yaffs_tags_compat_install(struct yaffs_dev *dev) -+{ -+ if (dev->param.is_yaffs2) -+ return; -+ -+ if (!dev->tagger.write_chunk_tags_fn) -+ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; -+ -+ if (!dev->tagger.read_chunk_tags_fn) -+ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; -+ -+ if (!dev->tagger.query_block_fn) -+ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; -+ -+ if (!dev->tagger.mark_bad_fn) -+ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; -+} -+#endif diff --git a/target/linux/generic/patches-3.18/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch b/target/linux/generic/patches-3.18/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch deleted file mode 100644 index c1f7367dd8..0000000000 --- a/target/linux/generic/patches-3.18/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch +++ /dev/null @@ -1,155 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -329,6 +329,33 @@ static int yaffs_readpage(struct file *f - return ret; - } - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid()) -+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid()) -+#else -+#define YCRED_FSUID() YCRED(current)->fsuid -+#define YCRED_FSGID() YCRED(current)->fsgid -+ -+static inline uid_t i_uid_read(const struct inode *inode) -+{ -+ return inode->i_uid; -+} -+ -+static inline gid_t i_gid_read(const struct inode *inode) -+{ -+ return inode->i_gid; -+} -+ -+static inline void i_uid_write(struct inode *inode, uid_t uid) -+{ -+ inode->i_uid = uid; -+} -+ -+static inline void i_gid_write(struct inode *inode, gid_t gid) -+{ -+ inode->i_gid = gid; -+} -+#endif - - static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val) - { -@@ -1225,9 +1252,9 @@ static int yaffs_mknod(struct inode *dir - struct yaffs_obj *parent = yaffs_inode_to_obj(dir); - - int error = -ENOSPC; -- uid_t uid = YCRED(current)->fsuid; -+ uid_t uid = YCRED_FSUID(); - gid_t gid = -- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; -+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID(); - - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) - mode |= S_ISGID; -@@ -1424,9 +1451,9 @@ static int yaffs_symlink(struct inode *d - { - struct yaffs_obj *obj; - struct yaffs_dev *dev; -- uid_t uid = YCRED(current)->fsuid; -+ uid_t uid = YCRED_FSUID(); - gid_t gid = -- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; -+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID(); - - yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); - -@@ -1829,8 +1856,8 @@ static void yaffs_fill_inode_from_obj(st - - inode->i_ino = obj->obj_id; - inode->i_mode = obj->yst_mode; -- inode->i_uid = obj->yst_uid; -- inode->i_gid = obj->yst_gid; -+ i_uid_write(inode, obj->yst_uid); -+ i_gid_write(inode, obj->yst_gid); - #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) - inode->i_blksize = inode->i_sb->s_blocksize; - #endif -@@ -1856,7 +1883,7 @@ static void yaffs_fill_inode_from_obj(st - - 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, i_uid_read(inode), i_gid_read(inode), - inode->i_size, atomic_read(&inode->i_count)); - - switch (obj->yst_mode & S_IFMT) { ---- a/fs/yaffs2/yaffs_attribs.c -+++ b/fs/yaffs2/yaffs_attribs.c -@@ -14,6 +14,48 @@ - #include "yaffs_guts.h" - #include "yaffs_attribs.h" - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+static inline uid_t ia_uid_read(const struct iattr *iattr) -+{ -+ return from_kuid(&init_user_ns, iattr->ia_uid); -+} -+ -+static inline gid_t ia_gid_read(const struct iattr *iattr) -+{ -+ return from_kgid(&init_user_ns, iattr->ia_gid); -+} -+ -+static inline void ia_uid_write(struct iattr *iattr, uid_t uid) -+{ -+ iattr->ia_uid = make_kuid(&init_user_ns, uid); -+} -+ -+static inline void ia_gid_write(struct iattr *iattr, gid_t gid) -+{ -+ iattr->ia_gid = make_kgid(&init_user_ns, gid); -+} -+#else -+static inline uid_t ia_uid_read(const struct iattr *iattr) -+{ -+ return iattr->ia_uid; -+} -+ -+static inline gid_t ia_gid_read(const struct iattr *inode) -+{ -+ return iattr->ia_gid; -+} -+ -+static inline void ia_uid_write(struct iattr *iattr, uid_t uid) -+{ -+ iattr->ia_uid = uid; -+} -+ -+static inline void ia_gid_write(struct iattr *iattr, gid_t gid) -+{ -+ iattr->ia_gid = gid; -+} -+#endif -+ - void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) - { - obj->yst_uid = oh->yst_uid; -@@ -77,9 +119,9 @@ int yaffs_set_attribs(struct yaffs_obj * - if (valid & ATTR_MODE) - obj->yst_mode = attr->ia_mode; - if (valid & ATTR_UID) -- obj->yst_uid = attr->ia_uid; -+ obj->yst_uid = ia_uid_read(attr); - if (valid & ATTR_GID) -- obj->yst_gid = attr->ia_gid; -+ obj->yst_gid = ia_gid_read(attr); - - if (valid & ATTR_ATIME) - obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); -@@ -103,9 +145,9 @@ int yaffs_get_attribs(struct yaffs_obj * - - attr->ia_mode = obj->yst_mode; - valid |= ATTR_MODE; -- attr->ia_uid = obj->yst_uid; -+ ia_uid_write(attr, obj->yst_uid); - valid |= ATTR_UID; -- attr->ia_gid = obj->yst_gid; -+ ia_gid_write(attr, obj->yst_gid); - valid |= ATTR_GID; - - Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; diff --git a/target/linux/generic/patches-3.18/501-yaffs-add-missing-flush-arguments.patch b/target/linux/generic/patches-3.18/501-yaffs-add-missing-flush-arguments.patch new file mode 100644 index 0000000000..d5ccc3e81e --- /dev/null +++ b/target/linux/generic/patches-3.18/501-yaffs-add-missing-flush-arguments.patch @@ -0,0 +1,38 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -738,7 +738,7 @@ static int yaffs_file_flush(struct file + + yaffs_gross_lock(dev); + +- yaffs_flush_file(obj, 1, 0); ++ yaffs_flush_file(obj, 1, 0, 1); + + yaffs_gross_unlock(dev); + +@@ -768,7 +768,7 @@ static int yaffs_sync_object(struct file + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + "yaffs_sync_object"); + yaffs_gross_lock(dev); +- yaffs_flush_file(obj, 1, datasync); ++ yaffs_flush_file(obj, 1, datasync, 1); + yaffs_gross_unlock(dev); + return 0; + } +@@ -2187,7 +2187,7 @@ static void yaffs_flush_inodes(struct su + yaffs_trace(YAFFS_TRACE_OS, + "flushing obj %d", + obj->obj_id); +- yaffs_flush_file(obj, 1, 0); ++ yaffs_flush_file(obj, 1, 0, 1); + } + } + } +@@ -2200,7 +2200,7 @@ static void yaffs_flush_super(struct sup + + yaffs_flush_inodes(sb); + yaffs_update_dirty_dirs(dev); +- yaffs_flush_whole_cache(dev); ++ yaffs_flush_whole_cache(dev, 1); + if (do_checkpoint) + yaffs_checkpoint_save(dev); + } diff --git a/target/linux/generic/patches-3.18/502-yaffs-3.10-disable-proc-entry.patch b/target/linux/generic/patches-3.18/502-yaffs-3.10-disable-proc-entry.patch deleted file mode 100644 index 5b73d3898b..0000000000 --- a/target/linux/generic/patches-3.18/502-yaffs-3.10-disable-proc-entry.patch +++ /dev/null @@ -1,44 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -3025,6 +3025,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "y - #endif - - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - static struct proc_dir_entry *my_proc_entry; - - static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) -@@ -3398,6 +3399,7 @@ static int yaffs_proc_write(struct file - return yaffs_proc_debug_write(file, buf, count, data); - return yaffs_proc_write_trace_options(file, buf, count, data); - } -+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */ - - /* Stuff to handle installation of file systems */ - struct file_system_to_install { -@@ -3421,6 +3423,7 @@ static int __init init_yaffs_fs(void) - - mutex_init(&yaffs_context_lock); - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - /* Install the proc_fs entries */ - my_proc_entry = create_proc_entry("yaffs", - S_IRUGO | S_IFREG, YPROC_ROOT); -@@ -3432,6 +3435,7 @@ static int __init init_yaffs_fs(void) - } else { - return -ENOMEM; - } -+#endif - - /* Now add the file system entries */ - -@@ -3468,7 +3472,9 @@ static void __exit exit_yaffs_fs(void) - yaffs_trace(YAFFS_TRACE_ALWAYS, - "yaffs built " __DATE__ " " __TIME__ " removing."); - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - remove_proc_entry("yaffs", YPROC_ROOT); -+#endif - - fsinst = fs_to_install; - diff --git a/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch new file mode 100644 index 0000000000..a18cf6fd7b --- /dev/null +++ b/target/linux/generic/patches-3.18/502-yaffs-fix-compat-tags-handling.patch @@ -0,0 +1,239 @@ +Subject: yaffs: fix compat tags handling + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -17,7 +17,9 @@ + #include "yaffs_getblockinfo.h" + #include "yaffs_trace.h" + ++#if 0 + static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++#endif + + + /********** Tags ECC calculations *********/ +@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta + return 0; + } + ++#if 0 + /********** Tags **********/ + + static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; + } ++#else ++ ++#include "yaffs_packedtags1.h" ++ ++static int yaffs_tags_compat_write(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ u8 tag_buf[9]; ++ int retval; ++ ++ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ ++ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); ++ compile_time_assertion(sizeof(struct yaffs_tags) == 8); ++ ++ yaffs_pack_tags1(&pt1, tags); ++ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * tags, one with is_deleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++ if (!dev->param.tags_9bytes) { ++ if (tags->is_deleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++ memcpy(tag_buf, &pt1, 8); ++ } else { ++ if (tags->is_deleted) { ++ memset(tag_buf, 0xff, 8); ++ tag_buf[8] = 0; ++ } else { ++ memcpy(tag_buf, &pt1, 8); ++ tag_buf[8] = 0xff; ++ } ++ } ++ ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, ++ (data) ? dev->data_bytes_per_chunk : 0, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8); ++ ++ return retval; ++} ++ ++/* Return with empty extended tags but add ecc_result. ++ */ ++static int return_empty_tags(struct yaffs_ext_tags *tags, ++ enum yaffs_ecc_result ecc_result, ++ int retval) ++{ ++ if (tags) { ++ memset(tags, 0, sizeof(*tags)); ++ tags->ecc_result = ecc_result; ++ } ++ ++ return retval; ++} ++ ++static int yaffs_tags_compat_read(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ enum yaffs_ecc_result ecc_result; ++ int retval; ++ int deleted; ++ u8 tag_buf[9]; ++ ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8, ++ &ecc_result); ++ ++ switch (ecc_result) { ++ case YAFFS_ECC_RESULT_NO_ERROR: ++ case YAFFS_ECC_RESULT_FIXED: ++ break; ++ ++ case YAFFS_ECC_RESULT_UNFIXED: ++ default: ++ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. */ ++ if (yaffs_check_ff(tag_buf, 8)) { ++ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_OK); ++ } ++ ++ memcpy(&pt1, tag_buf, 8); ++ ++ if (!dev->param.tags_9bytes) { ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++ } else { ++ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; ++ } ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. */ ++ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->n_tags_ecc_fixed++; ++ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->n_tags_ecc_unfixed++; ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, ++ YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] ++ */ ++ pt1.should_be_ff = 0xffffffff; ++ yaffs_unpack_tags1(tags, &pt1); ++ tags->ecc_result = ecc_result; ++ ++ /* Set deleted state */ ++ tags->is_deleted = deleted; ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_ext_tags tags; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); ++ ++ *seq_number = 0; ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ if (retval == YAFFS_FAIL) { ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ goto out; ++ } ++ ++ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, ++ NULL, &tags); ++ ++ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", ++ block_no); ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else if (tags.chunk_used) { ++ *seq_number = tags.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ retval = YAFFS_OK; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %u state %d", ++ *seq_number, *state); ++ ++ return retval; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if (dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} ++#endif diff --git a/target/linux/generic/patches-3.18/503-yaffs-3.12-convert-readdir-to-iterate.patch b/target/linux/generic/patches-3.18/503-yaffs-3.12-convert-readdir-to-iterate.patch deleted file mode 100644 index 586c141e0a..0000000000 --- a/target/linux/generic/patches-3.18/503-yaffs-3.12-convert-readdir-to-iterate.patch +++ /dev/null @@ -1,129 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -1701,6 +1701,110 @@ static void yaffs_remove_obj_callback(st - - /*-----------------------------------------------------------------*/ - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) -+static int yaffs_readdir(struct file *file, struct dir_context *ctx) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ struct yaffs_search_context *sc; -+ struct inode *inode = file->f_dentry->d_inode; -+ unsigned long offset, curoffs; -+ struct yaffs_obj *l; -+ int ret_val = 0; -+ -+ char name[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ obj = yaffs_dentry_to_obj(file->f_dentry); -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ yaffs_dev_to_lc(dev)->readdir_process = current; -+ -+ offset = ctx->pos; -+ -+ sc = yaffs_new_search(obj); -+ if (!sc) { -+ ret_val = -ENOMEM; -+ goto out; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: starting at %d", (int)offset); -+ -+ if (offset == 0) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry . ino %d", -+ (int)inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (!dir_emit_dot(file, ctx)) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ ctx->pos++; -+ } -+ if (offset == 1) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry .. ino %d", -+ (int)file->f_dentry->d_parent->d_inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (!dir_emit_dotdot(file, ctx)) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ ctx->pos++; -+ } -+ -+ curoffs = 1; -+ -+ /* If the directory has changed since the open or last call to -+ readdir, rewind to after the 2 canned entries. */ -+ if (file->f_version != inode->i_version) { -+ offset = 2; -+ ctx->pos = offset; -+ file->f_version = inode->i_version; -+ } -+ -+ while (sc->next_return) { -+ curoffs++; -+ l = sc->next_return; -+ if (curoffs >= offset) { -+ 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(ctx, name, strlen(name), -+ this_inode, this_type) < 0) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ -+ yaffs_gross_lock(dev); -+ -+ offset++; -+ ctx->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; -@@ -1807,10 +1911,15 @@ out: - - return ret_val; - } -+#endif - - static const struct file_operations yaffs_dir_operations = { - .read = generic_read_dir, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) -+ .iterate = yaffs_readdir, -+#else - .readdir = yaffs_readdir, -+#endif - .fsync = yaffs_sync_object, - .llseek = generic_file_llseek, - }; diff --git a/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch index 4858519ca1..9ecaa72832 100644 --- a/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch +++ b/target/linux/generic/patches-3.18/503-yaffs-add-tags-9bytes-mount-option.patch @@ -4,7 +4,7 @@ Signed-off-by: Gabor Juhos --- --- a/fs/yaffs2/yaffs_vfs.c +++ b/fs/yaffs2/yaffs_vfs.c -@@ -2634,6 +2634,7 @@ static const struct super_operations yaf +@@ -2605,6 +2605,7 @@ static const struct super_operations yaf struct yaffs_options { int inband_tags; @@ -12,7 +12,7 @@ Signed-off-by: Gabor Juhos int skip_checkpoint_read; int skip_checkpoint_write; int no_cache; -@@ -2673,6 +2674,8 @@ static int yaffs_parse_options(struct ya +@@ -2644,6 +2645,8 @@ static int yaffs_parse_options(struct ya if (!strcmp(cur_opt, "inband-tags")) { options->inband_tags = 1; @@ -21,7 +21,7 @@ Signed-off-by: Gabor Juhos } else if (!strcmp(cur_opt, "tags-ecc-off")) { options->tags_ecc_on = 0; options->tags_ecc_overridden = 1; -@@ -2746,7 +2749,6 @@ static struct super_block *yaffs_interna +@@ -2717,7 +2720,6 @@ static struct super_block *yaffs_interna struct yaffs_param *param; int read_only = 0; @@ -29,7 +29,7 @@ Signed-off-by: Gabor Juhos struct yaffs_options options; -@@ -2786,6 +2788,9 @@ static struct super_block *yaffs_interna +@@ -2757,6 +2759,9 @@ static struct super_block *yaffs_interna memset(&options, 0, sizeof(options)); @@ -39,7 +39,7 @@ Signed-off-by: Gabor Juhos if (yaffs_parse_options(&options, data_str)) { /* Option parsing failed */ return NULL; -@@ -2819,17 +2824,22 @@ static struct super_block *yaffs_interna +@@ -2790,17 +2795,22 @@ static struct super_block *yaffs_interna } /* Added NCB 26/5/2006 for completeness */ @@ -68,7 +68,7 @@ Signed-off-by: Gabor Juhos return NULL; /* OK, so if we got here, we have an MTD that's NAND and looks -@@ -2890,7 +2900,8 @@ static struct super_block *yaffs_interna +@@ -2857,7 +2867,8 @@ static struct super_block *yaffs_interna param->n_reserved_blocks = 5; param->n_caches = (options.no_cache) ? 0 : 10; @@ -80,15 +80,7 @@ Signed-off-by: Gabor Juhos if (options.lazy_loading_overridden) --- a/fs/yaffs2/yaffs_mtdif.c +++ b/fs/yaffs2/yaffs_mtdif.c -@@ -16,6 +16,7 @@ - #include "yaffs_mtdif.h" - - #include "linux/mtd/mtd.h" -+#include "uapi/linux/major.h" - #include "linux/types.h" - #include "linux/time.h" - #include "linux/mtd/nand.h" -@@ -276,7 +277,8 @@ struct mtd_info * yaffs_get_mtd_device(d +@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d return mtd; } @@ -98,7 +90,7 @@ Signed-off-by: Gabor Juhos { if (yaffs_version == 2) { if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || -@@ -295,6 +297,12 @@ int yaffs_verify_mtd(struct mtd_info *mt +@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt ); return -1; } diff --git a/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch new file mode 100644 index 0000000000..11c6da0516 --- /dev/null +++ b/target/linux/generic/patches-3.18/504-yaffs-3.16-new-fops.patch @@ -0,0 +1,25 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -774,7 +774,21 @@ static int yaffs_sync_object(struct file + } + + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) ++static const struct file_operations yaffs_file_operations = { ++ .read = new_sync_read, ++ .read_iter = generic_file_read_iter, ++ .write = new_sync_write, ++ .write_iter = generic_file_write_iter, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = iter_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) + static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, diff --git a/target/linux/generic/patches-3.18/504-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-3.18/504-yaffs-fix-compat-tags-handling.patch deleted file mode 100644 index a18cf6fd7b..0000000000 --- a/target/linux/generic/patches-3.18/504-yaffs-fix-compat-tags-handling.patch +++ /dev/null @@ -1,239 +0,0 @@ -Subject: yaffs: fix compat tags handling - -Signed-off-by: Gabor Juhos ---- ---- a/fs/yaffs2/yaffs_tagscompat.c -+++ b/fs/yaffs2/yaffs_tagscompat.c -@@ -17,7 +17,9 @@ - #include "yaffs_getblockinfo.h" - #include "yaffs_trace.h" - -+#if 0 - static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); -+#endif - - - /********** Tags ECC calculations *********/ -@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta - return 0; - } - -+#if 0 - /********** Tags **********/ - - static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, -@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya - if(!dev->tagger.mark_bad_fn) - dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; - } -+#else -+ -+#include "yaffs_packedtags1.h" -+ -+static int yaffs_tags_compat_write(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 *data, -+ const struct yaffs_ext_tags *tags) -+{ -+ struct yaffs_packed_tags1 pt1; -+ u8 tag_buf[9]; -+ int retval; -+ -+ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ -+ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); -+ compile_time_assertion(sizeof(struct yaffs_tags) == 8); -+ -+ yaffs_pack_tags1(&pt1, tags); -+ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); -+ -+ /* When deleting a chunk, the upper layer provides only skeletal -+ * tags, one with is_deleted set. However, we need to update the -+ * tags, not erase them completely. So we use the NAND write property -+ * that only zeroed-bits stick and set tag bytes to all-ones and -+ * zero just the (not) deleted bit. -+ */ -+ if (!dev->param.tags_9bytes) { -+ if (tags->is_deleted) { -+ memset(&pt1, 0xff, 8); -+ /* clear delete status bit to indicate deleted */ -+ pt1.deleted = 0; -+ } -+ memcpy(tag_buf, &pt1, 8); -+ } else { -+ if (tags->is_deleted) { -+ memset(tag_buf, 0xff, 8); -+ tag_buf[8] = 0; -+ } else { -+ memcpy(tag_buf, &pt1, 8); -+ tag_buf[8] = 0xff; -+ } -+ } -+ -+ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, -+ data, -+ (data) ? dev->data_bytes_per_chunk : 0, -+ tag_buf, -+ (dev->param.tags_9bytes) ? 9 : 8); -+ -+ return retval; -+} -+ -+/* Return with empty extended tags but add ecc_result. -+ */ -+static int return_empty_tags(struct yaffs_ext_tags *tags, -+ enum yaffs_ecc_result ecc_result, -+ int retval) -+{ -+ if (tags) { -+ memset(tags, 0, sizeof(*tags)); -+ tags->ecc_result = ecc_result; -+ } -+ -+ return retval; -+} -+ -+static int yaffs_tags_compat_read(struct yaffs_dev *dev, -+ int nand_chunk, -+ u8 *data, -+ struct yaffs_ext_tags *tags) -+{ -+ struct yaffs_packed_tags1 pt1; -+ enum yaffs_ecc_result ecc_result; -+ int retval; -+ int deleted; -+ u8 tag_buf[9]; -+ -+ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, -+ data, dev->param.total_bytes_per_chunk, -+ tag_buf, -+ (dev->param.tags_9bytes) ? 9 : 8, -+ &ecc_result); -+ -+ switch (ecc_result) { -+ case YAFFS_ECC_RESULT_NO_ERROR: -+ case YAFFS_ECC_RESULT_FIXED: -+ break; -+ -+ case YAFFS_ECC_RESULT_UNFIXED: -+ default: -+ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); -+ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); -+ return YAFFS_FAIL; -+ } -+ -+ /* Check for a blank/erased chunk. */ -+ if (yaffs_check_ff(tag_buf, 8)) { -+ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ -+ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, -+ YAFFS_OK); -+ } -+ -+ memcpy(&pt1, tag_buf, 8); -+ -+ if (!dev->param.tags_9bytes) { -+ /* Read deleted status (bit) then return it to it's non-deleted -+ * state before performing tags mini-ECC check. pt1.deleted is -+ * inverted. -+ */ -+ deleted = !pt1.deleted; -+ pt1.deleted = 1; -+ } else { -+ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; -+ } -+ -+ /* Check the packed tags mini-ECC and correct if necessary/possible. */ -+ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); -+ switch (retval) { -+ case 0: -+ /* no tags error, use MTD result */ -+ break; -+ case 1: -+ /* recovered tags-ECC error */ -+ dev->n_tags_ecc_fixed++; -+ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) -+ ecc_result = YAFFS_ECC_RESULT_FIXED; -+ break; -+ default: -+ /* unrecovered tags-ECC error */ -+ dev->n_tags_ecc_unfixed++; -+ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, -+ YAFFS_FAIL); -+ } -+ -+ /* Unpack the tags to extended form and set ECC result. -+ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] -+ */ -+ pt1.should_be_ff = 0xffffffff; -+ yaffs_unpack_tags1(tags, &pt1); -+ tags->ecc_result = ecc_result; -+ -+ /* Set deleted state */ -+ tags->is_deleted = deleted; -+ return YAFFS_OK; -+} -+ -+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) -+{ -+ return dev->drv.drv_mark_bad_fn(dev, block_no); -+} -+ -+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, -+ int block_no, -+ enum yaffs_block_state *state, -+ u32 *seq_number) -+{ -+ struct yaffs_ext_tags tags; -+ int retval; -+ -+ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); -+ -+ *seq_number = 0; -+ -+ retval = dev->drv.drv_check_bad_fn(dev, block_no); -+ if (retval == YAFFS_FAIL) { -+ *state = YAFFS_BLOCK_STATE_DEAD; -+ goto out; -+ } -+ -+ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, -+ NULL, &tags); -+ -+ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { -+ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", -+ block_no); -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; -+ } else if (tags.chunk_used) { -+ *seq_number = tags.seq_number; -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; -+ } else { -+ *state = YAFFS_BLOCK_STATE_EMPTY; -+ } -+ -+ retval = YAFFS_OK; -+ -+out: -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "block query returns seq %u state %d", -+ *seq_number, *state); -+ -+ return retval; -+} -+ -+void yaffs_tags_compat_install(struct yaffs_dev *dev) -+{ -+ if (dev->param.is_yaffs2) -+ return; -+ -+ if (!dev->tagger.write_chunk_tags_fn) -+ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; -+ -+ if (!dev->tagger.read_chunk_tags_fn) -+ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; -+ -+ if (!dev->tagger.query_block_fn) -+ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; -+ -+ if (!dev->tagger.mark_bad_fn) -+ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; -+} -+#endif diff --git a/target/linux/generic/patches-3.18/505-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-3.18/505-yaffs-3.16-new-fops.patch deleted file mode 100644 index be88ab9525..0000000000 --- a/target/linux/generic/patches-3.18/505-yaffs-3.16-new-fops.patch +++ /dev/null @@ -1,32 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -794,15 +794,15 @@ static int yaffs_sync_object(struct file - - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) - static const struct file_operations yaffs_file_operations = { -- .read = do_sync_read, -- .write = do_sync_write, -- .aio_read = generic_file_aio_read, -- .aio_write = generic_file_aio_write, -+ .read = new_sync_read, -+ .write = new_sync_write, -+ .read_iter = generic_file_read_iter, -+ .write_iter = generic_file_write_iter, - .mmap = generic_file_mmap, - .flush = yaffs_file_flush, - .fsync = yaffs_sync_object, - .splice_read = generic_file_splice_read, -- .splice_write = generic_file_splice_write, -+ .splice_write = iter_file_splice_write, - .llseek = generic_file_llseek, - }; - -@@ -1050,7 +1050,7 @@ static int yaffs_readlink(struct dentry - if (!alias) - return -ENOMEM; - -- ret = vfs_readlink(dentry, buffer, buflen, alias); -+ ret = readlink_copy(buffer, buflen, alias); - kfree(alias); - return ret; - } diff --git a/target/linux/generic/patches-4.0/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch b/target/linux/generic/patches-4.0/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch deleted file mode 100644 index c1f7367dd8..0000000000 --- a/target/linux/generic/patches-4.0/501-yaffs-3.5-convert-to-use-kuid_t-kgid_t.patch +++ /dev/null @@ -1,155 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -329,6 +329,33 @@ static int yaffs_readpage(struct file *f - return ret; - } - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+#define YCRED_FSUID() from_kuid(&init_user_ns, current_fsuid()) -+#define YCRED_FSGID() from_kgid(&init_user_ns, current_fsgid()) -+#else -+#define YCRED_FSUID() YCRED(current)->fsuid -+#define YCRED_FSGID() YCRED(current)->fsgid -+ -+static inline uid_t i_uid_read(const struct inode *inode) -+{ -+ return inode->i_uid; -+} -+ -+static inline gid_t i_gid_read(const struct inode *inode) -+{ -+ return inode->i_gid; -+} -+ -+static inline void i_uid_write(struct inode *inode, uid_t uid) -+{ -+ inode->i_uid = uid; -+} -+ -+static inline void i_gid_write(struct inode *inode, gid_t gid) -+{ -+ inode->i_gid = gid; -+} -+#endif - - static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val) - { -@@ -1225,9 +1252,9 @@ static int yaffs_mknod(struct inode *dir - struct yaffs_obj *parent = yaffs_inode_to_obj(dir); - - int error = -ENOSPC; -- uid_t uid = YCRED(current)->fsuid; -+ uid_t uid = YCRED_FSUID(); - gid_t gid = -- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; -+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID(); - - if ((dir->i_mode & S_ISGID) && S_ISDIR(mode)) - mode |= S_ISGID; -@@ -1424,9 +1451,9 @@ static int yaffs_symlink(struct inode *d - { - struct yaffs_obj *obj; - struct yaffs_dev *dev; -- uid_t uid = YCRED(current)->fsuid; -+ uid_t uid = YCRED_FSUID(); - gid_t gid = -- (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid; -+ (dir->i_mode & S_ISGID) ? i_gid_read(dir) : YCRED_FSGID(); - - yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink"); - -@@ -1829,8 +1856,8 @@ static void yaffs_fill_inode_from_obj(st - - inode->i_ino = obj->obj_id; - inode->i_mode = obj->yst_mode; -- inode->i_uid = obj->yst_uid; -- inode->i_gid = obj->yst_gid; -+ i_uid_write(inode, obj->yst_uid); -+ i_gid_write(inode, obj->yst_gid); - #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)) - inode->i_blksize = inode->i_sb->s_blocksize; - #endif -@@ -1856,7 +1883,7 @@ static void yaffs_fill_inode_from_obj(st - - 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, i_uid_read(inode), i_gid_read(inode), - inode->i_size, atomic_read(&inode->i_count)); - - switch (obj->yst_mode & S_IFMT) { ---- a/fs/yaffs2/yaffs_attribs.c -+++ b/fs/yaffs2/yaffs_attribs.c -@@ -14,6 +14,48 @@ - #include "yaffs_guts.h" - #include "yaffs_attribs.h" - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) -+static inline uid_t ia_uid_read(const struct iattr *iattr) -+{ -+ return from_kuid(&init_user_ns, iattr->ia_uid); -+} -+ -+static inline gid_t ia_gid_read(const struct iattr *iattr) -+{ -+ return from_kgid(&init_user_ns, iattr->ia_gid); -+} -+ -+static inline void ia_uid_write(struct iattr *iattr, uid_t uid) -+{ -+ iattr->ia_uid = make_kuid(&init_user_ns, uid); -+} -+ -+static inline void ia_gid_write(struct iattr *iattr, gid_t gid) -+{ -+ iattr->ia_gid = make_kgid(&init_user_ns, gid); -+} -+#else -+static inline uid_t ia_uid_read(const struct iattr *iattr) -+{ -+ return iattr->ia_uid; -+} -+ -+static inline gid_t ia_gid_read(const struct iattr *inode) -+{ -+ return iattr->ia_gid; -+} -+ -+static inline void ia_uid_write(struct iattr *iattr, uid_t uid) -+{ -+ iattr->ia_uid = uid; -+} -+ -+static inline void ia_gid_write(struct iattr *iattr, gid_t gid) -+{ -+ iattr->ia_gid = gid; -+} -+#endif -+ - void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) - { - obj->yst_uid = oh->yst_uid; -@@ -77,9 +119,9 @@ int yaffs_set_attribs(struct yaffs_obj * - if (valid & ATTR_MODE) - obj->yst_mode = attr->ia_mode; - if (valid & ATTR_UID) -- obj->yst_uid = attr->ia_uid; -+ obj->yst_uid = ia_uid_read(attr); - if (valid & ATTR_GID) -- obj->yst_gid = attr->ia_gid; -+ obj->yst_gid = ia_gid_read(attr); - - if (valid & ATTR_ATIME) - obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); -@@ -103,9 +145,9 @@ int yaffs_get_attribs(struct yaffs_obj * - - attr->ia_mode = obj->yst_mode; - valid |= ATTR_MODE; -- attr->ia_uid = obj->yst_uid; -+ ia_uid_write(attr, obj->yst_uid); - valid |= ATTR_UID; -- attr->ia_gid = obj->yst_gid; -+ ia_gid_write(attr, obj->yst_gid); - valid |= ATTR_GID; - - Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; diff --git a/target/linux/generic/patches-4.0/501-yaffs-add-missing-flush-arguments.patch b/target/linux/generic/patches-4.0/501-yaffs-add-missing-flush-arguments.patch new file mode 100644 index 0000000000..d5ccc3e81e --- /dev/null +++ b/target/linux/generic/patches-4.0/501-yaffs-add-missing-flush-arguments.patch @@ -0,0 +1,38 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -738,7 +738,7 @@ static int yaffs_file_flush(struct file + + yaffs_gross_lock(dev); + +- yaffs_flush_file(obj, 1, 0); ++ yaffs_flush_file(obj, 1, 0, 1); + + yaffs_gross_unlock(dev); + +@@ -768,7 +768,7 @@ static int yaffs_sync_object(struct file + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC, + "yaffs_sync_object"); + yaffs_gross_lock(dev); +- yaffs_flush_file(obj, 1, datasync); ++ yaffs_flush_file(obj, 1, datasync, 1); + yaffs_gross_unlock(dev); + return 0; + } +@@ -2187,7 +2187,7 @@ static void yaffs_flush_inodes(struct su + yaffs_trace(YAFFS_TRACE_OS, + "flushing obj %d", + obj->obj_id); +- yaffs_flush_file(obj, 1, 0); ++ yaffs_flush_file(obj, 1, 0, 1); + } + } + } +@@ -2200,7 +2200,7 @@ static void yaffs_flush_super(struct sup + + yaffs_flush_inodes(sb); + yaffs_update_dirty_dirs(dev); +- yaffs_flush_whole_cache(dev); ++ yaffs_flush_whole_cache(dev, 1); + if (do_checkpoint) + yaffs_checkpoint_save(dev); + } diff --git a/target/linux/generic/patches-4.0/502-yaffs-3.10-disable-proc-entry.patch b/target/linux/generic/patches-4.0/502-yaffs-3.10-disable-proc-entry.patch deleted file mode 100644 index 5b73d3898b..0000000000 --- a/target/linux/generic/patches-4.0/502-yaffs-3.10-disable-proc-entry.patch +++ /dev/null @@ -1,44 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -3025,6 +3025,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "y - #endif - - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - static struct proc_dir_entry *my_proc_entry; - - static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev) -@@ -3398,6 +3399,7 @@ static int yaffs_proc_write(struct file - return yaffs_proc_debug_write(file, buf, count, data); - return yaffs_proc_write_trace_options(file, buf, count, data); - } -+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) */ - - /* Stuff to handle installation of file systems */ - struct file_system_to_install { -@@ -3421,6 +3423,7 @@ static int __init init_yaffs_fs(void) - - mutex_init(&yaffs_context_lock); - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - /* Install the proc_fs entries */ - my_proc_entry = create_proc_entry("yaffs", - S_IRUGO | S_IFREG, YPROC_ROOT); -@@ -3432,6 +3435,7 @@ static int __init init_yaffs_fs(void) - } else { - return -ENOMEM; - } -+#endif - - /* Now add the file system entries */ - -@@ -3468,7 +3472,9 @@ static void __exit exit_yaffs_fs(void) - yaffs_trace(YAFFS_TRACE_ALWAYS, - "yaffs built " __DATE__ " " __TIME__ " removing."); - -+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)) - remove_proc_entry("yaffs", YPROC_ROOT); -+#endif - - fsinst = fs_to_install; - diff --git a/target/linux/generic/patches-4.0/502-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-4.0/502-yaffs-fix-compat-tags-handling.patch new file mode 100644 index 0000000000..a18cf6fd7b --- /dev/null +++ b/target/linux/generic/patches-4.0/502-yaffs-fix-compat-tags-handling.patch @@ -0,0 +1,239 @@ +Subject: yaffs: fix compat tags handling + +Signed-off-by: Gabor Juhos +--- +--- a/fs/yaffs2/yaffs_tagscompat.c ++++ b/fs/yaffs2/yaffs_tagscompat.c +@@ -17,7 +17,9 @@ + #include "yaffs_getblockinfo.h" + #include "yaffs_trace.h" + ++#if 0 + static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); ++#endif + + + /********** Tags ECC calculations *********/ +@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta + return 0; + } + ++#if 0 + /********** Tags **********/ + + static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, +@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; + } ++#else ++ ++#include "yaffs_packedtags1.h" ++ ++static int yaffs_tags_compat_write(struct yaffs_dev *dev, ++ int nand_chunk, ++ const u8 *data, ++ const struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ u8 tag_buf[9]; ++ int retval; ++ ++ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ ++ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); ++ compile_time_assertion(sizeof(struct yaffs_tags) == 8); ++ ++ yaffs_pack_tags1(&pt1, tags); ++ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); ++ ++ /* When deleting a chunk, the upper layer provides only skeletal ++ * tags, one with is_deleted set. However, we need to update the ++ * tags, not erase them completely. So we use the NAND write property ++ * that only zeroed-bits stick and set tag bytes to all-ones and ++ * zero just the (not) deleted bit. ++ */ ++ if (!dev->param.tags_9bytes) { ++ if (tags->is_deleted) { ++ memset(&pt1, 0xff, 8); ++ /* clear delete status bit to indicate deleted */ ++ pt1.deleted = 0; ++ } ++ memcpy(tag_buf, &pt1, 8); ++ } else { ++ if (tags->is_deleted) { ++ memset(tag_buf, 0xff, 8); ++ tag_buf[8] = 0; ++ } else { ++ memcpy(tag_buf, &pt1, 8); ++ tag_buf[8] = 0xff; ++ } ++ } ++ ++ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, ++ data, ++ (data) ? dev->data_bytes_per_chunk : 0, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8); ++ ++ return retval; ++} ++ ++/* Return with empty extended tags but add ecc_result. ++ */ ++static int return_empty_tags(struct yaffs_ext_tags *tags, ++ enum yaffs_ecc_result ecc_result, ++ int retval) ++{ ++ if (tags) { ++ memset(tags, 0, sizeof(*tags)); ++ tags->ecc_result = ecc_result; ++ } ++ ++ return retval; ++} ++ ++static int yaffs_tags_compat_read(struct yaffs_dev *dev, ++ int nand_chunk, ++ u8 *data, ++ struct yaffs_ext_tags *tags) ++{ ++ struct yaffs_packed_tags1 pt1; ++ enum yaffs_ecc_result ecc_result; ++ int retval; ++ int deleted; ++ u8 tag_buf[9]; ++ ++ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, ++ data, dev->param.total_bytes_per_chunk, ++ tag_buf, ++ (dev->param.tags_9bytes) ? 9 : 8, ++ &ecc_result); ++ ++ switch (ecc_result) { ++ case YAFFS_ECC_RESULT_NO_ERROR: ++ case YAFFS_ECC_RESULT_FIXED: ++ break; ++ ++ case YAFFS_ECC_RESULT_UNFIXED: ++ default: ++ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); ++ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); ++ return YAFFS_FAIL; ++ } ++ ++ /* Check for a blank/erased chunk. */ ++ if (yaffs_check_ff(tag_buf, 8)) { ++ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, ++ YAFFS_OK); ++ } ++ ++ memcpy(&pt1, tag_buf, 8); ++ ++ if (!dev->param.tags_9bytes) { ++ /* Read deleted status (bit) then return it to it's non-deleted ++ * state before performing tags mini-ECC check. pt1.deleted is ++ * inverted. ++ */ ++ deleted = !pt1.deleted; ++ pt1.deleted = 1; ++ } else { ++ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; ++ } ++ ++ /* Check the packed tags mini-ECC and correct if necessary/possible. */ ++ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); ++ switch (retval) { ++ case 0: ++ /* no tags error, use MTD result */ ++ break; ++ case 1: ++ /* recovered tags-ECC error */ ++ dev->n_tags_ecc_fixed++; ++ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) ++ ecc_result = YAFFS_ECC_RESULT_FIXED; ++ break; ++ default: ++ /* unrecovered tags-ECC error */ ++ dev->n_tags_ecc_unfixed++; ++ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, ++ YAFFS_FAIL); ++ } ++ ++ /* Unpack the tags to extended form and set ECC result. ++ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] ++ */ ++ pt1.should_be_ff = 0xffffffff; ++ yaffs_unpack_tags1(tags, &pt1); ++ tags->ecc_result = ecc_result; ++ ++ /* Set deleted state */ ++ tags->is_deleted = deleted; ++ return YAFFS_OK; ++} ++ ++static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) ++{ ++ return dev->drv.drv_mark_bad_fn(dev, block_no); ++} ++ ++static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, ++ int block_no, ++ enum yaffs_block_state *state, ++ u32 *seq_number) ++{ ++ struct yaffs_ext_tags tags; ++ int retval; ++ ++ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); ++ ++ *seq_number = 0; ++ ++ retval = dev->drv.drv_check_bad_fn(dev, block_no); ++ if (retval == YAFFS_FAIL) { ++ *state = YAFFS_BLOCK_STATE_DEAD; ++ goto out; ++ } ++ ++ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, ++ NULL, &tags); ++ ++ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { ++ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", ++ block_no); ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else if (tags.chunk_used) { ++ *seq_number = tags.seq_number; ++ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; ++ } else { ++ *state = YAFFS_BLOCK_STATE_EMPTY; ++ } ++ ++ retval = YAFFS_OK; ++ ++out: ++ yaffs_trace(YAFFS_TRACE_MTD, ++ "block query returns seq %u state %d", ++ *seq_number, *state); ++ ++ return retval; ++} ++ ++void yaffs_tags_compat_install(struct yaffs_dev *dev) ++{ ++ if (dev->param.is_yaffs2) ++ return; ++ ++ if (!dev->tagger.write_chunk_tags_fn) ++ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; ++ ++ if (!dev->tagger.read_chunk_tags_fn) ++ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; ++ ++ if (!dev->tagger.query_block_fn) ++ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; ++ ++ if (!dev->tagger.mark_bad_fn) ++ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; ++} ++#endif diff --git a/target/linux/generic/patches-4.0/503-yaffs-3.12-convert-readdir-to-iterate.patch b/target/linux/generic/patches-4.0/503-yaffs-3.12-convert-readdir-to-iterate.patch deleted file mode 100644 index 586c141e0a..0000000000 --- a/target/linux/generic/patches-4.0/503-yaffs-3.12-convert-readdir-to-iterate.patch +++ /dev/null @@ -1,129 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -1701,6 +1701,110 @@ static void yaffs_remove_obj_callback(st - - /*-----------------------------------------------------------------*/ - -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) -+static int yaffs_readdir(struct file *file, struct dir_context *ctx) -+{ -+ struct yaffs_obj *obj; -+ struct yaffs_dev *dev; -+ struct yaffs_search_context *sc; -+ struct inode *inode = file->f_dentry->d_inode; -+ unsigned long offset, curoffs; -+ struct yaffs_obj *l; -+ int ret_val = 0; -+ -+ char name[YAFFS_MAX_NAME_LENGTH + 1]; -+ -+ obj = yaffs_dentry_to_obj(file->f_dentry); -+ dev = obj->my_dev; -+ -+ yaffs_gross_lock(dev); -+ -+ yaffs_dev_to_lc(dev)->readdir_process = current; -+ -+ offset = ctx->pos; -+ -+ sc = yaffs_new_search(obj); -+ if (!sc) { -+ ret_val = -ENOMEM; -+ goto out; -+ } -+ -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: starting at %d", (int)offset); -+ -+ if (offset == 0) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry . ino %d", -+ (int)inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (!dir_emit_dot(file, ctx)) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ ctx->pos++; -+ } -+ if (offset == 1) { -+ yaffs_trace(YAFFS_TRACE_OS, -+ "yaffs_readdir: entry .. ino %d", -+ (int)file->f_dentry->d_parent->d_inode->i_ino); -+ yaffs_gross_unlock(dev); -+ if (!dir_emit_dotdot(file, ctx)) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ yaffs_gross_lock(dev); -+ offset++; -+ ctx->pos++; -+ } -+ -+ curoffs = 1; -+ -+ /* If the directory has changed since the open or last call to -+ readdir, rewind to after the 2 canned entries. */ -+ if (file->f_version != inode->i_version) { -+ offset = 2; -+ ctx->pos = offset; -+ file->f_version = inode->i_version; -+ } -+ -+ while (sc->next_return) { -+ curoffs++; -+ l = sc->next_return; -+ if (curoffs >= offset) { -+ 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(ctx, name, strlen(name), -+ this_inode, this_type) < 0) { -+ yaffs_gross_lock(dev); -+ goto out; -+ } -+ -+ yaffs_gross_lock(dev); -+ -+ offset++; -+ ctx->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; -@@ -1807,10 +1911,15 @@ out: - - return ret_val; - } -+#endif - - static const struct file_operations yaffs_dir_operations = { - .read = generic_read_dir, -+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) -+ .iterate = yaffs_readdir, -+#else - .readdir = yaffs_readdir, -+#endif - .fsync = yaffs_sync_object, - .llseek = generic_file_llseek, - }; diff --git a/target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch b/target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch index 4858519ca1..9ecaa72832 100644 --- a/target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch +++ b/target/linux/generic/patches-4.0/503-yaffs-add-tags-9bytes-mount-option.patch @@ -4,7 +4,7 @@ Signed-off-by: Gabor Juhos --- --- a/fs/yaffs2/yaffs_vfs.c +++ b/fs/yaffs2/yaffs_vfs.c -@@ -2634,6 +2634,7 @@ static const struct super_operations yaf +@@ -2605,6 +2605,7 @@ static const struct super_operations yaf struct yaffs_options { int inband_tags; @@ -12,7 +12,7 @@ Signed-off-by: Gabor Juhos int skip_checkpoint_read; int skip_checkpoint_write; int no_cache; -@@ -2673,6 +2674,8 @@ static int yaffs_parse_options(struct ya +@@ -2644,6 +2645,8 @@ static int yaffs_parse_options(struct ya if (!strcmp(cur_opt, "inband-tags")) { options->inband_tags = 1; @@ -21,7 +21,7 @@ Signed-off-by: Gabor Juhos } else if (!strcmp(cur_opt, "tags-ecc-off")) { options->tags_ecc_on = 0; options->tags_ecc_overridden = 1; -@@ -2746,7 +2749,6 @@ static struct super_block *yaffs_interna +@@ -2717,7 +2720,6 @@ static struct super_block *yaffs_interna struct yaffs_param *param; int read_only = 0; @@ -29,7 +29,7 @@ Signed-off-by: Gabor Juhos struct yaffs_options options; -@@ -2786,6 +2788,9 @@ static struct super_block *yaffs_interna +@@ -2757,6 +2759,9 @@ static struct super_block *yaffs_interna memset(&options, 0, sizeof(options)); @@ -39,7 +39,7 @@ Signed-off-by: Gabor Juhos if (yaffs_parse_options(&options, data_str)) { /* Option parsing failed */ return NULL; -@@ -2819,17 +2824,22 @@ static struct super_block *yaffs_interna +@@ -2790,17 +2795,22 @@ static struct super_block *yaffs_interna } /* Added NCB 26/5/2006 for completeness */ @@ -68,7 +68,7 @@ Signed-off-by: Gabor Juhos return NULL; /* OK, so if we got here, we have an MTD that's NAND and looks -@@ -2890,7 +2900,8 @@ static struct super_block *yaffs_interna +@@ -2857,7 +2867,8 @@ static struct super_block *yaffs_interna param->n_reserved_blocks = 5; param->n_caches = (options.no_cache) ? 0 : 10; @@ -80,15 +80,7 @@ Signed-off-by: Gabor Juhos if (options.lazy_loading_overridden) --- a/fs/yaffs2/yaffs_mtdif.c +++ b/fs/yaffs2/yaffs_mtdif.c -@@ -16,6 +16,7 @@ - #include "yaffs_mtdif.h" - - #include "linux/mtd/mtd.h" -+#include "uapi/linux/major.h" - #include "linux/types.h" - #include "linux/time.h" - #include "linux/mtd/nand.h" -@@ -276,7 +277,8 @@ struct mtd_info * yaffs_get_mtd_device(d +@@ -278,7 +278,8 @@ struct mtd_info * yaffs_get_mtd_device(d return mtd; } @@ -98,7 +90,7 @@ Signed-off-by: Gabor Juhos { if (yaffs_version == 2) { if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE || -@@ -295,6 +297,12 @@ int yaffs_verify_mtd(struct mtd_info *mt +@@ -297,6 +298,12 @@ int yaffs_verify_mtd(struct mtd_info *mt ); return -1; } diff --git a/target/linux/generic/patches-4.0/504-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-4.0/504-yaffs-3.16-new-fops.patch new file mode 100644 index 0000000000..11c6da0516 --- /dev/null +++ b/target/linux/generic/patches-4.0/504-yaffs-3.16-new-fops.patch @@ -0,0 +1,25 @@ +--- a/fs/yaffs2/yaffs_vfs.c ++++ b/fs/yaffs2/yaffs_vfs.c +@@ -774,7 +774,21 @@ static int yaffs_sync_object(struct file + } + + +-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) ++static const struct file_operations yaffs_file_operations = { ++ .read = new_sync_read, ++ .read_iter = generic_file_read_iter, ++ .write = new_sync_write, ++ .write_iter = generic_file_write_iter, ++ .mmap = generic_file_mmap, ++ .flush = yaffs_file_flush, ++ .fsync = yaffs_sync_object, ++ .splice_read = generic_file_splice_read, ++ .splice_write = iter_file_splice_write, ++ .llseek = generic_file_llseek, ++}; ++ ++#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) + static const struct file_operations yaffs_file_operations = { + .read = do_sync_read, + .write = do_sync_write, diff --git a/target/linux/generic/patches-4.0/504-yaffs-fix-compat-tags-handling.patch b/target/linux/generic/patches-4.0/504-yaffs-fix-compat-tags-handling.patch deleted file mode 100644 index a18cf6fd7b..0000000000 --- a/target/linux/generic/patches-4.0/504-yaffs-fix-compat-tags-handling.patch +++ /dev/null @@ -1,239 +0,0 @@ -Subject: yaffs: fix compat tags handling - -Signed-off-by: Gabor Juhos ---- ---- a/fs/yaffs2/yaffs_tagscompat.c -+++ b/fs/yaffs2/yaffs_tagscompat.c -@@ -17,7 +17,9 @@ - #include "yaffs_getblockinfo.h" - #include "yaffs_trace.h" - -+#if 0 - static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); -+#endif - - - /********** Tags ECC calculations *********/ -@@ -71,6 +73,7 @@ int yaffs_check_tags_ecc(struct yaffs_ta - return 0; - } - -+#if 0 - /********** Tags **********/ - - static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, -@@ -379,3 +382,214 @@ void yaffs_tags_compat_install(struct ya - if(!dev->tagger.mark_bad_fn) - dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; - } -+#else -+ -+#include "yaffs_packedtags1.h" -+ -+static int yaffs_tags_compat_write(struct yaffs_dev *dev, -+ int nand_chunk, -+ const u8 *data, -+ const struct yaffs_ext_tags *tags) -+{ -+ struct yaffs_packed_tags1 pt1; -+ u8 tag_buf[9]; -+ int retval; -+ -+ /* we assume that yaffs_packed_tags1 and yaffs_tags are compatible */ -+ compile_time_assertion(sizeof(struct yaffs_packed_tags1) == 12); -+ compile_time_assertion(sizeof(struct yaffs_tags) == 8); -+ -+ yaffs_pack_tags1(&pt1, tags); -+ yaffs_calc_tags_ecc((struct yaffs_tags *)&pt1); -+ -+ /* When deleting a chunk, the upper layer provides only skeletal -+ * tags, one with is_deleted set. However, we need to update the -+ * tags, not erase them completely. So we use the NAND write property -+ * that only zeroed-bits stick and set tag bytes to all-ones and -+ * zero just the (not) deleted bit. -+ */ -+ if (!dev->param.tags_9bytes) { -+ if (tags->is_deleted) { -+ memset(&pt1, 0xff, 8); -+ /* clear delete status bit to indicate deleted */ -+ pt1.deleted = 0; -+ } -+ memcpy(tag_buf, &pt1, 8); -+ } else { -+ if (tags->is_deleted) { -+ memset(tag_buf, 0xff, 8); -+ tag_buf[8] = 0; -+ } else { -+ memcpy(tag_buf, &pt1, 8); -+ tag_buf[8] = 0xff; -+ } -+ } -+ -+ retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk, -+ data, -+ (data) ? dev->data_bytes_per_chunk : 0, -+ tag_buf, -+ (dev->param.tags_9bytes) ? 9 : 8); -+ -+ return retval; -+} -+ -+/* Return with empty extended tags but add ecc_result. -+ */ -+static int return_empty_tags(struct yaffs_ext_tags *tags, -+ enum yaffs_ecc_result ecc_result, -+ int retval) -+{ -+ if (tags) { -+ memset(tags, 0, sizeof(*tags)); -+ tags->ecc_result = ecc_result; -+ } -+ -+ return retval; -+} -+ -+static int yaffs_tags_compat_read(struct yaffs_dev *dev, -+ int nand_chunk, -+ u8 *data, -+ struct yaffs_ext_tags *tags) -+{ -+ struct yaffs_packed_tags1 pt1; -+ enum yaffs_ecc_result ecc_result; -+ int retval; -+ int deleted; -+ u8 tag_buf[9]; -+ -+ retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk, -+ data, dev->param.total_bytes_per_chunk, -+ tag_buf, -+ (dev->param.tags_9bytes) ? 9 : 8, -+ &ecc_result); -+ -+ switch (ecc_result) { -+ case YAFFS_ECC_RESULT_NO_ERROR: -+ case YAFFS_ECC_RESULT_FIXED: -+ break; -+ -+ case YAFFS_ECC_RESULT_UNFIXED: -+ default: -+ return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, 0); -+ tags->block_bad = dev->drv.drv_check_bad_fn(dev, nand_chunk); -+ return YAFFS_FAIL; -+ } -+ -+ /* Check for a blank/erased chunk. */ -+ if (yaffs_check_ff(tag_buf, 8)) { -+ /* when blank, upper layers want ecc_result to be <= NO_ERROR */ -+ return return_empty_tags(tags, YAFFS_ECC_RESULT_NO_ERROR, -+ YAFFS_OK); -+ } -+ -+ memcpy(&pt1, tag_buf, 8); -+ -+ if (!dev->param.tags_9bytes) { -+ /* Read deleted status (bit) then return it to it's non-deleted -+ * state before performing tags mini-ECC check. pt1.deleted is -+ * inverted. -+ */ -+ deleted = !pt1.deleted; -+ pt1.deleted = 1; -+ } else { -+ deleted = (hweight8(tag_buf[8]) < 7) ? 1 : 0; -+ } -+ -+ /* Check the packed tags mini-ECC and correct if necessary/possible. */ -+ retval = yaffs_check_tags_ecc((struct yaffs_tags *)&pt1); -+ switch (retval) { -+ case 0: -+ /* no tags error, use MTD result */ -+ break; -+ case 1: -+ /* recovered tags-ECC error */ -+ dev->n_tags_ecc_fixed++; -+ if (ecc_result == YAFFS_ECC_RESULT_NO_ERROR) -+ ecc_result = YAFFS_ECC_RESULT_FIXED; -+ break; -+ default: -+ /* unrecovered tags-ECC error */ -+ dev->n_tags_ecc_unfixed++; -+ return return_empty_tags(tags, YAFFS_ECC_RESULT_UNFIXED, -+ YAFFS_FAIL); -+ } -+ -+ /* Unpack the tags to extended form and set ECC result. -+ * [set should_be_ff just to keep yaffs_unpack_tags1 happy] -+ */ -+ pt1.should_be_ff = 0xffffffff; -+ yaffs_unpack_tags1(tags, &pt1); -+ tags->ecc_result = ecc_result; -+ -+ /* Set deleted state */ -+ tags->is_deleted = deleted; -+ return YAFFS_OK; -+} -+ -+static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no) -+{ -+ return dev->drv.drv_mark_bad_fn(dev, block_no); -+} -+ -+static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, -+ int block_no, -+ enum yaffs_block_state *state, -+ u32 *seq_number) -+{ -+ struct yaffs_ext_tags tags; -+ int retval; -+ -+ yaffs_trace(YAFFS_TRACE_MTD, "%s %d", __func__, block_no); -+ -+ *seq_number = 0; -+ -+ retval = dev->drv.drv_check_bad_fn(dev, block_no); -+ if (retval == YAFFS_FAIL) { -+ *state = YAFFS_BLOCK_STATE_DEAD; -+ goto out; -+ } -+ -+ yaffs_tags_compat_read(dev, block_no * dev->param.chunks_per_block, -+ NULL, &tags); -+ -+ if (tags.ecc_result != YAFFS_ECC_RESULT_NO_ERROR) { -+ yaffs_trace(YAFFS_TRACE_MTD, "block %d is marked bad", -+ block_no); -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; -+ } else if (tags.chunk_used) { -+ *seq_number = tags.seq_number; -+ *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; -+ } else { -+ *state = YAFFS_BLOCK_STATE_EMPTY; -+ } -+ -+ retval = YAFFS_OK; -+ -+out: -+ yaffs_trace(YAFFS_TRACE_MTD, -+ "block query returns seq %u state %d", -+ *seq_number, *state); -+ -+ return retval; -+} -+ -+void yaffs_tags_compat_install(struct yaffs_dev *dev) -+{ -+ if (dev->param.is_yaffs2) -+ return; -+ -+ if (!dev->tagger.write_chunk_tags_fn) -+ dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_write; -+ -+ if (!dev->tagger.read_chunk_tags_fn) -+ dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_read; -+ -+ if (!dev->tagger.query_block_fn) -+ dev->tagger.query_block_fn = yaffs_tags_compat_query_block; -+ -+ if (!dev->tagger.mark_bad_fn) -+ dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; -+} -+#endif diff --git a/target/linux/generic/patches-4.0/505-yaffs-3.16-new-fops.patch b/target/linux/generic/patches-4.0/505-yaffs-3.16-new-fops.patch deleted file mode 100644 index be88ab9525..0000000000 --- a/target/linux/generic/patches-4.0/505-yaffs-3.16-new-fops.patch +++ /dev/null @@ -1,32 +0,0 @@ ---- a/fs/yaffs2/yaffs_vfs.c -+++ b/fs/yaffs2/yaffs_vfs.c -@@ -794,15 +794,15 @@ static int yaffs_sync_object(struct file - - #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)) - static const struct file_operations yaffs_file_operations = { -- .read = do_sync_read, -- .write = do_sync_write, -- .aio_read = generic_file_aio_read, -- .aio_write = generic_file_aio_write, -+ .read = new_sync_read, -+ .write = new_sync_write, -+ .read_iter = generic_file_read_iter, -+ .write_iter = generic_file_write_iter, - .mmap = generic_file_mmap, - .flush = yaffs_file_flush, - .fsync = yaffs_sync_object, - .splice_read = generic_file_splice_read, -- .splice_write = generic_file_splice_write, -+ .splice_write = iter_file_splice_write, - .llseek = generic_file_llseek, - }; - -@@ -1050,7 +1050,7 @@ static int yaffs_readlink(struct dentry - if (!alias) - return -ENOMEM; - -- ret = vfs_readlink(dentry, buffer, buflen, alias); -+ ret = readlink_copy(buffer, buflen, alias); - kfree(alias); - return ret; - }