nand flash作为市面上最主要的非易失性闪存技术之一,应用在各种固态大容量存储解决方案中。由于nand flash自身的特点,nand存储器往往需要一款专用的nand文件系统进行管理。开源的yaffs文件系统由于其优异的性能,在nand flash中受到广泛的应用。

1. yaffs文件系统

从yaffs官网下载最新的yaffs源码,进入到yaffs目录,给Linux内核加上yaffs文件系统补丁。

  1. ./patch-ker.sh c m /usr/linux-4.10.10

由于yaffs滞后于Linux内核以及自身更新的不同步,编译yaffs将会产生较多的错误。此处根据linux-4.10.10内核编译错误进行更改,大部分是更改yaffs与Linux内核的接口文件yaffs_vfs.c。

1.1. 编译归类一

  1. fs/yaffs2/yaffs_vfs.c:423:13: error: 'PAGE_CACHE_SIZE'undeclared (first use in this function)
  2. n_bytes = PAGE_CACHE_SIZE;
  3. fs/yaffs2/yaffs_vfs.c: In function'yaffs_write_begin':
  4. fs/yaffs2/yaffs_vfs.c:525:25: error:'PAGE_CACHE_SHIFT' undeclared (first use in this function)
  5. pgoff_t index = pos >> PAGE_CACHE_SHIFT;
  6. fs/yaffs2/yaffs_vfs.c:574:3: error:implicit declaration of function 'page_cache_release'[-Werror=implicit-function-declaration]
  7. page_cache_release(pg);

内核不再在中定义PAGE_CACHE_SHIFT、PAGE_CACHE_SIZE、page_cache_release,在yaffs_vfs.c中加入宏定义。

  1. +#define PAGE_CACHE_SHIFT PAGE_SHIFT
  2. +#define PAGE_CACHE_SIZE PAGE_SIZE
  3. +#define page_cache_release(page) put_page(page)

1.2. 编译归类二

  1. fs/yaffs2/yaffs_vfs.c: In function'yaffs_readpage_nolock':
  2. fs/yaffs2/yaffs_vfs.c:294:29: error:'struct file' has no member named 'f_dentry'
  3. obj = yaffs_dentry_to_obj(f->f_dentry);

内核struct file结构体的更改,在yaffs_vfs.c中更改f_dentry的定义。

  1. +#define f_dentry f_path.dentry

1.3. 编译归类三

  1. fs/yaffs2/yaffs_vfs.c: At top level:
  2. fs/yaffs2/yaffs_vfs.c:789:10: error:'new_sync_read' undeclared here (not in a function)
  3. .read = new_sync_read,
  4. fs/yaffs2/yaffs_vfs.c:790:11: error:'new_sync_write' undeclared here (not in a function)
  5. .write = new_sync_write,

内核不再有new_sync_read、new_sync_write接口,不再需要file_operations的.read、.write接口,同样注释yaffs_file_operations的.read,.write接口。

  1. - .read= new_sync_read,
  2. - .write= new_sync_write,

1.4. 编译归类四

  1. fs/yaffs2/yaffs_vfs.c: At top level:
  2. fs/yaffs2/yaffs_vfs.c:1047:2: error:unknown field 'setxattr' specified in initializer
  3. .setxattr = yaffs_setxattr,
  4. ^
  5. fs/yaffs2/yaffs_vfs.c:1047:2: warning:initialization from incompatible pointer type [enabled by default]
  6. fs/yaffs2/yaffs_vfs.c:1047:2: warning:(near initialization for 'yaffs_file_inode_operations.getattr') [enabled bydefault]
  7. fs/yaffs2/yaffs_vfs.c:1048:2: error:unknown field 'getxattr' specified in initializer
  8. .getxattr = yaffs_getxattr,
  9. ^
  10. fs/yaffs2/yaffs_vfs.c:1048:2: warning:initialization from incompatible pointer type [enabled by default]
  11. fs/yaffs2/yaffs_vfs.c:1048:2: warning:(near initialization for 'yaffs_file_inode_operations.listxattr') [enabled bydefault]
  12. fs/yaffs2/yaffs_vfs.c:1050:2: error:unknown field 'removexattr' specified in initializer
  13. .removexattr = yaffs_removexattr,

