nand flash作为市面上最主要的非易失性闪存技术之一,应用在各种固态大容量存储解决方案中。由于nand flash自身的特点,nand存储器往往需要一款专用的nand文件系统进行管理。开源的yaffs文件系统由于其优异的性能,在nand flash中受到广泛的应用。
1. yaffs文件系统
从yaffs官网下载最新的yaffs源码,进入到yaffs目录,给Linux内核加上yaffs文件系统补丁。
./patch-ker.sh c m /usr/linux-4.10.10
由于yaffs滞后于Linux内核以及自身更新的不同步,编译yaffs将会产生较多的错误。此处根据linux-4.10.10内核编译错误进行更改,大部分是更改yaffs与Linux内核的接口文件yaffs_vfs.c。
1.1. 编译归类一
fs/yaffs2/yaffs_vfs.c:423:13: error: 'PAGE_CACHE_SIZE'undeclared (first use in this function)
n_bytes = PAGE_CACHE_SIZE;
^
fs/yaffs2/yaffs_vfs.c: In function'yaffs_write_begin':
fs/yaffs2/yaffs_vfs.c:525:25: error:'PAGE_CACHE_SHIFT' undeclared (first use in this function)
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
^
fs/yaffs2/yaffs_vfs.c:574:3: error:implicit declaration of function 'page_cache_release'[-Werror=implicit-function-declaration]
page_cache_release(pg);
内核不再在<linux/pagemap.h>中定义PAGE_CACHE_SHIFT、PAGE_CACHE_SIZE、page_cache_release,在yaffs_vfs.c中加入宏定义。
+#define PAGE_CACHE_SHIFT PAGE_SHIFT
+#define PAGE_CACHE_SIZE PAGE_SIZE
+#define page_cache_release(page) put_page(page)
1.2. 编译归类二
fs/yaffs2/yaffs_vfs.c: In function'yaffs_readpage_nolock':
fs/yaffs2/yaffs_vfs.c:294:29: error:'struct file' has no member named 'f_dentry'
obj = yaffs_dentry_to_obj(f->f_dentry);
内核struct file结构体的更改,在yaffs_vfs.c中更改f_dentry的定义。
+#define f_dentry f_path.dentry
1.3. 编译归类三
fs/yaffs2/yaffs_vfs.c: At top level:
fs/yaffs2/yaffs_vfs.c:789:10: error:'new_sync_read' undeclared here (not in a f
unction)
.read = new_sync_read,
fs/yaffs2/yaffs_vfs.c:790:11: error:'new_sync_write' undeclared here (not in a
function)
.write = new_sync_write,
内核不再有new_sync_read、new_sync_write接口,不再需要file_operations的.read、.write接口,同样注释yaffs_file_operations的.read,.write接口。
- .read= new_sync_read,
- .write= new_sync_write,
1.4. 编译归类四
fs/yaffs2/yaffs_vfs.c: At top level:
fs/yaffs2/yaffs_vfs.c:1047:2: error:unknown field 'setxattr' specified in initializer
.setxattr = yaffs_setxattr,
^
fs/yaffs2/yaffs_vfs.c:1047:2: warning:initialization from incompatible pointer type [enabled by default]
fs/yaffs2/yaffs_vfs.c:1047:2: warning:(near initialization for 'yaffs_file_inode_operations.getattr') [enabled bydefault]
fs/yaffs2/yaffs_vfs.c:1048:2: error:unknown field 'getxattr' specified in initializer
.getxattr = yaffs_getxattr,
^
fs/yaffs2/yaffs_vfs.c:1048:2: warning:initialization from incompatible pointer type [enabled by default]
fs/yaffs2/yaffs_vfs.c:1048:2: warning:(near initialization for 'yaffs_file_inode_operations.listxattr') [enabled bydefault]
fs/yaffs2/yaffs_vfs.c:1050:2: error:unknown field 'removexattr' specified in initializer
.removexattr = yaffs_removexattr,
内核struct inode_operations结构体移除了.setxattr、.getxattr、.removexattr接口,注释掉.setxattr、 .getxattr、 .removexattr,更改yaffs使用通用的xattr处理,并更改yaffs_setxattr、yaffs_getxattr的接口定义。
-static int yaffs_setxattr(struct dentry*dentry, const char *name,
+
+static int yaffs_setxattr(struct dentry*dentry, struct inode *node, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
@@ -941,8 +948,9 @@
return error;
}
-static ssize_t yaffs_getxattr(structdentry * dentry, const char *name,
- void*buff, size_t size)
+
+static ssize_t yaffs_getxattr(structdentry * dentry, struct inode *node,
+ constchar *name, void *buff, size_t size)
{
struct inode *inode = dentry->d_inode;
int error = 0;
@@ -1016,13 +1024,39 @@
return error;
}
+static int yaffs_xattr_get(const structxattr_handler *handler,
+ structdentry *dentry, struct inode *inode,
+ constchar *name, void *buff, size_t size)
+{
+ returnyaffs_getxattr(dentry, inode, name, buff, size);
+}
+
+static int yaffs_xattr_set(const structxattr_handler *handler,
+ structdentry *dentry, struct inode *inode,
+ constchar *name, const void *value, size_t size,
+ intflags)
+{
+ if(value)
+ returnyaffs_setxattr(dentry, inode, name, value, size, flags);
+ else
+ returnyaffs_removexattr(dentry, name);
+}
+
+static const struct xattr_handleryaffs_xattr_handler = {
+ .prefix= "", /* match anything */
+ .get= yaffs_xattr_get,
+ .set= yaffs_xattr_set,
+};
+
+static const struct xattr_handler*yaffs_xattr_handlers[] = {
+ &yaffs_xattr_handler,
+ NULL
+};
+
static const struct inode_operationsyaffs_file_inode_operations = {
.setattr = yaffs_setattr,
- .setxattr= yaffs_setxattr,
- .getxattr= yaffs_getxattr,
.listxattr = yaffs_listxattr,
- .removexattr= yaffs_removexattr,
};
/*-----------------------------------------------------------------*/
@@ -2783,6 +2796,7 @@
sb->s_magic = YAFFS_MAGIC;
sb->s_op = &yaffs_super_ops;
+ sb->s_xattr= yaffs_xattr_handlers;
sb->s_flags |= MS_NOATIME;
1.5. 编译归类五
fs/yaffs2/yaffs_vfs.c: In function'yaffs_setattr':
fs/yaffs2/yaffs_vfs.c:898:3: error:implicit declaration of function 'inode_change_ok'[-Werror=implicit-function-declaration]
error = inode_change_ok(inode, attr);
内核用setattr_prepare()替代inode_change_ok()。
- error= inode_change_ok(inode, attr);
+ error= setattr_prepare(dentry, attr);
1.6. 编译归类六
fs/yaffs2/yaffs_vfs.c:1050:2: warning:initialization from incompatible pointer type [enabled by default]
fs/yaffs2/yaffs_vfs.c:1050:2: warning:(near initialization for 'yaffs_file_inode_operations.fiemap') [enabled bydefault]
fs/yaffs2/yaffs_vfs.c: In function'yaffs_follow_link':
fs/yaffs2/yaffs_vfs.c:1103:2: error:implicit declaration of function 'nd_set_link' [-Werror=implicit-function-declaration]
nd_set_link(nd, alias);
^
fs/yaffs2/yaffs_vfs.c: At top level:
fs/yaffs2/yaffs_vfs.c:1143:2: error:unknown field 'follow_link' specified in initializer
.follow_link = yaffs_follow_link,
^
fs/yaffs2/yaffs_vfs.c:1143:2: warning:initialization from incompatible pointer type [enabled by default]
fs/yaffs2/yaffs_vfs.c:1143:2: warning:(near initialization for 'yaffs_symlink_inode_operations.create') [enabled bydefault]
fs/yaffs2/yaffs_vfs.c:1145:2: error:unknown field 'put_link' specified in initializer
.put_link = yaffs_put_link,
struct inode_operations结构体中,内核用.get_link替代.follow_link/.put_link。
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
-static void *yaffs_follow_link(structdentry *dentry, struct nameidata *nd)
+static const char*yaffs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call*done)
{
void *ret;
-#else
-static int yaffs_follow_link(structdentry *dentry, struct nameidata *nd)
-{
- intret
-#endif
+
unsigned char *alias;
int ret_int = 0;
- structyaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
+ structyaffs_dev *dev;
- yaffs_gross_lock(dev);
+ if(!dentry)
+ returnERR_PTR(-ECHILD);
+ dev= yaffs_dentry_to_obj(dentry)->my_dev;
+
+ yaffs_gross_lock(dev);
alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
yaffs_gross_unlock(dev);
@@ -1074,24 +1107,14 @@
ret_int = -ENOMEM;
goto out;
}
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
- nd_set_link(nd,alias);
+ set_delayed_call(done,kfree_link, alias);
ret = alias;
out:
if (ret_int)
ret = ERR_PTR(ret_int);
return ret;
-#else
- ret= vfs_follow_link(nd, alias);
- kfree(alias);
-out:
- if(ret_int)
- ret= ret_int;
- returnret;
-#endif
}
static const struct inode_operationsyaffs_symlink_inode_operations = {
.readlink = yaffs_readlink,
- .follow_link= yaffs_follow_link,
-#if (YAFFS_NEW_FOLLOW_LINK == 1)
- .put_link= yaffs_put_link,
-#endif
+ .get_link= yaffs_get_link,
.setattr = yaffs_setattr,
- .setxattr= yaffs_setxattr,
- .getxattr= yaffs_getxattr,
.listxattr = yaffs_listxattr,
- .removexattr= yaffs_removexattr,
};
1.7. 编译归类七
fs/yaffs2/yaffs_vfs.c:1606:2: warning:initialization from incompatible pointer type [enabled by default]
.rename= yaffs_rename,
内核rename接口定义的变更,rename包含rename2操作。
static int yaffs_rename(struct inode*old_dir, struct dentry *old_dentry,
- structinode *new_dir, struct dentry *new_dentry)
+ structinode *new_dir, struct dentry *new_dentry,
+ unsignedint flags)
{
struct yaffs_dev *dev;
int ret_val = YAFFS_FAIL;
struct yaffs_obj *target;
+ if(flags)
+ return-EINVAL;
+
yaffs_trace(YAFFS_TRACE_OS,"yaffs_rename");
1.8. 编译归类八
In file included fromfs/yaffs2/yaffs_guts.c:18:0:
fs/yaffs2/yaffs_endian.h:32:1: error:unknown type name 'Y_LOFF_T'
static inline Y_LOFF_T swap_loff_t(Y_LOFF_Tlval)
^
fs/yaffs2/yaffs_endian.h:32:36: error:unknown type name 'Y_LOFF_T'
static inline Y_LOFF_T swap_loff_t(Y_LOFF_Tlval)
未定义Y_LOFF_T,在yaffs_endian.h中加入Y_LOFF_T的定义。
#ifndef Y_LOFF_T
#define Y_LOFF_T loff_t
#endif
1.9. 编译归类九
fs/yaffs2/yaffs_nameval.c:145:5: error:conflicting types for 'nval_get'
int nval_get(struct yaffs_dev *dev,
^
In file included fromfs/yaffs2/yaffs_nameval.c:28:0:
fs/yaffs2/yaffs_nameval.h:25:5: note:previous declaration of 'nval_get' was here
int nval_get(struct yaffs_dev *dev,
^
fs/yaffs2/yaffs_nameval.c:185:5: error:conflicting types for 'nval_list'
int nval_list(struct yaffs_dev *dev, constchar *xb, int xb_size, char *buf, int bsize)
^
In file included from fs/yaffs2/yaffs_nameval.c:28:0:
fs/yaffs2/yaffs_nameval.h:28:5: note:previous declaration of 'nval_list' was here
int nval_list(struct yaffs_dev *dev,
头文件声明的错误,在yaffs_nameval.h中加入yaffs_guts.h头文件。
#include "yaffs_guts.h"
1.10. 编译归类十
fs/built-in.o: In function `yaffs_check_obj_details_loaded':
/usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:3254:undefined reference to `yaffs_do_endian_oh'
fs/built-in.o: In function`yaffs_oh_size_load':
/usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:5165:undefined reference to `yaffs_do_endian_u32'
/usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:5166:undefined reference to `yaffs_do_endian_u32'
fs/built-in.o: In function`yaffs_update_oh':
/usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:3401:undefined reference to `yaffs_do_endian_oh'
链接错误,Makefile中加入yaffs_endian.o
yaffs-y += yaffs_endian.o
2. 内核配置
Linux配置支持yaffs文件系统,选中File systems->Miscellaneousfilesystems->yaffs2 file system support。
3. mkyaffs2image
yaffs源码包中附带了mkyaffs2image工具,mkyaffs2image工具可以把主机的某一目录内容制作成nandflash烧录镜像文件。在主机上进行编译mkyaffs2image工具时,同样会编译错误,这是工具源码与yaffs源码更新不同步,造成接口上的差异,根据错误提示更改即可。默认的mkyaffs2image工具没有ecc layout信息,一般不在mkyaffs2image工具中修改相应的ecc layout信息,由bootloader固化时更正相应的ecc layout。
./mkyaffs2image /root/rootfs/busybox rootfs.bin
4. 固化启动
笔者的bootloader可以实现从sd卡更新bootloader、内核、根文件系统。
更改bootloader的启动参数,使之从nandflash挂载根文件系统,编译并把生成的二进制代码文件重命名为bootloader.bin放在sd卡/image目录下。
const char BootCmd[] = "noinitrd root=/dev/mtdblock3rootfstype=yaffs2 init=/init console=ttySAC0";
更改Linux内核的配置,取消initramfs根文件系统,重新编译,生成的zImage重命名为kernel.bin放在sd卡/image目录下。
mkyaffs2image工具制作的yaffs根文件系统镜像文件rootfs.bin放在sd卡/image目录下。
通过串口,按住空格键上电启动,bootloader将进入到下载模式,选择从sd卡更新bootloader、kernel、rootfs到nand flash。
从nand flash启动Linux系统。
5. 附录
https://pan.baidu.com/s/1slczwhJ
bootloader源码以及使用说明
https://pan.baidu.com/s/1eRDJtNs
Qt5.8官网源码
https://pan.baidu.com/s/1nuGmSqt
本系列例程的根文件系统
https://pan.baidu.com/s/1i5btLGT
opev3.2.0官网源码
https://pan.baidu.com/s/1pLpuHw3
yaffs官网源码
https://pan.baidu.com/s/1bpkZynt
busybox-1.26.2官网源码
https://pan.baidu.com/s/1i4EtjfR
tslib官网源码
https://pan.baidu.com/s/1i5MGRhb
mplayer-1.3.0官网源码
https://pan.baidu.com/s/1sl0fXlr
基于S3C2416修改的linux-4.10.10源码