('entity_view:node:345:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0uSLUFkJuGZhldH2THc3q7dZ6XBZMRtzCzhQYhx4AjYM','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:3076:\"<article role=\"article\" about=\"/yaffs-gpl-licence\" typeof=\"schema:WebPage\" class=\"page full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs - GPL Licence\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p>Yaffs is the property of Aleph One Limited.</p>\n<ul>\n<li>Yaffs is <a href=\"/get-yaffs\">available free of charge</a> under the <a href=\"http://www.gnu.org/copyleft/gpl.html\" target=\"_self\" title=\"Gnu Public Licence\">GNU General Public Licence,</a>&nbsp;version 2 (GPL).</li>\n<li>Linking Yaffs to other software creates a derived work and our&nbsp;interpretation of linking includes dynamic and runtime linking;&nbsp;any use of Yaffs creates a derived work.&nbsp;</li>\n<li>Under the GPL, you can test Yaffs with your product on your computers. Do not distribute this test version unless your product is normally licensed under the GPL. If you do not copy and distribute it, there are no requirement under the GPL regarding distribution of a derived work.&nbsp;&nbsp;</li>\n<li>Under the terms of the GPL, derived works must be licensed using the GPL, unless&nbsp;you have a <a href=\"/commercial-licences\">Commercial Licence</a> for Yaffs.</li>\n<li>When you distribute GPLed object code you must make the full source code available too, to anyone who uses your product.&nbsp;(Sections 3.a and 3.b of the GPL, and the sections that follow.)&nbsp;&nbsp;</li>\n</ul>\n<p>Circumstances where you need to licence Yaffs other than under the GPL include:-</p>\n<ul>\n<li>If you want to use Yaffs, but want to distribute your code under your licence.</li>\n<li>If you want to run a statically-linked commercial RTOS on top of a Yaffs filesystem.</li>\n<li>if you want to sublicence Yaffs to your customers (under terms other than the GPL).</li>\n<li>If you want to use Yaffs with WindowsCE version 4.&nbsp;WinCE version 3 can use GPL code but WinCE v.4 and later need an additional filesystem interface layer which is not part of Yaffs. This is available at extra cost; please contact us.</li>\n</ul>\n<p>In these cases, our <a href=\"/commercial-licences\">Commercial Licence</a> is appropriate.</p>\n<p>If you aren\'t sure whether your needs will be covered by the GPL version, <a href=\"/contact\">get in touch with us</a>.</p>\n<h2>Support</h2>\n<p>While Yaffs is released under GPL we can provide standard support options, consulting in its application to your particular product, or development of specific features to suit your needs or hardware.&nbsp;</p>\n<h2>Helping us to improve Yaffs</h2>\n<p>Although the code is downloadable at no charge, buying this product allows you to express your appreciation of Yaffs. Alternatively you can make a Donation to Aleph One Ltd via PayPal. You can do this at <a href=\"http://www.paypal.com\" target=\"_blank\" title=\"PayPal\">PayPal </a>by sending any sum to <a href=\"denied:mailto:sales@aleph1.co.uk\">sales@aleph1.co.uk</a>&nbsp; We shall appreciate it!</p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:18:\"/yaffs-gpl-licence\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/345\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:18:\"/yaffs-gpl-licence\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:345\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:56:\"<span property=\"schema:name\">Yaffs - GPL Licence</span>\n\";}}',-1,1504768313.766,1,'config:filter.format.full_html config:system.site node:345 node_view rendered user:4','306'),('entity_view:node:345:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"345\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:345\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504768313.763,1,'config:filter.format.full_html config:system.site node:345 node_view rendered user:4','306'),('entity_view:node:345:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:2882:\"<span property=\"schema:name\">Yaffs - GPL Licence</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p>Yaffs is the property of Aleph One Limited.</p>\n<ul>\n<li>Yaffs is <a href=\"/get-yaffs\">available free of charge</a> under the <a href=\"http://www.gnu.org/copyleft/gpl.html\" target=\"_self\" title=\"Gnu Public Licence\">GNU General Public Licence,</a>&nbsp;version 2 (GPL).</li>\n<li>Linking Yaffs to other software creates a derived work and our&nbsp;interpretation of linking includes dynamic and runtime linking;&nbsp;any use of Yaffs creates a derived work.&nbsp;</li>\n<li>Under the GPL, you can test Yaffs with your product on your computers. Do not distribute this test version unless your product is normally licensed under the GPL. If you do not copy and distribute it, there are no requirement under the GPL regarding distribution of a derived work.&nbsp;&nbsp;</li>\n<li>Under the terms of the GPL, derived works must be licensed using the GPL, unless&nbsp;you have a <a href=\"/commercial-licences\">Commercial Licence</a> for Yaffs.</li>\n<li>When you distribute GPLed object code you must make the full source code available too, to anyone who uses your product.&nbsp;(Sections 3.a and 3.b of the GPL, and the sections that follow.)&nbsp;&nbsp;</li>\n</ul>\n<p>Circumstances where you need to licence Yaffs other than under the GPL include:-</p>\n<ul>\n<li>If you want to use Yaffs, but want to distribute your code under your licence.</li>\n<li>If you want to run a statically-linked commercial RTOS on top of a Yaffs filesystem.</li>\n<li>if you want to sublicence Yaffs to your customers (under terms other than the GPL).</li>\n<li>If you want to use Yaffs with WindowsCE version 4.&nbsp;WinCE version 3 can use GPL code but WinCE v.4 and later need an additional filesystem interface layer which is not part of Yaffs. This is available at extra cost; please contact us.</li>\n</ul>\n<p>In these cases, our <a href=\"/commercial-licences\">Commercial Licence</a> is appropriate.</p>\n<p>If you aren\'t sure whether your needs will be covered by the GPL version, <a href=\"/contact\">get in touch with us</a>.</p>\n<h2>Support</h2>\n<p>While Yaffs is released under GPL we can provide standard support options, consulting in its application to your particular product, or development of specific features to suit your needs or hardware.&nbsp;</p>\n<h2>Helping us to improve Yaffs</h2>\n<p>Although the code is downloadable at no charge, buying this product allows you to express your appreciation of Yaffs. Alternatively you can make a Donation to Aleph One Ltd via PayPal. You can do this at <a href=\"http://www.paypal.com\" target=\"_blank\" title=\"PayPal\">PayPal </a>by sending any sum to <a href=\"denied:mailto:sales@aleph1.co.uk\">sales@aleph1.co.uk</a>&nbsp; We shall appreciate it!</p>\n</div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:345\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1508500824.046,1,'config:filter.format.full_html node:345 node_view rendered','297'),('entity_view:node:345:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"345\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:345\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1508500824.043,1,'config:filter.format.full_html node:345 node_view rendered','297'),('entity_view:node:347:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0cyhABXZYlb3cE24QH_vIUZRLJmJZ4t_uRCsPIx579PE','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:10854:\"<article role=\"article\" about=\"/archives/yaffs-nand-specific-flash-file-system-introductory-article\" class=\"book is-promoted is-sticky full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">Written by Charles Manning - Originally published at Linuxdevices.org Sept 20th 2002\n<h3>PHB Summary</h3>\nYAFFS stands for \"yet another flash file system\"(*). As far as I am aware, YAFFS is the only file system, under any operating system, that has been designed specifically for use with NAND flash. YAFFS is thus designed to work within the constraints of, and exploit the features of, NAND flash to maximise performance. YAFFS uses journaling, error correction and verification techniques tuned to the way NAND typically fails, to enhance robustness. The result is a file system that exploits low-cost NAND chips and is both fast and robust. YAFFS is highly portable and runs under Linux, ucLinux and Windows CE. YAFFS is an open source project.\n<h3>Why NAND flash?</h3>\nEmbedded and mobile systems are increasingly using NAND flash for storage because it has various advantages over other storage technologies. As always though, life is a compromise and those advantages come with some limitations that need to be addressed to provide a robust flash file system. Hard disks are not a viable storage option for many embedded and handheld systems because they are too big, too fragile and use too much power. For some years now, people have been using common-old NOR flash for file system storage. JFFS and JFFS2 do an excellent job of this for Linux. For storage applications NOR flash is not that great because it is not very dense (ie. not much storage per chip), is costly and is slow to write. NAND flash, on the other hand, is low cost, dense and writes fast, but has other limitations. The most common consumer usage of NAND flash is on SmartMedia cards which are just NAND chips bonded to a carrier card. Consumer use of SmartMedia is driving down NAND prices while driving up densities. The standard SmartMedia file system is FAT based and is thus liable to corruptions due to power failures, crashes and other acts of demonic forces. This raises robustness concerns, particularly in embedded systems where a corrupted file system can kill the device. What\'s really needed is a journaling file system that is able to work around the limitations of NAND and exploit it for best performance.\n<h3>History</h3>\nThe lead-up to YAFFS started with an investigation into modifying the JFFS2 flash file system to work with NAND flash (**) for some Aleph One customers. It seemed reasonable that the best way to get a file system for NAND flash would be just \"tweaking\" an existing flash file system. On deeper investigation, it became apparent that designing a new file system specifically for NAND might have some benefits.\n<table border=\"1\" cellpadding=\"1\" style=\"width: 568px; border-color: #000000; border-spacing: 0px;\">\n<col width=\"186\" /><col width=\"187\" /><col width=\"186\" />\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p></p>\n </td>\n <td style=\"width: 187px;\">\n <p>NOR (typical, varies a lot)</p>\n </td>\n <td style=\"width: 186px;\">\n <p>NAND</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Density</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Up to 32MB chips</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Currently 256MB and growing.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Cost per MB</p>\n </td>\n <td style=\"width: 187px;\">\n <p>$1-$2</p>\n </td>\n <td style=\"width: 186px;\">\n <p>25c</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Access</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Random</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Page oriented with spare area on each page. Sequential access within a page.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Programmability</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Can modify a single bit.</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Very limited re-programming.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Read speed</p>\n </td>\n <td style=\"width: 187px;\">\n <p>50-100nS</p>\n </td>\n <td style=\"width: 186px;\">\n <p>10uS page \"seek\" + 50nS per byte</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Program time</p>\n </td>\n <td style=\"width: 187px;\">\n <p>5uS per byte</p>\n </td>\n <td style=\"width: 186px;\">\n <p>200uS per page</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Erasure time</p>\n </td>\n <td style=\"width: 187px;\">\n <p>1s per 64kB block</p>\n </td>\n <td style=\"width: 186px;\">\n <p>2ms per 16kB block</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Reliability</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Relatively immune to corruption. No bad blocks.</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Needs error correction. Bad blocks marked when shipped.</p>\n </td>\n</tr>\n</table>\nDesigning an effective flash file system is a difficult task and you need to jump through many hoops of fire to get a useful system. Although both are called \"Flash\", NOR and NAND flash have very different properties. Thus, a flash file system that works with NOR incorporates various mechanisms that are not required for NAND, and NAND needs extra mechanisms not required for NOR. For example, garbage collection performance is largely determined by the erasure time. NOR erases very slowly and thus an effective NOR garbage collection strategy is relatively complex and limits the design options. In comparison NAND erases very quickly; thus these limitations don\'t apply. Another major difference is that NAND is shipped with marked bad blocks on the device, while NOR chips are shipped defect free. Thus, one expects to encounter some failures in NAND and should design accordingly. This lead me to believe that it would be worth designing a file system specifically for NAND flash, exploiting the features of NAND to simplify the design and catering to NAND specific limitations directly, rather than trying to \"bend\" NAND to work with an existing file system architecture, or vice versa. The first conceptual design for YAFFS was drawn up in late December 2001. Once the customers bought in to the idea, things progressed rapidly. The first line of code was cut in January 2002. By May 2002 we had the first publicly available CVS code. We now have at least six different companies using or experimenting with YAFFS in embedded or handheld systems. YAFFS is already very stable and is converging rapidly. We expect to see YAFFS-based products shipped before the end of the year.\n<h3>Design approach</h3>\nRather than develop and debug code inside the Linux kernel, I took the approach of developing the file system \"guts\" algorithms - the most complex part -- in a user space program. To achieve this, the code is split into four sections:\n<ul>\n<li>\n<p>yaffs_guts: The file system algorithms. This code is fully portable C.</p>\n </li>\n<li>\n<p>yaffs_fs.c: Interface layer to the Linux VFS. Can be replaced with a test harness for user space developing of yaffs_guts.c</p>\n </li>\n<li>\n<p>nand interface: wrapper layer between yaffs_guts and the NAND memory access functions. eg. calls Linux mtd layer or RAM emulation layer.</p>\n </li>\n<li>\n<p>Portability functions: wrapper functions for services such as memory allocation etc.</p>\n </li>\n</ul>\nThis modular design has provided a lot of flexibility for testing and development. A user space program and DDD is a far more rapid development environment than continually changing the Linux kernel. Also, a RAM-based NAND emulation layer provides an excellent way to debug the file system in-kernel without special hardware. A further spin-off has been that YAFFS is portable to other operating systems. For example, a port of YAFFS for Windows CE was readily achieved by writing a new wrapper layer to hook up to the WinCE file system manager and new NAND access layer. yaffs_guts.c remains 100% portable(***). YAFFS is thus likely to be easily portable to other OSs too.\n<h3>Results</h3>\nRemoving surplus constraints has lead to a simpler design that has improved performance and robustness as well and reduced development time. YAFFS reads and writes pretty fast. There is no significant hit due to garbage collection (ie. in most situations garbage collection overheads would not impact usage). It is difficult to give meaningful benchmarks given non-standard hardware. However herewith some results achieved on a StrongARM-based board with 128MB of NAND flash. Write speed is approx 800kB per second and read speed is approx 1.5MB per second. In a weekend stress test I wrote, triple-verified then deleted 25gigabytes of file data without a single bit of file data being corrupted. 25GB exceeds the design lifetime of most embedded or handheld devices.\n<h3>Future</h3>\nAlthough YAFFS already performs well, there is still a lot of room for improvement. Development is continuing to enhance performance and robustness as well as add support software such as utilities, bootloader support and analysis tools. I expect to see ports to other OSs too. Increasing the user base of YAFFS is an important way to get more eyes over the code and test it under a wider set of scenarios. The YAFFS development community is growing well with good involvement from people all over the world. YAFFS is realising all the benefits open source projects hope for and will, we expect, continue to grow.\n<h3>Resources</h3>\nThe YAFFS project home page is <a href=\"http://www.aleph1.co.uk/yaffs/\">http://www.aleph1.co.uk/yaffs/</a> This provides further YAFFS documentation and instructions for GIT access and the YAFFS mailing list.\n<h3>Footnotes:</h3>\n(*)The YAFFS name came from the first concept document proposing yet another flash file system. Some how that name just stuck. (**) NAND support has since been added to JFFS2 by others. The YAFFS, JFFS2 and mtd communities cooperate to provide a rich flexible set of solutions to draw from. As is the nature of open source projects, JFFS2 code was used as a reference for some parts of the YAFFS development, particularly for figuring out the VFS interface. Google for further info on JFFS2 and mtd. (***) Some features were added to the guts to enhance WinCE usage. For example, the string comparison function was made configurable to be either strcmp or scricmp because Windows file names are case insensitive.\n<h3>Bio</h3>\nCharles Manning (aka The Embedded Janitor) lives near Christchurch, New Zealand, and has been developing and mopping up embedded systems for twenty years. His hobbies include fly tying and spinning wool. Charles can be reached at <a href=\"denied:mailto:charles@aleph1.co.uk\">charles@aleph1.co.uk</a>. </div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:68:\"/archives/yaffs-nand-specific-flash-file-system-introductory-article\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/347\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:68:\"/archives/yaffs-nand-specific-flash-file-system-introductory-article\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:347\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:79:\"<span>YAFFS: the NAND-specific flash file system - Introductory Article</span>\n\";}}',-1,1504654455.415,1,'config:filter.format.full_html config:system.site node:347 node_view rendered user:3','303'),('entity_view:node:347:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"347\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:347\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504654455.411,1,'config:filter.format.full_html config:system.site node:347 node_view rendered user:3','303'),('entity_view:node:347:rss:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:10875:\"<span>YAFFS: the NAND-specific flash file system - Introductory Article</span>\n<span><span lang=\"\" about=\"/user/wookey\" typeof=\"schema:Person\" property=\"schema:name\" datatype=\"\">Wookey</span></span>\n<span>26 July, 2006 - 2:11pm</span>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">Written by Charles Manning - Originally published at Linuxdevices.org Sept 20th 2002\n<h3>PHB Summary</h3>\nYAFFS stands for \"yet another flash file system\"(*). As far as I am aware, YAFFS is the only file system, under any operating system, that has been designed specifically for use with NAND flash. YAFFS is thus designed to work within the constraints of, and exploit the features of, NAND flash to maximise performance. YAFFS uses journaling, error correction and verification techniques tuned to the way NAND typically fails, to enhance robustness. The result is a file system that exploits low-cost NAND chips and is both fast and robust. YAFFS is highly portable and runs under Linux, ucLinux and Windows CE. YAFFS is an open source project.\n<h3>Why NAND flash?</h3>\nEmbedded and mobile systems are increasingly using NAND flash for storage because it has various advantages over other storage technologies. As always though, life is a compromise and those advantages come with some limitations that need to be addressed to provide a robust flash file system. Hard disks are not a viable storage option for many embedded and handheld systems because they are too big, too fragile and use too much power. For some years now, people have been using common-old NOR flash for file system storage. JFFS and JFFS2 do an excellent job of this for Linux. For storage applications NOR flash is not that great because it is not very dense (ie. not much storage per chip), is costly and is slow to write. NAND flash, on the other hand, is low cost, dense and writes fast, but has other limitations. The most common consumer usage of NAND flash is on SmartMedia cards which are just NAND chips bonded to a carrier card. Consumer use of SmartMedia is driving down NAND prices while driving up densities. The standard SmartMedia file system is FAT based and is thus liable to corruptions due to power failures, crashes and other acts of demonic forces. This raises robustness concerns, particularly in embedded systems where a corrupted file system can kill the device. What\'s really needed is a journaling file system that is able to work around the limitations of NAND and exploit it for best performance.\n<h3>History</h3>\nThe lead-up to YAFFS started with an investigation into modifying the JFFS2 flash file system to work with NAND flash (**) for some Aleph One customers. It seemed reasonable that the best way to get a file system for NAND flash would be just \"tweaking\" an existing flash file system. On deeper investigation, it became apparent that designing a new file system specifically for NAND might have some benefits.\n<table border=\"1\" cellpadding=\"1\" style=\"width: 568px; border-color: #000000; border-spacing: 0px;\">\n<col width=\"186\" /><col width=\"187\" /><col width=\"186\" />\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p></p>\n </td>\n <td style=\"width: 187px;\">\n <p>NOR (typical, varies a lot)</p>\n </td>\n <td style=\"width: 186px;\">\n <p>NAND</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Density</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Up to 32MB chips</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Currently 256MB and growing.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Cost per MB</p>\n </td>\n <td style=\"width: 187px;\">\n <p>$1-$2</p>\n </td>\n <td style=\"width: 186px;\">\n <p>25c</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Access</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Random</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Page oriented with spare area on each page. Sequential access within a page.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Programmability</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Can modify a single bit.</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Very limited re-programming.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Read speed</p>\n </td>\n <td style=\"width: 187px;\">\n <p>50-100nS</p>\n </td>\n <td style=\"width: 186px;\">\n <p>10uS page \"seek\" + 50nS per byte</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Program time</p>\n </td>\n <td style=\"width: 187px;\">\n <p>5uS per byte</p>\n </td>\n <td style=\"width: 186px;\">\n <p>200uS per page</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Erasure time</p>\n </td>\n <td style=\"width: 187px;\">\n <p>1s per 64kB block</p>\n </td>\n <td style=\"width: 186px;\">\n <p>2ms per 16kB block</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Reliability</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Relatively immune to corruption. No bad blocks.</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Needs error correction. Bad blocks marked when shipped.</p>\n </td>\n</tr>\n</table>\nDesigning an effective flash file system is a difficult task and you need to jump through many hoops of fire to get a useful system. Although both are called \"Flash\", NOR and NAND flash have very different properties. Thus, a flash file system that works with NOR incorporates various mechanisms that are not required for NAND, and NAND needs extra mechanisms not required for NOR. For example, garbage collection performance is largely determined by the erasure time. NOR erases very slowly and thus an effective NOR garbage collection strategy is relatively complex and limits the design options. In comparison NAND erases very quickly; thus these limitations don\'t apply. Another major difference is that NAND is shipped with marked bad blocks on the device, while NOR chips are shipped defect free. Thus, one expects to encounter some failures in NAND and should design accordingly. This lead me to believe that it would be worth designing a file system specifically for NAND flash, exploiting the features of NAND to simplify the design and catering to NAND specific limitations directly, rather than trying to \"bend\" NAND to work with an existing file system architecture, or vice versa. The first conceptual design for YAFFS was drawn up in late December 2001. Once the customers bought in to the idea, things progressed rapidly. The first line of code was cut in January 2002. By May 2002 we had the first publicly available CVS code. We now have at least six different companies using or experimenting with YAFFS in embedded or handheld systems. YAFFS is already very stable and is converging rapidly. We expect to see YAFFS-based products shipped before the end of the year.\n<h3>Design approach</h3>\nRather than develop and debug code inside the Linux kernel, I took the approach of developing the file system \"guts\" algorithms - the most complex part -- in a user space program. To achieve this, the code is split into four sections:\n<ul>\n<li>\n<p>yaffs_guts: The file system algorithms. This code is fully portable C.</p>\n </li>\n<li>\n<p>yaffs_fs.c: Interface layer to the Linux VFS. Can be replaced with a test harness for user space developing of yaffs_guts.c</p>\n </li>\n<li>\n<p>nand interface: wrapper layer between yaffs_guts and the NAND memory access functions. eg. calls Linux mtd layer or RAM emulation layer.</p>\n </li>\n<li>\n<p>Portability functions: wrapper functions for services such as memory allocation etc.</p>\n </li>\n</ul>\nThis modular design has provided a lot of flexibility for testing and development. A user space program and DDD is a far more rapid development environment than continually changing the Linux kernel. Also, a RAM-based NAND emulation layer provides an excellent way to debug the file system in-kernel without special hardware. A further spin-off has been that YAFFS is portable to other operating systems. For example, a port of YAFFS for Windows CE was readily achieved by writing a new wrapper layer to hook up to the WinCE file system manager and new NAND access layer. yaffs_guts.c remains 100% portable(***). YAFFS is thus likely to be easily portable to other OSs too.\n<h3>Results</h3>\nRemoving surplus constraints has lead to a simpler design that has improved performance and robustness as well and reduced development time. YAFFS reads and writes pretty fast. There is no significant hit due to garbage collection (ie. in most situations garbage collection overheads would not impact usage). It is difficult to give meaningful benchmarks given non-standard hardware. However herewith some results achieved on a StrongARM-based board with 128MB of NAND flash. Write speed is approx 800kB per second and read speed is approx 1.5MB per second. In a weekend stress test I wrote, triple-verified then deleted 25gigabytes of file data without a single bit of file data being corrupted. 25GB exceeds the design lifetime of most embedded or handheld devices.\n<h3>Future</h3>\nAlthough YAFFS already performs well, there is still a lot of room for improvement. Development is continuing to enhance performance and robustness as well as add support software such as utilities, bootloader support and analysis tools. I expect to see ports to other OSs too. Increasing the user base of YAFFS is an important way to get more eyes over the code and test it under a wider set of scenarios. The YAFFS development community is growing well with good involvement from people all over the world. YAFFS is realising all the benefits open source projects hope for and will, we expect, continue to grow.\n<h3>Resources</h3>\nThe YAFFS project home page is <a href=\"http://www.aleph1.co.uk/yaffs/\">http://www.aleph1.co.uk/yaffs/</a> This provides further YAFFS documentation and instructions for GIT access and the YAFFS mailing list.\n<h3>Footnotes:</h3>\n(*)The YAFFS name came from the first concept document proposing yet another flash file system. Some how that name just stuck. (**) NAND support has since been added to JFFS2 by others. The YAFFS, JFFS2 and mtd communities cooperate to provide a rich flexible set of solutions to draw from. As is the nature of open source projects, JFFS2 code was used as a reference for some parts of the YAFFS development, particularly for figuring out the VFS interface. Google for further info on JFFS2 and mtd. (***) Some features were added to the guts to enhance WinCE usage. For example, the string comparison function was made configurable to be either strcmp or scricmp because Windows file names are case insensitive.\n<h3>Bio</h3>\nCharles Manning (aka The Embedded Janitor) lives near Christchurch, New Zealand, and has been developing and mopping up embedded systems for twenty years. His hobbies include fly tying and spinning wool. Charles can be reached at <a href=\"denied:mailto:charles@aleph1.co.uk\">charles@aleph1.co.uk</a>. </div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:347\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}}',-1,1504783535.237,1,'config:filter.format.full_html node:347 node_view rendered user:3','297'),('entity_view:node:347:rss:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"347\";i:3;s:3:\"rss\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:347\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504783535.224,1,'config:filter.format.full_html node:347 node_view rendered user:3','297'),('entity_view:node:347:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:10719:\"<span>YAFFS: the NAND-specific flash file system - Introductory Article</span>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">Written by Charles Manning - Originally published at Linuxdevices.org Sept 20th 2002\n<h3>PHB Summary</h3>\nYAFFS stands for \"yet another flash file system\"(*). As far as I am aware, YAFFS is the only file system, under any operating system, that has been designed specifically for use with NAND flash. YAFFS is thus designed to work within the constraints of, and exploit the features of, NAND flash to maximise performance. YAFFS uses journaling, error correction and verification techniques tuned to the way NAND typically fails, to enhance robustness. The result is a file system that exploits low-cost NAND chips and is both fast and robust. YAFFS is highly portable and runs under Linux, ucLinux and Windows CE. YAFFS is an open source project.\n<h3>Why NAND flash?</h3>\nEmbedded and mobile systems are increasingly using NAND flash for storage because it has various advantages over other storage technologies. As always though, life is a compromise and those advantages come with some limitations that need to be addressed to provide a robust flash file system. Hard disks are not a viable storage option for many embedded and handheld systems because they are too big, too fragile and use too much power. For some years now, people have been using common-old NOR flash for file system storage. JFFS and JFFS2 do an excellent job of this for Linux. For storage applications NOR flash is not that great because it is not very dense (ie. not much storage per chip), is costly and is slow to write. NAND flash, on the other hand, is low cost, dense and writes fast, but has other limitations. The most common consumer usage of NAND flash is on SmartMedia cards which are just NAND chips bonded to a carrier card. Consumer use of SmartMedia is driving down NAND prices while driving up densities. The standard SmartMedia file system is FAT based and is thus liable to corruptions due to power failures, crashes and other acts of demonic forces. This raises robustness concerns, particularly in embedded systems where a corrupted file system can kill the device. What\'s really needed is a journaling file system that is able to work around the limitations of NAND and exploit it for best performance.\n<h3>History</h3>\nThe lead-up to YAFFS started with an investigation into modifying the JFFS2 flash file system to work with NAND flash (**) for some Aleph One customers. It seemed reasonable that the best way to get a file system for NAND flash would be just \"tweaking\" an existing flash file system. On deeper investigation, it became apparent that designing a new file system specifically for NAND might have some benefits.\n<table border=\"1\" cellpadding=\"1\" style=\"width: 568px; border-color: #000000; border-spacing: 0px;\">\n<col width=\"186\" /><col width=\"187\" /><col width=\"186\" />\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p></p>\n </td>\n <td style=\"width: 187px;\">\n <p>NOR (typical, varies a lot)</p>\n </td>\n <td style=\"width: 186px;\">\n <p>NAND</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Density</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Up to 32MB chips</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Currently 256MB and growing.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Cost per MB</p>\n </td>\n <td style=\"width: 187px;\">\n <p>$1-$2</p>\n </td>\n <td style=\"width: 186px;\">\n <p>25c</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Access</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Random</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Page oriented with spare area on each page. Sequential access within a page.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Programmability</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Can modify a single bit.</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Very limited re-programming.</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Read speed</p>\n </td>\n <td style=\"width: 187px;\">\n <p>50-100nS</p>\n </td>\n <td style=\"width: 186px;\">\n <p>10uS page \"seek\" + 50nS per byte</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Program time</p>\n </td>\n <td style=\"width: 187px;\">\n <p>5uS per byte</p>\n </td>\n <td style=\"width: 186px;\">\n <p>200uS per page</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Erasure time</p>\n </td>\n <td style=\"width: 187px;\">\n <p>1s per 64kB block</p>\n </td>\n <td style=\"width: 186px;\">\n <p>2ms per 16kB block</p>\n </td>\n</tr>\n<tr valign=\"top\">\n <td style=\"width: 186px;\">\n <p>Reliability</p>\n </td>\n <td style=\"width: 187px;\">\n <p>Relatively immune to corruption. No bad blocks.</p>\n </td>\n <td style=\"width: 186px;\">\n <p>Needs error correction. Bad blocks marked when shipped.</p>\n </td>\n</tr>\n</table>\nDesigning an effective flash file system is a difficult task and you need to jump through many hoops of fire to get a useful system. Although both are called \"Flash\", NOR and NAND flash have very different properties. Thus, a flash file system that works with NOR incorporates various mechanisms that are not required for NAND, and NAND needs extra mechanisms not required for NOR. For example, garbage collection performance is largely determined by the erasure time. NOR erases very slowly and thus an effective NOR garbage collection strategy is relatively complex and limits the design options. In comparison NAND erases very quickly; thus these limitations don\'t apply. Another major difference is that NAND is shipped with marked bad blocks on the device, while NOR chips are shipped defect free. Thus, one expects to encounter some failures in NAND and should design accordingly. This lead me to believe that it would be worth designing a file system specifically for NAND flash, exploiting the features of NAND to simplify the design and catering to NAND specific limitations directly, rather than trying to \"bend\" NAND to work with an existing file system architecture, or vice versa. The first conceptual design for YAFFS was drawn up in late December 2001. Once the customers bought in to the idea, things progressed rapidly. The first line of code was cut in January 2002. By May 2002 we had the first publicly available CVS code. We now have at least six different companies using or experimenting with YAFFS in embedded or handheld systems. YAFFS is already very stable and is converging rapidly. We expect to see YAFFS-based products shipped before the end of the year.\n<h3>Design approach</h3>\nRather than develop and debug code inside the Linux kernel, I took the approach of developing the file system \"guts\" algorithms - the most complex part -- in a user space program. To achieve this, the code is split into four sections:\n<ul>\n<li>\n<p>yaffs_guts: The file system algorithms. This code is fully portable C.</p>\n </li>\n<li>\n<p>yaffs_fs.c: Interface layer to the Linux VFS. Can be replaced with a test harness for user space developing of yaffs_guts.c</p>\n </li>\n<li>\n<p>nand interface: wrapper layer between yaffs_guts and the NAND memory access functions. eg. calls Linux mtd layer or RAM emulation layer.</p>\n </li>\n<li>\n<p>Portability functions: wrapper functions for services such as memory allocation etc.</p>\n </li>\n</ul>\nThis modular design has provided a lot of flexibility for testing and development. A user space program and DDD is a far more rapid development environment than continually changing the Linux kernel. Also, a RAM-based NAND emulation layer provides an excellent way to debug the file system in-kernel without special hardware. A further spin-off has been that YAFFS is portable to other operating systems. For example, a port of YAFFS for Windows CE was readily achieved by writing a new wrapper layer to hook up to the WinCE file system manager and new NAND access layer. yaffs_guts.c remains 100% portable(***). YAFFS is thus likely to be easily portable to other OSs too.\n<h3>Results</h3>\nRemoving surplus constraints has lead to a simpler design that has improved performance and robustness as well and reduced development time. YAFFS reads and writes pretty fast. There is no significant hit due to garbage collection (ie. in most situations garbage collection overheads would not impact usage). It is difficult to give meaningful benchmarks given non-standard hardware. However herewith some results achieved on a StrongARM-based board with 128MB of NAND flash. Write speed is approx 800kB per second and read speed is approx 1.5MB per second. In a weekend stress test I wrote, triple-verified then deleted 25gigabytes of file data without a single bit of file data being corrupted. 25GB exceeds the design lifetime of most embedded or handheld devices.\n<h3>Future</h3>\nAlthough YAFFS already performs well, there is still a lot of room for improvement. Development is continuing to enhance performance and robustness as well as add support software such as utilities, bootloader support and analysis tools. I expect to see ports to other OSs too. Increasing the user base of YAFFS is an important way to get more eyes over the code and test it under a wider set of scenarios. The YAFFS development community is growing well with good involvement from people all over the world. YAFFS is realising all the benefits open source projects hope for and will, we expect, continue to grow.\n<h3>Resources</h3>\nThe YAFFS project home page is <a href=\"http://www.aleph1.co.uk/yaffs/\">http://www.aleph1.co.uk/yaffs/</a> This provides further YAFFS documentation and instructions for GIT access and the YAFFS mailing list.\n<h3>Footnotes:</h3>\n(*)The YAFFS name came from the first concept document proposing yet another flash file system. Some how that name just stuck. (**) NAND support has since been added to JFFS2 by others. The YAFFS, JFFS2 and mtd communities cooperate to provide a rich flexible set of solutions to draw from. As is the nature of open source projects, JFFS2 code was used as a reference for some parts of the YAFFS development, particularly for figuring out the VFS interface. Google for further info on JFFS2 and mtd. (***) Some features were added to the guts to enhance WinCE usage. For example, the string comparison function was made configurable to be either strcmp or scricmp because Windows file names are case insensitive.\n<h3>Bio</h3>\nCharles Manning (aka The Embedded Janitor) lives near Christchurch, New Zealand, and has been developing and mopping up embedded systems for twenty years. His hobbies include fly tying and spinning wool. Charles can be reached at <a href=\"denied:mailto:charles@aleph1.co.uk\">charles@aleph1.co.uk</a>. </div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:347\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505630853.877,1,'config:filter.format.full_html node:347 node_view rendered','296'),('entity_view:node:347:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"347\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:347\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505630853.874,1,'config:filter.format.full_html node:347 node_view rendered','296'),('entity_view:node:347:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1561:\"<article role=\"article\" about=\"/archives/yaffs-nand-specific-flash-file-system-introductory-article\" class=\"book is-promoted is-sticky teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/archives/yaffs-nand-specific-flash-file-system-introductory-article\" rel=\"bookmark\"><span>YAFFS: the NAND-specific flash file system - Introductory Article</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">YAFFS stands for \"yet another flash file system\"(*). As far as I am aware, YAFFS is the only file system, under any operating system, that has been designed specifically for use with NAND flash. YAFFS is thus designed to work within the constraints of, and exploit the features of, NAND flash to maximise performance. YAFFS uses journaling, error correction and verification techniques tuned to the way NAND typically fails, to enhance robustness. The result is a file system that exploits low-cost NAND chips and is both fast and robust. YAFFS is highly portable and runs under Linux, ucLinux and Windows CE. YAFFS is an open source project. </div>\n      <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/archives/yaffs-nand-specific-flash-file-system-introductory-article\" rel=\"tag\" title=\"YAFFS: the NAND-specific flash file system - Introductory Article\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about YAFFS: the NAND-specific flash file system - Introductory Article</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:347\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}}',-1,1504640549.211,1,'config:filter.format.full_html node:347 node_view rendered user:3','297'),('entity_view:node:347:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"347\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:347\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504640549.209,1,'config:filter.format.full_html node:347 node_view rendered user:3','297'),('entity_view:node:348:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b06s_RCoeUeAl5hx4ZBbvlntLVNFM0miLFChlWHocptGU','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:2099:\"<article role=\"article\" about=\"/archives/yaffs1-memory-footprint\" class=\"book is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p>Yaffs claims a \'low memory footprint\', but what exactly does that mean? How low is low?</p>\n<p>Calculating an exact footprint is no easy task. There are many dependencies. Here is an approximation for Yaffs1 on Linux, assuming the standard block size of 512bytes per page and 16kB per block.</p>\n<ol>\n<li>Code size. This is dependent on various factors including CPU choice, optiomisation options etc. As a rough guide, the yaffs.o Linux module for x86 is around 55kBytes. This could be made smaller by stripping the debug text and ECC code if you don\'t need that. </li>\n<li>Run-time data structures. Some of these are fixed size and others are generated in runtime and change as your file structures change. As a rough guide though I will give the following:\n<ol type=\"a\">\n <li>Each yaffs partition needs a device structure of less than 1kB + approx 2-4kB stack with the current implementation. </li>\n <li>If shortOpCaches are enabled, then 524 bytes per cache entry (5 to 10 is a good number). </li>\n <li>About 120 bytes per file. (With short name caching enabled) </li>\n <li>About 4 bytes per block of NAND (ie. about 128 bytes per MB of NAND). </li>\n <li>About 4kBytes of RAM per MB of NAND for building the file TNode trees that are used to locate the data chunks. </li>\n</ol>\n </li>\n</ol>\n<p>Thus for a system using a 64MByte NAND and say 500 files you can budget on approx:</p>\n<ul>\n<li>1) 55kBytes </li>\n<li>2a) 5kB </li>\n<li>2b) 3kB (5 cache entries) </li>\n<li>2c) 60kB </li>\n<li>2d) 16kB </li>\n<li>2e) 256kB </li>\n</ul>\n<b>Total 410kBytes</b>\n<p>The last item, the tnodes, is the biggest expense in Yaffs. This can be reduced significantly by using a larger page size.</p>\n<p>There are some opportunities to tune some of these numbers so please feel free to discusss further if required.</p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:33:\"/archives/yaffs1-memory-footprint\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/348\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:33:\"/archives/yaffs1-memory-footprint\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:348\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:37:\"<span>Yaffs1 memory footprint</span>\n\";}}',-1,1504631342.564,1,'config:filter.format.full_html config:system.site node:348 node_view rendered user:3','304'),('entity_view:node:348:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"348\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:348\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504631342.548,1,'config:filter.format.full_html config:system.site node:348 node_view rendered user:3','304'),('entity_view:node:348:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1967:\"<span>Yaffs1 memory footprint</span>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p>Yaffs claims a \'low memory footprint\', but what exactly does that mean? How low is low?</p>\n<p>Calculating an exact footprint is no easy task. There are many dependencies. Here is an approximation for Yaffs1 on Linux, assuming the standard block size of 512bytes per page and 16kB per block.</p>\n<ol>\n<li>Code size. This is dependent on various factors including CPU choice, optiomisation options etc. As a rough guide, the yaffs.o Linux module for x86 is around 55kBytes. This could be made smaller by stripping the debug text and ECC code if you don\'t need that. </li>\n<li>Run-time data structures. Some of these are fixed size and others are generated in runtime and change as your file structures change. As a rough guide though I will give the following:\n<ol type=\"a\">\n <li>Each yaffs partition needs a device structure of less than 1kB + approx 2-4kB stack with the current implementation. </li>\n <li>If shortOpCaches are enabled, then 524 bytes per cache entry (5 to 10 is a good number). </li>\n <li>About 120 bytes per file. (With short name caching enabled) </li>\n <li>About 4 bytes per block of NAND (ie. about 128 bytes per MB of NAND). </li>\n <li>About 4kBytes of RAM per MB of NAND for building the file TNode trees that are used to locate the data chunks. </li>\n</ol>\n </li>\n</ol>\n<p>Thus for a system using a 64MByte NAND and say 500 files you can budget on approx:</p>\n<ul>\n<li>1) 55kBytes </li>\n<li>2a) 5kB </li>\n<li>2b) 3kB (5 cache entries) </li>\n<li>2c) 60kB </li>\n<li>2d) 16kB </li>\n<li>2e) 256kB </li>\n</ul>\n<b>Total 410kBytes</b>\n<p>The last item, the tnodes, is the biggest expense in Yaffs. This can be reduced significantly by using a larger page size.</p>\n<p>There are some opportunities to tune some of these numbers so please feel free to discusss further if required.</p>\n</div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:348\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505414723.039,1,'config:filter.format.full_html node:348 node_view rendered','297'),('entity_view:node:348:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"348\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:348\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505414723.035,1,'config:filter.format.full_html node:348 node_view rendered','297'),('entity_view:node:348:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:969:\"<article role=\"article\" about=\"/archives/yaffs1-memory-footprint\" class=\"book is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/archives/yaffs1-memory-footprint\" rel=\"bookmark\"><span>Yaffs1 memory footprint</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">Yaffs claims a \'low memory footprint\', but what exactly does that mean? How low is low?\n<p>Calculating an exact footprint is no easy task. There are many dependencies. Here is an approximation for Yaffs1 on Linux, assuming the standard block size of 512bytes per page and 16kB per block.</p>\n</div>\n      <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/archives/yaffs1-memory-footprint\" rel=\"tag\" title=\"Yaffs1 memory footprint\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about Yaffs1 memory footprint</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:348\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}}',-1,1504637011.154,1,'config:filter.format.full_html node:348 node_view rendered user:3','298'),('entity_view:node:348:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"348\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:348\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504637011.151,1,'config:filter.format.full_html node:348 node_view rendered user:3','298'),('entity_view:node:351:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0EqhumKfGKmez6viHJcv4I5PulSdmAp5MfwmIjiSDYCM','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:3543:\"<article role=\"article\" about=\"/yaffs-debugging\" typeof=\"schema:WebPage\" class=\"page is-promoted is-sticky full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"YAFFS Debugging\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h1>How to control debugging in yaffs</h1>\n<p>YAFFS provides a debugging mechanism which can be controlled at runtime if you have access to /proc, normally via a shell. If you need to trace things before you get to a shell, then you can set default trace options at compile time.</p>\n<h2>Available Trace Flags</h2>\n<table>\n<tr>\n <th>name</th>\n <th>C #define</th>\n <th>bitmask value</th>\n</tr>\n<tr>\n <td>error </td>\n <td>YAFFS_TRACE_ERROR </td>\n <td>0x00000001</td>\n</tr>\n<tr>\n <td>os </td>\n <td>YAFFS_TRACE_OS </td>\n <td>0x00000002</td>\n</tr>\n<tr>\n <td>allocate </td>\n <td>YAFFS_TRACE_ALLOCATE </td>\n <td>0x00000004</td>\n</tr>\n<tr>\n <td>scan </td>\n <td>YAFFS_TRACE_SCAN </td>\n <td>0x00000008</td>\n</tr>\n<tr>\n <td>bad_blocks </td>\n <td>YAFFS_TRACE_BAD_BLOCKS </td>\n <td>0x00000010</td>\n</tr>\n<tr>\n <td>erase </td>\n <td>YAFFS_TRACE_ERASE </td>\n <td>0x00000020</td>\n</tr>\n<tr>\n <td>gc </td>\n <td>YAFFS_TRACE_GC </td>\n <td>0x00000040</td>\n</tr>\n<tr>\n <td>write </td>\n <td>YAFFS_TRACE_WRITE </td>\n <td>0x00000080</td>\n</tr>\n<tr>\n <td>tracing </td>\n <td>YAFFS_TRACE_TRACING </td>\n <td>0x00000100</td>\n</tr>\n<tr>\n <td>deletion </td>\n <td>YAFFS_TRACE_DELETION </td>\n <td>0x00000200</td>\n</tr>\n<tr>\n <td>buffers </td>\n <td>YAFFS_TRACE_BUFFERS </td>\n <td>0x00000400</td>\n</tr>\n<tr>\n <td>nandaccess </td>\n <td>YAFFS_TRACE_NANDACCESS </td>\n <td>0x00000800</td>\n</tr>\n<tr>\n <td>gc_detail </td>\n <td>YAFFS_TRACE_GC_DETAIL </td>\n <td>0x00001000</td>\n</tr>\n<tr>\n <td>scan_debug </td>\n <td>YAFFS_TRACE_SCAN_DEBUG </td>\n <td>0x00002000</td>\n</tr>\n<tr>\n <td>mtd </td>\n <td>YAFFS_TRACE_MTD </td>\n <td>0x00004000</td>\n</tr>\n<tr>\n <td>always </td>\n <td>YAFFS_TRACE_ALWAYS </td>\n <td>0x40000000</td>\n</tr>\n<tr>\n <td>bug </td>\n <td>YAFFS_TRACE_BUG </td>\n <td>0x80000000</td>\n</tr>\n</table>\n<h2>Flag meanings</h2>\n<p>The flags cover possible debugging messages from various aspects of the filesystem - initial scanning, mtd interface, writing, nand access, garbage collection, OS interaction etc. Turning on everything results an awful lot of trace info, so it is usually best to just enable a few relevant flags.</p>\n<h2>Setting flags at runtime</h2>\n<p>The flags can be set or cleared by echoing the name of the flag into /proc/yaffs with a \'+\' or \'-\':<br />\n<code>echo +os-write &gt; /proc/yaffs</code></p>\n<p>It can be set to to all or none using \'=\', and then flags can be added or removed:<br />\n<code>echo =none+os+write &gt; /proc/yaffs</code></p>\n<p>And you can use numerical values, if you are so inclined (using standard C format):<br />\n<code>echo 0xf00001 &gt; /proc/yaffs</code></p>\n<p>So<br />\n<code>echo all &gt; /proc/yaffs</code><br />\nwill turn all tracing on</p>\n<p><b>Note</b> that you only see the output showing you the current trace state if the \'always\' (YAFFS_TRACE_ALWAYS) flag is set, so to see what you are doing do this:<br />\n<code>echo +always &gt; /proc/yaffs</code></p>\n<h2>Setting flags at compile time</h2>\n<p>Flags can be set in the code at compile-time by setting <code>yaffs_traceMask</code> in <code>yaffs_fs.c</code> (add new flags to <code>always</code> and <code>bad_blocks</code> which are set by default)</p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:16:\"/yaffs-debugging\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/351\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:16:\"/yaffs-debugging\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:351\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:52:\"<span property=\"schema:name\">YAFFS Debugging</span>\n\";}}',-1,1504746766.844,1,'config:filter.format.full_html config:system.site node:351 node_view rendered user:3','301'),('entity_view:node:351:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"351\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:351\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504746766.842,1,'config:filter.format.full_html config:system.site node:351 node_view rendered user:3','301'),('entity_view:node:351:rss:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:3577:\"<span property=\"schema:name\">YAFFS Debugging</span>\n<span rel=\"schema:author\"><span lang=\"\" about=\"/user/wookey\" typeof=\"schema:Person\" property=\"schema:name\" datatype=\"\">Wookey</span></span>\n<span property=\"schema:dateCreated\" content=\"2006-09-15T21:32:13+00:00\">15 September, 2006 - 10:32pm</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h1>How to control debugging in yaffs</h1>\n<p>YAFFS provides a debugging mechanism which can be controlled at runtime if you have access to /proc, normally via a shell. If you need to trace things before you get to a shell, then you can set default trace options at compile time.</p>\n<h2>Available Trace Flags</h2>\n<table>\n<tr>\n <th>name</th>\n <th>C #define</th>\n <th>bitmask value</th>\n</tr>\n<tr>\n <td>error </td>\n <td>YAFFS_TRACE_ERROR </td>\n <td>0x00000001</td>\n</tr>\n<tr>\n <td>os </td>\n <td>YAFFS_TRACE_OS </td>\n <td>0x00000002</td>\n</tr>\n<tr>\n <td>allocate </td>\n <td>YAFFS_TRACE_ALLOCATE </td>\n <td>0x00000004</td>\n</tr>\n<tr>\n <td>scan </td>\n <td>YAFFS_TRACE_SCAN </td>\n <td>0x00000008</td>\n</tr>\n<tr>\n <td>bad_blocks </td>\n <td>YAFFS_TRACE_BAD_BLOCKS </td>\n <td>0x00000010</td>\n</tr>\n<tr>\n <td>erase </td>\n <td>YAFFS_TRACE_ERASE </td>\n <td>0x00000020</td>\n</tr>\n<tr>\n <td>gc </td>\n <td>YAFFS_TRACE_GC </td>\n <td>0x00000040</td>\n</tr>\n<tr>\n <td>write </td>\n <td>YAFFS_TRACE_WRITE </td>\n <td>0x00000080</td>\n</tr>\n<tr>\n <td>tracing </td>\n <td>YAFFS_TRACE_TRACING </td>\n <td>0x00000100</td>\n</tr>\n<tr>\n <td>deletion </td>\n <td>YAFFS_TRACE_DELETION </td>\n <td>0x00000200</td>\n</tr>\n<tr>\n <td>buffers </td>\n <td>YAFFS_TRACE_BUFFERS </td>\n <td>0x00000400</td>\n</tr>\n<tr>\n <td>nandaccess </td>\n <td>YAFFS_TRACE_NANDACCESS </td>\n <td>0x00000800</td>\n</tr>\n<tr>\n <td>gc_detail </td>\n <td>YAFFS_TRACE_GC_DETAIL </td>\n <td>0x00001000</td>\n</tr>\n<tr>\n <td>scan_debug </td>\n <td>YAFFS_TRACE_SCAN_DEBUG </td>\n <td>0x00002000</td>\n</tr>\n<tr>\n <td>mtd </td>\n <td>YAFFS_TRACE_MTD </td>\n <td>0x00004000</td>\n</tr>\n<tr>\n <td>always </td>\n <td>YAFFS_TRACE_ALWAYS </td>\n <td>0x40000000</td>\n</tr>\n<tr>\n <td>bug </td>\n <td>YAFFS_TRACE_BUG </td>\n <td>0x80000000</td>\n</tr>\n</table>\n<h2>Flag meanings</h2>\n<p>The flags cover possible debugging messages from various aspects of the filesystem - initial scanning, mtd interface, writing, nand access, garbage collection, OS interaction etc. Turning on everything results an awful lot of trace info, so it is usually best to just enable a few relevant flags.</p>\n<h2>Setting flags at runtime</h2>\n<p>The flags can be set or cleared by echoing the name of the flag into /proc/yaffs with a \'+\' or \'-\':<br />\n<code>echo +os-write &gt; /proc/yaffs</code></p>\n<p>It can be set to to all or none using \'=\', and then flags can be added or removed:<br />\n<code>echo =none+os+write &gt; /proc/yaffs</code></p>\n<p>And you can use numerical values, if you are so inclined (using standard C format):<br />\n<code>echo 0xf00001 &gt; /proc/yaffs</code></p>\n<p>So<br />\n<code>echo all &gt; /proc/yaffs</code><br />\nwill turn all tracing on</p>\n<p><b>Note</b> that you only see the output showing you the current trace state if the \'always\' (YAFFS_TRACE_ALWAYS) flag is set, so to see what you are doing do this:<br />\n<code>echo +always &gt; /proc/yaffs</code></p>\n<h2>Setting flags at compile time</h2>\n<p>Flags can be set in the code at compile-time by setting <code>yaffs_traceMask</code> in <code>yaffs_fs.c</code> (add new flags to <code>always</code> and <code>bad_blocks</code> which are set by default)</p>\n</div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:351\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}}',-1,1504783534.909,1,'config:filter.format.full_html node:351 node_view rendered user:3','295'),('entity_view:node:351:rss:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"351\";i:3;s:3:\"rss\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:351\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504783534.878,1,'config:filter.format.full_html node:351 node_view rendered user:3','295'),('entity_view:node:351:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:3329:\"<span property=\"schema:name\">YAFFS Debugging</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h1>How to control debugging in yaffs</h1>\n<p>YAFFS provides a debugging mechanism which can be controlled at runtime if you have access to /proc, normally via a shell. If you need to trace things before you get to a shell, then you can set default trace options at compile time.</p>\n<h2>Available Trace Flags</h2>\n<table>\n<tr>\n <th>name</th>\n <th>C #define</th>\n <th>bitmask value</th>\n</tr>\n<tr>\n <td>error </td>\n <td>YAFFS_TRACE_ERROR </td>\n <td>0x00000001</td>\n</tr>\n<tr>\n <td>os </td>\n <td>YAFFS_TRACE_OS </td>\n <td>0x00000002</td>\n</tr>\n<tr>\n <td>allocate </td>\n <td>YAFFS_TRACE_ALLOCATE </td>\n <td>0x00000004</td>\n</tr>\n<tr>\n <td>scan </td>\n <td>YAFFS_TRACE_SCAN </td>\n <td>0x00000008</td>\n</tr>\n<tr>\n <td>bad_blocks </td>\n <td>YAFFS_TRACE_BAD_BLOCKS </td>\n <td>0x00000010</td>\n</tr>\n<tr>\n <td>erase </td>\n <td>YAFFS_TRACE_ERASE </td>\n <td>0x00000020</td>\n</tr>\n<tr>\n <td>gc </td>\n <td>YAFFS_TRACE_GC </td>\n <td>0x00000040</td>\n</tr>\n<tr>\n <td>write </td>\n <td>YAFFS_TRACE_WRITE </td>\n <td>0x00000080</td>\n</tr>\n<tr>\n <td>tracing </td>\n <td>YAFFS_TRACE_TRACING </td>\n <td>0x00000100</td>\n</tr>\n<tr>\n <td>deletion </td>\n <td>YAFFS_TRACE_DELETION </td>\n <td>0x00000200</td>\n</tr>\n<tr>\n <td>buffers </td>\n <td>YAFFS_TRACE_BUFFERS </td>\n <td>0x00000400</td>\n</tr>\n<tr>\n <td>nandaccess </td>\n <td>YAFFS_TRACE_NANDACCESS </td>\n <td>0x00000800</td>\n</tr>\n<tr>\n <td>gc_detail </td>\n <td>YAFFS_TRACE_GC_DETAIL </td>\n <td>0x00001000</td>\n</tr>\n<tr>\n <td>scan_debug </td>\n <td>YAFFS_TRACE_SCAN_DEBUG </td>\n <td>0x00002000</td>\n</tr>\n<tr>\n <td>mtd </td>\n <td>YAFFS_TRACE_MTD </td>\n <td>0x00004000</td>\n</tr>\n<tr>\n <td>always </td>\n <td>YAFFS_TRACE_ALWAYS </td>\n <td>0x40000000</td>\n</tr>\n<tr>\n <td>bug </td>\n <td>YAFFS_TRACE_BUG </td>\n <td>0x80000000</td>\n</tr>\n</table>\n<h2>Flag meanings</h2>\n<p>The flags cover possible debugging messages from various aspects of the filesystem - initial scanning, mtd interface, writing, nand access, garbage collection, OS interaction etc. Turning on everything results an awful lot of trace info, so it is usually best to just enable a few relevant flags.</p>\n<h2>Setting flags at runtime</h2>\n<p>The flags can be set or cleared by echoing the name of the flag into /proc/yaffs with a \'+\' or \'-\':<br />\n<code>echo +os-write &gt; /proc/yaffs</code></p>\n<p>It can be set to to all or none using \'=\', and then flags can be added or removed:<br />\n<code>echo =none+os+write &gt; /proc/yaffs</code></p>\n<p>And you can use numerical values, if you are so inclined (using standard C format):<br />\n<code>echo 0xf00001 &gt; /proc/yaffs</code></p>\n<p>So<br />\n<code>echo all &gt; /proc/yaffs</code><br />\nwill turn all tracing on</p>\n<p><b>Note</b> that you only see the output showing you the current trace state if the \'always\' (YAFFS_TRACE_ALWAYS) flag is set, so to see what you are doing do this:<br />\n<code>echo +always &gt; /proc/yaffs</code></p>\n<h2>Setting flags at compile time</h2>\n<p>Flags can be set in the code at compile-time by setting <code>yaffs_traceMask</code> in <code>yaffs_fs.c</code> (add new flags to <code>always</code> and <code>bad_blocks</code> which are set by default)</p>\n</div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:351\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1506813386.454,1,'config:filter.format.full_html node:351 node_view rendered','294'),('entity_view:node:351:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"351\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:351\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1506813386.451,1,'config:filter.format.full_html node:351 node_view rendered','294'),('entity_view:node:351:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:974:\"<article role=\"article\" about=\"/yaffs-debugging\" typeof=\"schema:WebPage\" class=\"page is-promoted is-sticky teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-debugging\" rel=\"bookmark\"><span property=\"schema:name\">YAFFS Debugging</span>\n</a>\n    </h2>\n      <span property=\"schema:name\" content=\"YAFFS Debugging\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p>YAFFS provides a debugging mechanism which can be controlled at runtime, or set at build time. This page descirbes the options available and how to use them, for when you need to do some troubleshooting.</p>\n</div>\n      <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-debugging\" rel=\"tag\" title=\"YAFFS Debugging\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about YAFFS Debugging</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:351\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}}',-1,1504640549.196,1,'config:filter.format.full_html node:351 node_view rendered user:3','295'),('entity_view:node:351:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"351\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:351\";i:2;s:9:\"node_view\";i:3;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504640549.195,1,'config:filter.format.full_html node:351 node_view rendered user:3','295'),('entity_view:node:353:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0NVH6wHNJmJvA9qvtpldBPwWQEneQ6P8tcgdPH8r5ZPo','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:3396:\"<article role=\"article\" about=\"/yaffs-licence-faqs\" typeof=\"schema:WebPage\" class=\"page is-promoted full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs Licence FAQs\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><h3>Do we need a Licence for Yaffs ?</h3>\n\n<p>Yaffs is and will remain free of charge from <a href=\"/node/346\">our web site</a>.  You can grab the latest version and work and test and play with it without charge.<br /><br />\nIt comes with a GNU General Public Public Licence, version 2,  : <a href=\"http://www.gnu.org/licenses/gpl-2.0.html\">http://www.gnu.org/licenses/gpl-2.0.html</a>   As usual with GPL work, if you sell or distribute work embodying Yaffs you also have an obligation to disclose your associated Source Code to anyone who asks.</p>\n\n<h3>What if we link other code to Yaffs ?</h3>\n\n<p>The GPL obligation is not affected by the kind of linking between Yaffs and any associated code, nor is it affected by your disclosure of modifications you make to the code and release back into the main line.  For example if you use Yaffs under GPL with Linux you should treat it just the same as Linux code; if you want to publish a patched kernel please do.</p>\n\n<h3>We do not want to disclose Source Code</h3>\n\n<p>Because Aleph One Limited created and owns Yaffs we can sell you a Licence to use Yaffs which does not have the GNU GPLV2 obligations.  Such a licence is always perpetual, world-wide, non-exclusive. and free of any continuing royalty obligations.  It is paid for by a single fee at the time of signing a Licence Agreement between you and Aleph One.</p>\n\n<p>The fee depends on the number of distinct Products in which Yaffs will be used, and there is a base price of GBP £10,000.  If more than one Product is included in the same Licence there is usually a reduction in the second fee.</p>\n\n<h3>What do we do next ?</h3>\n\n<p>Tell us some more about the product you will use Yaffs in.  We like the Agreement to contain a brief description of the hardware involved and the part number or product name and any internal code name.  If you want us to sign a Non-Disclosure Agreement before you give us these details, send it to us; we are used to signing them.  We can send you a standard form if you do not have one.</p>\n\n<p>Then we will send a draft Agreement and price to you, and negotiate until we are both satisfied.  Next we each sign and exchange copies of the Agreement and you pay us.</p>\n\n<h3>What happens when we sign a Licence ?</h3>\n\n<p>When we have both signed a Licence Agreement and you have paid us we provide you with a tarball of files whose headers show that this code is under a proprietary Licence which you have bought from us.  You use these files to create the FS code you embed in your Products.</p>\n\n<h3>Is there more information about licensing?</h3>\n\n<p>Yes there is!</p>\n\n<ul><li>More detail about the <a href=\"/yaffs-licence-sample\">definition of a Product is given </a><a href=\"/node/32\">i</a><a href=\"/yaffs-licence-sample\">n our sample commercial licence</a>. </li>\n	<li>Notes which give <a href=\"/licences-more-background-and-detail\">further background and detail about our licensing</a>.</li>\n</ul><p> </p>\n\n<p> </p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:19:\"/yaffs-licence-faqs\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/353\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:19:\"/yaffs-licence-faqs\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:353\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:55:\"<span property=\"schema:name\">Yaffs Licence FAQs</span>\n\";}}',-1,1504655076.733,1,'config:filter.format.basic_html config:system.site node:353 node_view rendered user:4','273'),('entity_view:node:353:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"353\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:353\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504655076.731,1,'config:filter.format.basic_html config:system.site node:353 node_view rendered user:4','273'),('entity_view:node:353:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:3189:\"<span property=\"schema:name\">Yaffs Licence FAQs</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><h3>Do we need a Licence for Yaffs ?</h3>\n\n<p>Yaffs is and will remain free of charge from <a href=\"/node/346\">our web site</a>.  You can grab the latest version and work and test and play with it without charge.<br /><br />\nIt comes with a GNU General Public Public Licence, version 2,  : <a href=\"http://www.gnu.org/licenses/gpl-2.0.html\">http://www.gnu.org/licenses/gpl-2.0.html</a>   As usual with GPL work, if you sell or distribute work embodying Yaffs you also have an obligation to disclose your associated Source Code to anyone who asks.</p>\n\n<h3>What if we link other code to Yaffs ?</h3>\n\n<p>The GPL obligation is not affected by the kind of linking between Yaffs and any associated code, nor is it affected by your disclosure of modifications you make to the code and release back into the main line.  For example if you use Yaffs under GPL with Linux you should treat it just the same as Linux code; if you want to publish a patched kernel please do.</p>\n\n<h3>We do not want to disclose Source Code</h3>\n\n<p>Because Aleph One Limited created and owns Yaffs we can sell you a Licence to use Yaffs which does not have the GNU GPLV2 obligations.  Such a licence is always perpetual, world-wide, non-exclusive. and free of any continuing royalty obligations.  It is paid for by a single fee at the time of signing a Licence Agreement between you and Aleph One.</p>\n\n<p>The fee depends on the number of distinct Products in which Yaffs will be used, and there is a base price of GBP £10,000.  If more than one Product is included in the same Licence there is usually a reduction in the second fee.</p>\n\n<h3>What do we do next ?</h3>\n\n<p>Tell us some more about the product you will use Yaffs in.  We like the Agreement to contain a brief description of the hardware involved and the part number or product name and any internal code name.  If you want us to sign a Non-Disclosure Agreement before you give us these details, send it to us; we are used to signing them.  We can send you a standard form if you do not have one.</p>\n\n<p>Then we will send a draft Agreement and price to you, and negotiate until we are both satisfied.  Next we each sign and exchange copies of the Agreement and you pay us.</p>\n\n<h3>What happens when we sign a Licence ?</h3>\n\n<p>When we have both signed a Licence Agreement and you have paid us we provide you with a tarball of files whose headers show that this code is under a proprietary Licence which you have bought from us.  You use these files to create the FS code you embed in your Products.</p>\n\n<h3>Is there more information about licensing?</h3>\n\n<p>Yes there is!</p>\n\n<ul><li>More detail about the <a href=\"/yaffs-licence-sample\">definition of a Product is given </a><a href=\"/node/32\">i</a><a href=\"/yaffs-licence-sample\">n our sample commercial licence</a>. </li>\n	<li>Notes which give <a href=\"/licences-more-background-and-detail\">further background and detail about our licensing</a>.</li>\n</ul><p> </p>\n\n<p> </p></div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:353\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505902414.114,1,'config:filter.format.basic_html node:353 node_view rendered','264'),('entity_view:node:353:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"353\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:353\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505902414.109,1,'config:filter.format.basic_html node:353 node_view rendered','264'),('entity_view:node:353:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:859:\"<article role=\"article\" about=\"/yaffs-licence-faqs\" typeof=\"schema:WebPage\" class=\"page is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-licence-faqs\" rel=\"bookmark\"><span property=\"schema:name\">Yaffs Licence FAQs</span>\n</a>\n    </h2>\n      <span property=\"schema:name\" content=\"Yaffs Licence FAQs\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Some questions about the commercial licence for Yaffs and how we arrive at one.</p></div>\n      <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-licence-faqs\" rel=\"tag\" title=\"Yaffs Licence FAQs\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about Yaffs Licence FAQs</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:353\";i:2;s:9:\"node_view\";i:3;s:6:\"user:4\";}s:7:\"max-age\";i:-1;}}',-1,1504637011.134,1,'config:filter.format.basic_html node:353 node_view rendered user:4','267'),('entity_view:node:353:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"353\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:353\";i:2;s:9:\"node_view\";i:3;s:6:\"user:4\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504637011.132,1,'config:filter.format.basic_html node:353 node_view rendered user:4','267'),('entity_view:node:357:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0FQcD2Wq7LZtKTKEgGYFN7qtq5N37FQoi6Rj2jSZ7Dbc','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:777:\"<article role=\"article\" about=\"/yaffs-flash-file-system-embedded-use\" typeof=\"schema:Article\" class=\"article full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs - A Flash File System For Embedded Use\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Yaffs (Yet Another Flash File System) is an open-source file system specifically designed to be fast, robust and suitable for embedded use with NAND and NOR Flash.  It is widely used with Linux, RTOSs, or no OS at all, in consumer devices. It is available under GNU Public License, GPL, or on commercial terms from Aleph One.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:37:\"/yaffs-flash-file-system-embedded-use\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/357\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:37:\"/yaffs-flash-file-system-embedded-use\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:357\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:81:\"<span property=\"schema:name\">Yaffs - A Flash File System For Embedded Use</span>\n\";}}',-1,1504851495.662,1,'config:filter.format.basic_html config:system.site node:357 node_view rendered user:1','279'),('entity_view:node:357:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"357\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:357\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504851495.635,1,'config:filter.format.basic_html config:system.site node:357 node_view rendered user:1','279'),('entity_view:node:357:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:561:\"<span property=\"schema:name\">Yaffs - A Flash File System For Embedded Use</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Yaffs (Yet Another Flash File System) is an open-source file system specifically designed to be fast, robust and suitable for embedded use with NAND and NOR Flash.  It is widely used with Linux, RTOSs, or no OS at all, in consumer devices. It is available under GNU Public License, GPL, or on commercial terms from Aleph One.</p></div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:357\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505630914.679,1,'config:filter.format.basic_html node:357 node_view rendered','266'),('entity_view:node:357:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"357\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:357\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505630914.677,1,'config:filter.format.basic_html node:357 node_view rendered','266'),('entity_view:node:358:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0o4BPtNm6uHEHDf3HLG-iqL5Utny9LbNChIAHN-AhKhQ','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:712:\"<article role=\"article\" about=\"/internal-history-yaffs\" typeof=\"schema:Article\" class=\"article is-promoted full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"The Internal History of YAFFS\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">The following archive documents will give you some insight into the internal history of YAFFS\n<ul>\n<li><a href=\"/node/39\">YAFFS Development notes</a>.</li>\n<li><a href=\"/node/42\">State of NAND MTD driver at start of project</a></li>\n<li><a href=\"/node/42\">YAFFS History</a></li>\n</ul>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:23:\"/internal-history-yaffs\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/358\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:23:\"/internal-history-yaffs\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:358\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:66:\"<span property=\"schema:name\">The Internal History of YAFFS</span>\n\";}}',-1,1505019833.068,1,'config:filter.format.full_html config:system.site node:358 node_view rendered user:1','308'),('entity_view:node:358:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"358\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:358\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505019833.066,1,'config:filter.format.full_html config:system.site node:358 node_view rendered user:1','308'),('entity_view:node:358:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:907:\"<article role=\"article\" about=\"/internal-history-yaffs\" typeof=\"schema:Article\" class=\"article is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/internal-history-yaffs\" rel=\"bookmark\"><span property=\"schema:name\">The Internal History of YAFFS</span>\n</a>\n    </h2>\n      <span property=\"schema:name\" content=\"The Internal History of YAFFS\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">A brief look into the history of YAFFS through a look at the the internals.</div>\n      <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/internal-history-yaffs\" rel=\"tag\" title=\"The Internal History of YAFFS\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about The Internal History of YAFFS</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:358\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1504637011.111,1,'config:filter.format.full_html node:358 node_view rendered user:1','302'),('entity_view:node:358:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"358\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:358\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504637011.108,1,'config:filter.format.full_html node:358 node_view rendered user:1','302'),('entity_view:node:359:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b02SbQrhkqWDd8p8kTOkBZugivFmGA1xcpBbQOb3aeT9g','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:2087:\"<article role=\"article\" about=\"/comparison-between-yaffs-yaffs2-and-jffs2\" typeof=\"schema:Article\" class=\"article is-promoted full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Comparison between Yaffs (Yaffs2) and JFFS2\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>On Friday 02 March 2007 10:59, Charles F Johnson wrote:</p>\n\n<p>\"I\'m trying to understand the relative merits of JFFS2 vs YAFFS2. The response on the YAFFS mailing list is quite positive as far as leading me to believe that there are actual products shipping.\"</p>\n\n<p><br />\nCharles Manning replied:<br />\nAt a technical level, it is very difficult to make X vs Y comparisons because there are many factors involved which manifest differently on different systems therefore \'your mileage will vary\'. But, as a general rule of thumb, the following might help:</p>\n\n<p>1) YAFFS uses less run-time RAM to hold its state, so YAFFS scales better than JFFS2. There are quite a few systems using large NAND arrays (the largest partitions I know of are around the 6Gbyte mark).<br /><br />\n2) YAFFS garbage collection is simpler and faster, typically making for better performance under hard writing.<br /><br />\n3) YAFFS uses a whole page per file for headers, and does not provide compression. This means that JFFS2 is probably a better fit to small partitions. The flip side is that a lot of data (eg. MP3) does not compress very well, and enabling compression really hurts performance.<br /><br />\n4) While YAFFS has been used on NOR, it does not fit very well (because YAFFS does not use erase suspend). Thus if you\'re using smaller NAND partitions and using JFFS2 on NOR, then a JFFS2-only solution is very appealing.<br /><br />\nAll the above can generally boil down to: If you\'re using less than about 64MB the pain vs gain might play in favour of JFFS2. As you increase partition size, YAFFS makes more and more sense.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:42:\"/comparison-between-yaffs-yaffs2-and-jffs2\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/359\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:42:\"/comparison-between-yaffs-yaffs2-and-jffs2\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:359\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:80:\"<span property=\"schema:name\">Comparison between Yaffs (Yaffs2) and JFFS2</span>\n\";}}',-1,1504686203.175,1,'config:filter.format.basic_html config:system.site node:359 node_view rendered user:1','277'),('entity_view:node:359:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"359\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:359\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504686203.172,1,'config:filter.format.basic_html config:system.site node:359 node_view rendered user:1','277'),('entity_view:node:359:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1854:\"<span property=\"schema:name\">Comparison between Yaffs (Yaffs2) and JFFS2</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>On Friday 02 March 2007 10:59, Charles F Johnson wrote:</p>\n\n<p>\"I\'m trying to understand the relative merits of JFFS2 vs YAFFS2. The response on the YAFFS mailing list is quite positive as far as leading me to believe that there are actual products shipping.\"</p>\n\n<p><br />\nCharles Manning replied:<br />\nAt a technical level, it is very difficult to make X vs Y comparisons because there are many factors involved which manifest differently on different systems therefore \'your mileage will vary\'. But, as a general rule of thumb, the following might help:</p>\n\n<p>1) YAFFS uses less run-time RAM to hold its state, so YAFFS scales better than JFFS2. There are quite a few systems using large NAND arrays (the largest partitions I know of are around the 6Gbyte mark).<br /><br />\n2) YAFFS garbage collection is simpler and faster, typically making for better performance under hard writing.<br /><br />\n3) YAFFS uses a whole page per file for headers, and does not provide compression. This means that JFFS2 is probably a better fit to small partitions. The flip side is that a lot of data (eg. MP3) does not compress very well, and enabling compression really hurts performance.<br /><br />\n4) While YAFFS has been used on NOR, it does not fit very well (because YAFFS does not use erase suspend). Thus if you\'re using smaller NAND partitions and using JFFS2 on NOR, then a JFFS2-only solution is very appealing.<br /><br />\nAll the above can generally boil down to: If you\'re using less than about 64MB the pain vs gain might play in favour of JFFS2. As you increase partition size, YAFFS makes more and more sense.</p></div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:359\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1506307655.081,1,'config:filter.format.basic_html node:359 node_view rendered','264'),('entity_view:node:359:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"359\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:359\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1506307655.068,1,'config:filter.format.basic_html node:359 node_view rendered','264'),('entity_view:node:359:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1069:\"<article role=\"article\" about=\"/comparison-between-yaffs-yaffs2-and-jffs2\" typeof=\"schema:Article\" class=\"article is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/comparison-between-yaffs-yaffs2-and-jffs2\" rel=\"bookmark\"><span property=\"schema:name\">Comparison between Yaffs (Yaffs2) and JFFS2</span>\n</a>\n    </h2>\n      <span property=\"schema:name\" content=\"Comparison between Yaffs (Yaffs2) and JFFS2\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">If you are trying to decide between Yaffs and JFFS2 then this note will give you an idea of the relative advantages of each.</div>\n      <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/comparison-between-yaffs-yaffs2-and-jffs2\" rel=\"tag\" title=\"Comparison between Yaffs (Yaffs2) and JFFS2\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about Comparison between Yaffs (Yaffs2) and JFFS2</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:359\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.906,1,'config:filter.format.basic_html node:359 node_view rendered user:1','271'),('entity_view:node:359:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"359\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:359\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.904,1,'config:filter.format.basic_html node:359 node_view rendered user:1','271'),('entity_view:node:360:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0SPlVdim3MxOYoQHo7KiB02kLdC1gL3DJB5dI_BjWpjA','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1094:\"<article role=\"article\" about=\"/archives/paper-investigating-log-management-crash-recovery-mechanism\" typeof=\"schema:Article\" class=\"article full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Paper investigating a log management &amp; crash recovery mechanism\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p><a href=\"http://www.cis.nctu.edu.tw/~lpchang/papers/SAC_wu_sac06.pdf\">This paper</a> proposes a method for efficient initialization and crash recovery for Flash-memory file systems. A log management scheme for the Flash-memory file systems is presented. The proposed log management method is implemented in a log-record manager and a logger. It was written by Chin-Hsein Wu, Tei-Wei Kuo and Li-Pen Change of the Department of Computer Science of National Taiwan University, Taipei, TAIWAN, and presented at an international SAC Conference in 2006. Copyright 2006 ACM 1-59593-108-2/06/0004</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:69:\"/archives/paper-investigating-log-management-crash-recovery-mechanism\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/360\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:69:\"/archives/paper-investigating-log-management-crash-recovery-mechanism\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:360\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:104:\"<span property=\"schema:name\">Paper investigating a log management &amp; crash recovery mechanism</span>\n\";}}',-1,1504645779.339,1,'config:filter.format.basic_html config:system.site node:360 node_view rendered user:1','278'),('entity_view:node:360:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"360\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:360\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504645778.983,1,'config:filter.format.basic_html config:system.site node:360 node_view rendered user:1','278'),('entity_view:node:365:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0Uf1gceR1X5uFydJvoLjMk-FSf9D1h-Ot9uJBP0MO3Kk','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:508:\"<article role=\"article\" about=\"/paying-us\" typeof=\"schema:WebPage\" class=\"page full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Paying us\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">You can pay us, as Aleph One Ltd, for an agreed product or service by clicking <a href=\"http://www.aleph1.co.uk/other\">HERE </a> </div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:10:\"/paying-us\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/365\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:10:\"/paying-us\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:365\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:46:\"<span property=\"schema:name\">Paying us</span>\n\";}}',-1,1505362018.630,1,'config:filter.format.full_html config:system.site node:365 node_view rendered user:4','303'),('entity_view:node:365:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"365\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:365\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505362018.620,1,'config:filter.format.full_html config:system.site node:365 node_view rendered user:4','303'),('entity_view:node:366:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0JdCQGGTuvF2SC3NqMvS-JjL_v2UwhWjyuCXxN5MIpAg','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:310:\"<article role=\"article\" about=\"/yaffs-embedded-structure\" class=\"image is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">YAFFS embedded structure</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:25:\"/yaffs-embedded-structure\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/366\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:25:\"/yaffs-embedded-structure\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:366\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:38:\"<span>YAFFS embedded structure</span>\n\";}}',-1,1504999824.056,1,'config:filter.format.full_html config:system.site node:366 node_view rendered user:1','307'),('entity_view:node:366:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"366\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:366\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504999824.054,1,'config:filter.format.full_html config:system.site node:366 node_view rendered user:1','307'),('entity_view:node:366:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:681:\"<article role=\"article\" about=\"/yaffs-embedded-structure\" class=\"image is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-embedded-structure\" rel=\"bookmark\"><span>YAFFS embedded structure</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-embedded-structure\" rel=\"tag\" title=\"YAFFS embedded structure\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about YAFFS embedded structure</span></a></li></ul>\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">YAFFS embedded structure</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:366\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.831,1,'config:filter.format.full_html node:366 node_view rendered user:1','301'),('entity_view:node:366:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"366\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:366\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.815,1,'config:filter.format.full_html node:366 node_view rendered user:1','301'),('entity_view:node:367:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0lejC87gdmFjnz-98sAKK8HdkTri8jALgRL7XOQuzzyA','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1774:\"<article role=\"article\" about=\"/archives/yaffs-talk-pdf-slides-celf-2007\" typeof=\"schema:WebPage\" class=\"page full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs Talk - PDF of slides from CELF, 2007\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n      <div class=\"field field--name-upload field--type-file field--label-hidden field--items\">\n              <div class=\"field--item\"><span class=\"file file--mime-application-pdf file--application-pdf icon-before\"><span class=\"file-icon\"><span class=\"icon glyphicon glyphicon-file text-primary\" aria-hidden=\"true\"></span></span><span class=\"file-link\"><a href=\"https://yaffs.net/sites/default/files/downloads/yaffs.pdf\" type=\"application/pdf; length=177635\" title=\"Open file in new window\" target=\"_blank\" data-toggle=\"tooltip\" data-placement=\"bottom\">yaffs.pdf</a></span><span class=\"file-size\">173.47 KB</span></span></div>\n          </div>\n  \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Attached is a PDF with slides from the Yaffs talk at CELF\'s Embedded Linux Conference Europe 2007. If you are able to view Ogg Theora video files, the talk is also <a href=\"http://free-electrons.com/pub/video/2007/elce/elce-2007-wookey-yaffs.ogg\">online</a>. Ogg Theora is a Free video format. Free players are available for all platforms. See the list <a href=\"http://wiki.xiph.org/index.php/TheoraSoftwarePlayers\">here</a>. If in doubt, VLC is probably available for your operating system.</p>\n\n<p>If you prefer to go straight to the .pdf if clides  click <a href=\"http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf\">http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf</a></p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:41:\"/archives/yaffs-talk-pdf-slides-celf-2007\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/367\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:41:\"/archives/yaffs-talk-pdf-slides-celf-2007\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:6:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"file:87\";i:3;s:8:\"node:367\";i:4;s:9:\"node_view\";i:5;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:79:\"<span property=\"schema:name\">Yaffs Talk - PDF of slides from CELF, 2007</span>\n\";}}',-1,1504960416.751,1,'config:filter.format.basic_html config:system.site file:87 node:367 node_view rendered user:1','282'),('entity_view:node:367:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"367\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:6:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"file:87\";i:3;s:8:\"node:367\";i:4;s:9:\"node_view\";i:5;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504960416.749,1,'config:filter.format.basic_html config:system.site file:87 node:367 node_view rendered user:1','282'),('entity_view:node:367:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1557:\"<span property=\"schema:name\">Yaffs Talk - PDF of slides from CELF, 2007</span>\n\n      <div class=\"field field--name-upload field--type-file field--label-hidden field--items\">\n              <div class=\"field--item\"><span class=\"file file--mime-application-pdf file--application-pdf icon-before\"><span class=\"file-icon\"><span class=\"icon glyphicon glyphicon-file text-primary\" aria-hidden=\"true\"></span></span><span class=\"file-link\"><a href=\"https://yaffs.net/sites/default/files/downloads/yaffs.pdf\" type=\"application/pdf; length=177635\" title=\"Open file in new window\" target=\"_blank\" data-toggle=\"tooltip\" data-placement=\"bottom\">yaffs.pdf</a></span><span class=\"file-size\">173.47 KB</span></span></div>\n          </div>\n  \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Attached is a PDF with slides from the Yaffs talk at CELF\'s Embedded Linux Conference Europe 2007. If you are able to view Ogg Theora video files, the talk is also <a href=\"http://free-electrons.com/pub/video/2007/elce/elce-2007-wookey-yaffs.ogg\">online</a>. Ogg Theora is a Free video format. Free players are available for all platforms. See the list <a href=\"http://wiki.xiph.org/index.php/TheoraSoftwarePlayers\">here</a>. If in doubt, VLC is probably available for your operating system.</p>\n\n<p>If you prefer to go straight to the .pdf if clides  click <a href=\"http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf\">http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf</a></p></div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:7:\"file:87\";i:2;s:8:\"node:367\";i:3;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1506813386.375,1,'config:filter.format.basic_html file:87 node:367 node_view rendered','269'),('entity_view:node:367:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"367\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:7:\"file:87\";i:2;s:8:\"node:367\";i:3;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1506813386.372,1,'config:filter.format.basic_html file:87 node:367 node_view rendered','269'),('entity_view:node:368:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0150aYqZg4wJHPsn3Vb_zltatWjZIl1lOrWFA1LDNPas','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:3422:\"<article role=\"article\" about=\"/ideas-list\" class=\"book is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><b>Overview</b> <br />\n<br />\n<div>\nYAFFS is an Open Source flash file system used in many embedded applications such as mobile phones, PDAs, aerospace and point of sale. YAFFS is mainly used in Linux systems but is also used with other OSs. YAFFS is even used in the Google Android platform! <br />\n <br />\n<div>\n We\'re looking for some bright minds interested in the GSoC concept - <a href=\"http://code.google.com/soc/2008\">Google 2008 Summer of Code</a> - to help make YAFFS even better. The particular area of interst here is performance improvement, and enriching the YAFFS development environment with support tools.\n <p>We strongly encourage student generated ideas, as well as further ideas from the YAFFS community. <br />\n  <br />\n  <b>Performance analysis</b> <br />\n  </p>\n <div>\n  Performance is increasingly important in delivering high quality user experience on media-rich devices such as Google Android-based devices. High file system performance leads to slicker UI and faster data transfers. High performance also reduces flash memory read/writes which  reduces power consumption, meaning better battery life. <br />\n   <br />\n  <div>\n   Our major focus for GSoC is to develop a performance analysis framework and tools that will help to identify opportunities for improvement as well as evaluate the performance impact of code changes. It would be great if this performance toolkit could be generalised for other applications, but that\'s beyond the focus of what we want to achieve here. <br />\n    <br />\n   <div>\n    We have some ideas to seed this, but encourage students to think of their own ideas too.\n   </div>\n   <div>\n    * Develop an environment-neutral data gathering framework.\n   </div>\n   <div>\n    * Write a FUSE wrapper for YAFFS to improve test scripting. Include the data gathering framework in the FUSE wrapper.\n   </div>\n   <div>\n    * Extend the Android simulator with these tools, thus allowing performance analysis of Linux-based mobile devices.\n   </div>\n   <div>\n    * Develop performance-analysis display tools to allow clear observation of gathered data.\n   </div>\n   <div>\n    * Help in performance analysis. <br />\n     <br />\n     <b>Other ideas</b> <br />\n   </div>\n   <div>\n    We have some ideas of things we\'d like to see done, but are not sufficient for a GSoC project on their own. These could be included with other ideas to make sufficient scope for a GSoc project. These tasks include: <br />\n     <br />\n   </div>\n   <div>\n    * If documentation is your delight we would love to have someone build on the existing material and generate lucid new docs on How to integrate YAFFS, How it works, YDI Interface details, and anything else your training or experience makes clear our users would benefit from.\n   </div>\n   <div>\n    * Develop developer-support tools such as unyaffs: a tool to take a yaffs image and unpack the files on the host device. <br />\n     *Improve/rewrite mkyaffsimage and related mtdutils to make image generation and extraction easier to do.\n    <p>&nbsp; </p>\n   </div>\n   <div>\n    Got some ideas of you own? Give us a yell!\n   </div>\n  </div>\n </div>\n</div>\n</div>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:11:\"/ideas-list\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/368\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:11:\"/ideas-list\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:368\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:24:\"<span>IDEAS List</span>\n\";}}',-1,1504639310.394,1,'config:filter.format.full_html config:system.site node:368 node_view rendered user:4','303'),('entity_view:node:368:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"368\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:368\";i:3;s:9:\"node_view\";i:4;s:6:\"user:4\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504639310.392,1,'config:filter.format.full_html config:system.site node:368 node_view rendered user:4','303'),('entity_view:node:368:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:702:\"<article role=\"article\" about=\"/ideas-list\" class=\"book is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/ideas-list\" rel=\"bookmark\"><span>IDEAS List</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">This describes YAFFS subject areas that need work done, in order to get the attention of those involved in Google\'s Summer of Code</div>\n      <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/ideas-list\" rel=\"tag\" title=\"IDEAS List\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about IDEAS List</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:368\";i:2;s:9:\"node_view\";i:3;s:6:\"user:4\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.719,1,'config:filter.format.full_html node:368 node_view rendered user:4','297'),('entity_view:node:368:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"368\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:368\";i:2;s:9:\"node_view\";i:3;s:6:\"user:4\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.706,1,'config:filter.format.full_html node:368 node_view rendered user:4','297'),('entity_view:node:369:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0zo04bScdszpuzXTCTVkcBeQAYIVaMt3a6_6VAPI1p4U','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:34024:\"<article role=\"article\" about=\"/yaffs-porting-guide\" typeof=\"schema:WebPage\" class=\"page full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs Porting Guide\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>version 2.0</p>\n\n<p>Last changed: rrw@kynesim.co.uk, 2009-03-20<br />\n </p>\n\n<h3>Purpose</h3>\n\n<p>The purpose of this document is to describe how to bring up Yaffs2 on a board previously unsupported using the Yaffs Direct Interface, with an example using eCos on a Balloon board.</p>\n\n<p>Before we start you probably want to have the data sheet for the NAND chips you are using in front you so that you can refer to it as we go along.</p>\n\n<h3>Background and NAND Flash Properties</h3>\n\n<p>NAND flash is generally arranged in <em>pages</em> and <em>blocks</em>. A page contains a section of data bytes and then a section of out-of-band (<em>OOB</em>) data bytes. Blocks contain a number of pages .<br /><a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram\" height=\"335\" src=\"/sites/yaffs.net/files/images/yaffs_porting_guide_html_2de490f8.png\" width=\"783\" /></a></p>\n\n<p>The OOB section of each page is used keep track of various things like file system state, error correction data and bad block marking.</p>\n\n<p>NAND flash is programmed (written to) and read on a largely page basis (though with some level of random access) and is erased on a block basis. That is, to erase a page, you must erase the rest of the containing block along with it.</p>\n\n<p>When programming NAND flash only 1\'s can be programmed to 0\'s, so to change a byte containing 0x00 to 0xFF it must be erased, along with the rest of the block. However subsequent programs may still be made without an erase if no 0s are to be changed to 1s, this might be useful in a scenario where subsequent data might regularly have this property.</p>\n\n<p>When manufactured NAND flash contains bad blocks, these are blocks that are not reliable and any data in them will commonly corrupt easily. These must be kept track of and the OOB data section is used to mark a bad block.</p>\n\n<p>NAND in general is prone to bit errors and for that reason the OOB data is also used to write error correction codes (ECC) so that some errors can be corrected.</p>\n\n<h3>Yaffs NAND Model</h3>\n\n<p>It is probably a good thing to detail at this point how Yaffs2 expects the NAND to behave so that you are aware of what you have to provide in the NAND driver to get YAFF running. Yaffs uses some different terminology in that it refers to a page as a <em>chunk</em>.</p>\n\n<p>Yaffs2 uses a fairly abstract model for NAND flash, this allows a lot of flexibility in the way Yaffs can be used. Yaffs is designed for NAND flash and makes the following assumptions and definitions:</p>\n\n<ul><li>NAND flash is arranged in blocks. Each block is the same size and comprises an integer number of chunks. Each block is treated as a single erasable item.</li>\n	<li>A page (chunk) equates to the allocation units of flash.</li>\n	<li>All accesses (reads and writes) are page (chunk) aligned.</li>\n	<li>When programming a NAND flash, only the zero bits in the pattern being programmed are relevant, and one bits are \"don\'t care\". For example, if a byte already contains the binary pattern 1010, then programming 1001 will result in the pattern which is the logical AND of these two patterns i.e. 1000. This is different to NOR flash.</li>\n</ul><p>Yaffs identifies blocks by their block number and chunks by their chunk Id. Yaffs treats a blank (0xFF filled) block as being free or erased. Thus, the equivalent of formatting for a Yaffs partition is to erase all the blocks that are not bad.</p>\n\n<p>Therefore Yaffs minimally needs access to functions that enable it to erase blocks and to read and write on a page basis. It is also helpful to be able to read only OOB data as reading/writing a full page to only view/update OOB data will cost many serial read cycles over the bus. This is an overhead that can be avoided using the random access read and write features of some nand chips.</p>\n\n<p> </p>\n\n<h2>Writing a Driver for NAND flash Chips</h2>\n\n<h3>Writing a Driver for the Samsung 628 K9F2G08U0M PCB0 on the Balloon Board (v3.01)</h3>\n\n<p>For the Balloon board the NAND chips hang off the CPLD which is in turn hooked up to the system bus. This is quite board specific and in this case reading the VHDL code reveals how to change the values on the pins of the NAND chips. You may look at the code by downloading the balloon source code (Appendix A) and looking at balloon3.vhd and Balloon_nand.vhd in balloon/vhdl/fpga/.</p>\n\n<p>It will be likely that this is significantly different on your platform and you should consult the relevant data sheets and documentation to determine how to access the NAND hardware on your board. I will present an example of the balloon board in order to give an overview of the kind of thing that is required.</p>\n\n<p>On the Balloon the CPLD routes data on the bus with certain address to the logic on the CPLD that actually controls the flash chips. They are as follows:</p>\n\n<p><code>NAND Data Bus : 0x10e00000</code> <code>NAND Control 2: 0x10e00010</code> <code>NAND Control : 0x10e00014</code></p>\n\n<p>Sending data to the \'NAND Data Bus\' address will put that data onto the I/O pins of the NAND chips. All of the nand chips are hooked up to the same pins on the CPLD so writing to the \'NAND Data Bus\' address will put the value written on the I/O pins for <em>all</em> of the available flash chips. To isolate the chip you want to work with using the chip enable pin on each flash chip.</p>\n\n<p>This is done by writing to the \'NAND Control\' (0x10e00014) address. When writing to \'NAND control\', the CPLD takes the data value on the bus and routes each bit to a different wire. This bit field is structured as follows:</p>\n\n<p> </p>\n\n<table><colgroup><col /><col /></colgroup><tr><td><em>Pin Attached To</em></td>\n			<td><em>Bit in NAND Control value</em></td>\n		</tr><tr><td>CLE (Control Latch Enable)</td>\n			<td>0</td>\n		</tr><tr><td>ALE (Address Latch Enable)</td>\n			<td>1</td>\n		</tr><tr><td>nCE0 (not Chip Enable for chip 0)</td>\n			<td>2</td>\n		</tr><tr><td>nCE1 (for chip 1)</td>\n			<td>3</td>\n		</tr><tr><td>nCE2 (for chip 2)</td>\n			<td>4</td>\n		</tr><tr><td>nCE3 (for chip 3)</td>\n			<td>5</td>\n		</tr><tr><td>nSE (not Chip Enable for chip 0)</td>\n			<td>6</td>\n		</tr><tr><td>nWP (not Write Protect)</td>\n			<td>7</td>\n		</tr></table><p> </p>\n\n<p>So for example bit 1 on the data lines is put onto the ALE pin on the physical chip. Bits prefixed with \'n\' are active low, for example chip 0 is selected when nCE0 is low and nCE1-3 are high.</p>\n\n<p> </p>\n\n<p>So writing to \'NAND Control\' we can change the values of the pins on the flash. Again, CLE, ALE, nSE and nWP change the value of the corresponding pin on all the flash chips available, nCE[0-3] will select the chip you are using.</p>\n\n<p>Finally, NAND flash typically comes in couple of flavours, 8 bit wide (x8) and 16 bit wide (x16). This means that x8 chips have 8 I/O pins and x16 have 16. The logic on the CPLD on the Balloon can handle both if you tell it which you are currently dealing with. Writing to \'NAND Control 2\' a value of 1 puts the CPLD logic for the NAND chips into x8 mode and 0 into x16 mode. I will assume for the rest of this document that there are only x8 chips connected to the balloon but it should be fairly trivial to extend it to support both.</p>\n\n<h3>Using the Flash Chips</h3>\n\n<p>The flash chips we\'re using have a number of commands, each triggered by a sequence of one or two command codes. You will want to refer to the data sheets for precise details of these functions, but I will briefly describe some of them in this document. The command set that we have for the particular chip we\'re using is table 1 on page 7 of the data sheet.</p>\n\n<p>To input a command there is generally one or two command input cycles. For two cycle commands there is generally an initial command followed by some data needed to complete the command then another command cycle to notify that the relevant data has been input and to start execution. For example for read operations the command 0x00 is latched in followed by some address input cycles followed by the command 0x30 to start the operation. With this in mind I will now describe how to input commands, the \'Command Latch Cycle\'.</p>\n\n<p>Note that for this section I have assumed that the bus is sufficiently slow that the set-up and hold times are not an issue, if you have a fast bus then you may have to wait for a small amount of time (refer to the data sheet) after changing values on the pins (by writing to the correct address) so that set-up and hold times are not violated.</p>\n\n<h3>Command Latch Cycle</h3>\n\n<p>For the command latch cycle you need to first select a chip by setting the relevant nCE low and then you need to set the CLE bit high, that means writing to the \'NAND Control\' address. ALE must also be low and should be set at the same time as CLE. It is then a case of putting the command value onto the I/O pins by writing to the \'NAND Data Bus\' address the value of the command you want. This will then latch in the command, afterwards you will need to clear the CLE bit again.</p>\n\n<p>You will also notice from looking at the data sheet that something needs to be done with the nWE (not <strong>w</strong>rite <strong>e</strong>nable) pin (specifically it should be low while latching in the command), but that I have yet to describe a mechanism for changing its value. This is because it is dealt with by the logic in the CPLD and whenever data is sent to the data address the CPLD will toggle nWE appropriately. (This is also true of nRE (not <strong>r</strong>ead <strong>e</strong>nable) when reading). This process is implemented in the nand_chip_select and the send_command functions (flash.c).</p>\n\n<h3>Address Latch Cycle and Addressing</h3>\n\n<p>The process for the Address Latch Cycle is similar to that for command latching (with the sense of ALE and CLE reversed) and can be looked at in the data sheet and is implemented in send_address in flash.c. The addressing is done by row and column. There are 5 address cycles on the flash chips we\'re looking at. The first cycle contains bits 0-7 of the column address, the second bits 8-11 with the remaining bits of the byte to be sent low. The row address is over 3 more cycles in a similar fashion.</p>\n\n<p>You may wish to chose to address the individual bytes of the chip with the OOB data not directly addressable. This has enabled me to lump several chips into the same address space and select the correct chip based on the address. Addresses then need to be converted to row and column. You should also check that they are page/block aligned in the relevant places if that\'s what your functions expect. It needn\'t be done this way any you could use page numbers instead of bytes just as easily.</p>\n\n<p><br /><a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram 2\" height=\"209\" src=\"sites/yaffs.net/files/images/yaffs_porting_guide_html_m11b1f893.png\" width=\"654\" /></a></p>\n\n<p> </p>\n\n<p>The \'row\' is essentially the page index and the \'column\' is the index into to that page, so if you wanted to read from the start of page 213 you would send 0 for the column and 213 for the row. Conversely if you wanted just the OOB bytes from the same page you would send a column value of 2048 (given a page size of 2048+64 bytes).</p>\n\n<p><br /><a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram 3\" height=\"271\" src=\"sites/yaffs.net/files/images/yaffs_porting_guide_html_m4650262f.png\" width=\"347\" /></a></p>\n\n<p> </p>\n\n<h3>Finding Chip information</h3>\n\n<p>You will then need to find out which chips are active (e.g. on the balloon there are 4 possible chips, not all of which will exist) and what type of chips they are. For this there is the \'Read ID\' operation. This operation is implemented in the read_ids function in flash.c. The result of the operation gives the manufacturer and device code of the chip and information about the chip (page size, block size, oob size etc). To find which chips are available, loop through the possible chips and start a Read ID command on each of them, if the expected data is returned then there is a chip at that location.</p>\n\n<p>The operation is started by sending the command 0x90 and then one address cycle of 0x00. There are then 5 read cycles which give you data about the device. A description of how to unpack this information from the returned bytes is located on page 32 of the data sheet for the chip described here.</p>\n\n<p>This then gives you how many chips you have and what layout the data in them has.</p>\n\n<h3>Bad Block Checking</h3>\n\n<p>Contained within a nand chip are blocks that the manufacturer will not guarantee the reliability of (this is to increase yield in manufacturing) and so bad blocks must be kept track of. The Samsung chips come with the first byte (or word for x16) of the first and second page of each bad block not programmed as 0xFF.</p>\n\n<p>This bad block marking should be maintained and should be added to in the same way when a bad block is is discovered. Yaffs will expect you to provide a function it can call to mark a particular block as bad when yaffs decides it is necessary.</p>\n\n<p>Yaffs keeps track of bad blocks itself so that the driver doesn\'t need to worry about masking out bad blocks.</p>\n\n<h3>Erasing a Block</h3>\n\n<p>An example of this operation is given in nand_erase_block in flash.c. If you are addressing the nand by bytes then you must first check that the address is aligned to the start of a block and then convert the address into a block number. If there is more than one chip this will involve working out which chip the address refers to and then selecting the correct chip. This can be seen in the select_chip function in flash.c. You must then send the first command cycle for the erase operation before sending 3 cycles of address and then finally the last command cycle.</p>\n\n<p>For the erase operation the 3 address cycles are different than for the read/write operations. Only address bits A18 to A29 is valid (for x8) while A12 to A17 is ignored. In terms of the ordinary 5 cycles address input you only need to deal with the last 3 cycles and of those only the highest 2 bits of the 3rd cycle are used and the full 4th and 5th cycle are used.</p>\n\n<p>Once the operation has been started the program can check the progress of the operation by sending a command of 70h. Each subsequent read will contain the read status. The driver should wait until the read is complete (by the read status operation), the read status operation also contains information about whether the erase failed and this information should be returned from the function doing the erase.</p>\n\n<h3>Reading a Page</h3>\n\n<p>Reading a page is performed by first selecting the correct chip and then converting the address to a row and column number. You can then sending the first command cycle for the read operation followed by 5 address cycles as described in the previous sections. The second command cycle then starts the read operation. The driver must then wait for the data to be retrieved into the data registers on the NAND before they can be read out over the bus. For the example chip this is 25us, consult the data sheet as this may differ. The data can then be read out sequentially byte by byte until all the data needed is obtained.</p>\n\n<h3>Writing a Page</h3>\n\n<p>Page program operations are performed by first selecting the correct chip converting the address to row and column numbers. The page program operation is initiated by the relevant fist command latch cycle (command 0x80) followed by an address latch cycle (as for read), serial data loading and then the second command latch cycle (command 0x10).</p>\n\n<p>The serial data loading is done by serially writing data to the I/O pins. Up to 2112 bytes (x8) can be loaded into the data registers. Once the second command cycle is sent the program is initiated and there is then a programming period where the loaded data is programmed into the appropriate cell. The driver should wait for this to complete by issuing a read status command (0x70) and monitoring the R/nB (ready / not busy) bit. The R/nB flag is on I/O pin 6 and can be checked by repeatedly reading from the \'NAND Data Bus\' address. Once the operation is complete the Write Status Bit (I/O 0 ) may be checked to confirm that the operation was successful.</p>\n\n<h2>Yaffs</h2>\n\n<h3>How To Use Yaffs</h3>\n\n<h3>Checking Out From Git</h3>\n\n<p>The first thing to do is to obtain the source code for Yaffs. This can be done from CVS, details of the process can be found at <a href=\"http://www.yaffs.net/download-yaffs-using-git\">http://www.yaffs.net/download-yaffs-using-git</a>.</p>\n\n<p>The following command will checkout the latest Git version using public read-only access, if you are using bash.</p>\n\n<p><code>$ </code>git clone git://www.aleph1.co.uk/yaffs2 </p>\n\n<h3>Making Some Tweaks to the Source Code</h3>\n\n<p>As of the latest version from CVS in January 2009, you will need to make a small number of changes before you can compile the source code without errors and warnings. There is a patch file included with this document.</p>\n\n<p>You will need to provide a definition of loff_t (in yaffs2/direct/ydirectenv.h) this is for holding the file size in bytes, you should make it big enough to hold the largest file size you wish to support. Unsigned long is probably a good place to start. You will need to edit yaffsfs.c to change a #if to a #ifdef. Then if you have the relevant warnings and -Werror switched on you will need to correct a couple of printf format strings to get the type right (changing a few \'%d\' to \'%ld\').</p>\n\n<p><code>change yaffs/ydirectenv.h </code></p>\n\n<p><code>+ typedef unsigned long loff_t; </code></p>\n\n<p><code>change yaffs2/direct/yaffsfs.c ~line 1117 </code></p>\n\n<p><code>- #if CONFIG_YAFFS_WINCE </code></p>\n\n<p><code>+ #ifdef CONFIG_YAFFS_WINCE</code></p>\n\n<h3>Relevant Files to the Direct Interface</h3>\n\n<p>There are quite a few files that get checked out, not all of which you will need to get going with the yaffs direct interface. The ones you will actually need are listed bellow, you do not need to compile the rest in.</p>\n\n<p><code><code>direct/yaffsfs.c </code></code></p>\n\n<p><code><code>yaffs_guts.c </code></code></p>\n\n<p><code><code>direct/yaffscfg.c </code></code></p>\n\n<p><code><code>yaffs_nand.c </code></code></p>\n\n<p><code><code>yaffs_tagsvalidity.c </code></code></p>\n\n<p><code><code>yaffs_checkptrw.c </code></code></p>\n\n<p><code><code>yaffs_qsort.c </code></code></p>\n\n<p><code><code>yaffs_tagscompat.c </code></code></p>\n\n<p><code><code>yaffs_ecc.c </code></code></p>\n\n<p><code><code>yaffs_packedtags2.c</code></code></p>\n\n<h3>Some Relevant Preprocessor Flags</h3>\n\n<p>There are many different configuration options for yaffs, here are a few that you should be aware of for using the yaffs direct interface.</p>\n\n<ul><li>CONFIG_YAFFS_DIRECT - Tell yaffs to use the direct interface.</li>\n	<li>CONFIG_YAFFS_YAFFS2 - Tell yaffs we want to use yaffs2</li>\n	<li>CONFIG_YAFFS_PROVIDE_DEFS - provides some definitions for file types and #includes linux/types.h, linux/fs.h, linux/stat.h (see yaffs2/devextras.h).</li>\n	<li>CONFIG_YAFFSFS_PROVIDE_VALUES - This may be used so that you can customise error values and constants like O_RDONLY to match the underlying system values, if itis not defined then it includes errno.h,sys/stat.h and fcntl.h (see yaffs2/direct/yaffsfs.h).</li>\n</ul><p>Specify these options when compiling yaffs, i.e. -DCONFIG_YAFFS_DIRECT etc.</p>\n\n<h3>Configuring</h3>\n\n<p>You will then need to provide yaffs with configuration information. This includes details about the nand flash you are using and also tells yaffs which functions to call when when it wants to read/write/erase parts of the flash, these functions will form the bridge between yaffs and the underlying hardware driver. This customisation is done in yaffscfg.h. Within yaffscfg.h you will need to provide a number of operating-system-like functions and a function to initialise yaffs. For example providing functions for malloc and free. Here is a breakdown of those functions that need to be implemented.</p>\n\n<h3>Operating System Functions</h3>\n\n<p><code><code>void yaffsfs_SetError(int err); </code> </code></p>\n\n<p>Report system errors, for example using errno if it exists.</p>\n\n<p><code><code>void *yaffs_malloc(size_t size);</code> <code>void yaffs_free(void *ptr);</code> </code></p>\n\n<p>As for the standard malloc and free functions, if they already exist on your system then you can just shim them.</p>\n\n<p><code><code>void yaffsfs_LocalInitialisation(void);</code> <code>void yaffsfs_Lock(void);</code> <code>void yaffsfs_Unlock(void);</code> </code></p>\n\n<p>Use yaffsfs_LocalInitalisation to initialise \"Real Time Operating System\" state, if the system is multi-threaded then it should initialise a semaphore/mutex for use by lock and unlock. Lock/unlock should use the semaphore set up in LocalInitialisation to lock yaffs from multi-threaded access.</p>\n\n<p><code><code>__u32 yaffsfs_CurrentTime(void);</code> </code></p>\n\n<p>This can be any time increment of use to the system. If this is not required, then it is fine to just use a function that returns zero.</p>\n\n<h3>Yaffs Startup Function</h3>\n\n<p><code><code>int yaffs_StartUp(void); </code> </code></p>\n\n<p><code><code>Return value: YAFFS_OK or YAFFS_FAIL</code> </code></p>\n\n<p>This functions should be used to provide yaffs with many details about the properties of the underlying nand device. Within this function you will need to set up a \'yaffs_Device\' (yaffs_guts.h) and a \'yaffsfs_DeviceConfiguration\' (direct/yaffscfg.h). How to set up a yaffs device will follow in the next section. Once you have set up the required yaffs_Device structures you should call yaffs_initialise (yaffs_guts.h) with a pointer to a null terminated array of yaffs_DeviceConfiguration structures. A yaffs_DeviceConfiguration structure contains a pointer to a yaffs_Device and the \'mount point\' string (prefix) that that device corresponds to.</p>\n\n<h3>Yaffs Devices</h3>\n\n<p>A yaffs device is a logical device that represents part of or a whole physical device. You might think of it as a \'partition\' on the nand. For example, it might cover the whole of the nand device or perhaps only claim half, with another yaffs_Device claiming the other half. It may also be used so that you can use a device other than a flash device (e.g. RAM) for testing purposes.</p>\n\n<p>A yaffs_Device keeps track of the start and end block, so you may have more than one yaffs_Device corresponding to the same physical device by altering the start and end block of the yaffs device.</p>\n\n<p>The fields on the yaffs_Device struct that you need to set up yourself are listed below, all other fields are setup automatically by yaffs.</p>\n\n<p><code><code>int nDataBytesPerChunk</code> </code></p>\n\n<p>As the name suggests this is the number of bytes per chunk, remembering that in yaffs terminology a page is referred to as a chunk, this is then the number of bytes per page. This is the number of data bytes, that is the number of bytes excluding the OOB byte data. E.g. if a page is 2048byte + 64bytes of OOB then set nDataBytesPerChunk to 2048.</p>\n\n<p><code><code>int nChunksPerBlock </code> </code></p>\n\n<p>Straightforwardly the number of chunks (pages on the nand) in each block on the physical nand device. Must be at least 2.</p>\n\n<p><code><code>int spareBytesPerChunk</code></code><br />\nThis is the size of the spare area, i.e. the number of OOB bytes per chunk (page)<code>. </code></p>\n\n<p><code><code>int startBlock</code> </code></p>\n\n<p>The block number (not the address in bytes) on the chip of the first block of this logical yaffs_Device. Beware, yaffs needs the first block to be free so you should not set this to 0, if it is then yaffs will add on one to it itself and also add on one to the end block which could be an issue if you wanted your device to start at block 0 and finish at the last block which might mean yaffs trying to write to a non-existent block.</p>\n\n<p><code><code>int endBlock</code> </code></p>\n\n<p>The block number on the chip of the last block for this logical yaffs_Device. If startBlock == 0 then yaffs will use endBlock+1. Must be at least startBlock + nReservedBlocks + 2.</p>\n\n<p><code><code>int nReservedBlocks</code> </code></p>\n\n<p>This is then number of erasable blocks that Yaffs must keep in reserve for garbage collection and to cover for block failures. This must be a minimum of 2, but 5 or so is better. If you are using a medium that is not expected to fail (eg. RAM for a RAM disk, or a host file system emulation then 2 is OK).</p>\n\n<p><code><code>int nShortOpCaches</code> </code></p>\n\n<p>This configures the number of entries in the Yaffs cache for this device. A value of zero defeats the cache. A value of 10 to 20 is recommended for most systems. Cannon be any bigger than YAFFS_MAX_SHORT_OP_CACHES.</p>\n\n<p><code><code>int useNANDECC</code> </code></p>\n\n<p>This is a flag that tells yaffs whether it should be doing ECC calculations or if it should be left to the driver.</p>\n\n<p><code><code>void *genericDevice</code> </code></p>\n\n<p>This is a pointer which should point to any data that the underlying nand driver will need to know to write and read from the physical device.</p>\n\n<p><code><code>int isYaffs2</code> </code></p>\n\n<p>Are we using Yaffs2? We only deal with Yaffs2 in this document.</p>\n\n<p><code><code>int inbandTags</code> </code></p>\n\n<p>Is there an OOB section? If not then this should be true. Only relevant to Yaffs2.</p>\n\n<p><code><code>_u32 totalBytesPerChunk</code> </code></p>\n\n<p>Possibly a misleading name, it should be equal to nDataBytesPerChunk not nDataBytesPerChunk + spareBytesPerChunk as the name might suggest. If inbandTags is true then yaffs sets nDataBytesPerChunk such that there is enough space for the data yaffs would normally store in the spare area.</p>\n\n<p><code><code>write/readChunkWithTagsFromNAND, markNANDBlockBad, queryNANDBlock</code> </code></p>\n\n<p>These are all pointers to functions that you shall provide to provide Yaffs with a method of writing/reading etc from the NAND.</p>\n\n<h3>NAND access functions</h3>\n\n<p>If you are using Yaffs2 you need to provide pointers to functions that Yaffs can call to write and read from the nand. Example implementations of these function can be seen in yaffs_mtdif.c, these are the functions written to do the same job for the linux mtd layer and provides the write and read functions. The following functions return YAFFS_OK on success and YAFFS_FAIL on failure.</p>\n\n<p><code><code>int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,</code> <code>int chunkInNAND, const __u8 * data,</code> <code>const yaffs_ExtendedTags * tags);</code> <code>dev: yaffs_Device to write to.</code> <code>chunkInNAND: Which page to write the chunk to.</code> <code>Data: Pointer to the data to write</code> <code>tags: Unpacked OOB data.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\n\n<p>This function is to write pages (chunks) to the nand. In this function you will probably want to first retrive any useful data that you put in dev-&gt;genericDevice (in the yaffs_StartUp function) and use it to call the function you wrote previously to write data to the nand. For yaffs2 data and tags should never be NULL. chunkInNand is the page number of the page to write to, not an address so it will need converting if that\'s what your underling functions to write to the nand expect.</p>\n\n<p>You will then need to pack the tags into a yaffs_PackedTags2 structure, this takes out the all relevant details from the yaffs_ExtendedTags tags structure and calculates ECC data on it before placing them in the packedtags2 structure. This structure is the OOB data you will want to write out to the nands spare area.</p>\n\n<p>How you write these out to the OOB data depends on your architecture, nand chips and therefore how bad block marking is done. If for example the first byte is used for bad block marking then simply writing the tags out after the first byte is acceptable. The ECC data in packed tags only covers error correction and detection for the tags in the OOB data, if you want ECC on the data then you must do that yourself.</p>\n\n<p>To perform ECC checks to the data bytes you may use the yaffs_ECCCalculate function which calculates ECC data for 256 byte sections of data. This function produces 3 bytes of ECC data per 256 bytes. Therefore for 2048 bytes of data in each page you would need (2048/256) * 3 = 8 * 3 = 24 extra bytes of ECC data. This can be written out after the bad block byte and packed tags data.<br />\n </p>\n\n<p><code><code>int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,</code> <code>int chunkInNAND, __u8 * data,</code> <code>yaffs_ExtendedTags * tags);</code> <code>dev: The yaffs_Device to read from.</code> <code>chunkInNAND: Which page to read from.</code> <code>Data: Pointer to a buffer to read data to.</code> <code>tags: Pointer to a buffer to unpacked OOB data into.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\n\n<p>This function should do the opposite to the previous function. Firstly, read in the data and OOB bytes. Secondly place the data bytes in the area pointed to by data, then unpack the OOB bytes into into the pointer to tags using yaffs_UnpackTags2.</p>\n\n<p>Once the tags have been unpacked you should then recalculate the ECC data on the data bytes you just read back, just as you did for the write operation. Then use the recalculated ECC and the ECC data read out of the OOB bytes with yaffs_ECCCorrect to correct the data.</p>\n\n<p>Depending on the return value from yaffs_ECCCorrect you should set tags-&gt;eccResult to reflect whether anything was corrected or the correction failed. yaffs_UnpackTags2 also sets tags-&gt;eccResult so you should only update it if the result of the data correction is worse than is already there. i.e. if after the tags are unpacked and eccResult is YAFFS_ECC_RESULT_FIXED and ECC correction on the data read back resulted in no errors then you should leave unpackedtags2 and YAFFS_ECC_RESULT_FIXED and not set it to YAFFS_ECC_RESULT_NO_ERROR.</p>\n\n<p><code><code>int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);</code> <code>dev: yaffs_Device to write to.</code> <code>blockNo: Which block to mark.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code></code></p>\n\n<p>This should mark the block bad. This probably means reading the OOB data and changing the relevant byte that marks the bad block, and writing the OOB data back.</p>\n\n<p><code><code>int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,</code> <code>yaffs_BlockState * state, __u32 *sequenceNumber);</code> <code>dev: The yaffs_Device to write to.</code> <code>blockNo: Which block to mark.</code> <code>state: Upon returning this should be set to the relevant state of this particular block.</code> <code>Sequence number: The Sequence number of this block. 0 if the block is unused.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\n\n<p>This should check whether or not the block is valid.</p>\n\n<p>If the bad block marker is set in the OOB then *state should be set to YAFFS_BLOCK_STATE_DEAD *sequenceNumber set to 0, and return YAFFS_FAIL.</p>\n\n<p>If the block is not bad then the tags should be unpacked. After the tags are unpacked, and it is found that chunk is used (see tags.chunkUsed) *sequenceNumber should be set to tags.sequenceNumber and *state to YAFFS_BLOCK_STATE_NEEDS_SCANNING, otherwise if the block is not used then *sequenceNumber should be 0 and *state should be set to YAFFS_BLOCK_STATE_EMPTY.</p>\n\n<h3>Application Interface</h3>\n\n<p>The yaffs provides a number of functions for applications to interface with it. These are mostly the same as the standard clib open/close etc prefixed with yaffs_ eg yaffs_open. These functions are defined in direct/yaffsfs.h.</p>\n\n<p>To initialise yaffs so that reading and writing can be done, you must call yaffs mount for each yaffs device you would like to use, e.g. yaffs_mount(\"/boot\"). This could be done at system boot if there is an operating system present so that the application need to worry about this. You will also need to call yaffs_unmount when you have finished so that yaffs may write any state it needs to to disk.</p>\n\n<p>If there is already an application interface for reading and writing files you may shim the relevant function calls with the related operating system calls.</p>\n\n<p>E.g. simply doing #define open(path, oflag, mode) yaffs_open(path, oflag, mode)</p>\n\n<p>Or having something more complex to provide redirection functions if there is more than one file system present.</p>\n\n<p><code><code>For example: int open(const char *path,...)<br />\n{<br />\n//Determine which file system is being used </code> <code>if(it_is_a_yaffs_path(path)) {</code> <code> return yaffs_open(...);<br />\n} else {<br />\n// Do something else<br />\n}<br />\n}</code></code></p>\n\n<h2>Appendices</h2>\n\n<h3>Appendix A - Accessing the Balloon Source Code</h3>\n\n<p>The latest source code for the balloon board can be checked out from SVN. There is different code for different balloon versions. Details of getting the source and setting up tool chains is decribed in the following page <a href=\"http://www.balloonboard.org/software.html\">http://www.balloonboard.org/software.html</a>. If you just want to take a look at the latest mainline code then the following will give you what you want.</p>\n\n<p>svn checkout svn://balloonboard.org/balloon/trunk/</p>\n\n<p> </p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:20:\"/yaffs-porting-guide\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/369\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:20:\"/yaffs-porting-guide\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:369\";i:3;s:9:\"node_view\";i:4;s:6:\"user:5\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:56:\"<span property=\"schema:name\">Yaffs Porting Guide</span>\n\";}}',-1,1504706619.240,1,'config:filter.format.basic_html config:system.site node:369 node_view rendered user:5','273'),('entity_view:node:369:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"369\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:369\";i:3;s:9:\"node_view\";i:4;s:6:\"user:5\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504706619.238,1,'config:filter.format.basic_html config:system.site node:369 node_view rendered user:5','273'),('entity_view:node:369:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:33828:\"<span property=\"schema:name\">Yaffs Porting Guide</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>version 2.0</p>\n\n<p>Last changed: rrw@kynesim.co.uk, 2009-03-20<br />\n </p>\n\n<h3>Purpose</h3>\n\n<p>The purpose of this document is to describe how to bring up Yaffs2 on a board previously unsupported using the Yaffs Direct Interface, with an example using eCos on a Balloon board.</p>\n\n<p>Before we start you probably want to have the data sheet for the NAND chips you are using in front you so that you can refer to it as we go along.</p>\n\n<h3>Background and NAND Flash Properties</h3>\n\n<p>NAND flash is generally arranged in <em>pages</em> and <em>blocks</em>. A page contains a section of data bytes and then a section of out-of-band (<em>OOB</em>) data bytes. Blocks contain a number of pages .<br /><a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram\" height=\"335\" src=\"/sites/yaffs.net/files/images/yaffs_porting_guide_html_2de490f8.png\" width=\"783\" /></a></p>\n\n<p>The OOB section of each page is used keep track of various things like file system state, error correction data and bad block marking.</p>\n\n<p>NAND flash is programmed (written to) and read on a largely page basis (though with some level of random access) and is erased on a block basis. That is, to erase a page, you must erase the rest of the containing block along with it.</p>\n\n<p>When programming NAND flash only 1\'s can be programmed to 0\'s, so to change a byte containing 0x00 to 0xFF it must be erased, along with the rest of the block. However subsequent programs may still be made without an erase if no 0s are to be changed to 1s, this might be useful in a scenario where subsequent data might regularly have this property.</p>\n\n<p>When manufactured NAND flash contains bad blocks, these are blocks that are not reliable and any data in them will commonly corrupt easily. These must be kept track of and the OOB data section is used to mark a bad block.</p>\n\n<p>NAND in general is prone to bit errors and for that reason the OOB data is also used to write error correction codes (ECC) so that some errors can be corrected.</p>\n\n<h3>Yaffs NAND Model</h3>\n\n<p>It is probably a good thing to detail at this point how Yaffs2 expects the NAND to behave so that you are aware of what you have to provide in the NAND driver to get YAFF running. Yaffs uses some different terminology in that it refers to a page as a <em>chunk</em>.</p>\n\n<p>Yaffs2 uses a fairly abstract model for NAND flash, this allows a lot of flexibility in the way Yaffs can be used. Yaffs is designed for NAND flash and makes the following assumptions and definitions:</p>\n\n<ul><li>NAND flash is arranged in blocks. Each block is the same size and comprises an integer number of chunks. Each block is treated as a single erasable item.</li>\n	<li>A page (chunk) equates to the allocation units of flash.</li>\n	<li>All accesses (reads and writes) are page (chunk) aligned.</li>\n	<li>When programming a NAND flash, only the zero bits in the pattern being programmed are relevant, and one bits are \"don\'t care\". For example, if a byte already contains the binary pattern 1010, then programming 1001 will result in the pattern which is the logical AND of these two patterns i.e. 1000. This is different to NOR flash.</li>\n</ul><p>Yaffs identifies blocks by their block number and chunks by their chunk Id. Yaffs treats a blank (0xFF filled) block as being free or erased. Thus, the equivalent of formatting for a Yaffs partition is to erase all the blocks that are not bad.</p>\n\n<p>Therefore Yaffs minimally needs access to functions that enable it to erase blocks and to read and write on a page basis. It is also helpful to be able to read only OOB data as reading/writing a full page to only view/update OOB data will cost many serial read cycles over the bus. This is an overhead that can be avoided using the random access read and write features of some nand chips.</p>\n\n<p> </p>\n\n<h2>Writing a Driver for NAND flash Chips</h2>\n\n<h3>Writing a Driver for the Samsung 628 K9F2G08U0M PCB0 on the Balloon Board (v3.01)</h3>\n\n<p>For the Balloon board the NAND chips hang off the CPLD which is in turn hooked up to the system bus. This is quite board specific and in this case reading the VHDL code reveals how to change the values on the pins of the NAND chips. You may look at the code by downloading the balloon source code (Appendix A) and looking at balloon3.vhd and Balloon_nand.vhd in balloon/vhdl/fpga/.</p>\n\n<p>It will be likely that this is significantly different on your platform and you should consult the relevant data sheets and documentation to determine how to access the NAND hardware on your board. I will present an example of the balloon board in order to give an overview of the kind of thing that is required.</p>\n\n<p>On the Balloon the CPLD routes data on the bus with certain address to the logic on the CPLD that actually controls the flash chips. They are as follows:</p>\n\n<p><code>NAND Data Bus : 0x10e00000</code> <code>NAND Control 2: 0x10e00010</code> <code>NAND Control : 0x10e00014</code></p>\n\n<p>Sending data to the \'NAND Data Bus\' address will put that data onto the I/O pins of the NAND chips. All of the nand chips are hooked up to the same pins on the CPLD so writing to the \'NAND Data Bus\' address will put the value written on the I/O pins for <em>all</em> of the available flash chips. To isolate the chip you want to work with using the chip enable pin on each flash chip.</p>\n\n<p>This is done by writing to the \'NAND Control\' (0x10e00014) address. When writing to \'NAND control\', the CPLD takes the data value on the bus and routes each bit to a different wire. This bit field is structured as follows:</p>\n\n<p> </p>\n\n<table><colgroup><col /><col /></colgroup><tr><td><em>Pin Attached To</em></td>\n			<td><em>Bit in NAND Control value</em></td>\n		</tr><tr><td>CLE (Control Latch Enable)</td>\n			<td>0</td>\n		</tr><tr><td>ALE (Address Latch Enable)</td>\n			<td>1</td>\n		</tr><tr><td>nCE0 (not Chip Enable for chip 0)</td>\n			<td>2</td>\n		</tr><tr><td>nCE1 (for chip 1)</td>\n			<td>3</td>\n		</tr><tr><td>nCE2 (for chip 2)</td>\n			<td>4</td>\n		</tr><tr><td>nCE3 (for chip 3)</td>\n			<td>5</td>\n		</tr><tr><td>nSE (not Chip Enable for chip 0)</td>\n			<td>6</td>\n		</tr><tr><td>nWP (not Write Protect)</td>\n			<td>7</td>\n		</tr></table><p> </p>\n\n<p>So for example bit 1 on the data lines is put onto the ALE pin on the physical chip. Bits prefixed with \'n\' are active low, for example chip 0 is selected when nCE0 is low and nCE1-3 are high.</p>\n\n<p> </p>\n\n<p>So writing to \'NAND Control\' we can change the values of the pins on the flash. Again, CLE, ALE, nSE and nWP change the value of the corresponding pin on all the flash chips available, nCE[0-3] will select the chip you are using.</p>\n\n<p>Finally, NAND flash typically comes in couple of flavours, 8 bit wide (x8) and 16 bit wide (x16). This means that x8 chips have 8 I/O pins and x16 have 16. The logic on the CPLD on the Balloon can handle both if you tell it which you are currently dealing with. Writing to \'NAND Control 2\' a value of 1 puts the CPLD logic for the NAND chips into x8 mode and 0 into x16 mode. I will assume for the rest of this document that there are only x8 chips connected to the balloon but it should be fairly trivial to extend it to support both.</p>\n\n<h3>Using the Flash Chips</h3>\n\n<p>The flash chips we\'re using have a number of commands, each triggered by a sequence of one or two command codes. You will want to refer to the data sheets for precise details of these functions, but I will briefly describe some of them in this document. The command set that we have for the particular chip we\'re using is table 1 on page 7 of the data sheet.</p>\n\n<p>To input a command there is generally one or two command input cycles. For two cycle commands there is generally an initial command followed by some data needed to complete the command then another command cycle to notify that the relevant data has been input and to start execution. For example for read operations the command 0x00 is latched in followed by some address input cycles followed by the command 0x30 to start the operation. With this in mind I will now describe how to input commands, the \'Command Latch Cycle\'.</p>\n\n<p>Note that for this section I have assumed that the bus is sufficiently slow that the set-up and hold times are not an issue, if you have a fast bus then you may have to wait for a small amount of time (refer to the data sheet) after changing values on the pins (by writing to the correct address) so that set-up and hold times are not violated.</p>\n\n<h3>Command Latch Cycle</h3>\n\n<p>For the command latch cycle you need to first select a chip by setting the relevant nCE low and then you need to set the CLE bit high, that means writing to the \'NAND Control\' address. ALE must also be low and should be set at the same time as CLE. It is then a case of putting the command value onto the I/O pins by writing to the \'NAND Data Bus\' address the value of the command you want. This will then latch in the command, afterwards you will need to clear the CLE bit again.</p>\n\n<p>You will also notice from looking at the data sheet that something needs to be done with the nWE (not <strong>w</strong>rite <strong>e</strong>nable) pin (specifically it should be low while latching in the command), but that I have yet to describe a mechanism for changing its value. This is because it is dealt with by the logic in the CPLD and whenever data is sent to the data address the CPLD will toggle nWE appropriately. (This is also true of nRE (not <strong>r</strong>ead <strong>e</strong>nable) when reading). This process is implemented in the nand_chip_select and the send_command functions (flash.c).</p>\n\n<h3>Address Latch Cycle and Addressing</h3>\n\n<p>The process for the Address Latch Cycle is similar to that for command latching (with the sense of ALE and CLE reversed) and can be looked at in the data sheet and is implemented in send_address in flash.c. The addressing is done by row and column. There are 5 address cycles on the flash chips we\'re looking at. The first cycle contains bits 0-7 of the column address, the second bits 8-11 with the remaining bits of the byte to be sent low. The row address is over 3 more cycles in a similar fashion.</p>\n\n<p>You may wish to chose to address the individual bytes of the chip with the OOB data not directly addressable. This has enabled me to lump several chips into the same address space and select the correct chip based on the address. Addresses then need to be converted to row and column. You should also check that they are page/block aligned in the relevant places if that\'s what your functions expect. It needn\'t be done this way any you could use page numbers instead of bytes just as easily.</p>\n\n<p><br /><a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram 2\" height=\"209\" src=\"sites/yaffs.net/files/images/yaffs_porting_guide_html_m11b1f893.png\" width=\"654\" /></a></p>\n\n<p> </p>\n\n<p>The \'row\' is essentially the page index and the \'column\' is the index into to that page, so if you wanted to read from the start of page 213 you would send 0 for the column and 213 for the row. Conversely if you wanted just the OOB bytes from the same page you would send a column value of 2048 (given a page size of 2048+64 bytes).</p>\n\n<p><br /><a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram 3\" height=\"271\" src=\"sites/yaffs.net/files/images/yaffs_porting_guide_html_m4650262f.png\" width=\"347\" /></a></p>\n\n<p> </p>\n\n<h3>Finding Chip information</h3>\n\n<p>You will then need to find out which chips are active (e.g. on the balloon there are 4 possible chips, not all of which will exist) and what type of chips they are. For this there is the \'Read ID\' operation. This operation is implemented in the read_ids function in flash.c. The result of the operation gives the manufacturer and device code of the chip and information about the chip (page size, block size, oob size etc). To find which chips are available, loop through the possible chips and start a Read ID command on each of them, if the expected data is returned then there is a chip at that location.</p>\n\n<p>The operation is started by sending the command 0x90 and then one address cycle of 0x00. There are then 5 read cycles which give you data about the device. A description of how to unpack this information from the returned bytes is located on page 32 of the data sheet for the chip described here.</p>\n\n<p>This then gives you how many chips you have and what layout the data in them has.</p>\n\n<h3>Bad Block Checking</h3>\n\n<p>Contained within a nand chip are blocks that the manufacturer will not guarantee the reliability of (this is to increase yield in manufacturing) and so bad blocks must be kept track of. The Samsung chips come with the first byte (or word for x16) of the first and second page of each bad block not programmed as 0xFF.</p>\n\n<p>This bad block marking should be maintained and should be added to in the same way when a bad block is is discovered. Yaffs will expect you to provide a function it can call to mark a particular block as bad when yaffs decides it is necessary.</p>\n\n<p>Yaffs keeps track of bad blocks itself so that the driver doesn\'t need to worry about masking out bad blocks.</p>\n\n<h3>Erasing a Block</h3>\n\n<p>An example of this operation is given in nand_erase_block in flash.c. If you are addressing the nand by bytes then you must first check that the address is aligned to the start of a block and then convert the address into a block number. If there is more than one chip this will involve working out which chip the address refers to and then selecting the correct chip. This can be seen in the select_chip function in flash.c. You must then send the first command cycle for the erase operation before sending 3 cycles of address and then finally the last command cycle.</p>\n\n<p>For the erase operation the 3 address cycles are different than for the read/write operations. Only address bits A18 to A29 is valid (for x8) while A12 to A17 is ignored. In terms of the ordinary 5 cycles address input you only need to deal with the last 3 cycles and of those only the highest 2 bits of the 3rd cycle are used and the full 4th and 5th cycle are used.</p>\n\n<p>Once the operation has been started the program can check the progress of the operation by sending a command of 70h. Each subsequent read will contain the read status. The driver should wait until the read is complete (by the read status operation), the read status operation also contains information about whether the erase failed and this information should be returned from the function doing the erase.</p>\n\n<h3>Reading a Page</h3>\n\n<p>Reading a page is performed by first selecting the correct chip and then converting the address to a row and column number. You can then sending the first command cycle for the read operation followed by 5 address cycles as described in the previous sections. The second command cycle then starts the read operation. The driver must then wait for the data to be retrieved into the data registers on the NAND before they can be read out over the bus. For the example chip this is 25us, consult the data sheet as this may differ. The data can then be read out sequentially byte by byte until all the data needed is obtained.</p>\n\n<h3>Writing a Page</h3>\n\n<p>Page program operations are performed by first selecting the correct chip converting the address to row and column numbers. The page program operation is initiated by the relevant fist command latch cycle (command 0x80) followed by an address latch cycle (as for read), serial data loading and then the second command latch cycle (command 0x10).</p>\n\n<p>The serial data loading is done by serially writing data to the I/O pins. Up to 2112 bytes (x8) can be loaded into the data registers. Once the second command cycle is sent the program is initiated and there is then a programming period where the loaded data is programmed into the appropriate cell. The driver should wait for this to complete by issuing a read status command (0x70) and monitoring the R/nB (ready / not busy) bit. The R/nB flag is on I/O pin 6 and can be checked by repeatedly reading from the \'NAND Data Bus\' address. Once the operation is complete the Write Status Bit (I/O 0 ) may be checked to confirm that the operation was successful.</p>\n\n<h2>Yaffs</h2>\n\n<h3>How To Use Yaffs</h3>\n\n<h3>Checking Out From Git</h3>\n\n<p>The first thing to do is to obtain the source code for Yaffs. This can be done from CVS, details of the process can be found at <a href=\"http://www.yaffs.net/download-yaffs-using-git\">http://www.yaffs.net/download-yaffs-using-git</a>.</p>\n\n<p>The following command will checkout the latest Git version using public read-only access, if you are using bash.</p>\n\n<p><code>$ </code>git clone git://www.aleph1.co.uk/yaffs2 </p>\n\n<h3>Making Some Tweaks to the Source Code</h3>\n\n<p>As of the latest version from CVS in January 2009, you will need to make a small number of changes before you can compile the source code without errors and warnings. There is a patch file included with this document.</p>\n\n<p>You will need to provide a definition of loff_t (in yaffs2/direct/ydirectenv.h) this is for holding the file size in bytes, you should make it big enough to hold the largest file size you wish to support. Unsigned long is probably a good place to start. You will need to edit yaffsfs.c to change a #if to a #ifdef. Then if you have the relevant warnings and -Werror switched on you will need to correct a couple of printf format strings to get the type right (changing a few \'%d\' to \'%ld\').</p>\n\n<p><code>change yaffs/ydirectenv.h </code></p>\n\n<p><code>+ typedef unsigned long loff_t; </code></p>\n\n<p><code>change yaffs2/direct/yaffsfs.c ~line 1117 </code></p>\n\n<p><code>- #if CONFIG_YAFFS_WINCE </code></p>\n\n<p><code>+ #ifdef CONFIG_YAFFS_WINCE</code></p>\n\n<h3>Relevant Files to the Direct Interface</h3>\n\n<p>There are quite a few files that get checked out, not all of which you will need to get going with the yaffs direct interface. The ones you will actually need are listed bellow, you do not need to compile the rest in.</p>\n\n<p><code><code>direct/yaffsfs.c </code></code></p>\n\n<p><code><code>yaffs_guts.c </code></code></p>\n\n<p><code><code>direct/yaffscfg.c </code></code></p>\n\n<p><code><code>yaffs_nand.c </code></code></p>\n\n<p><code><code>yaffs_tagsvalidity.c </code></code></p>\n\n<p><code><code>yaffs_checkptrw.c </code></code></p>\n\n<p><code><code>yaffs_qsort.c </code></code></p>\n\n<p><code><code>yaffs_tagscompat.c </code></code></p>\n\n<p><code><code>yaffs_ecc.c </code></code></p>\n\n<p><code><code>yaffs_packedtags2.c</code></code></p>\n\n<h3>Some Relevant Preprocessor Flags</h3>\n\n<p>There are many different configuration options for yaffs, here are a few that you should be aware of for using the yaffs direct interface.</p>\n\n<ul><li>CONFIG_YAFFS_DIRECT - Tell yaffs to use the direct interface.</li>\n	<li>CONFIG_YAFFS_YAFFS2 - Tell yaffs we want to use yaffs2</li>\n	<li>CONFIG_YAFFS_PROVIDE_DEFS - provides some definitions for file types and #includes linux/types.h, linux/fs.h, linux/stat.h (see yaffs2/devextras.h).</li>\n	<li>CONFIG_YAFFSFS_PROVIDE_VALUES - This may be used so that you can customise error values and constants like O_RDONLY to match the underlying system values, if itis not defined then it includes errno.h,sys/stat.h and fcntl.h (see yaffs2/direct/yaffsfs.h).</li>\n</ul><p>Specify these options when compiling yaffs, i.e. -DCONFIG_YAFFS_DIRECT etc.</p>\n\n<h3>Configuring</h3>\n\n<p>You will then need to provide yaffs with configuration information. This includes details about the nand flash you are using and also tells yaffs which functions to call when when it wants to read/write/erase parts of the flash, these functions will form the bridge between yaffs and the underlying hardware driver. This customisation is done in yaffscfg.h. Within yaffscfg.h you will need to provide a number of operating-system-like functions and a function to initialise yaffs. For example providing functions for malloc and free. Here is a breakdown of those functions that need to be implemented.</p>\n\n<h3>Operating System Functions</h3>\n\n<p><code><code>void yaffsfs_SetError(int err); </code> </code></p>\n\n<p>Report system errors, for example using errno if it exists.</p>\n\n<p><code><code>void *yaffs_malloc(size_t size);</code> <code>void yaffs_free(void *ptr);</code> </code></p>\n\n<p>As for the standard malloc and free functions, if they already exist on your system then you can just shim them.</p>\n\n<p><code><code>void yaffsfs_LocalInitialisation(void);</code> <code>void yaffsfs_Lock(void);</code> <code>void yaffsfs_Unlock(void);</code> </code></p>\n\n<p>Use yaffsfs_LocalInitalisation to initialise \"Real Time Operating System\" state, if the system is multi-threaded then it should initialise a semaphore/mutex for use by lock and unlock. Lock/unlock should use the semaphore set up in LocalInitialisation to lock yaffs from multi-threaded access.</p>\n\n<p><code><code>__u32 yaffsfs_CurrentTime(void);</code> </code></p>\n\n<p>This can be any time increment of use to the system. If this is not required, then it is fine to just use a function that returns zero.</p>\n\n<h3>Yaffs Startup Function</h3>\n\n<p><code><code>int yaffs_StartUp(void); </code> </code></p>\n\n<p><code><code>Return value: YAFFS_OK or YAFFS_FAIL</code> </code></p>\n\n<p>This functions should be used to provide yaffs with many details about the properties of the underlying nand device. Within this function you will need to set up a \'yaffs_Device\' (yaffs_guts.h) and a \'yaffsfs_DeviceConfiguration\' (direct/yaffscfg.h). How to set up a yaffs device will follow in the next section. Once you have set up the required yaffs_Device structures you should call yaffs_initialise (yaffs_guts.h) with a pointer to a null terminated array of yaffs_DeviceConfiguration structures. A yaffs_DeviceConfiguration structure contains a pointer to a yaffs_Device and the \'mount point\' string (prefix) that that device corresponds to.</p>\n\n<h3>Yaffs Devices</h3>\n\n<p>A yaffs device is a logical device that represents part of or a whole physical device. You might think of it as a \'partition\' on the nand. For example, it might cover the whole of the nand device or perhaps only claim half, with another yaffs_Device claiming the other half. It may also be used so that you can use a device other than a flash device (e.g. RAM) for testing purposes.</p>\n\n<p>A yaffs_Device keeps track of the start and end block, so you may have more than one yaffs_Device corresponding to the same physical device by altering the start and end block of the yaffs device.</p>\n\n<p>The fields on the yaffs_Device struct that you need to set up yourself are listed below, all other fields are setup automatically by yaffs.</p>\n\n<p><code><code>int nDataBytesPerChunk</code> </code></p>\n\n<p>As the name suggests this is the number of bytes per chunk, remembering that in yaffs terminology a page is referred to as a chunk, this is then the number of bytes per page. This is the number of data bytes, that is the number of bytes excluding the OOB byte data. E.g. if a page is 2048byte + 64bytes of OOB then set nDataBytesPerChunk to 2048.</p>\n\n<p><code><code>int nChunksPerBlock </code> </code></p>\n\n<p>Straightforwardly the number of chunks (pages on the nand) in each block on the physical nand device. Must be at least 2.</p>\n\n<p><code><code>int spareBytesPerChunk</code></code><br />\nThis is the size of the spare area, i.e. the number of OOB bytes per chunk (page)<code>. </code></p>\n\n<p><code><code>int startBlock</code> </code></p>\n\n<p>The block number (not the address in bytes) on the chip of the first block of this logical yaffs_Device. Beware, yaffs needs the first block to be free so you should not set this to 0, if it is then yaffs will add on one to it itself and also add on one to the end block which could be an issue if you wanted your device to start at block 0 and finish at the last block which might mean yaffs trying to write to a non-existent block.</p>\n\n<p><code><code>int endBlock</code> </code></p>\n\n<p>The block number on the chip of the last block for this logical yaffs_Device. If startBlock == 0 then yaffs will use endBlock+1. Must be at least startBlock + nReservedBlocks + 2.</p>\n\n<p><code><code>int nReservedBlocks</code> </code></p>\n\n<p>This is then number of erasable blocks that Yaffs must keep in reserve for garbage collection and to cover for block failures. This must be a minimum of 2, but 5 or so is better. If you are using a medium that is not expected to fail (eg. RAM for a RAM disk, or a host file system emulation then 2 is OK).</p>\n\n<p><code><code>int nShortOpCaches</code> </code></p>\n\n<p>This configures the number of entries in the Yaffs cache for this device. A value of zero defeats the cache. A value of 10 to 20 is recommended for most systems. Cannon be any bigger than YAFFS_MAX_SHORT_OP_CACHES.</p>\n\n<p><code><code>int useNANDECC</code> </code></p>\n\n<p>This is a flag that tells yaffs whether it should be doing ECC calculations or if it should be left to the driver.</p>\n\n<p><code><code>void *genericDevice</code> </code></p>\n\n<p>This is a pointer which should point to any data that the underlying nand driver will need to know to write and read from the physical device.</p>\n\n<p><code><code>int isYaffs2</code> </code></p>\n\n<p>Are we using Yaffs2? We only deal with Yaffs2 in this document.</p>\n\n<p><code><code>int inbandTags</code> </code></p>\n\n<p>Is there an OOB section? If not then this should be true. Only relevant to Yaffs2.</p>\n\n<p><code><code>_u32 totalBytesPerChunk</code> </code></p>\n\n<p>Possibly a misleading name, it should be equal to nDataBytesPerChunk not nDataBytesPerChunk + spareBytesPerChunk as the name might suggest. If inbandTags is true then yaffs sets nDataBytesPerChunk such that there is enough space for the data yaffs would normally store in the spare area.</p>\n\n<p><code><code>write/readChunkWithTagsFromNAND, markNANDBlockBad, queryNANDBlock</code> </code></p>\n\n<p>These are all pointers to functions that you shall provide to provide Yaffs with a method of writing/reading etc from the NAND.</p>\n\n<h3>NAND access functions</h3>\n\n<p>If you are using Yaffs2 you need to provide pointers to functions that Yaffs can call to write and read from the nand. Example implementations of these function can be seen in yaffs_mtdif.c, these are the functions written to do the same job for the linux mtd layer and provides the write and read functions. The following functions return YAFFS_OK on success and YAFFS_FAIL on failure.</p>\n\n<p><code><code>int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,</code> <code>int chunkInNAND, const __u8 * data,</code> <code>const yaffs_ExtendedTags * tags);</code> <code>dev: yaffs_Device to write to.</code> <code>chunkInNAND: Which page to write the chunk to.</code> <code>Data: Pointer to the data to write</code> <code>tags: Unpacked OOB data.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\n\n<p>This function is to write pages (chunks) to the nand. In this function you will probably want to first retrive any useful data that you put in dev-&gt;genericDevice (in the yaffs_StartUp function) and use it to call the function you wrote previously to write data to the nand. For yaffs2 data and tags should never be NULL. chunkInNand is the page number of the page to write to, not an address so it will need converting if that\'s what your underling functions to write to the nand expect.</p>\n\n<p>You will then need to pack the tags into a yaffs_PackedTags2 structure, this takes out the all relevant details from the yaffs_ExtendedTags tags structure and calculates ECC data on it before placing them in the packedtags2 structure. This structure is the OOB data you will want to write out to the nands spare area.</p>\n\n<p>How you write these out to the OOB data depends on your architecture, nand chips and therefore how bad block marking is done. If for example the first byte is used for bad block marking then simply writing the tags out after the first byte is acceptable. The ECC data in packed tags only covers error correction and detection for the tags in the OOB data, if you want ECC on the data then you must do that yourself.</p>\n\n<p>To perform ECC checks to the data bytes you may use the yaffs_ECCCalculate function which calculates ECC data for 256 byte sections of data. This function produces 3 bytes of ECC data per 256 bytes. Therefore for 2048 bytes of data in each page you would need (2048/256) * 3 = 8 * 3 = 24 extra bytes of ECC data. This can be written out after the bad block byte and packed tags data.<br />\n </p>\n\n<p><code><code>int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,</code> <code>int chunkInNAND, __u8 * data,</code> <code>yaffs_ExtendedTags * tags);</code> <code>dev: The yaffs_Device to read from.</code> <code>chunkInNAND: Which page to read from.</code> <code>Data: Pointer to a buffer to read data to.</code> <code>tags: Pointer to a buffer to unpacked OOB data into.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\n\n<p>This function should do the opposite to the previous function. Firstly, read in the data and OOB bytes. Secondly place the data bytes in the area pointed to by data, then unpack the OOB bytes into into the pointer to tags using yaffs_UnpackTags2.</p>\n\n<p>Once the tags have been unpacked you should then recalculate the ECC data on the data bytes you just read back, just as you did for the write operation. Then use the recalculated ECC and the ECC data read out of the OOB bytes with yaffs_ECCCorrect to correct the data.</p>\n\n<p>Depending on the return value from yaffs_ECCCorrect you should set tags-&gt;eccResult to reflect whether anything was corrected or the correction failed. yaffs_UnpackTags2 also sets tags-&gt;eccResult so you should only update it if the result of the data correction is worse than is already there. i.e. if after the tags are unpacked and eccResult is YAFFS_ECC_RESULT_FIXED and ECC correction on the data read back resulted in no errors then you should leave unpackedtags2 and YAFFS_ECC_RESULT_FIXED and not set it to YAFFS_ECC_RESULT_NO_ERROR.</p>\n\n<p><code><code>int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);</code> <code>dev: yaffs_Device to write to.</code> <code>blockNo: Which block to mark.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code></code></p>\n\n<p>This should mark the block bad. This probably means reading the OOB data and changing the relevant byte that marks the bad block, and writing the OOB data back.</p>\n\n<p><code><code>int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,</code> <code>yaffs_BlockState * state, __u32 *sequenceNumber);</code> <code>dev: The yaffs_Device to write to.</code> <code>blockNo: Which block to mark.</code> <code>state: Upon returning this should be set to the relevant state of this particular block.</code> <code>Sequence number: The Sequence number of this block. 0 if the block is unused.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\n\n<p>This should check whether or not the block is valid.</p>\n\n<p>If the bad block marker is set in the OOB then *state should be set to YAFFS_BLOCK_STATE_DEAD *sequenceNumber set to 0, and return YAFFS_FAIL.</p>\n\n<p>If the block is not bad then the tags should be unpacked. After the tags are unpacked, and it is found that chunk is used (see tags.chunkUsed) *sequenceNumber should be set to tags.sequenceNumber and *state to YAFFS_BLOCK_STATE_NEEDS_SCANNING, otherwise if the block is not used then *sequenceNumber should be 0 and *state should be set to YAFFS_BLOCK_STATE_EMPTY.</p>\n\n<h3>Application Interface</h3>\n\n<p>The yaffs provides a number of functions for applications to interface with it. These are mostly the same as the standard clib open/close etc prefixed with yaffs_ eg yaffs_open. These functions are defined in direct/yaffsfs.h.</p>\n\n<p>To initialise yaffs so that reading and writing can be done, you must call yaffs mount for each yaffs device you would like to use, e.g. yaffs_mount(\"/boot\"). This could be done at system boot if there is an operating system present so that the application need to worry about this. You will also need to call yaffs_unmount when you have finished so that yaffs may write any state it needs to to disk.</p>\n\n<p>If there is already an application interface for reading and writing files you may shim the relevant function calls with the related operating system calls.</p>\n\n<p>E.g. simply doing #define open(path, oflag, mode) yaffs_open(path, oflag, mode)</p>\n\n<p>Or having something more complex to provide redirection functions if there is more than one file system present.</p>\n\n<p><code><code>For example: int open(const char *path,...)<br />\n{<br />\n//Determine which file system is being used </code> <code>if(it_is_a_yaffs_path(path)) {</code> <code> return yaffs_open(...);<br />\n} else {<br />\n// Do something else<br />\n}<br />\n}</code></code></p>\n\n<h2>Appendices</h2>\n\n<h3>Appendix A - Accessing the Balloon Source Code</h3>\n\n<p>The latest source code for the balloon board can be checked out from SVN. There is different code for different balloon versions. Details of getting the source and setting up tool chains is decribed in the following page <a href=\"http://www.balloonboard.org/software.html\">http://www.balloonboard.org/software.html</a>. If you just want to take a look at the latest mainline code then the following will give you what you want.</p>\n\n<p>svn checkout svn://balloonboard.org/balloon/trunk/</p>\n\n<p> </p></div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:369\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505188402.891,1,'config:filter.format.basic_html node:369 node_view rendered','265'),('entity_view:node:369:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"369\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:369\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505188402.888,1,'config:filter.format.basic_html node:369 node_view rendered','265'),('entity_view:node:370:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0Ow_25iMMZ-LZJaCb7Pi-4CiscwKFtpaZEOhwccR5NOw','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:175:\"<article role=\"article\" about=\"/yaffs-porting-guide-html-2de490f8-png\" class=\"image is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:38:\"/yaffs-porting-guide-html-2de490f8-png\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/370\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:38:\"/yaffs-porting-guide-html-2de490f8-png\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:370\";i:2;s:9:\"node_view\";i:3;s:6:\"user:5\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:51:\"<span>yaffs_porting_guide_html_2de490f8.png</span>\n\";}}',-1,1504721477.587,1,'config:system.site node:370 node_view rendered user:5','262'),('entity_view:node:370:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"370\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:370\";i:2;s:9:\"node_view\";i:3;s:6:\"user:5\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504721477.584,1,'config:system.site node:370 node_view rendered user:5','262'),('entity_view:node:370:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:611:\"<article role=\"article\" about=\"/yaffs-porting-guide-html-2de490f8-png\" class=\"image is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-porting-guide-html-2de490f8-png\" rel=\"bookmark\"><span>yaffs_porting_guide_html_2de490f8.png</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-porting-guide-html-2de490f8-png\" rel=\"tag\" title=\"yaffs_porting_guide_html_2de490f8.png\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about yaffs_porting_guide_html_2de490f8.png</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:370\";i:1;s:9:\"node_view\";i:2;s:6:\"user:5\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.650,1,'node:370 node_view rendered user:5','256'),('entity_view:node:370:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"370\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:370\";i:1;s:9:\"node_view\";i:2;s:6:\"user:5\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.648,1,'node:370 node_view rendered user:5','256'),('entity_view:node:371:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0N_5zskAKXYJeoZTezVIzKF0SK1c_-j7N5nuwQvC2q3I','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:176:\"<article role=\"article\" about=\"/yaffs-porting-guide-html-m11b1f893-png\" class=\"image is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:39:\"/yaffs-porting-guide-html-m11b1f893-png\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/371\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:39:\"/yaffs-porting-guide-html-m11b1f893-png\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:371\";i:2;s:9:\"node_view\";i:3;s:6:\"user:5\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:52:\"<span>yaffs_porting_guide_html_m11b1f893.png</span>\n\";}}',-1,1504736786.096,1,'config:system.site node:371 node_view rendered user:5','262'),('entity_view:node:371:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"371\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:371\";i:2;s:9:\"node_view\";i:3;s:6:\"user:5\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504736786.088,1,'config:system.site node:371 node_view rendered user:5','262'),('entity_view:node:371:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:617:\"<article role=\"article\" about=\"/yaffs-porting-guide-html-m11b1f893-png\" class=\"image is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-porting-guide-html-m11b1f893-png\" rel=\"bookmark\"><span>yaffs_porting_guide_html_m11b1f893.png</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-porting-guide-html-m11b1f893-png\" rel=\"tag\" title=\"yaffs_porting_guide_html_m11b1f893.png\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about yaffs_porting_guide_html_m11b1f893.png</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:371\";i:1;s:9:\"node_view\";i:2;s:6:\"user:5\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.640,1,'node:371 node_view rendered user:5','256'),('entity_view:node:371:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"371\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:371\";i:1;s:9:\"node_view\";i:2;s:6:\"user:5\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.638,1,'node:371 node_view rendered user:5','256'),('entity_view:node:372:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0zHOFMwMGOmLRqPLwbNYJ8Fkfr4nwHKHGmV9BmbNTYKU','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:176:\"<article role=\"article\" about=\"/yaffs-porting-guide-html-m4650262f-png\" class=\"image is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:39:\"/yaffs-porting-guide-html-m4650262f-png\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/372\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:39:\"/yaffs-porting-guide-html-m4650262f-png\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:372\";i:2;s:9:\"node_view\";i:3;s:6:\"user:5\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:52:\"<span>yaffs_porting_guide_html_m4650262f.png</span>\n\";}}',-1,1504703978.155,1,'config:system.site node:372 node_view rendered user:5','262'),('entity_view:node:372:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"372\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:372\";i:2;s:9:\"node_view\";i:3;s:6:\"user:5\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504703978.146,1,'config:system.site node:372 node_view rendered user:5','262'),('entity_view:node:372:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:617:\"<article role=\"article\" about=\"/yaffs-porting-guide-html-m4650262f-png\" class=\"image is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-porting-guide-html-m4650262f-png\" rel=\"bookmark\"><span>yaffs_porting_guide_html_m4650262f.png</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-porting-guide-html-m4650262f-png\" rel=\"tag\" title=\"yaffs_porting_guide_html_m4650262f.png\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about yaffs_porting_guide_html_m4650262f.png</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:372\";i:1;s:9:\"node_view\";i:2;s:6:\"user:5\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.624,1,'node:372 node_view rendered user:5','256'),('entity_view:node:372:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"372\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:372\";i:1;s:9:\"node_view\";i:2;s:6:\"user:5\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.622,1,'node:372 node_view rendered user:5','256'),('entity_view:node:374:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0Lq276R2_3_5sRLMf8yXROhg7TE0NBs7jZ2c8hYwSBkY','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:154:\"<article role=\"article\" about=\"/yaffs-tnode-tree\" class=\"image is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:17:\"/yaffs-tnode-tree\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/374\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:17:\"/yaffs-tnode-tree\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:374\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:30:\"<span>YAFFS Tnode tree</span>\n\";}}',-1,1504628990.943,1,'config:system.site node:374 node_view rendered user:1','267'),('entity_view:node:374:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"374\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:374\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504628990.941,1,'config:system.site node:374 node_view rendered user:1','267'),('entity_view:node:374:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:30:\"<span>YAFFS Tnode tree</span>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:2:{i:0;s:8:\"node:374\";i:1;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505414722.944,1,'node:374 node_view rendered','254'),('entity_view:node:374:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"374\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:2:{i:0;s:8:\"node:374\";i:1;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505414722.941,1,'node:374 node_view rendered','254'),('entity_view:node:374:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:485:\"<article role=\"article\" about=\"/yaffs-tnode-tree\" class=\"image is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-tnode-tree\" rel=\"bookmark\"><span>YAFFS Tnode tree</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-tnode-tree\" rel=\"tag\" title=\"YAFFS Tnode tree\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about YAFFS Tnode tree</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:374\";i:1;s:9:\"node_view\";i:2;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.606,1,'node:374 node_view rendered user:1','261'),('entity_view:node:374:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"374\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:374\";i:1;s:9:\"node_view\";i:2;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.604,1,'node:374 node_view rendered user:1','261'),('entity_view:node:376:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0AYbG41HKiIPud_Xp83JqEYjQUB71zHg7hP689w56WKM','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:171:\"<article role=\"article\" about=\"/yaffs-directory-structure-example\" class=\"image is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:34:\"/yaffs-directory-structure-example\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/376\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:34:\"/yaffs-directory-structure-example\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:376\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:49:\"<span>YAFFS - directory structure example</span>\n\";}}',-1,1504634979.153,1,'config:system.site node:376 node_view rendered user:1','267'),('entity_view:node:376:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"376\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:376\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504634979.150,1,'config:system.site node:376 node_view rendered user:1','267'),('entity_view:node:376:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:593:\"<article role=\"article\" about=\"/yaffs-directory-structure-example\" class=\"image is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-directory-structure-example\" rel=\"bookmark\"><span>YAFFS - directory structure example</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-directory-structure-example\" rel=\"tag\" title=\"YAFFS - directory structure example\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about YAFFS - directory structure example</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:376\";i:1;s:9:\"node_view\";i:2;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.595,1,'node:376 node_view rendered user:1','261'),('entity_view:node:376:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"376\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:376\";i:1;s:9:\"node_view\";i:2;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.593,1,'node:376 node_view rendered user:1','261'),('entity_view:node:377:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0FVE-S4y23v7nrQX1O8CcaTPwJPSbIP8hE71O59cGP58','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:156:\"<article role=\"article\" about=\"/yaffs-block-states\" class=\"image is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:19:\"/yaffs-block-states\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/377\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:19:\"/yaffs-block-states\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:377\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:34:\"<span>YAFFS - Block states</span>\n\";}}',-1,1504719511.200,1,'config:system.site node:377 node_view rendered user:1','267'),('entity_view:node:377:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"377\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:377\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504719511.185,1,'config:system.site node:377 node_view rendered user:1','267'),('entity_view:node:377:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:503:\"<article role=\"article\" about=\"/yaffs-block-states\" class=\"image is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/yaffs-block-states\" rel=\"bookmark\"><span>YAFFS - Block states</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/yaffs-block-states\" rel=\"tag\" title=\"YAFFS - Block states\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about YAFFS - Block states</span></a></li></ul>\n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:377\";i:1;s:9:\"node_view\";i:2;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1504986924.584,1,'node:377 node_view rendered user:1','261'),('entity_view:node:377:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"377\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:8:\"node:377\";i:1;s:9:\"node_view\";i:2;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504986924.582,1,'node:377 node_view rendered user:1','261'),('entity_view:node:37:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b018DCui2JOvzO-vVcmbFbSbtoR2WAcfA4lQtWBMJxuSH0','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:33144:\"<article role=\"article\" about=\"/archives/yaffs-original-specification\" typeof=\"schema:WebPage\" class=\"page is-sticky full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs Original Specification\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>YAFFS (Yet Another Flash File System)</p>\n\n<h4>Version 0.3</h4>\n\n<h4>Charles Manning (and Wookey), December 2001</h4>\n\n<p><br />\n </p>\n\n<h2>Revision History</h2>\n\n<p>V0.0 20/12/01 First Draft</p>\n\n<table><tr><td>\n			<p>V0.1</p>\n			</td>\n			<td>\n			<p>11/01/02</p>\n			</td>\n			<td>\n			<p>Minor corrections &amp; cosmetics.<br />\n			Change use of data status byte.</p>\n			</td>\n		</tr><tr><td>\n			<p>V0.2</p>\n			</td>\n			<td>\n			<p>28/01/02</p>\n			</td>\n			<td>\n			<p>Added observations about inodes, file headers and hard links.</p>\n			</td>\n		</tr><tr><td>\n			<p>V0.3</p>\n			</td>\n			<td>\n			<p>26/02/02</p>\n			</td>\n			<td>\n			<p>W:Added some general observations on compatibility, partitions and bootloading.</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<h2>Scope</h2>\n\n<p>The purpose of this document is to outline a potential NAND-friendly file system for Linux.</p>\n\n<h2>Background</h2>\n\n<p>There are already various flash-file systems (FFSs) or block drivers for flash (on top of which a regular FS runs). There are pros and cons with all of these.</p>\n\n<p>Flash memory has quite a few constraints which will not be addressed here. Various approaches are available to work around these constraints to provide a file system. It is important to recognise that \"flash\" includes both NOR and NAND flash which have different sets of constraints. It is easy to be mislead by the generic term \"flash\" into thinking that approaches appropriate for NOR flash are immediately suitable for NAND flash.</p>\n\n<p>The NAND block drivers (eg. SmartMedia [currently not available for Linux] and DiskOnChip NFTL) typically use FAT16 as the file system. This isn\'t too robust and nor is it that flash-friendly. These block drivers provide a logical to physical mapping layer to emulate rewritable blocks that look like disk sectors. When used with FAT16, these file systems work reasonably well. They have a low memory footprint and scale well. Like all FAT based systems they are prone to corruption (\"lost clusters etc\").</p>\n\n<p>The other approach is to design an entire file system which does not work through a block driver layer and is flash-friendly. This allows more scope to work around issues.</p>\n\n<p>Currently, two Linux file systems that support NOR flash very well are JFFS and its derivative JFFS2. Both of these are based on the principles of journaling (hence the leading J) which significantly increases robustness - a particularly important feature in embedded systems. Unfortunately neither of these file systems scale particularly well in both boot time and RAM usage. Scaling is particularly relevant when one considers that a 16MB NOR array would be considered large while a 128MB NAND is available as a single chip.</p>\n\n<p>JFFS requires a RAM-based jffs_node structure for each journalling node in the flash. Each of these nodes is 48 bytes. JFFS2 makes a significant improvement here by reducing the equivalent structure (jffs2_raw_node_ref) to 16 bytes. Still, at say an average node-size of 512 bytes, a 128MB NAND might need 250000 of these ... 4MB!</p>\n\n<p>Both JFFS and JFFS2 require scanning the flash array at boot time to find the journaling nodes and determine the file structures. Since NAND is large, slow, serially accessed and needs ECC this does not scale well and will take an unacceptably long boot time for the target systems. As a thumb-suck, the scanning of a 128MB NAND array might take approx 25 seconds.</p>\n\n<p>The intentions of the design sketched here are:</p>\n\n<ul><li>\n	<p>Be NAND-flash friendly.</p>\n	</li>\n	<li>\n	<p>Robustness through journaling strategies.</p>\n	</li>\n	<li>\n	<p>Significantly reduce the RAM overheads and boot times associated with JFFSx.</p>\n	</li>\n</ul><p>This FS is intended primarily for internal NAND rather than removable NAND (SM cards). On removable SM cards Smartmedia compatibility is likely to be important so SM/FAT will normally be used, although of course YAFFS makes a lot of sense if reliability is more important than compatibility.</p>\n\n<h2>Overview</h2>\n\n<p>Here follows a simplified overview of YAFFS.</p>\n\n<p>YAFFS uses a physical flash format similar to SmartMedia. This is done for various reasons:</p>\n\n<ul><li>\n	<p>Some of the formatting, eg placement of bad block markers is determined by the NAND manufacturers and can\'t be changed.</p>\n	</li>\n	<li>\n	<p>Potential to reuse code.</p>\n	</li>\n	<li>\n	<p>If it ain\'t broke don\'t fix.</p>\n	</li>\n</ul><p>Some of the fields are obviously different to reflect the different usage. Despite the similarities YAFFS is not actually compatible with SM/FAT. SM cards need to be reformatted to switch from using SM/FAT to YAFFS or vice versa.</p>\n\n<p>File data is stored in fixed size \"chunks\" consistent with the size of a page (ie. 512 bytes). Each page is marked with a file id and chunk number. These tags are stored in the \"spare data\" region of the flash. The chunk number is determined by dividing the file position by the chunk size.</p>\n\n<p>When data in a file is overwritten, the relevant chunks are replaced by writing new pages to flash containing the new data but the same tags. The overwritten data is marked as \"discarded\".</p>\n\n<p>File \"headers\" are stored as a single page, marked so as to be differentiated from data pages.</p>\n\n<p>Pages are also marked with a short (2 bit) serial number that increments each time the page at this position is incremented. The reason for this is that if power loss/crash/other act of demonic forces happens before the replaced page is marked as discarded, it is possible to have two pages with the same tags. The serial number is used to arbitrate.</p>\n\n<p>A block containing only discarded pages (termed a <em>dirty block</em>) is an obvious candidate for garbage collection. Otherwise valid pages can be copied off a block thus rendering the whole block discarded and ready for garbage collection.</p>\n\n<p>In theory you don\'t need to hold the file structure in RAM... you could just scan the whole flash looking for pages when you need them. In practice though you\'d want better file access times than that! The mechanism proposed here is to have a list of __u16 page addresses associated with each file. Since there are 218 pages in a 128MB NAND, a __u16 is insufficient to uniquely identify a page but is does identify a group of 4 pages - a small enough region to search exhaustively. This mechanism is clearly expandable to larger NAND devices - within reason. The RAM overhead with this approach is approx 2 bytes per page - 512kB of RAM for a whole 128MB NAND.</p>\n\n<p>Boot-time scanning to build the file structure lists should require just one pass reading NAND. Since only the the spare data needs to be read, this should be relatively fast ( approx 3 seconds for 128MB). Improvements can be achieved by partitioning the NAND. ie. mount the critical partition first then mount the data partition afterwards.</p>\n\n<p>Various runtime improvements can be achieved by changing the \"chunk size\" to 1024 bytes or more. However this would likely reduce flash efficiency. As always, life is a compromise....</p>\n\n<p><br />\n </p>\n\n<h3>Spare area details</h3>\n\n<p>The following table summarizes the layout of the spare area of each page.</p>\n\n<p>Byte #SmartMedia usageYAFFS usage</p>\n\n<table><tr><td>\n			<p>0..511</p>\n			</td>\n			<td>\n			<p>Data</p>\n			</td>\n			<td>\n			<p>Data. either file data or file header depending on tags</p>\n			</td>\n		</tr><tr><td>\n			<p>512..515</p>\n			</td>\n			<td>\n			<p>Reserved</p>\n			</td>\n			<td>\n			<p>Tags</p>\n			</td>\n		</tr><tr><td>\n			<p>516</p>\n			</td>\n			<td>\n			<p>Data status byte. Not used in SM code from Samsung</p>\n			</td>\n			<td>\n			<p>Data status byte. If more than 4 bits are zero, then this page is discarded.</p>\n			</td>\n		</tr><tr><td>\n			<p>517</p>\n			</td>\n			<td>\n			<p>Block status byte</p>\n			</td>\n			<td>\n			<p>Block status byte</p>\n			</td>\n		</tr><tr><td>\n			<p>518..519</p>\n			</td>\n			<td>\n			<p>Block address</p>\n			</td>\n			<td>\n			<p>Tags</p>\n			</td>\n		</tr><tr><td>\n			<p>520..522</p>\n			</td>\n			<td>\n			<p>ECC on second 256 bytes part of data</p>\n			</td>\n			<td>\n			<p>ECC on second 256 bytes of data</p>\n			</td>\n		</tr><tr><td>\n			<p>523..524</p>\n			</td>\n			<td>\n			<p>Block address</p>\n			</td>\n			<td>\n			<p>Tags</p>\n			</td>\n		</tr><tr><td>\n			<p>525..527</p>\n			</td>\n			<td>\n			<p>ECC on first 256 bytes part of data</p>\n			</td>\n			<td>\n			<p>ECC on first 256 bytes part of data</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>The block status is a reserved value that shows whether the block is damaged.</p>\n\n<p>The data status tracks whether the page is valid. If less than 4 bits are zero, then the page is valid otherwise it is discarded.</p>\n\n<p>There are 8 bytes (64 bits) for use by YAFFS tags. This is partitioned as follows:</p>\n\n<p>Number of bitsUsage</p>\n\n<table><tr><td>\n			<p>18</p>\n			</td>\n			<td>\n			<p>18-bit file id. ie. Limit of 218 (over 260000) files. File id 0 is not valid and indicates a deleted page. File Id 0x3FFFF i is also not valid.</p>\n			</td>\n		</tr><tr><td>\n			<p>2</p>\n			</td>\n			<td>\n			<p>2-bit serial number.</p>\n			</td>\n		</tr><tr><td>\n			<p>20</p>\n			</td>\n			<td>\n			<p>20-bit page id within file. Limit of 220 pages per file. ie. over 500MB file max size. Page id 0 means the file header for this file.</p>\n			</td>\n		</tr><tr><td>\n			<p>10</p>\n			</td>\n			<td>\n			<p>10-bit counter of the number of bytes used in the page.</p>\n			</td>\n		</tr><tr><td>\n			<p>12</p>\n			</td>\n			<td>\n			<p>12-bit ECC on tags.</p>\n			</td>\n		</tr><tr><td>\n			<p>2</p>\n			</td>\n			<td>\n			<p>Unused. Keep as 1.</p>\n			</td>\n		</tr><tr><td>\n			<p><strong>64</strong></p>\n			</td>\n			<td>\n			<p><strong>Total</strong></p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>A bit of explanation on the usage of some of these fields:</p>\n\n<p>file Id is synonymous with inode.</p>\n\n<p>The serial number is incremented each time a page with the same file_id:page_id is rewritten (because of data changes or copy during garbage collection). When a page is replaced, there is a brief period during which there are two pages with the same id. The serial number resolves this. Since there should never be a difference of less than more than one, a two-bit counter is sufficient to determine which is the current page.</p>\n\n<p>When the page is rewritten, the file id, these data status byte and the 12-bit ECC are all written to zero.</p>\n\n<p>The byte counter indicates how many bytes are valid in this page. Since the page would not exist if it contains zero bytes, this field should thus hold 512 for all pages except the last page in the file. The use of counters means that the file length integrity is preserved while the file is open without having to constantly update the file length in the file header. The file header only needs to be refreshed when the file is closed (rather than whenever it is appended to). This field is wide enough to allow expansion to 1024-byte \"chunks\".</p>\n\n<p>File \"headers\" come in two flavours:</p>\n\n<ul><li>\n	<p>file info ( the mode, ower id, group id, length,...)</p>\n	</li>\n	<li>\n	<p>the hard link(s) that refers to the file.</p>\n	</li>\n</ul><p>A directory also appears as a file (ie. has an inode and hard link(s)) but has no data.</p>\n\n<p>The 12-bit ECC applies to only the tag data uses a similar algorithm to the 22-bit ECCs used for file system data. They are kept independent.</p>\n\n<h3>RAM data details</h3>\n\n<p>Block management details are reasonably obvious and, I feel, don\'t need to be addressed here apart from stating that there will be a structure to track block status (eg. number of pages in use, failed blocks, and which are candidates for garbage collection etc).</p>\n\n<p>The files need an indexing structure of sorts to locate and track the pages in the file. Some sort of tree structure should work rather well. The look-up needs to be quite efficient in both CPU time and space.</p>\n\n<h3>Page allocation and garbage collection</h3>\n\n<p>Pages are allocated sequentially from the currently selected block. When all the pages in the block are filled, another clean block is selected for allocation. At least two or three clean blocks are reserved for garbage collection purposes. If there are insufficient clean blocks available, then a dirty block ( ie one containing only discarded pages) is erased to free it up as a clean block. If no dirty blocks are available, then the dirtiest block is selected for garbage collection.</p>\n\n<p>Garbage collection is performed by copying the valid data pages into new data pages thus rendering all the pages in this block dirty and freeing it up for erasure. I also like the idea of selecting a block at random some small percentage of the time - thus reducing the chance of wear differences.</p>\n\n<p>Relative to NOR, NAND writes and erases very fast. Therefore garbage collection might be performed on-demand (eg. during a write) without significant degradation in performance. Alternatively garbage collection might be delegated to a kernel tasklet.</p>\n\n<p>Relative to JFFSx, the garbage collection presented here is incredibly simple - thanks mainly to the use of fixed-size pages instead of journaling nodes.</p>\n\n<h3>Flash writing</h3>\n\n<p>As presented here, YAFFS only writes to the page\'s data area once and to the spare area twice (once when new page is written and once when it gets stomped on) before an erasure. This is within the limits of the most restrictive NAND flashes.</p>\n\n<h3>Wear levelling</h3>\n\n<p>No wear levelling is explicitly used here. Instead we rely on two \"strategies\":</p>\n\n<ul><li>\n	<p>Reserving some blocks to cater for failure. You need to do this anyway with NAND. The main purpose behind wear levelling is to prevent some blocks getting more wear and failing. Since we expect, and handle, failure this is no longer as important.</p>\n	</li>\n	<li>\n	<p>The infrequent random block selection should prevent low-wear blocks getting \"stuck\".</p>\n	</li>\n</ul><h3>Partitioning</h3>\n\n<p>Partitioning is not included in this spec, but could be added if required.</p>\n\n<h3>Bootloading</h3>\n\n<p>Bootloaders cannot just read files direct from NAND due to the high probability of bad blocks. Because YAFFS is quite simple it will be relatively straightforward for bootloaders to read from it (eg reading a kernel).</p>\n\n<h3>Conclusion</h3>\n\n<p>YAFFS is very simple. It is also NAND-friendly, is relatively frugal with resources (especially RAM) and boots quickly. Like JFFSx it has journaling which makes it far more robust than FAT.</p>\n\n<p>While it might seem high-risk to develop YAFFS, it is probably about the same amount of effort as implementing changes to JFFS to get it to work effectively within the constraints of NAND. A resulting JFFSx system would still require significant amounts of RAM and have long boot times.</p>\n\n<p>While YAFFS is indeed a new file system internally, much of the file system glue code (including inode management, link management etc) can likely be stolen from JFFSx.</p>\n\n<p> </p>\n\n<p>YAFFS Development Notes</p>\n\n<h3>Build options</h3>\n\n<p>Yaffs can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\n\n<p>Of course the goal is to build yaffs as a file system running on top of real NAND flash, but yaffs can be built to run on a RAM emulation layer for in-kernel testing without NAND flash in the system.</p>\n\n<p>Building as an application allows the yaffs_guts algorithms to be tested/debugged in a more friendly debugging environment. The test harness is in yaffsdev.c</p>\n\n<h3>Trying it out</h3>\n\n<p>YAFFS can be built to run with either mtd or RAM emulation, or both. The file system that interfaces to mtd is called <strong>yaffs</strong>, the file system that uses internal ram is called <strong>yaffsram</strong>. YAFFS simultaneously supports both if they are enabled.</p>\n\n<ol><li>\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\n	</li>\n	<li>\n	<p>If you don\'t have mtd support in your kernel, then you might need to turn off USE_MTD otherwise the yaffs module might not load.</p>\n	</li>\n	<li>\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\n	</li>\n	<li>\n	<p>Load yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\n	</li>\n	<li>\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\n	</li>\n	<li>\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\n	</li>\n	<li>\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\n	</li>\n</ol><p><br />\n </p>\n\n<h3>YAFFS Data structures</h3>\n\n<p>All data types are defined in yaffs_guts.h</p>\n\n<p>Yaffs uses the following major objects:</p>\n\n<ul><li>\n	<p>yaffs_Object: A yaffs_Object can be a file, directory, symlink or hardlink. The yaffs_Objects \"know\" about their corresponding yaffs_ObjectHeader in NAND and the data for that object. yaffs_Objects also bind together the directory structure as follows:</p>\n	</li>\n	<li>\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\n	</li>\n	<li>\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\n	</li>\n	<li>\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\n	</li>\n	<li>\n	<p>yaffs_Tnode: yaffs_Tnodes form a tree structure that speeds up the search for data chunks in a file. As the file grows in size, the levels increase. The Tnodes are a constant size (32 bytes). Level 0 (ie the lowest level) comprise 16 2-byte entries giving an index used to search for the chunkId. Tnodes at other levels comprise 8 4-byte pointer entries to other tnodes lower in the tree.</p>\n	</li>\n	<li>\n	<p>yaffs_Device: this holds the device context and is in some ways analogous to the VFS superblock. It stores the data used to access the mtd as well as function pointers to access the NAND data.</p>\n	</li>\n</ul><p>The Tnodes and Objects are allocated in groups to reduce memory allocation/freeing overheads. Freed up tnodes and objects are kept in a free list and re-used.</p>\n\n<h3>yaffs_Object</h3>\n\n<p><br />\n </p>\n\n<p>struct yaffs_ObjectStruct</p>\n\n<p>{</p>\n\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\n\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\n\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\n\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\n\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\n\n<p>// object might be created before the data</p>\n\n<p>// is available (ie. file data records appear before the header).</p>\n\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\n\n<p>// read back the old one to update.</p>\n\n<p>__u16 sum; // sum of the name to speed searching</p>\n\n<p> </p>\n\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\n\n<p>// live on this list</p>\n\n<p>// directory structure stuff</p>\n\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\n\n<p>struct list_head siblings; // siblings in a directory</p>\n\n<p>// also used for linking up the free list</p>\n\n<p> </p>\n\n<p>// Where\'s my data in NAND?</p>\n\n<p>int chunkId; // where it lives</p>\n\n<p> </p>\n\n<p>__u32 objectId; // the object id value</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>__u32 st_mode; // protection</p>\n\n<p>__u32 st_uid; // user ID of owner</p>\n\n<p>__u32 st_gid; // group ID of owner</p>\n\n<p>__u32 st_atime; // time of last access</p>\n\n<p>__u32 st_mtime; // time of last modification</p>\n\n<p>__u32 st_ctime; // time of last change</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>yaffs_ObjectType variantType;</p>\n\n<p> </p>\n\n<p>yaffs_ObjectVariant variant;</p>\n\n<p> </p>\n\n<p>};</p>\n\n<p><br />\n </p>\n\n<p>Obvious stuff skipped....</p>\n\n<p>fake, renameAllowed, unlinkAllowed are special flags for handling \"fake\" objects which live in the file system but do not live on NAND. Currently there are only two such objects: the root object and the lost+found directory. None of these may be renamed or unlinked.</p>\n\n<p>serial, sum: see yaffs_ObjectHeader.</p>\n\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\n\n<p>valid indicates that the object has been loaded up. This is only used during scanning (yaffs_Scan()) since we can know of an object\'s existance - and thus need to create the object header - before we encounter the associated yaffs_ObjectHeader.</p>\n\n<p>hashlink is a list of Objects in the same hash bucket.</p>\n\n<p>The four variants hold extra info:</p>\n\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\n\n<p>Directories hold a list of children objects.</p>\n\n<p>Symlinks hold a pointer to the alias string. This is probably inefficient, but that probably does not matter since we don\'t expect to see many of these.</p>\n\n<p>Hardlinks hold information to identify the equivalent object.</p>\n\n<p><br />\n </p>\n\n<p><br />\n </p>\n\n<h3>File structure (tnodes)</h3>\n\n<p>File structures are done with a tiered indexing structure</p>\n\n<p><br />\n </p>\n\n<p><img alt=\"\" height=\"294\" src=\"yaffs/sv9349341.gif\" width=\"491\" /><br /><br />\n </p>\n\n<p>The file structure is maintained by a tree structure. Depending where it is in the tree, each tree node (<strong><em>tnode</em></strong>) (the blue/things) holds either:</p>\n\n<ul><li>\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\n	</li>\n	<li>\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\n	</li>\n</ul><p>When the file starts out, it is assigned only one low-level tnode. When the file expands past what a single tnode can hold, then it is assigned a second tnode and an internal node is added to point to the two tnodes. As the file grows, more low-level tnodes and high level tnodes are added.</p>\n\n<p>Traversing the tnode tree to find a particular page in a file is quite simple: each internal tnode is selected from by using 3 bits of the page offset in the file. The level 0 page resolves 4 bits.</p>\n\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\n\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\n\n<p>LevelBitsSelected value</p>\n\n<table><tr><td>\n			<p>3 or more if they exist</p>\n			</td>\n			<td>\n			<p>&gt;= 10</p>\n			</td>\n			<td>\n			<p>Zero</p>\n			</td>\n		</tr><tr><td>\n			<p>2</p>\n			</td>\n			<td>\n			<p>9 to 7</p>\n			</td>\n			<td>\n			<p>100 binary = 4</p>\n			</td>\n		</tr><tr><td>\n			<p>1</p>\n			</td>\n			<td>\n			<p>6 to 4</p>\n			</td>\n			<td>\n			<p>011 binary = 3</p>\n			</td>\n		</tr><tr><td>\n			<p>0</p>\n			</td>\n			<td>\n			<p>3 to 0</p>\n			</td>\n			<td>\n			<p>0101 binary = 5</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>Free tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\n\n<p>Each tnode takes 32 bytes. Each file needs at least one level 0 tnode. How many do we need? A full 16MB file system needs at least 16MB/512/16 = 2000 level zero tnodes. More for internal tnodes. More for files smaller than optimal.</p>\n\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\n\n<p><br />\n </p>\n\n<h3>NAND data</h3>\n\n<p>Data is stored on NAND in \"chunks\". Currently each chunk is the same size as a NAND flash page (ie. 512 bytes + 16 byte spare). In the future we might decide to allow for different chunk sizes. Chunks can hold either:</p>\n\n<ul><li>\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\n	</li>\n	<li>\n	<p>A chunk of file data.</p>\n	</li>\n</ul><p>The 16 byte spare area contains:</p>\n\n<ul><li>\n	<p>8 bytes of tags,</p>\n	</li>\n	<li>\n	<p>6 bytes of ECC data</p>\n	</li>\n	<li>\n	<p>1 byte block status (used to identify damaged blocks)</p>\n	</li>\n	<li>\n	<p>1 byte data status (currently unused).</p>\n	</li>\n</ul><p>The tags are made up as follows:</p>\n\n<p>typedef struct</p>\n\n<p>{</p>\n\n<p>unsigned chunkId:20; //chunk number in file</p>\n\n<p>unsigned serialNumber:2; //serial number for chunk</p>\n\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\n\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\n\n<p>unsigned ecc:12; //ECC on tags</p>\n\n<p>unsigned unusedStuff:2; //unused</p>\n\n<p>} yaffs_Tags;</p>\n\n<p> </p>\n\n<p>A chunkId of zero indicates that this chunk holds a yaffs_ObjectHeader. A non zero value indicates that this is a data chunk and the position of the chunk in the file (ie. the first chunk - at offset 0 - has chunkId 1). See yaffs_guts.c:yaffs_Scan () to see how this is done.</p>\n\n<p>When a chunk is replaced (eg. file details changed or a part of a file was overwritten), the new chunk is written before the old chunk is deleted. This means that we don\'t lose data if there is a power loss after the new chunk is created but before the old one is discarded, but it does mean that we can encounter the situation where we find both the old and the new chunks in flash. The serialNumber is incremented each time the chunk is written. 2 bits is sufficient to resolve any ambiguity.</p>\n\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\n\n<p>objectId says which object this chunk belongs to.</p>\n\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\n\n<p><br />\n </p>\n\n<h3>yaffs_ObjectHeader</h3>\n\n<p>typedef struct</p>\n\n<p>{</p>\n\n<p>yaffs_ObjectType type;</p>\n\n<p> </p>\n\n<p>// Apply to everything</p>\n\n<p>int parentObjectId;</p>\n\n<p>__u16 sum; // checksum of name</p>\n\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\n\n<p> </p>\n\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\n\n<p>__u32 st_mode; // protection</p>\n\n<p>__u32 st_uid; // user ID of owner</p>\n\n<p>__u32 st_gid; // group ID of owner</p>\n\n<p>__u32 st_atime; // time of last access</p>\n\n<p>__u32 st_mtime; // time of last modification</p>\n\n<p>__u32 st_ctime; // time of last change</p>\n\n<p> </p>\n\n<p>// File size applies to files only</p>\n\n<p>int fileSize;</p>\n\n<p> </p>\n\n<p>// Equivalent object id applies to hard links only.</p>\n\n<p>int equivalentObjectId;</p>\n\n<p>// alias only applies to symlinks</p>\n\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>} yaffs_ObjectHeader;</p>\n\n<p> </p>\n\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\n\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\n\n<p>parentObject is the objectId of this object\'s parent. name holds the object\'s name. Together these form the directory structure of the file system. Also worth mention is sum. This is a \"checksum\" on the name which speeds directory searching (ie. when searching the directory we only compare the name for those entries where sum matches).</p>\n\n<p>Obvious stuff skipped....</p>\n\n<p>equivalentObjectId is used by hardlinks. A hardlink to an object uses this field to specify the object that this links to. This way of doing things is a bit different than the normal Linux way of doing things (ie. keeping the links distinct from the inode) but is simpler and uses less space except for a few corner cases with hardlinks.</p>\n\n<p>alias is used by symlinks to hold the symlink alias string. This limits the size of the symlink alias. In future we should expand YAFFS to use data chunks to store aliases too long to fit into the yaffs_ObjectHeader.</p>\n\n<p><br />\n </p>\n\n<h3>NAND Interface</h3>\n\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\n\n<ul><li>\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\n	</li>\n	<li>\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\n	</li>\n	<li>\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\n	</li>\n	<li>\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\n	</li>\n</ul><p>In the Readxxx and Writexxx functions, the data and/or spare pointers may be NULL in which case these data transfers are ignored.</p>\n\n<p>A quick note about NAND:</p>\n\n<ul><li>\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\n	</li>\n	<li>\n	<p>Each NAND page holds 512 bytes of data and 16 \"spare\" bytes. Yaffs structures the spare area with tags used to identify what is stored in the data area. There are 32 such pages to a block.</p>\n	</li>\n	<li>\n	<p>NAND writes will only change 1 bits to 0. eg. if a byte holds 10110011 and you write 11011010 to it you will get the logical and of the two values: 10010010. The only way to get 1s again is to erase the entire block.</p>\n	</li>\n	<li>\n	<p>You may only write to a page a few times before erasing the entire block. Yaffs lives within these limitations. Each page only gets written to twice (once when written and once when discarded).</p>\n	</li>\n	<li>\n	<p>ECC is normally used with NAND to correct for single bit errors. YAFFS applies the ECC itself, so the MTD should not do this.</p>\n	</li>\n	<li>\n	<p>The current mtd interfaces are not particularly well suited to YAFFS and we will address the issue with the mtd group. (The mtd interface does not support page-oriented read/write which YAFFS would prefer).</p>\n	</li>\n</ul><p><br />\n </p>\n\n<h3>mkyaffs</h3>\n\n<p>mkyaffs is the tool to format a NAND mtd to be used for YAFFS. This is quite simple, just erase all the undamaged blocks. YAFFS treats erased blocks as free (empty) space.</p>\n\n<p><br />\n </p>\n\n<h2>Expected performance</h2>\n\n<p>The following numbers should give an indication of the performance we should expect from YAFFS.</p>\n\n<p>As an example, I\'ll use the following numbers. Since the hardware is capable of 50ns read/write, these numbers allow for some other ovberheads. Clearly though, the performance can be degraded in various ways.</p>\n\n<p>Seek10uS/page</p>\n\n<table><tr><td>\n			<p>Read</p>\n			</td>\n			<td>\n			<p>100nS/byte</p>\n			</td>\n		</tr><tr><td>\n			<p>Write</p>\n			</td>\n			<td>\n			<p>100nS/byte</p>\n			</td>\n		</tr><tr><td>\n			<p>Program</p>\n			</td>\n			<td>\n			<p>200uS/page</p>\n			</td>\n		</tr><tr><td>\n			<p>Erase</p>\n			</td>\n			<td>\n			<p>2mS/block</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>From this we can derive some higher-level numbers:</p>\n\n<p>OperationTimeCalculation</p>\n\n<table><tr><td>\n			<p>Read spare</p>\n			</td>\n			<td>\n			<p>12uS</p>\n			</td>\n			<td>\n			<p>seek + 16 * read</p>\n			</td>\n		</tr><tr><td>\n			<p>Read page</p>\n			</td>\n			<td>\n			<p>63 uS</p>\n			</td>\n			<td>\n			<p>seek + 528 * read</p>\n			</td>\n		</tr><tr><td>\n			<p>Write page</p>\n			</td>\n			<td>\n			<p>326 uS</p>\n			</td>\n			<td>\n			<p>seek + 528 * write + program + read page (for verification)</p>\n			</td>\n		</tr><tr><td>\n			<p>Discard page</p>\n			</td>\n			<td>\n			<p>212 uS</p>\n			</td>\n			<td>\n			<p>seek + 16 * write + program</p>\n			</td>\n		</tr><tr><td>\n			<p>Overwrite page</p>\n			</td>\n			<td>\n			<p>538 uS</p>\n			</td>\n			<td>\n			<p>write page + discard page</p>\n			</td>\n		</tr><tr><td>\n			<p>Erase overhead per page</p>\n			</td>\n			<td>\n			<p>63uS</p>\n			</td>\n			<td>\n			<p>erase/32</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>From this we can infer the following flash access times:</p>\n\n<p>OperationTimeCalculation</p>\n\n<table><tr><td>\n			<p>Read 1MB file</p>\n			</td>\n			<td>\n			<p>0.13s (about 7.5 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * read page</p>\n			</td>\n		</tr><tr><td>\n			<p>Write 1MB (clean system)</p>\n			</td>\n			<td>\n			<p>0.53s (about 1.8 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * write page</p>\n			</td>\n		</tr><tr><td>\n			<p>Overwrite 1MB file (no gc)</p>\n			</td>\n			<td>\n			<p>1.08s (about 0.9MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * overwrite page</p>\n			</td>\n		</tr><tr><td>\n			<p>Overwrite 1MB with 50% gc</p>\n			</td>\n			<td>\n			<p>2.4s (about 0.4 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\n			</td>\n		</tr><tr><td>\n			<p>Delete 1MB file</p>\n			</td>\n			<td>\n			<p>0.43s (about 2.2 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * discard page</p>\n			</td>\n		</tr><tr><td>\n			<p>Delete 1MB file with 50% gc</p>\n			</td>\n			<td>\n			<p>0.49s (about 2.0MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * discard page + 1000 * erase overhead</p>\n			</td>\n		</tr></table><p> </p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:38:\"/archives/yaffs-original-specification\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:8:\"/node/37\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:38:\"/archives/yaffs-original-specification\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"node:37\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:65:\"<span property=\"schema:name\">Yaffs Original Specification</span>\n\";}}',-1,1504638075.297,1,'config:filter.format.basic_html config:system.site node:37 node_view rendered user:1','278'),('entity_view:node:37:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:2:\"37\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"node:37\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504638075.295,1,'config:filter.format.basic_html config:system.site node:37 node_view rendered user:1','278'),('entity_view:node:37:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:32920:\"<span property=\"schema:name\">Yaffs Original Specification</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>YAFFS (Yet Another Flash File System)</p>\n\n<h4>Version 0.3</h4>\n\n<h4>Charles Manning (and Wookey), December 2001</h4>\n\n<p><br />\n </p>\n\n<h2>Revision History</h2>\n\n<p>V0.0 20/12/01 First Draft</p>\n\n<table><tr><td>\n			<p>V0.1</p>\n			</td>\n			<td>\n			<p>11/01/02</p>\n			</td>\n			<td>\n			<p>Minor corrections &amp; cosmetics.<br />\n			Change use of data status byte.</p>\n			</td>\n		</tr><tr><td>\n			<p>V0.2</p>\n			</td>\n			<td>\n			<p>28/01/02</p>\n			</td>\n			<td>\n			<p>Added observations about inodes, file headers and hard links.</p>\n			</td>\n		</tr><tr><td>\n			<p>V0.3</p>\n			</td>\n			<td>\n			<p>26/02/02</p>\n			</td>\n			<td>\n			<p>W:Added some general observations on compatibility, partitions and bootloading.</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<h2>Scope</h2>\n\n<p>The purpose of this document is to outline a potential NAND-friendly file system for Linux.</p>\n\n<h2>Background</h2>\n\n<p>There are already various flash-file systems (FFSs) or block drivers for flash (on top of which a regular FS runs). There are pros and cons with all of these.</p>\n\n<p>Flash memory has quite a few constraints which will not be addressed here. Various approaches are available to work around these constraints to provide a file system. It is important to recognise that \"flash\" includes both NOR and NAND flash which have different sets of constraints. It is easy to be mislead by the generic term \"flash\" into thinking that approaches appropriate for NOR flash are immediately suitable for NAND flash.</p>\n\n<p>The NAND block drivers (eg. SmartMedia [currently not available for Linux] and DiskOnChip NFTL) typically use FAT16 as the file system. This isn\'t too robust and nor is it that flash-friendly. These block drivers provide a logical to physical mapping layer to emulate rewritable blocks that look like disk sectors. When used with FAT16, these file systems work reasonably well. They have a low memory footprint and scale well. Like all FAT based systems they are prone to corruption (\"lost clusters etc\").</p>\n\n<p>The other approach is to design an entire file system which does not work through a block driver layer and is flash-friendly. This allows more scope to work around issues.</p>\n\n<p>Currently, two Linux file systems that support NOR flash very well are JFFS and its derivative JFFS2. Both of these are based on the principles of journaling (hence the leading J) which significantly increases robustness - a particularly important feature in embedded systems. Unfortunately neither of these file systems scale particularly well in both boot time and RAM usage. Scaling is particularly relevant when one considers that a 16MB NOR array would be considered large while a 128MB NAND is available as a single chip.</p>\n\n<p>JFFS requires a RAM-based jffs_node structure for each journalling node in the flash. Each of these nodes is 48 bytes. JFFS2 makes a significant improvement here by reducing the equivalent structure (jffs2_raw_node_ref) to 16 bytes. Still, at say an average node-size of 512 bytes, a 128MB NAND might need 250000 of these ... 4MB!</p>\n\n<p>Both JFFS and JFFS2 require scanning the flash array at boot time to find the journaling nodes and determine the file structures. Since NAND is large, slow, serially accessed and needs ECC this does not scale well and will take an unacceptably long boot time for the target systems. As a thumb-suck, the scanning of a 128MB NAND array might take approx 25 seconds.</p>\n\n<p>The intentions of the design sketched here are:</p>\n\n<ul><li>\n	<p>Be NAND-flash friendly.</p>\n	</li>\n	<li>\n	<p>Robustness through journaling strategies.</p>\n	</li>\n	<li>\n	<p>Significantly reduce the RAM overheads and boot times associated with JFFSx.</p>\n	</li>\n</ul><p>This FS is intended primarily for internal NAND rather than removable NAND (SM cards). On removable SM cards Smartmedia compatibility is likely to be important so SM/FAT will normally be used, although of course YAFFS makes a lot of sense if reliability is more important than compatibility.</p>\n\n<h2>Overview</h2>\n\n<p>Here follows a simplified overview of YAFFS.</p>\n\n<p>YAFFS uses a physical flash format similar to SmartMedia. This is done for various reasons:</p>\n\n<ul><li>\n	<p>Some of the formatting, eg placement of bad block markers is determined by the NAND manufacturers and can\'t be changed.</p>\n	</li>\n	<li>\n	<p>Potential to reuse code.</p>\n	</li>\n	<li>\n	<p>If it ain\'t broke don\'t fix.</p>\n	</li>\n</ul><p>Some of the fields are obviously different to reflect the different usage. Despite the similarities YAFFS is not actually compatible with SM/FAT. SM cards need to be reformatted to switch from using SM/FAT to YAFFS or vice versa.</p>\n\n<p>File data is stored in fixed size \"chunks\" consistent with the size of a page (ie. 512 bytes). Each page is marked with a file id and chunk number. These tags are stored in the \"spare data\" region of the flash. The chunk number is determined by dividing the file position by the chunk size.</p>\n\n<p>When data in a file is overwritten, the relevant chunks are replaced by writing new pages to flash containing the new data but the same tags. The overwritten data is marked as \"discarded\".</p>\n\n<p>File \"headers\" are stored as a single page, marked so as to be differentiated from data pages.</p>\n\n<p>Pages are also marked with a short (2 bit) serial number that increments each time the page at this position is incremented. The reason for this is that if power loss/crash/other act of demonic forces happens before the replaced page is marked as discarded, it is possible to have two pages with the same tags. The serial number is used to arbitrate.</p>\n\n<p>A block containing only discarded pages (termed a <em>dirty block</em>) is an obvious candidate for garbage collection. Otherwise valid pages can be copied off a block thus rendering the whole block discarded and ready for garbage collection.</p>\n\n<p>In theory you don\'t need to hold the file structure in RAM... you could just scan the whole flash looking for pages when you need them. In practice though you\'d want better file access times than that! The mechanism proposed here is to have a list of __u16 page addresses associated with each file. Since there are 218 pages in a 128MB NAND, a __u16 is insufficient to uniquely identify a page but is does identify a group of 4 pages - a small enough region to search exhaustively. This mechanism is clearly expandable to larger NAND devices - within reason. The RAM overhead with this approach is approx 2 bytes per page - 512kB of RAM for a whole 128MB NAND.</p>\n\n<p>Boot-time scanning to build the file structure lists should require just one pass reading NAND. Since only the the spare data needs to be read, this should be relatively fast ( approx 3 seconds for 128MB). Improvements can be achieved by partitioning the NAND. ie. mount the critical partition first then mount the data partition afterwards.</p>\n\n<p>Various runtime improvements can be achieved by changing the \"chunk size\" to 1024 bytes or more. However this would likely reduce flash efficiency. As always, life is a compromise....</p>\n\n<p><br />\n </p>\n\n<h3>Spare area details</h3>\n\n<p>The following table summarizes the layout of the spare area of each page.</p>\n\n<p>Byte #SmartMedia usageYAFFS usage</p>\n\n<table><tr><td>\n			<p>0..511</p>\n			</td>\n			<td>\n			<p>Data</p>\n			</td>\n			<td>\n			<p>Data. either file data or file header depending on tags</p>\n			</td>\n		</tr><tr><td>\n			<p>512..515</p>\n			</td>\n			<td>\n			<p>Reserved</p>\n			</td>\n			<td>\n			<p>Tags</p>\n			</td>\n		</tr><tr><td>\n			<p>516</p>\n			</td>\n			<td>\n			<p>Data status byte. Not used in SM code from Samsung</p>\n			</td>\n			<td>\n			<p>Data status byte. If more than 4 bits are zero, then this page is discarded.</p>\n			</td>\n		</tr><tr><td>\n			<p>517</p>\n			</td>\n			<td>\n			<p>Block status byte</p>\n			</td>\n			<td>\n			<p>Block status byte</p>\n			</td>\n		</tr><tr><td>\n			<p>518..519</p>\n			</td>\n			<td>\n			<p>Block address</p>\n			</td>\n			<td>\n			<p>Tags</p>\n			</td>\n		</tr><tr><td>\n			<p>520..522</p>\n			</td>\n			<td>\n			<p>ECC on second 256 bytes part of data</p>\n			</td>\n			<td>\n			<p>ECC on second 256 bytes of data</p>\n			</td>\n		</tr><tr><td>\n			<p>523..524</p>\n			</td>\n			<td>\n			<p>Block address</p>\n			</td>\n			<td>\n			<p>Tags</p>\n			</td>\n		</tr><tr><td>\n			<p>525..527</p>\n			</td>\n			<td>\n			<p>ECC on first 256 bytes part of data</p>\n			</td>\n			<td>\n			<p>ECC on first 256 bytes part of data</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>The block status is a reserved value that shows whether the block is damaged.</p>\n\n<p>The data status tracks whether the page is valid. If less than 4 bits are zero, then the page is valid otherwise it is discarded.</p>\n\n<p>There are 8 bytes (64 bits) for use by YAFFS tags. This is partitioned as follows:</p>\n\n<p>Number of bitsUsage</p>\n\n<table><tr><td>\n			<p>18</p>\n			</td>\n			<td>\n			<p>18-bit file id. ie. Limit of 218 (over 260000) files. File id 0 is not valid and indicates a deleted page. File Id 0x3FFFF i is also not valid.</p>\n			</td>\n		</tr><tr><td>\n			<p>2</p>\n			</td>\n			<td>\n			<p>2-bit serial number.</p>\n			</td>\n		</tr><tr><td>\n			<p>20</p>\n			</td>\n			<td>\n			<p>20-bit page id within file. Limit of 220 pages per file. ie. over 500MB file max size. Page id 0 means the file header for this file.</p>\n			</td>\n		</tr><tr><td>\n			<p>10</p>\n			</td>\n			<td>\n			<p>10-bit counter of the number of bytes used in the page.</p>\n			</td>\n		</tr><tr><td>\n			<p>12</p>\n			</td>\n			<td>\n			<p>12-bit ECC on tags.</p>\n			</td>\n		</tr><tr><td>\n			<p>2</p>\n			</td>\n			<td>\n			<p>Unused. Keep as 1.</p>\n			</td>\n		</tr><tr><td>\n			<p><strong>64</strong></p>\n			</td>\n			<td>\n			<p><strong>Total</strong></p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>A bit of explanation on the usage of some of these fields:</p>\n\n<p>file Id is synonymous with inode.</p>\n\n<p>The serial number is incremented each time a page with the same file_id:page_id is rewritten (because of data changes or copy during garbage collection). When a page is replaced, there is a brief period during which there are two pages with the same id. The serial number resolves this. Since there should never be a difference of less than more than one, a two-bit counter is sufficient to determine which is the current page.</p>\n\n<p>When the page is rewritten, the file id, these data status byte and the 12-bit ECC are all written to zero.</p>\n\n<p>The byte counter indicates how many bytes are valid in this page. Since the page would not exist if it contains zero bytes, this field should thus hold 512 for all pages except the last page in the file. The use of counters means that the file length integrity is preserved while the file is open without having to constantly update the file length in the file header. The file header only needs to be refreshed when the file is closed (rather than whenever it is appended to). This field is wide enough to allow expansion to 1024-byte \"chunks\".</p>\n\n<p>File \"headers\" come in two flavours:</p>\n\n<ul><li>\n	<p>file info ( the mode, ower id, group id, length,...)</p>\n	</li>\n	<li>\n	<p>the hard link(s) that refers to the file.</p>\n	</li>\n</ul><p>A directory also appears as a file (ie. has an inode and hard link(s)) but has no data.</p>\n\n<p>The 12-bit ECC applies to only the tag data uses a similar algorithm to the 22-bit ECCs used for file system data. They are kept independent.</p>\n\n<h3>RAM data details</h3>\n\n<p>Block management details are reasonably obvious and, I feel, don\'t need to be addressed here apart from stating that there will be a structure to track block status (eg. number of pages in use, failed blocks, and which are candidates for garbage collection etc).</p>\n\n<p>The files need an indexing structure of sorts to locate and track the pages in the file. Some sort of tree structure should work rather well. The look-up needs to be quite efficient in both CPU time and space.</p>\n\n<h3>Page allocation and garbage collection</h3>\n\n<p>Pages are allocated sequentially from the currently selected block. When all the pages in the block are filled, another clean block is selected for allocation. At least two or three clean blocks are reserved for garbage collection purposes. If there are insufficient clean blocks available, then a dirty block ( ie one containing only discarded pages) is erased to free it up as a clean block. If no dirty blocks are available, then the dirtiest block is selected for garbage collection.</p>\n\n<p>Garbage collection is performed by copying the valid data pages into new data pages thus rendering all the pages in this block dirty and freeing it up for erasure. I also like the idea of selecting a block at random some small percentage of the time - thus reducing the chance of wear differences.</p>\n\n<p>Relative to NOR, NAND writes and erases very fast. Therefore garbage collection might be performed on-demand (eg. during a write) without significant degradation in performance. Alternatively garbage collection might be delegated to a kernel tasklet.</p>\n\n<p>Relative to JFFSx, the garbage collection presented here is incredibly simple - thanks mainly to the use of fixed-size pages instead of journaling nodes.</p>\n\n<h3>Flash writing</h3>\n\n<p>As presented here, YAFFS only writes to the page\'s data area once and to the spare area twice (once when new page is written and once when it gets stomped on) before an erasure. This is within the limits of the most restrictive NAND flashes.</p>\n\n<h3>Wear levelling</h3>\n\n<p>No wear levelling is explicitly used here. Instead we rely on two \"strategies\":</p>\n\n<ul><li>\n	<p>Reserving some blocks to cater for failure. You need to do this anyway with NAND. The main purpose behind wear levelling is to prevent some blocks getting more wear and failing. Since we expect, and handle, failure this is no longer as important.</p>\n	</li>\n	<li>\n	<p>The infrequent random block selection should prevent low-wear blocks getting \"stuck\".</p>\n	</li>\n</ul><h3>Partitioning</h3>\n\n<p>Partitioning is not included in this spec, but could be added if required.</p>\n\n<h3>Bootloading</h3>\n\n<p>Bootloaders cannot just read files direct from NAND due to the high probability of bad blocks. Because YAFFS is quite simple it will be relatively straightforward for bootloaders to read from it (eg reading a kernel).</p>\n\n<h3>Conclusion</h3>\n\n<p>YAFFS is very simple. It is also NAND-friendly, is relatively frugal with resources (especially RAM) and boots quickly. Like JFFSx it has journaling which makes it far more robust than FAT.</p>\n\n<p>While it might seem high-risk to develop YAFFS, it is probably about the same amount of effort as implementing changes to JFFS to get it to work effectively within the constraints of NAND. A resulting JFFSx system would still require significant amounts of RAM and have long boot times.</p>\n\n<p>While YAFFS is indeed a new file system internally, much of the file system glue code (including inode management, link management etc) can likely be stolen from JFFSx.</p>\n\n<p> </p>\n\n<p>YAFFS Development Notes</p>\n\n<h3>Build options</h3>\n\n<p>Yaffs can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\n\n<p>Of course the goal is to build yaffs as a file system running on top of real NAND flash, but yaffs can be built to run on a RAM emulation layer for in-kernel testing without NAND flash in the system.</p>\n\n<p>Building as an application allows the yaffs_guts algorithms to be tested/debugged in a more friendly debugging environment. The test harness is in yaffsdev.c</p>\n\n<h3>Trying it out</h3>\n\n<p>YAFFS can be built to run with either mtd or RAM emulation, or both. The file system that interfaces to mtd is called <strong>yaffs</strong>, the file system that uses internal ram is called <strong>yaffsram</strong>. YAFFS simultaneously supports both if they are enabled.</p>\n\n<ol><li>\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\n	</li>\n	<li>\n	<p>If you don\'t have mtd support in your kernel, then you might need to turn off USE_MTD otherwise the yaffs module might not load.</p>\n	</li>\n	<li>\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\n	</li>\n	<li>\n	<p>Load yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\n	</li>\n	<li>\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\n	</li>\n	<li>\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\n	</li>\n	<li>\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\n	</li>\n</ol><p><br />\n </p>\n\n<h3>YAFFS Data structures</h3>\n\n<p>All data types are defined in yaffs_guts.h</p>\n\n<p>Yaffs uses the following major objects:</p>\n\n<ul><li>\n	<p>yaffs_Object: A yaffs_Object can be a file, directory, symlink or hardlink. The yaffs_Objects \"know\" about their corresponding yaffs_ObjectHeader in NAND and the data for that object. yaffs_Objects also bind together the directory structure as follows:</p>\n	</li>\n	<li>\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\n	</li>\n	<li>\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\n	</li>\n	<li>\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\n	</li>\n	<li>\n	<p>yaffs_Tnode: yaffs_Tnodes form a tree structure that speeds up the search for data chunks in a file. As the file grows in size, the levels increase. The Tnodes are a constant size (32 bytes). Level 0 (ie the lowest level) comprise 16 2-byte entries giving an index used to search for the chunkId. Tnodes at other levels comprise 8 4-byte pointer entries to other tnodes lower in the tree.</p>\n	</li>\n	<li>\n	<p>yaffs_Device: this holds the device context and is in some ways analogous to the VFS superblock. It stores the data used to access the mtd as well as function pointers to access the NAND data.</p>\n	</li>\n</ul><p>The Tnodes and Objects are allocated in groups to reduce memory allocation/freeing overheads. Freed up tnodes and objects are kept in a free list and re-used.</p>\n\n<h3>yaffs_Object</h3>\n\n<p><br />\n </p>\n\n<p>struct yaffs_ObjectStruct</p>\n\n<p>{</p>\n\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\n\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\n\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\n\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\n\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\n\n<p>// object might be created before the data</p>\n\n<p>// is available (ie. file data records appear before the header).</p>\n\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\n\n<p>// read back the old one to update.</p>\n\n<p>__u16 sum; // sum of the name to speed searching</p>\n\n<p> </p>\n\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\n\n<p>// live on this list</p>\n\n<p>// directory structure stuff</p>\n\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\n\n<p>struct list_head siblings; // siblings in a directory</p>\n\n<p>// also used for linking up the free list</p>\n\n<p> </p>\n\n<p>// Where\'s my data in NAND?</p>\n\n<p>int chunkId; // where it lives</p>\n\n<p> </p>\n\n<p>__u32 objectId; // the object id value</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>__u32 st_mode; // protection</p>\n\n<p>__u32 st_uid; // user ID of owner</p>\n\n<p>__u32 st_gid; // group ID of owner</p>\n\n<p>__u32 st_atime; // time of last access</p>\n\n<p>__u32 st_mtime; // time of last modification</p>\n\n<p>__u32 st_ctime; // time of last change</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>yaffs_ObjectType variantType;</p>\n\n<p> </p>\n\n<p>yaffs_ObjectVariant variant;</p>\n\n<p> </p>\n\n<p>};</p>\n\n<p><br />\n </p>\n\n<p>Obvious stuff skipped....</p>\n\n<p>fake, renameAllowed, unlinkAllowed are special flags for handling \"fake\" objects which live in the file system but do not live on NAND. Currently there are only two such objects: the root object and the lost+found directory. None of these may be renamed or unlinked.</p>\n\n<p>serial, sum: see yaffs_ObjectHeader.</p>\n\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\n\n<p>valid indicates that the object has been loaded up. This is only used during scanning (yaffs_Scan()) since we can know of an object\'s existance - and thus need to create the object header - before we encounter the associated yaffs_ObjectHeader.</p>\n\n<p>hashlink is a list of Objects in the same hash bucket.</p>\n\n<p>The four variants hold extra info:</p>\n\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\n\n<p>Directories hold a list of children objects.</p>\n\n<p>Symlinks hold a pointer to the alias string. This is probably inefficient, but that probably does not matter since we don\'t expect to see many of these.</p>\n\n<p>Hardlinks hold information to identify the equivalent object.</p>\n\n<p><br />\n </p>\n\n<p><br />\n </p>\n\n<h3>File structure (tnodes)</h3>\n\n<p>File structures are done with a tiered indexing structure</p>\n\n<p><br />\n </p>\n\n<p><img alt=\"\" height=\"294\" src=\"yaffs/sv9349341.gif\" width=\"491\" /><br /><br />\n </p>\n\n<p>The file structure is maintained by a tree structure. Depending where it is in the tree, each tree node (<strong><em>tnode</em></strong>) (the blue/things) holds either:</p>\n\n<ul><li>\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\n	</li>\n	<li>\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\n	</li>\n</ul><p>When the file starts out, it is assigned only one low-level tnode. When the file expands past what a single tnode can hold, then it is assigned a second tnode and an internal node is added to point to the two tnodes. As the file grows, more low-level tnodes and high level tnodes are added.</p>\n\n<p>Traversing the tnode tree to find a particular page in a file is quite simple: each internal tnode is selected from by using 3 bits of the page offset in the file. The level 0 page resolves 4 bits.</p>\n\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\n\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\n\n<p>LevelBitsSelected value</p>\n\n<table><tr><td>\n			<p>3 or more if they exist</p>\n			</td>\n			<td>\n			<p>&gt;= 10</p>\n			</td>\n			<td>\n			<p>Zero</p>\n			</td>\n		</tr><tr><td>\n			<p>2</p>\n			</td>\n			<td>\n			<p>9 to 7</p>\n			</td>\n			<td>\n			<p>100 binary = 4</p>\n			</td>\n		</tr><tr><td>\n			<p>1</p>\n			</td>\n			<td>\n			<p>6 to 4</p>\n			</td>\n			<td>\n			<p>011 binary = 3</p>\n			</td>\n		</tr><tr><td>\n			<p>0</p>\n			</td>\n			<td>\n			<p>3 to 0</p>\n			</td>\n			<td>\n			<p>0101 binary = 5</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>Free tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\n\n<p>Each tnode takes 32 bytes. Each file needs at least one level 0 tnode. How many do we need? A full 16MB file system needs at least 16MB/512/16 = 2000 level zero tnodes. More for internal tnodes. More for files smaller than optimal.</p>\n\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\n\n<p><br />\n </p>\n\n<h3>NAND data</h3>\n\n<p>Data is stored on NAND in \"chunks\". Currently each chunk is the same size as a NAND flash page (ie. 512 bytes + 16 byte spare). In the future we might decide to allow for different chunk sizes. Chunks can hold either:</p>\n\n<ul><li>\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\n	</li>\n	<li>\n	<p>A chunk of file data.</p>\n	</li>\n</ul><p>The 16 byte spare area contains:</p>\n\n<ul><li>\n	<p>8 bytes of tags,</p>\n	</li>\n	<li>\n	<p>6 bytes of ECC data</p>\n	</li>\n	<li>\n	<p>1 byte block status (used to identify damaged blocks)</p>\n	</li>\n	<li>\n	<p>1 byte data status (currently unused).</p>\n	</li>\n</ul><p>The tags are made up as follows:</p>\n\n<p>typedef struct</p>\n\n<p>{</p>\n\n<p>unsigned chunkId:20; //chunk number in file</p>\n\n<p>unsigned serialNumber:2; //serial number for chunk</p>\n\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\n\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\n\n<p>unsigned ecc:12; //ECC on tags</p>\n\n<p>unsigned unusedStuff:2; //unused</p>\n\n<p>} yaffs_Tags;</p>\n\n<p> </p>\n\n<p>A chunkId of zero indicates that this chunk holds a yaffs_ObjectHeader. A non zero value indicates that this is a data chunk and the position of the chunk in the file (ie. the first chunk - at offset 0 - has chunkId 1). See yaffs_guts.c:yaffs_Scan () to see how this is done.</p>\n\n<p>When a chunk is replaced (eg. file details changed or a part of a file was overwritten), the new chunk is written before the old chunk is deleted. This means that we don\'t lose data if there is a power loss after the new chunk is created but before the old one is discarded, but it does mean that we can encounter the situation where we find both the old and the new chunks in flash. The serialNumber is incremented each time the chunk is written. 2 bits is sufficient to resolve any ambiguity.</p>\n\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\n\n<p>objectId says which object this chunk belongs to.</p>\n\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\n\n<p><br />\n </p>\n\n<h3>yaffs_ObjectHeader</h3>\n\n<p>typedef struct</p>\n\n<p>{</p>\n\n<p>yaffs_ObjectType type;</p>\n\n<p> </p>\n\n<p>// Apply to everything</p>\n\n<p>int parentObjectId;</p>\n\n<p>__u16 sum; // checksum of name</p>\n\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\n\n<p> </p>\n\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\n\n<p>__u32 st_mode; // protection</p>\n\n<p>__u32 st_uid; // user ID of owner</p>\n\n<p>__u32 st_gid; // group ID of owner</p>\n\n<p>__u32 st_atime; // time of last access</p>\n\n<p>__u32 st_mtime; // time of last modification</p>\n\n<p>__u32 st_ctime; // time of last change</p>\n\n<p> </p>\n\n<p>// File size applies to files only</p>\n\n<p>int fileSize;</p>\n\n<p> </p>\n\n<p>// Equivalent object id applies to hard links only.</p>\n\n<p>int equivalentObjectId;</p>\n\n<p>// alias only applies to symlinks</p>\n\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\n\n<p> </p>\n\n<p> </p>\n\n<p>} yaffs_ObjectHeader;</p>\n\n<p> </p>\n\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\n\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\n\n<p>parentObject is the objectId of this object\'s parent. name holds the object\'s name. Together these form the directory structure of the file system. Also worth mention is sum. This is a \"checksum\" on the name which speeds directory searching (ie. when searching the directory we only compare the name for those entries where sum matches).</p>\n\n<p>Obvious stuff skipped....</p>\n\n<p>equivalentObjectId is used by hardlinks. A hardlink to an object uses this field to specify the object that this links to. This way of doing things is a bit different than the normal Linux way of doing things (ie. keeping the links distinct from the inode) but is simpler and uses less space except for a few corner cases with hardlinks.</p>\n\n<p>alias is used by symlinks to hold the symlink alias string. This limits the size of the symlink alias. In future we should expand YAFFS to use data chunks to store aliases too long to fit into the yaffs_ObjectHeader.</p>\n\n<p><br />\n </p>\n\n<h3>NAND Interface</h3>\n\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\n\n<ul><li>\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\n	</li>\n	<li>\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\n	</li>\n	<li>\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\n	</li>\n	<li>\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\n	</li>\n</ul><p>In the Readxxx and Writexxx functions, the data and/or spare pointers may be NULL in which case these data transfers are ignored.</p>\n\n<p>A quick note about NAND:</p>\n\n<ul><li>\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\n	</li>\n	<li>\n	<p>Each NAND page holds 512 bytes of data and 16 \"spare\" bytes. Yaffs structures the spare area with tags used to identify what is stored in the data area. There are 32 such pages to a block.</p>\n	</li>\n	<li>\n	<p>NAND writes will only change 1 bits to 0. eg. if a byte holds 10110011 and you write 11011010 to it you will get the logical and of the two values: 10010010. The only way to get 1s again is to erase the entire block.</p>\n	</li>\n	<li>\n	<p>You may only write to a page a few times before erasing the entire block. Yaffs lives within these limitations. Each page only gets written to twice (once when written and once when discarded).</p>\n	</li>\n	<li>\n	<p>ECC is normally used with NAND to correct for single bit errors. YAFFS applies the ECC itself, so the MTD should not do this.</p>\n	</li>\n	<li>\n	<p>The current mtd interfaces are not particularly well suited to YAFFS and we will address the issue with the mtd group. (The mtd interface does not support page-oriented read/write which YAFFS would prefer).</p>\n	</li>\n</ul><p><br />\n </p>\n\n<h3>mkyaffs</h3>\n\n<p>mkyaffs is the tool to format a NAND mtd to be used for YAFFS. This is quite simple, just erase all the undamaged blocks. YAFFS treats erased blocks as free (empty) space.</p>\n\n<p><br />\n </p>\n\n<h2>Expected performance</h2>\n\n<p>The following numbers should give an indication of the performance we should expect from YAFFS.</p>\n\n<p>As an example, I\'ll use the following numbers. Since the hardware is capable of 50ns read/write, these numbers allow for some other ovberheads. Clearly though, the performance can be degraded in various ways.</p>\n\n<p>Seek10uS/page</p>\n\n<table><tr><td>\n			<p>Read</p>\n			</td>\n			<td>\n			<p>100nS/byte</p>\n			</td>\n		</tr><tr><td>\n			<p>Write</p>\n			</td>\n			<td>\n			<p>100nS/byte</p>\n			</td>\n		</tr><tr><td>\n			<p>Program</p>\n			</td>\n			<td>\n			<p>200uS/page</p>\n			</td>\n		</tr><tr><td>\n			<p>Erase</p>\n			</td>\n			<td>\n			<p>2mS/block</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>From this we can derive some higher-level numbers:</p>\n\n<p>OperationTimeCalculation</p>\n\n<table><tr><td>\n			<p>Read spare</p>\n			</td>\n			<td>\n			<p>12uS</p>\n			</td>\n			<td>\n			<p>seek + 16 * read</p>\n			</td>\n		</tr><tr><td>\n			<p>Read page</p>\n			</td>\n			<td>\n			<p>63 uS</p>\n			</td>\n			<td>\n			<p>seek + 528 * read</p>\n			</td>\n		</tr><tr><td>\n			<p>Write page</p>\n			</td>\n			<td>\n			<p>326 uS</p>\n			</td>\n			<td>\n			<p>seek + 528 * write + program + read page (for verification)</p>\n			</td>\n		</tr><tr><td>\n			<p>Discard page</p>\n			</td>\n			<td>\n			<p>212 uS</p>\n			</td>\n			<td>\n			<p>seek + 16 * write + program</p>\n			</td>\n		</tr><tr><td>\n			<p>Overwrite page</p>\n			</td>\n			<td>\n			<p>538 uS</p>\n			</td>\n			<td>\n			<p>write page + discard page</p>\n			</td>\n		</tr><tr><td>\n			<p>Erase overhead per page</p>\n			</td>\n			<td>\n			<p>63uS</p>\n			</td>\n			<td>\n			<p>erase/32</p>\n			</td>\n		</tr></table><p><br />\n </p>\n\n<p>From this we can infer the following flash access times:</p>\n\n<p>OperationTimeCalculation</p>\n\n<table><tr><td>\n			<p>Read 1MB file</p>\n			</td>\n			<td>\n			<p>0.13s (about 7.5 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * read page</p>\n			</td>\n		</tr><tr><td>\n			<p>Write 1MB (clean system)</p>\n			</td>\n			<td>\n			<p>0.53s (about 1.8 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * write page</p>\n			</td>\n		</tr><tr><td>\n			<p>Overwrite 1MB file (no gc)</p>\n			</td>\n			<td>\n			<p>1.08s (about 0.9MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * overwrite page</p>\n			</td>\n		</tr><tr><td>\n			<p>Overwrite 1MB with 50% gc</p>\n			</td>\n			<td>\n			<p>2.4s (about 0.4 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\n			</td>\n		</tr><tr><td>\n			<p>Delete 1MB file</p>\n			</td>\n			<td>\n			<p>0.43s (about 2.2 MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * discard page</p>\n			</td>\n		</tr><tr><td>\n			<p>Delete 1MB file with 50% gc</p>\n			</td>\n			<td>\n			<p>0.49s (about 2.0MB/s)</p>\n			</td>\n			<td>\n			<p>2000 * discard page + 1000 * erase overhead</p>\n			</td>\n		</tr></table><p> </p></div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:7:\"node:37\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505139221.378,1,'config:filter.format.basic_html node:37 node_view rendered','265'),('entity_view:node:37:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:2:\"37\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:7:\"node:37\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505139221.376,1,'config:filter.format.basic_html node:37 node_view rendered','265'),('entity_view:node:380:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0LyFRe20qwftKh_lq7NEMaWRH_kUSfAp_OauAneQ4YA4','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1185:\"<article role=\"article\" about=\"/support\" typeof=\"schema:WebPage\" class=\"page full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Support\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p>We offer support for Yaffs through the <a href=\"http://stoneboat.aleph1.co.uk/mailman/listinfo/yaffs\">Yaffs mailing list</a>. It\'s best to start by searching the <a href=\"http://www.aleph1.co.uk/lurker/list/yaffs.html\">list archive</a> to see if someone has already asked the same question.</p>\n<p>If you feel uncomfortable asking your question on an open mailing list you can try mailing us, but we (or you) may say \'You should be paying for this\', and if that is agreed, then we can accept payments via PayPal or other means.</p>\n<p>Serious long-term work is best done as a negotiated contract; for instance we have built special features for clients with very particular needs. If you think you may want this sort of help then <a href=\"/contact\">contact us</a>, telling us a bit about your problem.</p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:8:\"/support\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/380\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:8:\"/support\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:380\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:44:\"<span property=\"schema:name\">Support</span>\n\";}}',-1,1504637077.468,1,'config:filter.format.full_html config:system.site node:380 node_view rendered user:1','307'),('entity_view:node:380:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"380\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:380\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504637077.465,1,'config:filter.format.full_html config:system.site node:380 node_view rendered user:1','307'),('entity_view:node:382:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=18fcd943cd6a4b1276d3f25f62771b6a9dee7e45324f4ba05fe485922e155d7OL-kJ667AJ0dVSbpx8EuESuqIYPijjLZGIgAfv_dXdY','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:2821:\"<article data-quickedit-entity-id=\"node/382\" role=\"article\" class=\"contextual-region page full clearfix\" about=\"/get-yaffs\" typeof=\"schema:WebPage\">\n\n  \n    <div data-contextual-id=\"node:node=382:changed=1502716247&amp;langcode=en\"></div>  <span property=\"schema:name\" content=\"Get Yaffs\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" data-quickedit-field-id=\"node/382/body/und/full\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h2>Licences</h2>\n<p>Yaffs belongs to Aleph One Limited. It&nbsp;is available under two licences:</p>\n<ul>\n<li>The <a href=\"https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html\">GPL Version 2</a> (GNU Public Licence, Version 2). You can try it for free under this licence, and you can use Yaffs&nbsp;in GPL licensed software.&nbsp;</li>\n<li>A proprietary, <a href=\"commercial-licences\">commercial licence</a> from Aleph One Limited, for use with proprietary, or closed-source software.&nbsp;These licences are non-exclusive, perpetual, world-wide, royalty-free and paid for with a single fee for one product.</li>\n</ul>\n<p>Yaffs functionality is the same under both licences, and both licences are royalty-free, but the terms of the GPL place significant obligations on<strong>&nbsp;all who&nbsp;use Yaffs under GPL</strong>. Please be certain to <a href=\"/yaffs-gpl\">understand these legal obligations</a> before distributing any software together with Yaffs.</p>\n<h2>Download options</h2>\n<p>We use <a href=\"https://git-scm.com/\">Git</a> to manage our software development.</p>\n<ul>\n<li>To browse or download code,&nbsp;<strong><a href=\"http://www.aleph1.co.uk/gitweb?p=yaffs2.git;a=summary\" target=\"_self\">access our Git repository over the web</a></strong>. This is also the best option if you are behind a firewall that does not allow direct Git&nbsp;access.</li>\n<li>To get a tarball of the top of the tree, just click \'snapshot\' for the release that you want, or to quickly obtain a snapshot of the top of the tree you can <a href=\"http://aleph1.co.uk/gitweb?p=yaffs2.git;a=snapshot;h=HEAD;\" target=\"_self\">use this URL</a>.</li>\n<li>Clone Yaffs using:</li>\n</ul>\n<pre>\ngit clone git://www.aleph1.co.uk/yaffs2\n</pre>\n<ul>\n<li>If you are a registered developer with a server account you can get read/write access using:</li>\n</ul>\n<pre>\ngit clone ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2</pre>\n<p>&nbsp;&nbsp;</p>\n<p>If you have any questions, or would like to buy a commercial licence, please contact us either at&nbsp;+44 (0)1223 811679 or email&nbsp; <a href=\"denied:mailto:sales@aleph1.co.uk\">sales@aleph1.co.uk</a>&nbsp; or see our Contacts page:-&nbsp; <a href=\"http://www.aleph1.co.uk/contact\">http://www.aleph1.co.uk/contact</a></p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:3:{s:14:\"html_head_link\";a:12:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:10:\"/get-yaffs\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/382\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:11:\"delete-form\";s:4:\"href\";s:16:\"/node/382/delete\";}i:1;b:1;}i:3;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"edit-form\";s:4:\"href\";s:14:\"/node/382/edit\";}i:1;b:1;}i:4;a:2:{i:0;a:2:{s:3:\"rel\";s:15:\"version-history\";s:4:\"href\";s:19:\"/node/382/revisions\";}i:1;b:1;}i:5;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:10:\"/get-yaffs\";}i:1;b:1;}i:6;a:2:{i:0;a:2:{s:3:\"rel\";s:17:\"book-outline-form\";s:4:\"href\";s:17:\"/node/382/outline\";}i:1;b:1;}i:7;a:2:{i:0;a:2:{s:3:\"rel\";s:16:\"book-remove-form\";s:4:\"href\";s:24:\"/node/382/outline/remove\";}i:1;b:1;}i:8;a:2:{i:0;a:2:{s:3:\"rel\";s:10:\"devel-load\";s:4:\"href\";s:15:\"/devel/node/382\";}i:1;b:1;}i:9;a:2:{i:0;a:2:{s:3:\"rel\";s:12:\"devel-render\";s:4:\"href\";s:22:\"/devel/node/382/render\";}i:1;b:1;}i:10;a:2:{i:0;a:2:{s:3:\"rel\";s:16:\"devel-definition\";s:4:\"href\";s:26:\"/devel/node/382/definition\";}i:1;b:1;}i:11;a:2:{i:0;a:2:{s:3:\"rel\";s:11:\"token-devel\";s:4:\"href\";s:21:\"/node/382/devel/token\";}i:1;b:1;}}s:7:\"library\";a:1:{i:0;s:20:\"history/mark-as-read\";}s:14:\"drupalSettings\";a:1:{s:7:\"history\";a:1:{s:17:\"nodesToMarkAsRead\";a:1:{i:382;b:1;}}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:382\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:96:\"<span property=\"schema:name\" data-quickedit-field-id=\"node/382/title/und/full\">Get Yaffs</span>\n\";}}',-1,1504796007.540,1,'config:filter.format.full_html config:system.site node:382 node_view rendered user:1','313'),('entity_view:node:382:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0LnFj55D7sTyFxWVEYt2PXcC7uR3fK7Qi60hMtrtYzCw','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:2637:\"<article role=\"article\" about=\"/get-yaffs\" typeof=\"schema:WebPage\" class=\"page full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Get Yaffs\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h2>Licences</h2>\n<p>Yaffs belongs to Aleph One Limited. It&nbsp;is available under two licences:</p>\n<ul>\n<li>The <a href=\"https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html\">GPL Version 2</a> (GNU Public Licence, Version 2). You can try it for free under this licence, and you can use Yaffs&nbsp;in GPL licensed software.&nbsp;</li>\n<li>A proprietary, <a href=\"commercial-licences\">commercial licence</a> from Aleph One Limited, for use with proprietary, or closed-source software.&nbsp;These licences are non-exclusive, perpetual, world-wide, royalty-free and paid for with a single fee for one product.</li>\n</ul>\n<p>Yaffs functionality is the same under both licences, and both licences are royalty-free, but the terms of the GPL place significant obligations on<strong>&nbsp;all who&nbsp;use Yaffs under GPL</strong>. Please be certain to <a href=\"/yaffs-gpl\">understand these legal obligations</a> before distributing any software together with Yaffs.</p>\n<h2>Download options</h2>\n<p>We use <a href=\"https://git-scm.com/\">Git</a> to manage our software development.</p>\n<ul>\n<li>To browse or download code,&nbsp;<strong><a href=\"http://www.aleph1.co.uk/gitweb?p=yaffs2.git;a=summary\" target=\"_self\">access our Git repository over the web</a></strong>. This is also the best option if you are behind a firewall that does not allow direct Git&nbsp;access.</li>\n<li>To get a tarball of the top of the tree, just click \'snapshot\' for the release that you want, or to quickly obtain a snapshot of the top of the tree you can <a href=\"http://aleph1.co.uk/gitweb?p=yaffs2.git;a=snapshot;h=HEAD;\" target=\"_self\">use this URL</a>.</li>\n<li>Clone Yaffs using:</li>\n</ul>\n<pre>\ngit clone git://www.aleph1.co.uk/yaffs2\n</pre>\n<ul>\n<li>If you are a registered developer with a server account you can get read/write access using:</li>\n</ul>\n<pre>\ngit clone ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2</pre>\n<p>&nbsp;&nbsp;</p>\n<p>If you have any questions, or would like to buy a commercial licence, please contact us either at&nbsp;+44 (0)1223 811679 or email&nbsp; <a href=\"denied:mailto:sales@aleph1.co.uk\">sales@aleph1.co.uk</a>&nbsp; or see our Contacts page:-&nbsp; <a href=\"http://www.aleph1.co.uk/contact\">http://www.aleph1.co.uk/contact</a></p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:10:\"/get-yaffs\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/382\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:10:\"/get-yaffs\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:382\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:46:\"<span property=\"schema:name\">Get Yaffs</span>\n\";}}',-1,1504631498.051,1,'config:filter.format.full_html config:system.site node:382 node_view rendered user:1','313'),('entity_view:node:382:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=18fcd943cd6a4b1276d3f25f62771b6a9dee7e45324f4ba05fe485922e155d70:[user.roles:anonymous]=is-super-user','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"382\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:382\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504796007.536,1,'config:filter.format.full_html config:system.site node:382 node_view rendered user:1','313'),('entity_view:node:382:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"382\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:382\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504631498.049,1,'config:filter.format.full_html config:system.site node:382 node_view rendered user:1','313'),('entity_view:node:382:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:2451:\"<span property=\"schema:name\">Get Yaffs</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h2>Licences</h2>\n<p>Yaffs belongs to Aleph One Limited. It&nbsp;is available under two licences:</p>\n<ul>\n<li>The <a href=\"https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html\">GPL Version 2</a> (GNU Public Licence, Version 2). You can try it for free under this licence, and you can use Yaffs&nbsp;in GPL licensed software.&nbsp;</li>\n<li>A proprietary, <a href=\"commercial-licences\">commercial licence</a> from Aleph One Limited, for use with proprietary, or closed-source software.&nbsp;These licences are non-exclusive, perpetual, world-wide, royalty-free and paid for with a single fee for one product.</li>\n</ul>\n<p>Yaffs functionality is the same under both licences, and both licences are royalty-free, but the terms of the GPL place significant obligations on<strong>&nbsp;all who&nbsp;use Yaffs under GPL</strong>. Please be certain to <a href=\"/yaffs-gpl\">understand these legal obligations</a> before distributing any software together with Yaffs.</p>\n<h2>Download options</h2>\n<p>We use <a href=\"https://git-scm.com/\">Git</a> to manage our software development.</p>\n<ul>\n<li>To browse or download code,&nbsp;<strong><a href=\"http://www.aleph1.co.uk/gitweb?p=yaffs2.git;a=summary\" target=\"_self\">access our Git repository over the web</a></strong>. This is also the best option if you are behind a firewall that does not allow direct Git&nbsp;access.</li>\n<li>To get a tarball of the top of the tree, just click \'snapshot\' for the release that you want, or to quickly obtain a snapshot of the top of the tree you can <a href=\"http://aleph1.co.uk/gitweb?p=yaffs2.git;a=snapshot;h=HEAD;\" target=\"_self\">use this URL</a>.</li>\n<li>Clone Yaffs using:</li>\n</ul>\n<pre>\ngit clone git://www.aleph1.co.uk/yaffs2\n</pre>\n<ul>\n<li>If you are a registered developer with a server account you can get read/write access using:</li>\n</ul>\n<pre>\ngit clone ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2</pre>\n<p>&nbsp;&nbsp;</p>\n<p>If you have any questions, or would like to buy a commercial licence, please contact us either at&nbsp;+44 (0)1223 811679 or email&nbsp; <a href=\"denied:mailto:sales@aleph1.co.uk\">sales@aleph1.co.uk</a>&nbsp; or see our Contacts page:-&nbsp; <a href=\"http://www.aleph1.co.uk/contact\">http://www.aleph1.co.uk/contact</a></p>\n</div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:382\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505196111.305,1,'config:filter.format.full_html node:382 node_view rendered','300'),('entity_view:node:382:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"382\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:8:\"node:382\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505196111.303,1,'config:filter.format.full_html node:382 node_view rendered','300'),('entity_view:node:384:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0uN-ARabSB00JcvuxlwvzBghUbgT0T8wa7iVnEgZhWhU','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:853:\"<article role=\"article\" about=\"/features/royalty-free\" class=\"what-is-special-about-yaffs is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  <div class=\"field field--name-field-icon-text field--type-string field--label-above\">\n    <div class=\"field--label\">Icon - text</div>\n              <div class=\"field--item\">fa-thumbs-up</div>\n          </div>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p><strong>100% ROYALTY FREE</strong></p>\n\n<p>Of course there\'s no royalty when you use Yaffs under the GPL; it\'s the GPL!</p>\n\n<p>Our commercial licences are paid for once at the time of buying the Licence, and so they are also royalty free. No accounting and no need to worry about increasing costs as you make or sell more units.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:22:\"/features/royalty-free\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/384\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:22:\"/features/royalty-free\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:384\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:30:\"<span>Royalty Free... </span>\n\";}}',-1,1504685215.697,1,'config:filter.format.basic_html config:system.site node:384 node_view rendered user:1','278'),('entity_view:node:384:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"384\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:384\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504685215.695,1,'config:filter.format.basic_html config:system.site node:384 node_view rendered user:1','278'),('entity_view:node:384:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:823:\"<article role=\"article\" about=\"/features/royalty-free\" class=\"what-is-special-about-yaffs is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/features/royalty-free\" rel=\"bookmark\"><span>Royalty Free... </span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/features/royalty-free\" rel=\"tag\" title=\"Royalty Free... \" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about Royalty Free... </span></a></li></ul>\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">Whether you use Yaffs under the GNU General Public Licence or under a commercial licence, Yaffs is free of any royalty. No need to worry about rising costs for your hit product!</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:384\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1505144016.993,1,'config:filter.format.basic_html node:384 node_view rendered user:1','272'),('entity_view:node:384:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"384\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:384\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505144016.991,1,'config:filter.format.basic_html node:384 node_view rendered user:1','272'),('entity_view:node:385:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0tiH6t21ew1Df-kuN6um3YhfoiMqxHz6X3zh-1mCr0xc','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:924:\"<article role=\"article\" about=\"/features/robust-flash-file-system\" class=\"what-is-special-about-yaffs is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  <div class=\"field field--name-field-icon-text field--type-string field--label-above\">\n    <div class=\"field--label\">Icon - text</div>\n              <div class=\"field--item\">fa-shield</div>\n          </div>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>As part of our regular testing, we run power-fail tests. Whether it\'s during a read or a write, Yaffs is designed to preserve your existing data during a device power failure. And because Yaffs is open source, you can download the tests and run them yourself in the most severe conditions you expect the product to encounter. See:- http://www.yaffs.net/documents/yaffs-robustness-and-testing</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:34:\"/features/robust-flash-file-system\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/385\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:34:\"/features/robust-flash-file-system\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:385\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:43:\"<span>A robust flash file system...</span>\n\";}}',-1,1504703267.568,1,'config:filter.format.basic_html config:system.site node:385 node_view rendered user:1','278'),('entity_view:node:385:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"385\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:385\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504703267.566,1,'config:filter.format.basic_html config:system.site node:385 node_view rendered user:1','278'),('entity_view:node:385:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:856:\"<article role=\"article\" about=\"/features/robust-flash-file-system\" class=\"what-is-special-about-yaffs is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/features/robust-flash-file-system\" rel=\"bookmark\"><span>A robust flash file system...</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/features/robust-flash-file-system\" rel=\"tag\" title=\"A robust flash file system...\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about A robust flash file system...</span></a></li></ul>\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">After more than 100,000 <strong>random</strong> power-failures during reading or writing, a test file showed NO data corruption at all!</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:385\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1505144016.980,1,'config:filter.format.basic_html node:385 node_view rendered user:1','272'),('entity_view:node:385:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"385\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:385\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505144016.977,1,'config:filter.format.basic_html node:385 node_view rendered user:1','272'),('entity_view:node:388:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b082RgWLU_r9OMCMtQLEKzVwC_Evsefh6AyK6BvkdMH5c','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1092:\"<article role=\"article\" about=\"/features/yaffs-open-source\" class=\"what-is-special-about-yaffs is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  <div class=\"field field--name-field-icon-text field--type-string field--label-above\">\n    <div class=\"field--label\">Icon - text</div>\n              <div class=\"field--item\">fa-heart</div>\n          </div>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Yaffs is downloadable with a GNU General Public Licence v.2, as at  http://www.gnu.org/licenses/gpl-2.0.html   You get the source code, with all the benefits that brings. And of course, if you buy a commercial licence, you get the source code too, but without the encumberance of your responsibilities under the GNU GPL</p>\n\n<p>Because it\'s Open Source, you can always see what the code is doing and trace through; and having the code means you\'ll never be in a situation where you are critically dependent on us, either from a technical or a business perspective.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:27:\"/features/yaffs-open-source\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/388\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:27:\"/features/yaffs-open-source\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:388\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:37:\"<span>Yaffs is Open Source...</span>\n\";}}',-1,1504678492.590,1,'config:filter.format.basic_html config:system.site node:388 node_view rendered user:1','278'),('entity_view:node:388:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"388\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:388\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504678492.588,1,'config:filter.format.basic_html config:system.site node:388 node_view rendered user:1','278'),('entity_view:node:388:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:830:\"<article role=\"article\" about=\"/features/yaffs-open-source\" class=\"what-is-special-about-yaffs is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/features/yaffs-open-source\" rel=\"bookmark\"><span>Yaffs is Open Source...</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/features/yaffs-open-source\" rel=\"tag\" title=\"Yaffs is Open Source...\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about Yaffs is Open Source...</span></a></li></ul>\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">You can have a look at the code at any time. <a href=\"/downloads\">Download it now</a>! And it\'s suitable for GPL and commercially licensed projects.</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:388\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1505144016.968,1,'config:filter.format.basic_html node:388 node_view rendered user:1','272'),('entity_view:node:388:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"388\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:388\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505144016.965,1,'config:filter.format.basic_html node:388 node_view rendered user:1','272'),('entity_view:node:389:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0zAVTUHtpcNpIGqZBsMpenN41h2TavT32Xv7Fj96BITw','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:907:\"<article role=\"article\" about=\"/features/tried-and-tested-millions-devices\" class=\"what-is-special-about-yaffs is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  <div class=\"field field--name-field-icon-text field--type-string field--label-above\">\n    <div class=\"field--label\">Icon - text</div>\n              <div class=\"field--item\">fa-mobile-phone</div>\n          </div>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Yaffs is the leading Flash file system, running in millions of devices. It\'s been used on Linux computers, in cameras, mobile phones, hard drives, and on many custom boards. People and companies trust it to keep their data safe. Read more about <a href=\"/documents/yaffs-robustness-and-testing\">how we test Yaffs in our Robustness and Testing white paper</a>.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:43:\"/features/tried-and-tested-millions-devices\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/389\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:43:\"/features/tried-and-tested-millions-devices\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:389\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:56:\"<span>Tried and tested in millions of devices...</span>\n\";}}',-1,1504684283.314,1,'config:filter.format.basic_html config:system.site node:389 node_view rendered user:1','278'),('entity_view:node:389:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"389\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:389\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504684283.306,1,'config:filter.format.basic_html config:system.site node:389 node_view rendered user:1','278'),('entity_view:node:389:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:963:\"<article role=\"article\" about=\"/features/tried-and-tested-millions-devices\" class=\"what-is-special-about-yaffs is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/features/tried-and-tested-millions-devices\" rel=\"bookmark\"><span>Tried and tested in millions of devices...</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/features/tried-and-tested-millions-devices\" rel=\"tag\" title=\"Tried and tested in millions of devices...\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about Tried and tested in millions of devices...</span></a></li></ul>\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">Yaffs is widely used in Linux and proprietary commercial RTOSs. It\'s been included in hundreds of devices, and shipped as part of Google\'s Android, with millions of units sold.</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:389\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1505144016.954,1,'config:filter.format.basic_html node:389 node_view rendered user:1','272'),('entity_view:node:389:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"389\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:389\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505144016.952,1,'config:filter.format.basic_html node:389 node_view rendered user:1','272'),('entity_view:node:38:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01nbugb5peSIBdpsE6Z4DmkkmuSNwvcIWS_vkr6UEuiCs','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:10179:\"<article role=\"article\" about=\"/yaffs-2-specification\" typeof=\"schema:WebPage\" class=\"page is-sticky full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs 2 Specification\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h2>Summary</h2>\n<p>The original motivation for Yaffs 2 was to add support for the new NAND with 2kB pages instead of 512-byte pages and strictly sequential page writing order.</p>\n<p>To achieve this, a new design is used which also realises the following benefits:</p>\n<ul>\n<li>\n<p>Zero page rewrites means faster operation. (Yaffs1 uses a single rewrite in the spare area to delete a page).</p>\n </li>\n<li>\n<p>Ability to exploit simultaneous page programming on some chips.</p>\n </li>\n<li>\n<p>Improves performance relative to Yaffs1 speed(write:1.5x to 5x, delete: 4x, garbage collection: 2x)</p>\n </li>\n<li>\n<p>Lower RAM footprint (approx. 25% to 50% of Yaffs1).</p>\n </li>\n<li>\n<p>Can support Toshiba/Sandisk MLC parts.</p>\n </li>\n</ul>\n<p>Most of Yaffs1 and Yaffs2 code is common, therefore the code will likely be kept common with Yaffs1 vs Yaffs2 being run-time selected.</p>\n<h4>Method</h4>\n<p>The main philosophical difference between Yaffs&nbsp;and Yaffs2 is how discarded status is tracked. Since we can\'t do any re-writing, we can\'t use the \"discarded\" flags in Yaffs2.</p>\n<p>Instead Yaffs2 uses two mechanisms to resolve data state.</p>\n<ul>\n<li>\n<p>Yaffs2 chunks have more tag information, including a block sequence Id. From that we can determine the chunk sequence Id since the chunks are allocated sequentially in a block. Thus we always know the patch order for all chunks in the system.</p>\n </li>\n<li>\n<p>The above helps us track stale -vs- fresh data, but does not help determine when a file/object is deleted. Deletion is achieved by moving the object to the \"unlinked\" directory. We also keep track of the number of chunks (both stale and current) in the system for each object. While this number indicates that there are still chunks associated with this object we keep the deletion record. When the last trace of the object has been really erased from NAND, we can forget about the deletion record too.</p>\n </li>\n<li>\n<p>Since there is no deletion, a resize (shrinking) of a file will still have valid data chunks past the end of file on the NAND. However, we write a new ObjectHeader at the time of the resize, therefore this shows the shrunken file size.</p>\n </li>\n</ul>\n<p>This changes erasure slightly:</p>\n<ul>\n<li>\n<p>During garbage collection we can\'t just look at chunk state flags, instead we must read the tags of each chunk to determine which object\'s chunk count we must decrement. This step must also be performed when a block is erased (as part of deletion).</p>\n </li>\n</ul>\n<p>This makes erasure &amp; garbage collection more expensive (by adding reads), but remember that ion Yaffs2 we don\'t need to do page deletions which are much more expensive operations. Thus, all-up Yaffs2 wins.</p>\n<h4>Tag structure</h4>\n<p>Each chunk in Yaffs2 has the following information:</p>\n<p>Field</p>\n<p>Comment</p>\n<p>Size for 1kb chunks</p>\n<p>Size for 2kB chunks</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>blockState</p>\n   </td>\n  <td>\n  <p>Block state. non-0xFF for bad block</p>\n   </td>\n  <td>\n  <p>1 byte</p>\n   </td>\n  <td>\n  <p>1 byte</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>chunkId</p>\n   </td>\n  <td>\n  <p>32-bit chunk Id</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>objectId</p>\n   </td>\n  <td>\n  <p>32-bit object Id</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>nBytes</p>\n   </td>\n  <td>\n  <p>Number of data bytes in this chunk</p>\n   </td>\n  <td>\n  <p>2 bytes</p>\n   </td>\n  <td>\n  <p>2 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>blockSequence</p>\n   </td>\n  <td>\n  <p>sequence number for this block</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>tagsEcc</p>\n   </td>\n  <td>\n  <p>ECC on tags area</p>\n   </td>\n  <td>\n  <p>3 bytes</p>\n   </td>\n  <td>\n  <p>3 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>ecc</p>\n   </td>\n  <td>\n  <p>ECC, 3 bytes/256 bytes of data</p>\n   </td>\n  <td>\n  <p>12 bytes</p>\n   </td>\n  <td>\n  <p>24 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p><strong>Total</strong></p>\n   </td>\n  <td>\n  <p>&nbsp;</p>\n   </td>\n  <td>\n  <p><strong>30 bytes</strong></p>\n   </td>\n  <td>\n  <p><strong>42 bytes</strong></p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>To get enough spare bytes for this tagging structure requires a chunk-size of at least 1kB.</p>\n<p>The blockSequence increments each time a block is allocated. (ie. the first block allocated is block 1, and so on).</p>\n<h4>Scanning</h4>\n<p>The only reason we need to keep track of data status on NAND is to be able to recreate the file system state during scanning. Since we no longer have chunk deletion status flags we use a slightly different process for scanning a Yaffs2 system.</p>\n<p>In effect, Yaffs2 recreates its state by \"replaying the tape\". ie. it scans the chunks in their allocation order (block sequence Id order) rather than in their order on the media. This implies that at start up, the blocks must be read and their block sequence determined.</p>\n<h4>Performance</h4>\n<p>Times for 2kB read(units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Read</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>110</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>260</p>\n   </td>\n  <td>\n  <p>260</p>\n   </td>\n  <td>\n  <p>230</p>\n   </td>\n  <td>\n  <p>120</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>7.6</p>\n   </td>\n  <td>\n  <p>7.6</p>\n   </td>\n  <td>\n  <p>8.7</p>\n   </td>\n  <td>\n  <p>16.7</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1.1</p>\n   </td>\n  <td>\n  <p>2.2</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>Times for 2kB writes(units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Program</p>\n   </td>\n  <td>\n  <p>800</p>\n   </td>\n  <td>\n  <p>800</p>\n   </td>\n  <td>\n  <p>200</p>\n   </td>\n  <td>\n  <p>200</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Read</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>110</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>1320</p>\n   </td>\n  <td>\n  <p>1320</p>\n   </td>\n  <td>\n  <p>660</p>\n   </td>\n  <td>\n  <p>440</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>1.5</p>\n   </td>\n  <td>\n  <p>1.5</p>\n   </td>\n  <td>\n  <p>3</p>\n   </td>\n  <td>\n  <p>4.5</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>2</p>\n   </td>\n  <td>\n  <p>3</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>Times for 1MB delete (units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>20480</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Program</p>\n   </td>\n  <td>\n  <p>409600</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Erase</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>558080</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>1.8</p>\n   </td>\n  <td>\n  <p>7.8</p>\n   </td>\n  <td>\n  <p>62.5</p>\n   </td>\n  <td>\n  <p>62.5</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>4</p>\n   </td>\n  <td>\n  <p>34</p>\n   </td>\n  <td>\n  <p>34</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>Times for 1MB of garbage collection at 50% dirty (units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Delete 1MB</p>\n   </td>\n  <td>\n  <p>558080</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write 0.5MB</p>\n   </td>\n  <td>\n  <p>337920</p>\n   </td>\n  <td>\n  <p>337920</p>\n   </td>\n  <td>\n  <p>168960</p>\n   </td>\n  <td>\n  <p>112640</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>896000</p>\n   </td>\n  <td>\n  <p>465920</p>\n   </td>\n  <td>\n  <p>184960</p>\n   </td>\n  <td>\n  <p>128640</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>1.1</p>\n   </td>\n  <td>\n  <p>2.1</p>\n   </td>\n  <td>\n  <p>5.4</p>\n   </td>\n  <td>\n  <p>7.7</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1.9</p>\n   </td>\n  <td>\n  <p>4.9</p>\n   </td>\n  <td>\n  <p>7</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:22:\"/yaffs-2-specification\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:8:\"/node/38\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:22:\"/yaffs-2-specification\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"node:38\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:58:\"<span property=\"schema:name\">Yaffs 2 Specification</span>\n\";}}',-1,1504637009.385,1,'config:filter.format.full_html config:system.site node:38 node_view rendered user:3','303'),('entity_view:node:38:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:2:\"38\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"node:38\";i:3;s:9:\"node_view\";i:4;s:6:\"user:3\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504637009.383,1,'config:filter.format.full_html config:system.site node:38 node_view rendered user:3','303'),('entity_view:node:38:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:9971:\"<span property=\"schema:name\">Yaffs 2 Specification</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<h2>Summary</h2>\n<p>The original motivation for Yaffs 2 was to add support for the new NAND with 2kB pages instead of 512-byte pages and strictly sequential page writing order.</p>\n<p>To achieve this, a new design is used which also realises the following benefits:</p>\n<ul>\n<li>\n<p>Zero page rewrites means faster operation. (Yaffs1 uses a single rewrite in the spare area to delete a page).</p>\n </li>\n<li>\n<p>Ability to exploit simultaneous page programming on some chips.</p>\n </li>\n<li>\n<p>Improves performance relative to Yaffs1 speed(write:1.5x to 5x, delete: 4x, garbage collection: 2x)</p>\n </li>\n<li>\n<p>Lower RAM footprint (approx. 25% to 50% of Yaffs1).</p>\n </li>\n<li>\n<p>Can support Toshiba/Sandisk MLC parts.</p>\n </li>\n</ul>\n<p>Most of Yaffs1 and Yaffs2 code is common, therefore the code will likely be kept common with Yaffs1 vs Yaffs2 being run-time selected.</p>\n<h4>Method</h4>\n<p>The main philosophical difference between Yaffs&nbsp;and Yaffs2 is how discarded status is tracked. Since we can\'t do any re-writing, we can\'t use the \"discarded\" flags in Yaffs2.</p>\n<p>Instead Yaffs2 uses two mechanisms to resolve data state.</p>\n<ul>\n<li>\n<p>Yaffs2 chunks have more tag information, including a block sequence Id. From that we can determine the chunk sequence Id since the chunks are allocated sequentially in a block. Thus we always know the patch order for all chunks in the system.</p>\n </li>\n<li>\n<p>The above helps us track stale -vs- fresh data, but does not help determine when a file/object is deleted. Deletion is achieved by moving the object to the \"unlinked\" directory. We also keep track of the number of chunks (both stale and current) in the system for each object. While this number indicates that there are still chunks associated with this object we keep the deletion record. When the last trace of the object has been really erased from NAND, we can forget about the deletion record too.</p>\n </li>\n<li>\n<p>Since there is no deletion, a resize (shrinking) of a file will still have valid data chunks past the end of file on the NAND. However, we write a new ObjectHeader at the time of the resize, therefore this shows the shrunken file size.</p>\n </li>\n</ul>\n<p>This changes erasure slightly:</p>\n<ul>\n<li>\n<p>During garbage collection we can\'t just look at chunk state flags, instead we must read the tags of each chunk to determine which object\'s chunk count we must decrement. This step must also be performed when a block is erased (as part of deletion).</p>\n </li>\n</ul>\n<p>This makes erasure &amp; garbage collection more expensive (by adding reads), but remember that ion Yaffs2 we don\'t need to do page deletions which are much more expensive operations. Thus, all-up Yaffs2 wins.</p>\n<h4>Tag structure</h4>\n<p>Each chunk in Yaffs2 has the following information:</p>\n<p>Field</p>\n<p>Comment</p>\n<p>Size for 1kb chunks</p>\n<p>Size for 2kB chunks</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>blockState</p>\n   </td>\n  <td>\n  <p>Block state. non-0xFF for bad block</p>\n   </td>\n  <td>\n  <p>1 byte</p>\n   </td>\n  <td>\n  <p>1 byte</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>chunkId</p>\n   </td>\n  <td>\n  <p>32-bit chunk Id</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>objectId</p>\n   </td>\n  <td>\n  <p>32-bit object Id</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>nBytes</p>\n   </td>\n  <td>\n  <p>Number of data bytes in this chunk</p>\n   </td>\n  <td>\n  <p>2 bytes</p>\n   </td>\n  <td>\n  <p>2 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>blockSequence</p>\n   </td>\n  <td>\n  <p>sequence number for this block</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n  <td>\n  <p>4 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>tagsEcc</p>\n   </td>\n  <td>\n  <p>ECC on tags area</p>\n   </td>\n  <td>\n  <p>3 bytes</p>\n   </td>\n  <td>\n  <p>3 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>ecc</p>\n   </td>\n  <td>\n  <p>ECC, 3 bytes/256 bytes of data</p>\n   </td>\n  <td>\n  <p>12 bytes</p>\n   </td>\n  <td>\n  <p>24 bytes</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p><strong>Total</strong></p>\n   </td>\n  <td>\n  <p>&nbsp;</p>\n   </td>\n  <td>\n  <p><strong>30 bytes</strong></p>\n   </td>\n  <td>\n  <p><strong>42 bytes</strong></p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>To get enough spare bytes for this tagging structure requires a chunk-size of at least 1kB.</p>\n<p>The blockSequence increments each time a block is allocated. (ie. the first block allocated is block 1, and so on).</p>\n<h4>Scanning</h4>\n<p>The only reason we need to keep track of data status on NAND is to be able to recreate the file system state during scanning. Since we no longer have chunk deletion status flags we use a slightly different process for scanning a Yaffs2 system.</p>\n<p>In effect, Yaffs2 recreates its state by \"replaying the tape\". ie. it scans the chunks in their allocation order (block sequence Id order) rather than in their order on the media. This implies that at start up, the blocks must be read and their block sequence determined.</p>\n<h4>Performance</h4>\n<p>Times for 2kB read(units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Read</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>110</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>260</p>\n   </td>\n  <td>\n  <p>260</p>\n   </td>\n  <td>\n  <p>230</p>\n   </td>\n  <td>\n  <p>120</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>7.6</p>\n   </td>\n  <td>\n  <p>7.6</p>\n   </td>\n  <td>\n  <p>8.7</p>\n   </td>\n  <td>\n  <p>16.7</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1.1</p>\n   </td>\n  <td>\n  <p>2.2</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>Times for 2kB writes(units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Program</p>\n   </td>\n  <td>\n  <p>800</p>\n   </td>\n  <td>\n  <p>800</p>\n   </td>\n  <td>\n  <p>200</p>\n   </td>\n  <td>\n  <p>200</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>40</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n  <td>\n  <p>10</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Read</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>220</p>\n   </td>\n  <td>\n  <p>110</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>1320</p>\n   </td>\n  <td>\n  <p>1320</p>\n   </td>\n  <td>\n  <p>660</p>\n   </td>\n  <td>\n  <p>440</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>1.5</p>\n   </td>\n  <td>\n  <p>1.5</p>\n   </td>\n  <td>\n  <p>3</p>\n   </td>\n  <td>\n  <p>4.5</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>2</p>\n   </td>\n  <td>\n  <p>3</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>Times for 1MB delete (units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Seek</p>\n   </td>\n  <td>\n  <p>20480</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Program</p>\n   </td>\n  <td>\n  <p>409600</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>0</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Erase</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>558080</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>1.8</p>\n   </td>\n  <td>\n  <p>7.8</p>\n   </td>\n  <td>\n  <p>62.5</p>\n   </td>\n  <td>\n  <p>62.5</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>4</p>\n   </td>\n  <td>\n  <p>34</p>\n   </td>\n  <td>\n  <p>34</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>Times for 1MB of garbage collection at 50% dirty (units of 1uS).</p>\n<p>Operation</p>\n<p>Yaffs1</p>\n<p>Yaffs2 (512b pages)</p>\n<p>Yaffs2 (2kB pages)</p>\n<p>Yaffs2(2kB pages, x16)</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Delete 1MB</p>\n   </td>\n  <td>\n  <p>558080</p>\n   </td>\n  <td>\n  <p>128000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n  <td>\n  <p>16000</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write 0.5MB</p>\n   </td>\n  <td>\n  <p>337920</p>\n   </td>\n  <td>\n  <p>337920</p>\n   </td>\n  <td>\n  <p>168960</p>\n   </td>\n  <td>\n  <p>112640</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Total</p>\n   </td>\n  <td>\n  <p>896000</p>\n   </td>\n  <td>\n  <p>465920</p>\n   </td>\n  <td>\n  <p>184960</p>\n   </td>\n  <td>\n  <p>128640</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>MB/s</p>\n   </td>\n  <td>\n  <p>1.1</p>\n   </td>\n  <td>\n  <p>2.1</p>\n   </td>\n  <td>\n  <p>5.4</p>\n   </td>\n  <td>\n  <p>7.7</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Relative speed</p>\n   </td>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>1.9</p>\n   </td>\n  <td>\n  <p>4.9</p>\n   </td>\n  <td>\n  <p>7</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n</div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:7:\"node:38\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505139221.012,1,'config:filter.format.full_html node:38 node_view rendered','296'),('entity_view:node:38:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:2:\"38\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:7:\"node:38\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505139221.007,1,'config:filter.format.full_html node:38 node_view rendered','296'),('entity_view:node:391:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0YPzBu3y-ZamYhJwd7BFdDkXpLpXXp4e8wsoC4bYL4R0','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:141:\"<article role=\"article\" about=\"/get-yaffs-now-0\" class=\"image full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:16:\"/get-yaffs-now-0\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/391\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:16:\"/get-yaffs-now-0\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:391\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:27:\"<span>Get YAFFS now</span>\n\";}}',-1,1506274738.268,1,'config:system.site node:391 node_view rendered user:1','267'),('entity_view:node:391:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"391\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:4:{i:0;s:18:\"config:system.site\";i:1;s:8:\"node:391\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1506274738.265,1,'config:system.site node:391 node_view rendered user:1','267'),('entity_view:node:397:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0AELjw8RIsY1aWf-MU-oeO9IBBr5A0ZYmBX048cQIWKw','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:319:\"<article role=\"article\" about=\"/logos/design-electronics\" class=\"yaffs-user-logo full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Design Electronics use Yaffs</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:25:\"/logos/design-electronics\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/397\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:25:\"/logos/design-electronics\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:397\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:32:\"<span>Design Electronics</span>\n\";}}',-1,1505911891.999,1,'config:filter.format.basic_html config:system.site node:397 node_view rendered user:1','278'),('entity_view:node:397:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"397\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:397\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505911891.983,1,'config:filter.format.basic_html config:system.site node:397 node_view rendered user:1','278'),('entity_view:node:398:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0Jb3fEZNp08RioqwLyxOZ5W9lWAuDwrYWIrCCNb6jzJg','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:293:\"<article role=\"article\" about=\"/logos/eaton\" class=\"yaffs-user-logo full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Eaton use Yaffs</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:12:\"/logos/eaton\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/398\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:12:\"/logos/eaton\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:398\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:19:\"<span>Eaton</span>\n\";}}',-1,1508204519.575,1,'config:filter.format.basic_html config:system.site node:398 node_view rendered user:1','279'),('entity_view:node:398:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"398\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:398\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1508204519.573,1,'config:filter.format.basic_html config:system.site node:398 node_view rendered user:1','279'),('entity_view:node:399:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0bH3gUo6x21n2bpGESHkqqBjtu1_LMy2Dpnx_MoD2In4','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:311:\"<article role=\"article\" about=\"/logos/lancom-sytems\" class=\"yaffs-user-logo full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Lancom Systems use Yaffs.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:20:\"/logos/lancom-sytems\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/399\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:20:\"/logos/lancom-sytems\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:399\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:27:\"<span>LANCOM Sytems</span>\n\";}}',-1,1505177352.578,1,'config:filter.format.basic_html config:system.site node:399 node_view rendered user:1','278'),('entity_view:node:399:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"399\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:399\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505177352.575,1,'config:filter.format.basic_html config:system.site node:399 node_view rendered user:1','278'),('entity_view:node:39:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01N1vRUYLbwF9COFwL_w1_szV3rvUU5rU4q5n_-QPpiEQ','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:18184:\"<article role=\"article\" about=\"/archives/yaffs-development-notes\" typeof=\"schema:WebPage\" class=\"page is-sticky full clearfix\">\n\n  \n      <span property=\"schema:name\" content=\"Yaffs (Yaffs1) Development Notes\" class=\"hidden\"></span>\n\n\n  \n  <div class=\"content\">\n    \n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p><em>These notes relate to Yaffs1. Yaffs version 2, or Yaffs2, is the current version of Yaffs. While many of the details below remain the same, you can find up to date information split between the How Yaffs Works, Yaffs Tuning and Yaffs Direct documents.</em></p>\n<p>&nbsp;</p>\n<h2>Build options</h2>\n<p>Yaffs1 can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\n<p>Of course the goal is to build Yaffs as a file system running on top of real NAND flash, but yaffs can be built to run on a RAM emulation layer for in-kernel testing without NAND flash in the system.</p>\n<p>Building as an application allows the yaffs_guts algorithms to be tested/debugged in a more friendly debugging environment. The test harness is in yaffsdev.c</p>\n<h3>Trying it out</h3>\n<p>Yaffs1 can be built to run with either mtd or RAM emulation, or both. The file system that interfaces to mtd is called <strong>yaffs</strong>, the file system that uses internal ram is called <strong>yaffsram</strong>. Yaffs1 simultaneously supports both if they are enabled.</p>\n<ol>\n<li>\n<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\n </li>\n<li>\n<p>If you don\'t have mtd support in your kernel, then you might need to turn off USE_MTD otherwise the Yaffs module might not load.</p>\n </li>\n<li>\n<p>Type <strong>make clean; make</strong> to build yaffs</p>\n </li>\n<li>\n<p>Load Yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\n </li>\n<li>\n<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\n </li>\n<li>\n<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\n </li>\n<li>\n<p>Alternatively, to mount the mtd version of yaffs, <strong>mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\n </li>\n</ol>\n<p><br />\n&nbsp;</p>\n<h3>Yaffs1 Data structures</h3>\n<p>All data types are defined in yaffs_guts.h</p>\n<p>Yaffs1 uses the following major objects:</p>\n<ul>\n<li>\n<p>yaffs_Object: A yaffs_Object can be a file, directory, symlink or hardlink. The yaffs_Objects \"know\" about their corresponding yaffs_ObjectHeader in NAND and the data for that object. yaffs_Objects also bind together the directory structure as follows:</p>\n </li>\n<li>\n<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\n </li>\n<li>\n<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\n </li>\n<li>\n<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\n </li>\n<li>\n<p>yaffs_Tnode: yaffs_Tnodes form a tree structure that speeds up the search for data chunks in a file. As the file grows in size, the levels increase. The Tnodes are a constant size (32 bytes). Level 0 (ie the lowest level) comprise 16 2-byte entries giving an index used to search for the chunkId. Tnodes at other levels comprise 8 4-byte pointer entries to other tnodes lower in the tree.</p>\n </li>\n<li>\n<p>yaffs_Device: this holds the device context and is in some ways analogous to the VFS superblock. It stores the data used to access the mtd as well as function pointers to access the NAND data.</p>\n </li>\n</ul>\n<p>The Tnodes and Objects are allocated in groups to reduce memory allocation/freeing overheads. Freed up tnodes and objects are kept in a free list and re-used.</p>\n<h3>yaffs_Object</h3>\n<p>struct yaffs_ObjectStruct</p>\n<p>{</p>\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\n<p>// object might be created before the data</p>\n<p>// is available (ie. file data records appear before the header).</p>\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\n<p>// read back the old one to update.</p>\n<p>__u16 sum; // sum of the name to speed searching</p>\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\n<p>// live on this list</p>\n<p>// directory structure stuff</p>\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\n<p>struct list_head siblings; // siblings in a directory</p>\n<p>// also used for linking up the free list</p>\n<p>// Where\'s my data in NAND?</p>\n<p>int chunkId; // where it lives</p>\n<p>__u32 objectId; // the object id value</p>\n<p>__u32 st_mode; // protection</p>\n<p>__u32 st_uid; // user ID of owner</p>\n<p>__u32 st_gid; // group ID of owner</p>\n<p>__u32 st_atime; // time of last access</p>\n<p>__u32 st_mtime; // time of last modification</p>\n<p>__u32 st_ctime; // time of last change</p>\n<p>yaffs_ObjectType variantType;</p>\n<p>yaffs_ObjectVariant variant;</p>\n<p>};</p>\n<p><br />\n&nbsp;</p>\n<p>Obvious stuff skipped....</p>\n<p>fake, renameAllowed, unlinkAllowed are special flags for handling \"fake\" objects which live in the file system but do not live on NAND. Currently there are only two such objects: the root object and the lost+found directory. None of these may be renamed or unlinked.</p>\n<p>serial, sum: see yaffs_ObjectHeader.</p>\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\n<p>valid indicates that the object has been loaded up. This is only used during scanning (yaffs_Scan()) since we can know of an object\'s existance - and thus need to create the object header - before we encounter the associated yaffs_ObjectHeader.</p>\n<p>hashlink is a list of Objects in the same hash bucket.</p>\n<p>The four variants hold extra info:</p>\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\n<p>Directories hold a list of children objects.</p>\n<p>Symlinks hold a pointer to the alias string. This is probably inefficient, but that probably does not matter since we don\'t expect to see many of these.</p>\n<p>Hardlinks hold information to identify the equivalent object.</p>\n<p><br />\n&nbsp;</p>\n<h3>File structure (tnodes)</h3>\n<p>File structures are done with a tiered indexing structure</p>\n<p><br />\n&nbsp;</p>\n<p><img alt=\"\" height=\"294\" src=\"http://www.aleph1.co.uk/yaffs/sv9349341.gif\" width=\"491\" /><br />\n<br />\n&nbsp;</p>\n<p>The file structure is maintained by a tree structure. Depending where it is in the tree, each tree node (<strong><em>tnode</em></strong>) (the blue/things) holds either:</p>\n<ul>\n<li>\n<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\n </li>\n<li>\n<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\n </li>\n</ul>\n<p>When the file starts out, it is assigned only one low-level tnode. When the file expands past what a single tnode can hold, then it is assigned a second tnode and an internal node is added to point to the two tnodes. As the file grows, more low-level tnodes and high level tnodes are added.</p>\n<p>Traversing the tnode tree to find a particular page in a file is quite simple: each internal tnode is selected from by using 3 bits of the page offset in the file. The level 0 page resolves 4 bits.</p>\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\n<p>Level</p>\n<p>Bits</p>\n<p>Selected value</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>3 or more if they exist</p>\n   </td>\n  <td>\n  <p>&gt;= 10</p>\n   </td>\n  <td>\n  <p>Zero</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>2</p>\n   </td>\n  <td>\n  <p>9 to 7</p>\n   </td>\n  <td>\n  <p>100 binary = 4</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>6 to 4</p>\n   </td>\n  <td>\n  <p>011 binary = 3</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>3 to 0</p>\n   </td>\n  <td>\n  <p>0101 binary = 5</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\nFree tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\n<p>Each tnode takes 32 bytes. Each file needs at least one level 0 tnode. How many do we need? A full 16MB file system needs at least 16MB/512/16 = 2000 level zero tnodes. More for internal tnodes. More for files smaller than optimal.</p>\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\n<h3>NAND data</h3>\n<p>Data is stored on NAND in \"chunks\". Currently each chunk is the same size as a NAND flash page (ie. 512 bytes + 16 byte spare). In the future we might decide to allow for different chunk sizes. Chunks can hold either:</p>\n<ul>\n<li>\n<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\n </li>\n<li>\n<p>A chunk of file data.</p>\n </li>\n</ul>\n<p>The 16 byte spare area contains:</p>\n<ul>\n<li>\n<p>8 bytes of tags,</p>\n </li>\n<li>\n<p>6 bytes of ECC data</p>\n </li>\n<li>\n<p>1 byte block status (used to identify damaged blocks)</p>\n </li>\n<li>\n<p>1 byte data status (currently unused).</p>\n </li>\n</ul>\n<p>The tags are made up as follows:</p>\n<p>typedef struct</p>\n<p>{</p>\n<p>unsigned chunkId:20; //chunk number in file</p>\n<p>unsigned serialNumber:2; //serial number for chunk</p>\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\n<p>unsigned ecc:12; //ECC on tags</p>\n<p>unsigned unusedStuff:2; //unused</p>\n<p>} yaffs_Tags;</p>\n<p>&nbsp;</p>\n<p>A chunkId of zero indicates that this chunk holds a yaffs_ObjectHeader. A non zero value indicates that this is a data chunk and the position of the chunk in the file (ie. the first chunk - at offset 0 - has chunkId 1). See yaffs_guts.c:yaffs_Scan () to see how this is done.</p>\n<p>When a chunk is repalced (eg. file details changed or a part of a file was overwritten), the new chunk is written before the old chunk is deleted. This means that we don\'t lose data if there is a power loss after the new chunk is created but before the old one is discarded, but it does mean that we can encounter the situation where we find both the old and the new chunks in flash. The serialNumber is incremented each time the chunk is written. 2 bits is sufficient to resolve any ambiguity.</p>\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\n<p>objectId says which object this chunk belongs to.</p>\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\n<h3>yaffs_ObjectHeader</h3>\n<p>typedef struct</p>\n<p>{</p>\n<p>yaffs_ObjectType type;</p>\n<p>&nbsp;</p>\n<p>// Apply to everything</p>\n<p>int parentObjectId;</p>\n<p>__u16 sum; // checksum of name</p>\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\n<p>&nbsp;</p>\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\n<p>__u32 st_mode; // protection</p>\n<p>__u32 st_uid; // user ID of owner</p>\n<p>__u32 st_gid; // group ID of owner</p>\n<p>__u32 st_atime; // time of last access</p>\n<p>__u32 st_mtime; // time of last modification</p>\n<p>__u32 st_ctime; // time of last change</p>\n<p>&nbsp;</p>\n<p>// File size applies to files only</p>\n<p>int fileSize;</p>\n<p>&nbsp;</p>\n<p>// Equivalent object id applies to hard links only.</p>\n<p>int equivalentObjectId;</p>\n<p>// alias only applies to symlinks</p>\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\n<p>&nbsp;</p>\n<p>&nbsp;</p>\n<p>} yaffs_ObjectHeader;</p>\n<p>&nbsp;</p>\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\n<p>parentObject is the objectId of this object\'s parent. name holds the object\'s name. Together these form the directory structure of the file system. Also worth mention is sum. This is a \"checksum\" on the name which speeds directory searching (ie. when searching the directory we only compare the name for those entries where sum matches).</p>\n<p>Obvious stuff skipped....</p>\n<p>equivalentObjectId is used by hardlinks. A hardlink to an object uses this field to specify the object that this links to. This way of doing things is a bit different than the normal Linux way of doing things (ie. keeping the links distinct from the inode) but is simpler and uses less space except for a few corner cases with hardlinks.</p>\n<p>alias is used by symlinks to hold the symlink alias string. This limits the size of the symlink alias. In future we should expand Yaffs1 to use data chunks to store aliases too long to fit into the yaffs_ObjectHeader.</p>\n<h3>NAND Interface</h3>\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\n<ul>\n<li>\n<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\n </li>\n<li>\n<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\n </li>\n<li>\n<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\n </li>\n<li>\n<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\n </li>\n</ul>\n<p>In the Readxxx and Writexxx functions, the data and/or spare pointers may be NULL in which case these data transfers are ignored.</p>\n<p>A quick note about NAND:</p>\n<ul>\n<li>\n<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\n </li>\n<li>\n<p>Each NAND page holds 512 bytes of data and 16 \"spare\" bytes. Yaffs structures the spare area with tags used to identify what is stored in the data area. There are 32 such pages to a block.</p>\n </li>\n<li>\n<p>NAND writes will only change 1 bits to 0. eg. if a byte holds 10110011 and you write 11011010 to it you will get the logical and of the two values: 10010010. The only way to get 1s again is to erase the entire block.</p>\n </li>\n<li>\n<p>You may only write to a page a few times before erasing the entire block. Yaffs lives within these limitations. Each page only gets written to twice (once when written and once when discarded).</p>\n </li>\n<li>\n<p>ECC is normally used with NAND to correct for single bit errors. Yaffs1 applies the ECC itself, so the MTD should not do this.</p>\n </li>\n<li>\n<p>The current mtd interfaces are not particularly well suited to Yaffs1 and we will address the issue with the mtd group. (The mtd interface does not support page-oriented read/write which Yaffs1 would prefer).</p>\n </li>\n</ul>\n<h3>mkyaffs</h3>\n<p>mkyaffs is the tool to format a NAND mtd to be used for Yaffs1. This is quite simple, just erase all the undamaged blocks. Yaffs1 treats erased blocks as free (empty) space.</p>\n<h2>Expected performance</h2>\n<p>The following numbers should give an indication of the performance we should expect from Yaffs1.</p>\n<p>As an example, I\'ll use the following numbers. Since the hardware is capable of 50ns read/write, these numbers allow for some other ovberheads. Clearly though, the performance can be degraded in various ways.</p>\n<p>Seek</p>\n<p>10uS/page</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Read</p>\n   </td>\n  <td>\n  <p>100nS/byte</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write</p>\n   </td>\n  <td>\n  <p>100nS/byte</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Program</p>\n   </td>\n  <td>\n  <p>200uS/page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Erase</p>\n   </td>\n  <td>\n  <p>2mS/block</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p>&nbsp;</p>\n<p>From this we can derive some higher-level numbers:</p>\n<p>Operation</p>\n<p>Time</p>\n<p>Calculation</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Read spare</p>\n   </td>\n  <td>\n  <p>12uS</p>\n   </td>\n  <td>\n  <p>seek + 16 * read</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Read page</p>\n   </td>\n  <td>\n  <p>63 uS</p>\n   </td>\n  <td>\n  <p>seek + 528 * read</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write page</p>\n   </td>\n  <td>\n  <p>326 uS</p>\n   </td>\n  <td>\n  <p>seek + 528 * write + program + read page (for verification)</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Discard page</p>\n   </td>\n  <td>\n  <p>212 uS</p>\n   </td>\n  <td>\n  <p>seek + 16 * write + program</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Overwrite page</p>\n   </td>\n  <td>\n  <p>538 uS</p>\n   </td>\n  <td>\n  <p>write page + discard page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Erase overhead per page</p>\n   </td>\n  <td>\n  <p>63uS</p>\n   </td>\n  <td>\n  <p>erase/32</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>From this we can infer the following flash access times:</p>\n<p>Operation</p>\n<p>Time</p>\n<p>Calculation</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Read 1MB file</p>\n   </td>\n  <td>\n  <p>0.13s (about 7.5 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * read page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write 1MB (clean system)</p>\n   </td>\n  <td>\n  <p>0.53s (about 1.8 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * write page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Overwrite 1MB file (no gc)</p>\n   </td>\n  <td>\n  <p>1.08s (about 0.9MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * overwrite page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Overwrite 1MB with 50% gc</p>\n   </td>\n  <td>\n  <p>2.4s (about 0.4 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Delete 1MB file</p>\n   </td>\n  <td>\n  <p>0.43s (about 2.2 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * discard page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Delete 1MB file with 50% gc</p>\n   </td>\n  <td>\n  <p>0.49s (about 2.0MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * discard page + 1000 * erase overhead</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p>&nbsp;</p>\n</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:33:\"/archives/yaffs-development-notes\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:8:\"/node/39\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:33:\"/archives/yaffs-development-notes\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"node:39\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:69:\"<span property=\"schema:name\">Yaffs (Yaffs1) Development Notes</span>\n\";}}',-1,1504777992.277,1,'config:filter.format.full_html config:system.site node:39 node_view rendered user:1','310'),('entity_view:node:39:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:2:\"39\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:18:\"config:system.site\";i:2;s:7:\"node:39\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504777992.274,1,'config:filter.format.full_html config:system.site node:39 node_view rendered user:1','310'),('entity_view:node:39:search_result:[languages:language_interface]=en:[theme]=yaffs:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:17965:\"<span property=\"schema:name\">Yaffs (Yaffs1) Development Notes</span>\n\n            <div property=\"schema:text\" class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">\n<p><em>These notes relate to Yaffs1. Yaffs version 2, or Yaffs2, is the current version of Yaffs. While many of the details below remain the same, you can find up to date information split between the How Yaffs Works, Yaffs Tuning and Yaffs Direct documents.</em></p>\n<p>&nbsp;</p>\n<h2>Build options</h2>\n<p>Yaffs1 can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\n<p>Of course the goal is to build Yaffs as a file system running on top of real NAND flash, but yaffs can be built to run on a RAM emulation layer for in-kernel testing without NAND flash in the system.</p>\n<p>Building as an application allows the yaffs_guts algorithms to be tested/debugged in a more friendly debugging environment. The test harness is in yaffsdev.c</p>\n<h3>Trying it out</h3>\n<p>Yaffs1 can be built to run with either mtd or RAM emulation, or both. The file system that interfaces to mtd is called <strong>yaffs</strong>, the file system that uses internal ram is called <strong>yaffsram</strong>. Yaffs1 simultaneously supports both if they are enabled.</p>\n<ol>\n<li>\n<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\n </li>\n<li>\n<p>If you don\'t have mtd support in your kernel, then you might need to turn off USE_MTD otherwise the Yaffs module might not load.</p>\n </li>\n<li>\n<p>Type <strong>make clean; make</strong> to build yaffs</p>\n </li>\n<li>\n<p>Load Yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\n </li>\n<li>\n<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\n </li>\n<li>\n<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\n </li>\n<li>\n<p>Alternatively, to mount the mtd version of yaffs, <strong>mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\n </li>\n</ol>\n<p><br />\n&nbsp;</p>\n<h3>Yaffs1 Data structures</h3>\n<p>All data types are defined in yaffs_guts.h</p>\n<p>Yaffs1 uses the following major objects:</p>\n<ul>\n<li>\n<p>yaffs_Object: A yaffs_Object can be a file, directory, symlink or hardlink. The yaffs_Objects \"know\" about their corresponding yaffs_ObjectHeader in NAND and the data for that object. yaffs_Objects also bind together the directory structure as follows:</p>\n </li>\n<li>\n<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\n </li>\n<li>\n<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\n </li>\n<li>\n<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\n </li>\n<li>\n<p>yaffs_Tnode: yaffs_Tnodes form a tree structure that speeds up the search for data chunks in a file. As the file grows in size, the levels increase. The Tnodes are a constant size (32 bytes). Level 0 (ie the lowest level) comprise 16 2-byte entries giving an index used to search for the chunkId. Tnodes at other levels comprise 8 4-byte pointer entries to other tnodes lower in the tree.</p>\n </li>\n<li>\n<p>yaffs_Device: this holds the device context and is in some ways analogous to the VFS superblock. It stores the data used to access the mtd as well as function pointers to access the NAND data.</p>\n </li>\n</ul>\n<p>The Tnodes and Objects are allocated in groups to reduce memory allocation/freeing overheads. Freed up tnodes and objects are kept in a free list and re-used.</p>\n<h3>yaffs_Object</h3>\n<p>struct yaffs_ObjectStruct</p>\n<p>{</p>\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\n<p>// object might be created before the data</p>\n<p>// is available (ie. file data records appear before the header).</p>\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\n<p>// read back the old one to update.</p>\n<p>__u16 sum; // sum of the name to speed searching</p>\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\n<p>// live on this list</p>\n<p>// directory structure stuff</p>\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\n<p>struct list_head siblings; // siblings in a directory</p>\n<p>// also used for linking up the free list</p>\n<p>// Where\'s my data in NAND?</p>\n<p>int chunkId; // where it lives</p>\n<p>__u32 objectId; // the object id value</p>\n<p>__u32 st_mode; // protection</p>\n<p>__u32 st_uid; // user ID of owner</p>\n<p>__u32 st_gid; // group ID of owner</p>\n<p>__u32 st_atime; // time of last access</p>\n<p>__u32 st_mtime; // time of last modification</p>\n<p>__u32 st_ctime; // time of last change</p>\n<p>yaffs_ObjectType variantType;</p>\n<p>yaffs_ObjectVariant variant;</p>\n<p>};</p>\n<p><br />\n&nbsp;</p>\n<p>Obvious stuff skipped....</p>\n<p>fake, renameAllowed, unlinkAllowed are special flags for handling \"fake\" objects which live in the file system but do not live on NAND. Currently there are only two such objects: the root object and the lost+found directory. None of these may be renamed or unlinked.</p>\n<p>serial, sum: see yaffs_ObjectHeader.</p>\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\n<p>valid indicates that the object has been loaded up. This is only used during scanning (yaffs_Scan()) since we can know of an object\'s existance - and thus need to create the object header - before we encounter the associated yaffs_ObjectHeader.</p>\n<p>hashlink is a list of Objects in the same hash bucket.</p>\n<p>The four variants hold extra info:</p>\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\n<p>Directories hold a list of children objects.</p>\n<p>Symlinks hold a pointer to the alias string. This is probably inefficient, but that probably does not matter since we don\'t expect to see many of these.</p>\n<p>Hardlinks hold information to identify the equivalent object.</p>\n<p><br />\n&nbsp;</p>\n<h3>File structure (tnodes)</h3>\n<p>File structures are done with a tiered indexing structure</p>\n<p><br />\n&nbsp;</p>\n<p><img alt=\"\" height=\"294\" src=\"http://www.aleph1.co.uk/yaffs/sv9349341.gif\" width=\"491\" /><br />\n<br />\n&nbsp;</p>\n<p>The file structure is maintained by a tree structure. Depending where it is in the tree, each tree node (<strong><em>tnode</em></strong>) (the blue/things) holds either:</p>\n<ul>\n<li>\n<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\n </li>\n<li>\n<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\n </li>\n</ul>\n<p>When the file starts out, it is assigned only one low-level tnode. When the file expands past what a single tnode can hold, then it is assigned a second tnode and an internal node is added to point to the two tnodes. As the file grows, more low-level tnodes and high level tnodes are added.</p>\n<p>Traversing the tnode tree to find a particular page in a file is quite simple: each internal tnode is selected from by using 3 bits of the page offset in the file. The level 0 page resolves 4 bits.</p>\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\n<p>Level</p>\n<p>Bits</p>\n<p>Selected value</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>3 or more if they exist</p>\n   </td>\n  <td>\n  <p>&gt;= 10</p>\n   </td>\n  <td>\n  <p>Zero</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>2</p>\n   </td>\n  <td>\n  <p>9 to 7</p>\n   </td>\n  <td>\n  <p>100 binary = 4</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>1</p>\n   </td>\n  <td>\n  <p>6 to 4</p>\n   </td>\n  <td>\n  <p>011 binary = 3</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>0</p>\n   </td>\n  <td>\n  <p>3 to 0</p>\n   </td>\n  <td>\n  <p>0101 binary = 5</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\nFree tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\n<p>Each tnode takes 32 bytes. Each file needs at least one level 0 tnode. How many do we need? A full 16MB file system needs at least 16MB/512/16 = 2000 level zero tnodes. More for internal tnodes. More for files smaller than optimal.</p>\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\n<h3>NAND data</h3>\n<p>Data is stored on NAND in \"chunks\". Currently each chunk is the same size as a NAND flash page (ie. 512 bytes + 16 byte spare). In the future we might decide to allow for different chunk sizes. Chunks can hold either:</p>\n<ul>\n<li>\n<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\n </li>\n<li>\n<p>A chunk of file data.</p>\n </li>\n</ul>\n<p>The 16 byte spare area contains:</p>\n<ul>\n<li>\n<p>8 bytes of tags,</p>\n </li>\n<li>\n<p>6 bytes of ECC data</p>\n </li>\n<li>\n<p>1 byte block status (used to identify damaged blocks)</p>\n </li>\n<li>\n<p>1 byte data status (currently unused).</p>\n </li>\n</ul>\n<p>The tags are made up as follows:</p>\n<p>typedef struct</p>\n<p>{</p>\n<p>unsigned chunkId:20; //chunk number in file</p>\n<p>unsigned serialNumber:2; //serial number for chunk</p>\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\n<p>unsigned ecc:12; //ECC on tags</p>\n<p>unsigned unusedStuff:2; //unused</p>\n<p>} yaffs_Tags;</p>\n<p>&nbsp;</p>\n<p>A chunkId of zero indicates that this chunk holds a yaffs_ObjectHeader. A non zero value indicates that this is a data chunk and the position of the chunk in the file (ie. the first chunk - at offset 0 - has chunkId 1). See yaffs_guts.c:yaffs_Scan () to see how this is done.</p>\n<p>When a chunk is repalced (eg. file details changed or a part of a file was overwritten), the new chunk is written before the old chunk is deleted. This means that we don\'t lose data if there is a power loss after the new chunk is created but before the old one is discarded, but it does mean that we can encounter the situation where we find both the old and the new chunks in flash. The serialNumber is incremented each time the chunk is written. 2 bits is sufficient to resolve any ambiguity.</p>\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\n<p>objectId says which object this chunk belongs to.</p>\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\n<h3>yaffs_ObjectHeader</h3>\n<p>typedef struct</p>\n<p>{</p>\n<p>yaffs_ObjectType type;</p>\n<p>&nbsp;</p>\n<p>// Apply to everything</p>\n<p>int parentObjectId;</p>\n<p>__u16 sum; // checksum of name</p>\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\n<p>&nbsp;</p>\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\n<p>__u32 st_mode; // protection</p>\n<p>__u32 st_uid; // user ID of owner</p>\n<p>__u32 st_gid; // group ID of owner</p>\n<p>__u32 st_atime; // time of last access</p>\n<p>__u32 st_mtime; // time of last modification</p>\n<p>__u32 st_ctime; // time of last change</p>\n<p>&nbsp;</p>\n<p>// File size applies to files only</p>\n<p>int fileSize;</p>\n<p>&nbsp;</p>\n<p>// Equivalent object id applies to hard links only.</p>\n<p>int equivalentObjectId;</p>\n<p>// alias only applies to symlinks</p>\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\n<p>&nbsp;</p>\n<p>&nbsp;</p>\n<p>} yaffs_ObjectHeader;</p>\n<p>&nbsp;</p>\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\n<p>parentObject is the objectId of this object\'s parent. name holds the object\'s name. Together these form the directory structure of the file system. Also worth mention is sum. This is a \"checksum\" on the name which speeds directory searching (ie. when searching the directory we only compare the name for those entries where sum matches).</p>\n<p>Obvious stuff skipped....</p>\n<p>equivalentObjectId is used by hardlinks. A hardlink to an object uses this field to specify the object that this links to. This way of doing things is a bit different than the normal Linux way of doing things (ie. keeping the links distinct from the inode) but is simpler and uses less space except for a few corner cases with hardlinks.</p>\n<p>alias is used by symlinks to hold the symlink alias string. This limits the size of the symlink alias. In future we should expand Yaffs1 to use data chunks to store aliases too long to fit into the yaffs_ObjectHeader.</p>\n<h3>NAND Interface</h3>\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\n<ul>\n<li>\n<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\n </li>\n<li>\n<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\n </li>\n<li>\n<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\n </li>\n<li>\n<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\n </li>\n</ul>\n<p>In the Readxxx and Writexxx functions, the data and/or spare pointers may be NULL in which case these data transfers are ignored.</p>\n<p>A quick note about NAND:</p>\n<ul>\n<li>\n<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\n </li>\n<li>\n<p>Each NAND page holds 512 bytes of data and 16 \"spare\" bytes. Yaffs structures the spare area with tags used to identify what is stored in the data area. There are 32 such pages to a block.</p>\n </li>\n<li>\n<p>NAND writes will only change 1 bits to 0. eg. if a byte holds 10110011 and you write 11011010 to it you will get the logical and of the two values: 10010010. The only way to get 1s again is to erase the entire block.</p>\n </li>\n<li>\n<p>You may only write to a page a few times before erasing the entire block. Yaffs lives within these limitations. Each page only gets written to twice (once when written and once when discarded).</p>\n </li>\n<li>\n<p>ECC is normally used with NAND to correct for single bit errors. Yaffs1 applies the ECC itself, so the MTD should not do this.</p>\n </li>\n<li>\n<p>The current mtd interfaces are not particularly well suited to Yaffs1 and we will address the issue with the mtd group. (The mtd interface does not support page-oriented read/write which Yaffs1 would prefer).</p>\n </li>\n</ul>\n<h3>mkyaffs</h3>\n<p>mkyaffs is the tool to format a NAND mtd to be used for Yaffs1. This is quite simple, just erase all the undamaged blocks. Yaffs1 treats erased blocks as free (empty) space.</p>\n<h2>Expected performance</h2>\n<p>The following numbers should give an indication of the performance we should expect from Yaffs1.</p>\n<p>As an example, I\'ll use the following numbers. Since the hardware is capable of 50ns read/write, these numbers allow for some other ovberheads. Clearly though, the performance can be degraded in various ways.</p>\n<p>Seek</p>\n<p>10uS/page</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Read</p>\n   </td>\n  <td>\n  <p>100nS/byte</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write</p>\n   </td>\n  <td>\n  <p>100nS/byte</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Program</p>\n   </td>\n  <td>\n  <p>200uS/page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Erase</p>\n   </td>\n  <td>\n  <p>2mS/block</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p>&nbsp;</p>\n<p>From this we can derive some higher-level numbers:</p>\n<p>Operation</p>\n<p>Time</p>\n<p>Calculation</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Read spare</p>\n   </td>\n  <td>\n  <p>12uS</p>\n   </td>\n  <td>\n  <p>seek + 16 * read</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Read page</p>\n   </td>\n  <td>\n  <p>63 uS</p>\n   </td>\n  <td>\n  <p>seek + 528 * read</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write page</p>\n   </td>\n  <td>\n  <p>326 uS</p>\n   </td>\n  <td>\n  <p>seek + 528 * write + program + read page (for verification)</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Discard page</p>\n   </td>\n  <td>\n  <p>212 uS</p>\n   </td>\n  <td>\n  <p>seek + 16 * write + program</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Overwrite page</p>\n   </td>\n  <td>\n  <p>538 uS</p>\n   </td>\n  <td>\n  <p>write page + discard page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Erase overhead per page</p>\n   </td>\n  <td>\n  <p>63uS</p>\n   </td>\n  <td>\n  <p>erase/32</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p><br />\n&nbsp;</p>\n<p>From this we can infer the following flash access times:</p>\n<p>Operation</p>\n<p>Time</p>\n<p>Calculation</p>\n<table>\n<tbody>\n <tr>\n </tr>\n <tr>\n  <td>\n  <p>Read 1MB file</p>\n   </td>\n  <td>\n  <p>0.13s (about 7.5 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * read page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Write 1MB (clean system)</p>\n   </td>\n  <td>\n  <p>0.53s (about 1.8 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * write page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Overwrite 1MB file (no gc)</p>\n   </td>\n  <td>\n  <p>1.08s (about 0.9MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * overwrite page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Overwrite 1MB with 50% gc</p>\n   </td>\n  <td>\n  <p>2.4s (about 0.4 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Delete 1MB file</p>\n   </td>\n  <td>\n  <p>0.43s (about 2.2 MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * discard page</p>\n   </td>\n </tr>\n <tr>\n  <td>\n  <p>Delete 1MB file with 50% gc</p>\n   </td>\n  <td>\n  <p>0.49s (about 2.0MB/s)</p>\n   </td>\n  <td>\n  <p>2000 * discard page + 1000 * erase overhead</p>\n   </td>\n </tr>\n</tbody>\n</table>\n<p>&nbsp;</p>\n</div>\n      \";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:7:\"node:39\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;}}',-1,1505139221.344,1,'config:filter.format.full_html node:39 node_view rendered','297'),('entity_view:node:39:search_result:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:2:\"39\";i:3;s:13:\"search_result\";}s:8:\"contexts\";a:4:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:17:\"url.path.is_front\";i:3;s:16:\"user.permissions\";}s:4:\"tags\";a:3:{i:0;s:30:\"config:filter.format.full_html\";i:1;s:7:\"node:39\";i:2;s:9:\"node_view\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505139221.342,1,'config:filter.format.full_html node:39 node_view rendered','297'),('entity_view:node:400:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b05shBIa1rjinwW61ccdG8xL9h6XmBZ6TwSst_dvxpUTw','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:298:\"<article role=\"article\" about=\"/logos/bernina\" class=\"yaffs-user-logo full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Bernina use Yaffs.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:14:\"/logos/bernina\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/400\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:14:\"/logos/bernina\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:400\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:21:\"<span>Bernina</span>\n\";}}',-1,1505827191.269,1,'config:filter.format.basic_html config:system.site node:400 node_view rendered user:1','278'),('entity_view:node:400:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"400\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:400\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505827191.263,1,'config:filter.format.basic_html config:system.site node:400 node_view rendered user:1','278'),('entity_view:node:401:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0gOO6DdBGbLE9Fgd0rArqGXDIBTszUnU7wiLjCuOpSWk','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:299:\"<article role=\"article\" about=\"/logos/gallagher\" class=\"yaffs-user-logo full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Used by Gallagher</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:16:\"/logos/gallagher\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/401\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:16:\"/logos/gallagher\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:401\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:23:\"<span>Gallagher</span>\n\";}}',-1,1506102766.546,1,'config:filter.format.basic_html config:system.site node:401 node_view rendered user:1','280'),('entity_view:node:401:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"401\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:401\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1506102766.543,1,'config:filter.format.basic_html config:system.site node:401 node_view rendered user:1','280'),('entity_view:node:407:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0OOs4htQoiIF17gfDFz9xe_CLus6bKJGx0_OV93aPEjE','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:708:\"<article role=\"article\" about=\"/features/booting-fast\" class=\"what-is-special-about-yaffs is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  <div class=\"field field--name-field-icon-text field--type-string field--label-above\">\n    <div class=\"field--label\">Icon - text</div>\n              <div class=\"field--item\">fa-space-shuttle</div>\n          </div>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>Being quick to boot was one of the fundamental requirements in Yaffs\' design. Boot-time scanning to build the file structure lists should require just one pass reading NAND memory.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:22:\"/features/booting-fast\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/407\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:22:\"/features/booting-fast\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:407\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:32:\"<span>Booting is fast...</span>\n\";}}',-1,1504948131.087,1,'config:filter.format.basic_html config:system.site node:407 node_view rendered user:1','278'),('entity_view:node:407:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"407\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:407\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504948131.081,1,'config:filter.format.basic_html config:system.site node:407 node_view rendered user:1','278'),('entity_view:node:407:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:774:\"<article role=\"article\" about=\"/features/booting-fast\" class=\"what-is-special-about-yaffs is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/features/booting-fast\" rel=\"bookmark\"><span>Booting is fast...</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/features/booting-fast\" rel=\"tag\" title=\"Booting is fast...\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about Booting is fast...</span></a></li></ul>\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">It is important for a Flash filesystem to boot fast, so boot speed was a fundamental consideration in the design of Yaffs.</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:407\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1505144016.941,1,'config:filter.format.basic_html node:407 node_view rendered user:1','272'),('entity_view:node:407:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"407\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:407\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505144016.939,1,'config:filter.format.basic_html node:407 node_view rendered user:1','272'),('entity_view:node:408:full:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b0YN866JtIRQbEizHOIATkZSl4BH4VcBoMHbRsOh0R8C0','a:5:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:1294:\"<article role=\"article\" about=\"/features/active-community\" class=\"what-is-special-about-yaffs is-promoted full clearfix\">\n\n  \n    \n\n  \n  <div class=\"content\">\n    \n  <div class=\"field field--name-field-icon-text field--type-string field--label-above\">\n    <div class=\"field--label\">Icon - text</div>\n              <div class=\"field--item\">fa-users</div>\n          </div>\n\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\"><p>You can learn from the experience of people and companies who are working with Yaffs. Thousands of developers have used Yaffs successfully, and commercially-licensed Yaffs has many customers that use it repeatedly. Have a look at the mailing list - it\'s a great place to start if you have some questions.<br /><a href=\"http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs\">http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs</a></p>\n\n<p>The searchable archive of postings is at <a href=\"http://lists.aleph1.co.uk/lurker/list/yaffs.html\">http://lists.aleph1.co.uk/lurker/list/yaffs.html   </a>Or search online to see the variety of work done with Yaffs as its basis - from research papers through to skunkworks projects for testing particular concepts.</p></div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:1:{s:14:\"html_head_link\";a:3:{i:0;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"canonical\";s:4:\"href\";s:26:\"/features/active-community\";}i:1;b:1;}i:1;a:2:{i:0;a:2:{s:3:\"rel\";s:9:\"shortlink\";s:4:\"href\";s:9:\"/node/408\";}i:1;b:1;}i:2;a:2:{i:0;a:2:{s:3:\"rel\";s:8:\"revision\";s:4:\"href\";s:26:\"/features/active-community\";}i:1;b:1;}}}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:408\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}s:17:\"#cache_properties\";a:1:{i:0;s:6:\"#title\";}s:6:\"#title\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:36:\"<span>An active community...</span>\n\";}}',-1,1504630260.889,1,'config:filter.format.basic_html config:system.site node:408 node_view rendered user:1','278'),('entity_view:node:408:full:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01:[user.roles:anonymous]=0','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"408\";i:3;s:4:\"full\";}s:8:\"contexts\";a:7:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";i:5;s:20:\"user.roles:anonymous\";i:6;s:24:\"user.roles:authenticated\";}s:4:\"tags\";a:5:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:18:\"config:system.site\";i:2;s:8:\"node:408\";i:3;s:9:\"node_view\";i:4;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1504630260.887,1,'config:filter.format.basic_html config:system.site node:408 node_view rendered user:1','278'),('entity_view:node:408:teaser:[languages:language_interface]=en:[theme]=yaffs:[timezone]=Europe/London:[url.path.is_front]=is_front.0:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:3:{s:7:\"#markup\";O:25:\"Drupal\\Core\\Render\\Markup\":1:{s:9:\"\0*\0string\";s:788:\"<article role=\"article\" about=\"/features/active-community\" class=\"what-is-special-about-yaffs is-promoted teaser clearfix\">\n\n  \n      <h2>\n      <a href=\"/features/active-community\" rel=\"bookmark\"><span>An active community...</span>\n</a>\n    </h2>\n    \n\n  \n  <div class=\"content\">\n    <ul class=\"links inline list-inline\"><li class=\"node-readmore\"><a href=\"/features/active-community\" rel=\"tag\" title=\"An active community...\" hreflang=\"und\">Read more<span class=\"visually-hidden\"> about An active community...</span></a></li></ul>\n            <div class=\"field field--name-body field--type-text-with-summary field--label-hidden field--item\">There\'s an active community of people who use Yaffs and who have developed with Yaffs, just a click or two away.</div>\n      \n  </div>\n\n</article>\n\";}s:9:\"#attached\";a:0:{}s:6:\"#cache\";a:3:{s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:408\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;}}',-1,1505144016.927,1,'config:filter.format.basic_html node:408 node_view rendered user:1','272'),('entity_view:node:408:teaser:[languages:language_interface]=en:[theme]=yaffs:[user.permissions]=aa7fc4c8fb40c7a8665ccd12fea07926dff0f59b9ee3346bc513c6399bee5b01','a:2:{s:15:\"#cache_redirect\";b:1;s:6:\"#cache\";a:5:{s:4:\"keys\";a:4:{i:0;s:11:\"entity_view\";i:1;s:4:\"node\";i:2;s:3:\"408\";i:3;s:6:\"teaser\";}s:8:\"contexts\";a:5:{i:0;s:28:\"languages:language_interface\";i:1;s:5:\"theme\";i:2;s:8:\"timezone\";i:3;s:17:\"url.path.is_front\";i:4;s:16:\"user.permissions\";}s:4:\"tags\";a:4:{i:0;s:31:\"config:filter.format.basic_html\";i:1;s:8:\"node:408\";i:2;s:9:\"node_view\";i:3;s:6:\"user:1\";}s:7:\"max-age\";i:-1;s:3:\"bin\";s:6:\"render\";}}',-1,1505144016.923,1,'config:filter.format.basic_html node:408 node_view rendered user:1','272');