内核struct inode_operations结构体移除了.setxattr、.getxattr、.removexattr接口,注释掉.setxattr、 .getxattr、 .removexattr,更改yaffs使用通用的xattr处理,并更改yaffs_setxattr、yaffs_getxattr的接口定义。

  1. -static int yaffs_setxattr(struct dentry*dentry, const char *name,
  2. +
  3. +static int yaffs_setxattr(struct dentry*dentry, struct inode *node, const char *name,
  4. const void *value, size_t size, int flags)
  5. {
  6. struct inode *inode = dentry->d_inode;
  7. @@ -941,8 +948,9 @@
  8. return error;
  9. }
  10. -static ssize_t yaffs_getxattr(structdentry * dentry, const char *name,
  11. - void*buff, size_t size)
  12. +
  13. +static ssize_t yaffs_getxattr(structdentry * dentry, struct inode *node,
  14. + constchar *name, void *buff, size_t size)
  15. {
  16. struct inode *inode = dentry->d_inode;
  17. int error = 0;
  18. @@ -1016,13 +1024,39 @@
  19. return error;
  20. }
  21. +static int yaffs_xattr_get(const structxattr_handler *handler,
  22. + structdentry *dentry, struct inode *inode,
  23. + constchar *name, void *buff, size_t size)
  24. +{
  25. + returnyaffs_getxattr(dentry, inode, name, buff, size);
  26. +}
  27. +
  28. +static int yaffs_xattr_set(const structxattr_handler *handler,
  29. + structdentry *dentry, struct inode *inode,
  30. + constchar *name, const void *value, size_t size,
  31. + intflags)
  32. +{
  33. + if(value)
  34. + returnyaffs_setxattr(dentry, inode, name, value, size, flags);
  35. + else
  36. + returnyaffs_removexattr(dentry, name);
  37. +}
  38. +
  39. +static const struct xattr_handleryaffs_xattr_handler = {
  40. + .prefix= "", /* match anything */
  41. + .get= yaffs_xattr_get,
  42. + .set= yaffs_xattr_set,
  43. +};
  44. +
  45. +static const struct xattr_handler*yaffs_xattr_handlers[] = {
  46. + &yaffs_xattr_handler,
  47. + NULL
  48. +};
  49. +
  50. static const struct inode_operationsyaffs_file_inode_operations = {
  51. .setattr = yaffs_setattr,
  52. - .setxattr= yaffs_setxattr,
  53. - .getxattr= yaffs_getxattr,
  54. .listxattr = yaffs_listxattr,
  55. - .removexattr= yaffs_removexattr,
  56. };
  57. /*-----------------------------------------------------------------*/
  58. @@ -2783,6 +2796,7 @@
  59. sb->s_magic = YAFFS_MAGIC;
  60. sb->s_op = &yaffs_super_ops;
  61. + sb->s_xattr= yaffs_xattr_handlers;
  62. 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. 编译归类六

  1. fs/yaffs2/yaffs_vfs.c:1050:2: warning:initialization from incompatible pointer type [enabled by default]
  2. fs/yaffs2/yaffs_vfs.c:1050:2: warning:(near initialization for 'yaffs_file_inode_operations.fiemap') [enabled bydefault]
  3. fs/yaffs2/yaffs_vfs.c: In function'yaffs_follow_link':
  4. fs/yaffs2/yaffs_vfs.c:1103:2: error:implicit declaration of function 'nd_set_link' [-Werror=implicit-function-declaration]
  5. nd_set_link(nd, alias);
  6. ^
  7. fs/yaffs2/yaffs_vfs.c: At top level:
  8. fs/yaffs2/yaffs_vfs.c:1143:2: error:unknown field 'follow_link' specified in initializer
  9. .follow_link = yaffs_follow_link,
  10. ^
  11. fs/yaffs2/yaffs_vfs.c:1143:2: warning:initialization from incompatible pointer type [enabled by default]
  12. fs/yaffs2/yaffs_vfs.c:1143:2: warning:(near initialization for 'yaffs_symlink_inode_operations.create') [enabled bydefault]
  13. fs/yaffs2/yaffs_vfs.c:1145:2: error:unknown field 'put_link' specified in initializer
  14. .put_link = yaffs_put_link,
  15. struct inode_operations结构体中,内核用.get_link替代.follow_link/.put_link
  16. -#if (YAFFS_NEW_FOLLOW_LINK == 1)
  17. -static void *yaffs_follow_link(structdentry *dentry, struct nameidata *nd)
  18. +static const char*yaffs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call*done)
  19. {
  20. void *ret;
  21. -#else
  22. -static int yaffs_follow_link(structdentry *dentry, struct nameidata *nd)
  23. -{
  24. - intret
  25. -#endif
  26. +
  27. unsigned char *alias;
  28. int ret_int = 0;
  29. - structyaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
  30. + structyaffs_dev *dev;
  31. - yaffs_gross_lock(dev);
  32. + if(!dentry)
  33. + returnERR_PTR(-ECHILD);
  34. + dev= yaffs_dentry_to_obj(dentry)->my_dev;
  35. +
  36. + yaffs_gross_lock(dev);
  37. alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
  38. yaffs_gross_unlock(dev);
  39. @@ -1074,24 +1107,14 @@
  40. ret_int = -ENOMEM;
  41. goto out;
  42. }
  43. -#if (YAFFS_NEW_FOLLOW_LINK == 1)
  44. - nd_set_link(nd,alias);
  45. + set_delayed_call(done,kfree_link, alias);
  46. ret = alias;
  47. out:
  48. if (ret_int)
  49. ret = ERR_PTR(ret_int);
  50. return ret;
  51. -#else
  52. - ret= vfs_follow_link(nd, alias);
  53. - kfree(alias);
  54. -out:
  55. - if(ret_int)
  56. - ret= ret_int;
  57. - returnret;
  58. -#endif
  59. }
  60. static const struct inode_operationsyaffs_symlink_inode_operations = {
  61. .readlink = yaffs_readlink,
  62. - .follow_link= yaffs_follow_link,
  63. -#if (YAFFS_NEW_FOLLOW_LINK == 1)
  64. - .put_link= yaffs_put_link,
  65. -#endif
  66. + .get_link= yaffs_get_link,
  67. .setattr = yaffs_setattr,
  68. - .setxattr= yaffs_setxattr,
  69. - .getxattr= yaffs_getxattr,
  70. .listxattr = yaffs_listxattr,
  71. - .removexattr= yaffs_removexattr,
  72. };

