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);
内核不再在
+#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 function).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 hereint 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 hereint 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系统。