1.7. 编译归类七

  1. fs/yaffs2/yaffs_vfs.c:1606:2: warning:initialization from incompatible pointer type [enabled by default]
  2. .rename= yaffs_rename,

内核rename接口定义的变更,rename包含rename2操作。

  1. static int yaffs_rename(struct inode*old_dir, struct dentry *old_dentry,
  2. - structinode *new_dir, struct dentry *new_dentry)
  3. + structinode *new_dir, struct dentry *new_dentry,
  4. + unsignedint flags)
  5. {
  6. struct yaffs_dev *dev;
  7. int ret_val = YAFFS_FAIL;
  8. struct yaffs_obj *target;
  9. + if(flags)
  10. + return-EINVAL;
  11. +
  12. yaffs_trace(YAFFS_TRACE_OS,"yaffs_rename");

1.8. 编译归类八

  1. In file included fromfs/yaffs2/yaffs_guts.c:18:0:
  2. fs/yaffs2/yaffs_endian.h:32:1: error:unknown type name 'Y_LOFF_T'
  3. static inline Y_LOFF_T swap_loff_t(Y_LOFF_Tlval)
  4. ^
  5. fs/yaffs2/yaffs_endian.h:32:36: error:unknown type name 'Y_LOFF_T'
  6. static inline Y_LOFF_T swap_loff_t(Y_LOFF_Tlval)

未定义Y_LOFF_T,在yaffs_endian.h中加入Y_LOFF_T的定义。

  1. #ifndef Y_LOFF_T
  2. #define Y_LOFF_T loff_t
  3. #endif

1.9. 编译归类九

  1. fs/yaffs2/yaffs_nameval.c:145:5: error:conflicting types for 'nval_get'
  2. int nval_get(struct yaffs_dev *dev,
  3. ^
  4. In file included fromfs/yaffs2/yaffs_nameval.c:28:0:
  5. fs/yaffs2/yaffs_nameval.h:25:5: note:previous declaration of 'nval_get' was here
  6. int nval_get(struct yaffs_dev *dev,
  7. ^
  8. fs/yaffs2/yaffs_nameval.c:185:5: error:conflicting types for 'nval_list'
  9. int nval_list(struct yaffs_dev *dev, constchar *xb, int xb_size, char *buf, int bsize)
  10. ^
  11. In file included from fs/yaffs2/yaffs_nameval.c:28:0:
  12. fs/yaffs2/yaffs_nameval.h:28:5: note:previous declaration of 'nval_list' was here
  13. int nval_list(struct yaffs_dev *dev,

头文件声明的错误,在yaffs_nameval.h中加入yaffs_guts.h头文件。

  1. #include "yaffs_guts.h"

1.10. 编译归类十

  1. fs/built-in.o: In function `yaffs_check_obj_details_loaded':
  2. /usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:3254:undefined reference to `yaffs_do_endian_oh'
  3. fs/built-in.o: In function`yaffs_oh_size_load':
  4. /usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:5165:undefined reference to `yaffs_do_endian_u32'
  5. /usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:5166:undefined reference to `yaffs_do_endian_u32'
  6. fs/built-in.o: In function`yaffs_update_oh':
  7. /usr/linux-4.10.10/fs/yaffs2/yaffs_guts.c:3401:undefined reference to `yaffs_do_endian_oh'

链接错误,Makefile中加入yaffs_endian.o

  1. yaffs-y += yaffs_endian.o

2. 内核配置

Linux配置支持yaffs文件系统,选中File systems->Miscellaneousfilesystems->yaffs2 file system support。

17_YAFFS文件系统 - 图1

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目录下。

  1. 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系统。

17_YAFFS文件系统 - 图2