commit;

--
-- Table structure for table `node__field_access_control`
--

CREATE TABLE `node__field_access_control` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_access_control_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_access_control_target_id` (`field_access_control_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_access_control.';

--
-- Dumping data for table `node__field_access_control`
--

set autocommit=0;
INSERT INTO `node__field_access_control` VALUES ('restr',0,481,630,'en',0,347);
commit;

--
-- Table structure for table `node__field_document_type`
--

CREATE TABLE `node__field_document_type` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_document_type_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_document_type_target_id` (`field_document_type_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_document_type.';

--
-- Dumping data for table `node__field_document_type`
--

set autocommit=0;
INSERT INTO `node__field_document_type` VALUES ('page',0,32,633,'und',0,343),('page',0,37,570,'und',0,346),('page',0,38,571,'und',0,345),('page',0,39,572,'und',0,346),('page',0,40,551,'und',0,346),('page',0,41,567,'und',0,346),('page',0,42,573,'und',0,346),('page',0,43,553,'und',0,346),('page',0,61,556,'und',0,346),('page',0,62,557,'und',0,346),('page',0,342,574,'und',0,346),('page',0,344,576,'und',0,343),('page',0,353,577,'und',0,343),('article',0,358,544,'und',0,345),('article',0,359,579,'und',0,345),('article',0,360,580,'und',0,346),('page',0,367,610,'und',0,346),('page',0,369,582,'und',0,345),('paper',0,409,627,'und',0,344),('paper',0,420,605,'und',0,345),('paper',0,448,584,'und',0,343),('paper',0,451,628,'und',0,344),('paper',0,453,606,'und',0,344),('article',0,454,607,'und',0,345),('paper',0,455,608,'und',0,345),('page',0,462,590,'und',0,343),('paper',0,466,637,'und',0,343),('paper',0,479,592,'und',0,344),('page',0,489,516,'en',0,344);
commit;

--
-- Table structure for table `node__field_help_video`
--

CREATE TABLE `node__field_help_video` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_help_video_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the file entity.',
  `field_help_video_display` tinyint(3) unsigned DEFAULT '1' COMMENT 'Flag to control whether this file should be displayed when viewing content.',
  `field_help_video_description` text COMMENT 'A description of the file.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_help_video_target_id` (`field_help_video_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_help_video.';

--
-- Dumping data for table `node__field_help_video`
--

set autocommit=0;
commit;

--
-- Table structure for table `node__field_icon_text`
--

CREATE TABLE `node__field_icon_text` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_icon_text_value` varchar(255) NOT NULL,
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_icon_text.';

--
-- Dumping data for table `node__field_icon_text`
--

set autocommit=0;
INSERT INTO `node__field_icon_text` VALUES ('what_is_special_about_yaffs',0,384,385,'und',0,'fa-thumbs-up'),('what_is_special_about_yaffs',0,385,386,'und',0,'fa-shield'),('what_is_special_about_yaffs',0,388,389,'und',0,'fa-heart'),('what_is_special_about_yaffs',0,389,390,'und',0,'fa-mobile-phone'),('what_is_special_about_yaffs',0,407,408,'und',0,'fa-space-shuttle'),('what_is_special_about_yaffs',0,408,409,'und',0,'fa-users'),('what_is_special_about_yaffs',0,414,415,'und',0,'fa-cogs'),('what_is_special_about_yaffs',0,415,416,'und',0,'fa-credit-card'),('what_is_special_about_yaffs',0,416,417,'und',0,'fa-bullseye'),('what_is_special_about_yaffs',0,417,418,'und',0,'fa-map-signs'),('what_is_special_about_yaffs',0,418,419,'und',0,'fa-lock'),('what_is_special_about_yaffs',0,426,427,'und',0,'fa-stethoscope'),('what_is_special_about_yaffs',0,427,428,'und',0,'fa-truck'),('what_is_special_about_yaffs',0,428,429,'und',0,'fa-microchip'),('what_is_special_about_yaffs',0,433,434,'und',0,'fa-plug'),('what_is_special_about_yaffs',0,434,435,'und',0,'fa-sort-amount-asc'),('what_is_special_about_yaffs',0,435,436,'und',0,'fa-check-square'),('what_is_special_about_yaffs',0,436,437,'und',0,'fa-puzzle-piece');
commit;

--
-- Table structure for table `node__field_image`
--

CREATE TABLE `node__field_image` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_image_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the file entity.',
  `field_image_alt` varchar(512) DEFAULT NULL COMMENT 'Alternative image text, for the image''s ''alt'' attribute.',
  `field_image_title` varchar(1024) DEFAULT NULL COMMENT 'Image title text, for the image''s ''title'' attribute.',
  `field_image_width` int(10) unsigned DEFAULT NULL COMMENT 'The width of the image in pixels.',
  `field_image_height` int(10) unsigned DEFAULT NULL COMMENT 'The height of the image in pixels.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_image_target_id` (`field_image_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_image.';

--
-- Dumping data for table `node__field_image`
--

set autocommit=0;
INSERT INTO `node__field_image` VALUES ('case_study',0,503,643,'en',0,113,'Tape Replacement Ltd Logo','',555,170);
commit;

--
-- Table structure for table `node__field_logo_link`
--

CREATE TABLE `node__field_logo_link` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_logo_link_uri` varchar(2048) DEFAULT NULL COMMENT 'The URI of the link.',
  `field_logo_link_title` varchar(255) DEFAULT NULL COMMENT 'The link text.',
  `field_logo_link_options` longblob COMMENT 'Serialized array of options for the link.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_logo_link_uri` (`field_logo_link_uri`(30))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_logo_link.';

--
-- Dumping data for table `node__field_logo_link`
--

set autocommit=0;
INSERT INTO `node__field_logo_link` VALUES ('yaffs_user_logo',0,457,475,'und',0,'http://www.android.com/','Google Android','a:0:{}'),('yaffs_user_logo',0,460,478,'und',0,'http://www.leica-geosystems.com/','Leica Geosystems','a:0:{}');
commit;

--
-- Table structure for table `node__field_organisation`
--

CREATE TABLE `node__field_organisation` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_organisation_value` varchar(255) NOT NULL,
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_organisation.';

--
-- Dumping data for table `node__field_organisation`
--

set autocommit=0;
INSERT INTO `node__field_organisation` VALUES ('case_study',0,503,643,'en',0,'Tape Replacement Ltd');
commit;

--
-- Table structure for table `node__field_tags`
--

CREATE TABLE `node__field_tags` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_tags_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_tags_target_id` (`field_tags_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_tags.';

--
-- Dumping data for table `node__field_tags`
--

set autocommit=0;
commit;

--
-- Table structure for table `node__field_teaser_image`
--

CREATE TABLE `node__field_teaser_image` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_teaser_image_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the file entity.',
  `field_teaser_image_alt` varchar(512) DEFAULT NULL COMMENT 'Alternative image text, for the image''s ''alt'' attribute.',
  `field_teaser_image_title` varchar(1024) DEFAULT NULL COMMENT 'Image title text, for the image''s ''title'' attribute.',
  `field_teaser_image_width` int(10) unsigned DEFAULT NULL COMMENT 'The width of the image in pixels.',
  `field_teaser_image_height` int(10) unsigned DEFAULT NULL COMMENT 'The height of the image in pixels.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_teaser_image_target_id` (`field_teaser_image_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_teaser_image.';

--
-- Dumping data for table `node__field_teaser_image`
--

set autocommit=0;
INSERT INTO `node__field_teaser_image` VALUES ('paper',0,409,627,'und',0,108,'Preview of HowYaffsWorks.pdf','',150,194),('paper',0,420,605,'und',0,79,'Preview of YaffsRobustnessAndTesting.pdf',NULL,NULL,NULL),('paper',0,451,628,'und',0,109,'Preview of YaffsTuning.pdf',NULL,NULL,NULL),('paper',0,453,606,'und',0,81,'Preview of YaffsDirect.pdf',NULL,NULL,NULL),('paper',0,455,608,'und',0,84,'Preview of YaffsNandFailureMitigation.pdf',NULL,NULL,NULL),('paper',0,466,637,'und',0,110,'Preview of ConsiderationsInChoosingAFlashFileSystem.pdf','',150,212);
commit;

--
-- Table structure for table `node__field_url`
--

CREATE TABLE `node__field_url` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_url_uri` varchar(2048) DEFAULT NULL COMMENT 'The URI of the link.',
  `field_url_title` varchar(255) DEFAULT NULL COMMENT 'The link text.',
  `field_url_options` longblob COMMENT 'Serialized array of options for the link.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_url_uri` (`field_url_uri`(30))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_url.';

--
-- Dumping data for table `node__field_url`
--

set autocommit=0;
INSERT INTO `node__field_url` VALUES ('case_study',0,503,643,'en',0,'http://www.tape-replacement.com/','http://www.tape-replacement.com/','a:0:{}');
commit;

--
-- Table structure for table `node__field_video`
--

CREATE TABLE `node__field_video` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_video_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the file entity.',
  `field_video_data` varchar(512) DEFAULT NULL COMMENT 'Additional video metadata.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_video_target_id` (`field_video_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_video.';

--
-- Dumping data for table `node__field_video`
--

set autocommit=0;
INSERT INTO `node__field_video` VALUES ('help_video',0,458,476,'und',0,97,NULL),('help_video',0,459,477,'und',0,99,NULL);
commit;

--
-- Table structure for table `node__field_yaffs_user_logo`
--

CREATE TABLE `node__field_yaffs_user_logo` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `field_yaffs_user_logo_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the file entity.',
  `field_yaffs_user_logo_alt` varchar(512) DEFAULT NULL COMMENT 'Alternative image text, for the image''s ''alt'' attribute.',
  `field_yaffs_user_logo_title` varchar(1024) DEFAULT NULL COMMENT 'Image title text, for the image''s ''title'' attribute.',
  `field_yaffs_user_logo_width` int(10) unsigned DEFAULT NULL COMMENT 'The width of the image in pixels.',
  `field_yaffs_user_logo_height` int(10) unsigned DEFAULT NULL COMMENT 'The height of the image in pixels.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `field_yaffs_user_logo_target_id` (`field_yaffs_user_logo_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field field_yaffs_user_logo.';

--
-- Dumping data for table `node__field_yaffs_user_logo`
--

set autocommit=0;
INSERT INTO `node__field_yaffs_user_logo` VALUES ('yaffs_user_logo',0,397,398,'und',0,40,'','',427,302),('yaffs_user_logo',0,398,399,'und',0,46,'','',591,249),('yaffs_user_logo',0,399,400,'und',0,43,'','',2118,531),('yaffs_user_logo',0,400,401,'und',0,45,'','',1024,153),('yaffs_user_logo',0,401,402,'und',0,47,'','',1796,580),('yaffs_user_logo',0,457,475,'und',0,48,'','',170,71),('yaffs_user_logo',0,460,478,'und',0,44,'','',351,228);
commit;

--
-- Table structure for table `node__upload`
--

CREATE TABLE `node__upload` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `upload_target_id` int(10) unsigned NOT NULL COMMENT 'The ID of the file entity.',
  `upload_display` tinyint(3) unsigned DEFAULT '1' COMMENT 'Flag to control whether this file should be displayed when viewing content.',
  `upload_description` text COMMENT 'A description of the file.',
  PRIMARY KEY (`entity_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `upload_target_id` (`upload_target_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field upload.';

--
-- Dumping data for table `node__upload`
--

set autocommit=0;
INSERT INTO `node__upload` VALUES ('page',0,367,610,'und',0,87,1,''),('paper',0,409,627,'und',0,76,1,''),('paper',0,420,605,'und',0,78,1,''),('paper',0,451,628,'und',0,85,1,''),('paper',0,453,606,'und',0,80,1,''),('article',0,454,607,'und',0,82,1,''),('paper',0,455,608,'und',0,83,1,''),('paper',0,466,637,'und',0,77,1,'');
commit;

--
-- Table structure for table `node_access`
--

CREATE TABLE `node_access` (
  `nid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The node.nid this record affects.',
  `langcode` varchar(12) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language.langcode of this node.',
  `fallback` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT 'Boolean indicating whether this record should be used as a fallback if a language condition is not provided.',
  `gid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'The grant ID a user must possess in the specified realm to gain this row''s privileges on the node.',
  `realm` varchar(255) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The realm in which the user must possess the grant ID. Each node access node can define one or more realms.',
  `grant_view` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Boolean indicating whether a user with the realm/grant pair can view this node.',
  `grant_update` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Boolean indicating whether a user with the realm/grant pair can edit this node.',
  `grant_delete` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Boolean indicating whether a user with the realm/grant pair can delete this node.',
  PRIMARY KEY (`nid`,`gid`,`realm`,`langcode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Identifies which realm/grant pairs a user must possess in…';

--
-- Dumping data for table `node_access`
--

set autocommit=0;
INSERT INTO `node_access` VALUES (31,'und',1,1,'permissions_by_term__uid_18',1,1,1),(31,'und',1,2,'permissions_by_term__uid_6',1,1,1),(31,'und',1,3,'permissions_by_term__uid_3',1,1,1),(31,'und',1,4,'permissions_by_term__uid_1',1,1,1),(31,'und',1,5,'permissions_by_term__uid_4',1,1,1),(31,'und',1,6,'permissions_by_term__uid_0',1,0,0),(31,'und',1,7,'permissions_by_term__uid_5',1,1,1),(31,'und',1,8,'permissions_by_term__uid_7',1,1,1),(32,'und',1,1,'permissions_by_term__uid_18',1,1,1),(32,'und',1,2,'permissions_by_term__uid_6',1,1,1),(32,'und',1,3,'permissions_by_term__uid_3',1,1,1),(32,'und',1,5,'permissions_by_term__uid_4',1,1,1),(32,'und',1,6,'permissions_by_term__uid_0',1,0,0),(32,'und',1,8,'permissions_by_term__uid_7',1,1,1),(32,'und',1,128,'permissions_by_term__uid_5',1,1,1),(32,'und',1,132,'permissions_by_term__uid_1',1,1,1),(37,'und',1,1,'permissions_by_term__uid_6',1,1,1),(37,'und',1,2,'permissions_by_term__uid_3',1,1,1),(37,'und',1,5,'permissions_by_term__uid_0',1,0,0),(37,'und',1,7,'permissions_by_term__uid_7',1,1,1),(37,'und',1,101,'permissions_by_term__uid_5',1,1,1),(37,'und',1,102,'permissions_by_term__uid_1',1,1,1),(37,'und',1,103,'permissions_by_term__uid_18',1,1,1),(37,'und',1,103,'permissions_by_term__uid_4',1,1,1),(38,'und',1,1,'permissions_by_term__uid_6',1,1,1),(38,'und',1,2,'permissions_by_term__uid_3',1,1,1),(38,'und',1,5,'permissions_by_term__uid_0',1,0,0),(38,'und',1,7,'permissions_by_term__uid_7',1,1,1),(38,'und',1,102,'permissions_by_term__uid_5',1,1,1),(38,'und',1,103,'permissions_by_term__uid_1',1,1,1),(38,'und',1,104,'permissions_by_term__uid_18',1,1,1),(38,'und',1,104,'permissions_by_term__uid_4',1,1,1),(39,'und',1,1,'permissions_by_term__uid_6',1,1,1),(39,'und',1,2,'permissions_by_term__uid_3',1,1,1),(39,'und',1,5,'permissions_by_term__uid_0',1,0,0),(39,'und',1,7,'permissions_by_term__uid_7',1,1,1),(39,'und',1,103,'permissions_by_term__uid_5',1,1,1),(39,'und',1,104,'permissions_by_term__uid_1',1,1,1),(39,'und',1,105,'permissions_by_term__uid_18',1,1,1),(39,'und',1,105,'permissions_by_term__uid_4',1,1,1),(40,'und',1,36,'permissions_by_term__uid_6',1,1,1),(40,'und',1,37,'permissions_by_term__uid_3',1,1,1),(40,'und',1,40,'permissions_by_term__uid_0',1,1,1),(40,'und',1,42,'permissions_by_term__uid_7',1,1,1),(40,'und',1,95,'permissions_by_term__uid_1',1,1,1),(40,'und',1,95,'permissions_by_term__uid_18',1,1,1),(40,'und',1,95,'permissions_by_term__uid_4',1,1,1),(40,'und',1,95,'permissions_by_term__uid_5',1,1,1),(41,'und',1,1,'permissions_by_term__uid_6',1,1,1),(41,'und',1,2,'permissions_by_term__uid_3',1,1,1),(41,'und',1,5,'permissions_by_term__uid_0',1,0,0),(41,'und',1,7,'permissions_by_term__uid_7',1,1,1),(41,'und',1,99,'permissions_by_term__uid_1',1,1,1),(41,'und',1,99,'permissions_by_term__uid_5',1,1,1),(41,'und',1,100,'permissions_by_term__uid_18',1,1,1),(41,'und',1,100,'permissions_by_term__uid_4',1,1,1),(42,'und',1,1,'permissions_by_term__uid_6',1,1,1),(42,'und',1,2,'permissions_by_term__uid_3',1,1,1),(42,'und',1,5,'permissions_by_term__uid_0',1,0,0),(42,'und',1,7,'permissions_by_term__uid_7',1,1,1),(42,'und',1,104,'permissions_by_term__uid_5',1,1,1),(42,'und',1,105,'permissions_by_term__uid_1',1,1,1),(42,'und',1,106,'permissions_by_term__uid_18',1,1,1),(42,'und',1,106,'permissions_by_term__uid_4',1,1,1),(43,'und',1,57,'permissions_by_term__uid_6',1,1,1),(43,'und',1,58,'permissions_by_term__uid_3',1,1,1),(43,'und',1,61,'permissions_by_term__uid_0',1,1,1),(43,'und',1,63,'permissions_by_term__uid_7',1,1,1),(43,'und',1,96,'permissions_by_term__uid_1',1,1,1),(43,'und',1,96,'permissions_by_term__uid_18',1,1,1),(43,'und',1,96,'permissions_by_term__uid_4',1,1,1),(43,'und',1,96,'permissions_by_term__uid_5',1,1,1),(44,'und',1,1,'permissions_by_term__uid_1',1,1,1),(44,'und',1,1,'permissions_by_term__uid_18',1,1,1),(44,'und',1,1,'permissions_by_term__uid_4',1,1,1),(44,'und',1,1,'permissions_by_term__uid_5',1,1,1),(44,'und',1,64,'permissions_by_term__uid_6',1,1,1),(44,'und',1,65,'permissions_by_term__uid_3',1,1,1),(44,'und',1,68,'permissions_by_term__uid_0',1,1,1),(44,'und',1,70,'permissions_by_term__uid_7',1,1,1),(61,'und',1,71,'permissions_by_term__uid_6',1,1,1),(61,'und',1,72,'permissions_by_term__uid_3',1,1,1),(61,'und',1,75,'permissions_by_term__uid_0',1,1,1),(61,'und',1,77,'permissions_by_term__uid_7',1,1,1),(61,'und',1,97,'permissions_by_term__uid_1',1,1,1),(61,'und',1,97,'permissions_by_term__uid_18',1,1,1),(61,'und',1,97,'permissions_by_term__uid_4',1,1,1),(61,'und',1,97,'permissions_by_term__uid_5',1,1,1),(62,'und',1,78,'permissions_by_term__uid_6',1,1,1),(62,'und',1,79,'permissions_by_term__uid_3',1,1,1),(62,'und',1,82,'permissions_by_term__uid_0',1,1,1),(62,'und',1,84,'permissions_by_term__uid_7',1,1,1),(62,'und',1,98,'permissions_by_term__uid_1',1,1,1),(62,'und',1,98,'permissions_by_term__uid_18',1,1,1),(62,'und',1,98,'permissions_by_term__uid_4',1,1,1),(62,'und',1,98,'permissions_by_term__uid_5',1,1,1),(73,'und',1,2,'permissions_by_term__uid_1',1,1,1),(73,'und',1,2,'permissions_by_term__uid_18',1,1,1),(73,'und',1,2,'permissions_by_term__uid_4',1,1,1),(73,'und',1,2,'permissions_by_term__uid_5',1,1,1),(73,'und',1,85,'permissions_by_term__uid_6',1,1,1),(73,'und',1,86,'permissions_by_term__uid_3',1,1,1),(73,'und',1,89,'permissions_by_term__uid_0',1,1,1),(73,'und',1,91,'permissions_by_term__uid_7',1,1,1),(77,'und',1,86,'permissions_by_term__uid_1',1,1,1),(77,'und',1,86,'permissions_by_term__uid_18',1,1,1),(77,'und',1,86,'permissions_by_term__uid_4',1,1,1),(77,'und',1,86,'permissions_by_term__uid_5',1,1,1),(77,'und',1,92,'permissions_by_term__uid_6',1,1,1),(77,'und',1,93,'permissions_by_term__uid_3',1,1,1),(77,'und',1,96,'permissions_by_term__uid_0',1,1,1),(77,'und',1,98,'permissions_by_term__uid_7',1,1,1),(79,'und',1,3,'permissions_by_term__uid_1',1,1,1),(79,'und',1,3,'permissions_by_term__uid_18',1,1,1),(79,'und',1,3,'permissions_by_term__uid_4',1,1,1),(79,'und',1,3,'permissions_by_term__uid_5',1,1,1),(79,'und',1,99,'permissions_by_term__uid_6',1,1,1),(79,'und',1,100,'permissions_by_term__uid_3',1,1,1),(79,'und',1,103,'permissions_by_term__uid_0',1,1,1),(79,'und',1,105,'permissions_by_term__uid_7',1,1,1),(110,'und',1,4,'permissions_by_term__uid_1',1,1,1),(110,'und',1,4,'permissions_by_term__uid_18',1,1,1),(110,'und',1,4,'permissions_by_term__uid_4',1,1,1),(110,'und',1,4,'permissions_by_term__uid_5',1,1,1),(110,'und',1,106,'permissions_by_term__uid_6',1,1,1),(110,'und',1,107,'permissions_by_term__uid_3',1,1,1),(110,'und',1,110,'permissions_by_term__uid_0',1,1,1),(110,'und',1,112,'permissions_by_term__uid_7',1,1,1),(111,'und',1,5,'permissions_by_term__uid_1',1,1,1),(111,'und',1,5,'permissions_by_term__uid_18',1,1,1),(111,'und',1,5,'permissions_by_term__uid_4',1,1,1),(111,'und',1,5,'permissions_by_term__uid_5',1,1,1),(111,'und',1,113,'permissions_by_term__uid_6',1,1,1),(111,'und',1,114,'permissions_by_term__uid_3',1,1,1),(111,'und',1,117,'permissions_by_term__uid_0',1,1,1),(111,'und',1,119,'permissions_by_term__uid_7',1,1,1),(112,'und',1,6,'permissions_by_term__uid_1',1,1,1),(112,'und',1,6,'permissions_by_term__uid_18',1,1,1),(112,'und',1,6,'permissions_by_term__uid_4',1,1,1),(112,'und',1,6,'permissions_by_term__uid_5',1,1,1),(112,'und',1,120,'permissions_by_term__uid_6',1,1,1),(112,'und',1,121,'permissions_by_term__uid_3',1,1,1),(112,'und',1,124,'permissions_by_term__uid_0',1,1,1),(112,'und',1,126,'permissions_by_term__uid_7',1,1,1),(113,'und',1,7,'permissions_by_term__uid_1',1,1,1),(113,'und',1,7,'permissions_by_term__uid_18',1,1,1),(113,'und',1,7,'permissions_by_term__uid_4',1,1,1),(113,'und',1,7,'permissions_by_term__uid_5',1,1,1),(113,'und',1,127,'permissions_by_term__uid_6',1,1,1),(113,'und',1,128,'permissions_by_term__uid_3',1,1,1),(113,'und',1,131,'permissions_by_term__uid_0',1,1,1),(113,'und',1,133,'permissions_by_term__uid_7',1,1,1),(114,'und',1,8,'permissions_by_term__uid_1',1,1,1),(114,'und',1,8,'permissions_by_term__uid_18',1,1,1),(114,'und',1,8,'permissions_by_term__uid_4',1,1,1),(114,'und',1,8,'permissions_by_term__uid_5',1,1,1),(114,'und',1,134,'permissions_by_term__uid_6',1,1,1),(114,'und',1,135,'permissions_by_term__uid_3',1,1,1),(114,'und',1,138,'permissions_by_term__uid_0',1,1,1),(114,'und',1,140,'permissions_by_term__uid_7',1,1,1),(115,'und',1,1,'permissions_by_term__uid_6',1,1,1),(115,'und',1,2,'permissions_by_term__uid_3',1,1,1),(115,'und',1,5,'permissions_by_term__uid_0',1,0,0),(115,'und',1,7,'permissions_by_term__uid_7',1,1,1),(115,'und',1,9,'permissions_by_term__uid_1',1,1,1),(115,'und',1,9,'permissions_by_term__uid_18',1,1,1),(115,'und',1,9,'permissions_by_term__uid_4',1,1,1),(115,'und',1,9,'permissions_by_term__uid_5',1,1,1),(116,'und',1,8,'permissions_by_term__uid_6',1,1,1),(116,'und',1,9,'permissions_by_term__uid_3',1,1,1),(116,'und',1,10,'permissions_by_term__uid_1',1,1,1),(116,'und',1,10,'permissions_by_term__uid_18',1,1,1),(116,'und',1,10,'permissions_by_term__uid_4',1,1,1),(116,'und',1,10,'permissions_by_term__uid_5',1,1,1),(116,'und',1,12,'permissions_by_term__uid_0',1,1,1),(116,'und',1,14,'permissions_by_term__uid_7',1,1,1),(117,'und',1,11,'permissions_by_term__uid_1',1,1,1),(117,'und',1,11,'permissions_by_term__uid_18',1,1,1),(117,'und',1,11,'permissions_by_term__uid_4',1,1,1),(117,'und',1,11,'permissions_by_term__uid_5',1,1,1),(117,'und',1,15,'permissions_by_term__uid_6',1,1,1),(117,'und',1,16,'permissions_by_term__uid_3',1,1,1),(117,'und',1,19,'permissions_by_term__uid_0',1,1,1),(117,'und',1,21,'permissions_by_term__uid_7',1,1,1),(118,'und',1,12,'permissions_by_term__uid_1',1,1,1),(118,'und',1,12,'permissions_by_term__uid_18',1,1,1),(118,'und',1,12,'permissions_by_term__uid_4',1,1,1),(118,'und',1,12,'permissions_by_term__uid_5',1,1,1),(118,'und',1,22,'permissions_by_term__uid_6',1,1,1),(118,'und',1,23,'permissions_by_term__uid_3',1,1,1),(118,'und',1,26,'permissions_by_term__uid_0',1,1,1),(118,'und',1,28,'permissions_by_term__uid_7',1,1,1),(119,'und',1,13,'permissions_by_term__uid_1',1,1,1),(119,'und',1,13,'permissions_by_term__uid_18',1,1,1),(119,'und',1,13,'permissions_by_term__uid_4',1,1,1),(119,'und',1,13,'permissions_by_term__uid_5',1,1,1),(119,'und',1,29,'permissions_by_term__uid_6',1,1,1),(119,'und',1,30,'permissions_by_term__uid_3',1,1,1),(119,'und',1,33,'permissions_by_term__uid_0',1,1,1),(119,'und',1,35,'permissions_by_term__uid_7',1,1,1),(120,'und',1,14,'permissions_by_term__uid_1',1,1,1),(120,'und',1,14,'permissions_by_term__uid_18',1,1,1),(120,'und',1,14,'permissions_by_term__uid_4',1,1,1),(120,'und',1,14,'permissions_by_term__uid_5',1,1,1),(120,'und',1,36,'permissions_by_term__uid_6',1,1,1),(120,'und',1,37,'permissions_by_term__uid_3',1,1,1),(120,'und',1,40,'permissions_by_term__uid_0',1,1,1),(120,'und',1,42,'permissions_by_term__uid_7',1,1,1),(121,'und',1,15,'permissions_by_term__uid_1',1,1,1),(121,'und',1,15,'permissions_by_term__uid_18',1,1,1),(121,'und',1,15,'permissions_by_term__uid_4',1,1,1),(121,'und',1,15,'permissions_by_term__uid_5',1,1,1),(121,'und',1,43,'permissions_by_term__uid_6',1,1,1),(121,'und',1,44,'permissions_by_term__uid_3',1,1,1),(121,'und',1,47,'permissions_by_term__uid_0',1,1,1),(121,'und',1,49,'permissions_by_term__uid_7',1,1,1),(122,'und',1,16,'permissions_by_term__uid_1',1,1,1),(122,'und',1,16,'permissions_by_term__uid_18',1,1,1),(122,'und',1,16,'permissions_by_term__uid_4',1,1,1),(122,'und',1,16,'permissions_by_term__uid_5',1,1,1),(122,'und',1,50,'permissions_by_term__uid_6',1,1,1),(122,'und',1,51,'permissions_by_term__uid_3',1,1,1),(122,'und',1,54,'permissions_by_term__uid_0',1,1,1),(122,'und',1,56,'permissions_by_term__uid_7',1,1,1),(123,'und',1,17,'permissions_by_term__uid_1',1,1,1),(123,'und',1,17,'permissions_by_term__uid_18',1,1,1),(123,'und',1,17,'permissions_by_term__uid_4',1,1,1),(123,'und',1,17,'permissions_by_term__uid_5',1,1,1),(123,'und',1,57,'permissions_by_term__uid_6',1,1,1),(123,'und',1,58,'permissions_by_term__uid_3',1,1,1),(123,'und',1,61,'permissions_by_term__uid_0',1,1,1),(123,'und',1,63,'permissions_by_term__uid_7',1,1,1),(124,'und',1,18,'permissions_by_term__uid_1',1,1,1),(124,'und',1,18,'permissions_by_term__uid_18',1,1,1),(124,'und',1,18,'permissions_by_term__uid_4',1,1,1),(124,'und',1,18,'permissions_by_term__uid_5',1,1,1),(124,'und',1,64,'permissions_by_term__uid_6',1,1,1),(124,'und',1,65,'permissions_by_term__uid_3',1,1,1),(124,'und',1,68,'permissions_by_term__uid_0',1,1,1),(124,'und',1,70,'permissions_by_term__uid_7',1,1,1),(125,'und',1,19,'permissions_by_term__uid_1',1,1,1),(125,'und',1,19,'permissions_by_term__uid_18',1,1,1),(125,'und',1,19,'permissions_by_term__uid_4',1,1,1),(125,'und',1,19,'permissions_by_term__uid_5',1,1,1),(125,'und',1,71,'permissions_by_term__uid_6',1,1,1),(125,'und',1,72,'permissions_by_term__uid_3',1,1,1),(125,'und',1,75,'permissions_by_term__uid_0',1,1,1),(125,'und',1,77,'permissions_by_term__uid_7',1,1,1),(126,'und',1,20,'permissions_by_term__uid_1',1,1,1),(126,'und',1,20,'permissions_by_term__uid_18',1,1,1),(126,'und',1,20,'permissions_by_term__uid_4',1,1,1),(126,'und',1,20,'permissions_by_term__uid_5',1,1,1),(126,'und',1,78,'permissions_by_term__uid_6',1,1,1),(126,'und',1,79,'permissions_by_term__uid_3',1,1,1),(126,'und',1,82,'permissions_by_term__uid_0',1,1,1),(126,'und',1,84,'permissions_by_term__uid_7',1,1,1),(127,'und',1,21,'permissions_by_term__uid_1',1,1,1),(127,'und',1,21,'permissions_by_term__uid_18',1,1,1),(127,'und',1,21,'permissions_by_term__uid_4',1,1,1),(127,'und',1,21,'permissions_by_term__uid_5',1,1,1),(127,'und',1,85,'permissions_by_term__uid_6',1,1,1),(127,'und',1,86,'permissions_by_term__uid_3',1,1,1),(127,'und',1,89,'permissions_by_term__uid_0',1,1,1),(127,'und',1,91,'permissions_by_term__uid_7',1,1,1),(128,'und',1,22,'permissions_by_term__uid_1',1,1,1),(128,'und',1,22,'permissions_by_term__uid_18',1,1,1),(128,'und',1,22,'permissions_by_term__uid_4',1,1,1),(128,'und',1,22,'permissions_by_term__uid_5',1,1,1),(128,'und',1,92,'permissions_by_term__uid_6',1,1,1),(128,'und',1,93,'permissions_by_term__uid_3',1,1,1),(128,'und',1,96,'permissions_by_term__uid_0',1,1,1),(128,'und',1,98,'permissions_by_term__uid_7',1,1,1),(129,'und',1,23,'permissions_by_term__uid_1',1,1,1),(129,'und',1,23,'permissions_by_term__uid_18',1,1,1),(129,'und',1,23,'permissions_by_term__uid_4',1,1,1),(129,'und',1,23,'permissions_by_term__uid_5',1,1,1),(129,'und',1,99,'permissions_by_term__uid_6',1,1,1),(129,'und',1,100,'permissions_by_term__uid_3',1,1,1),(129,'und',1,103,'permissions_by_term__uid_0',1,1,1),(129,'und',1,105,'permissions_by_term__uid_7',1,1,1),(130,'und',1,24,'permissions_by_term__uid_1',1,1,1),(130,'und',1,24,'permissions_by_term__uid_18',1,1,1),(130,'und',1,24,'permissions_by_term__uid_4',1,1,1),(130,'und',1,24,'permissions_by_term__uid_5',1,1,1),(130,'und',1,106,'permissions_by_term__uid_6',1,1,1),(130,'und',1,107,'permissions_by_term__uid_3',1,1,1),(130,'und',1,110,'permissions_by_term__uid_0',1,1,1),(130,'und',1,112,'permissions_by_term__uid_7',1,1,1),(131,'und',1,25,'permissions_by_term__uid_1',1,1,1),(131,'und',1,25,'permissions_by_term__uid_18',1,1,1),(131,'und',1,25,'permissions_by_term__uid_4',1,1,1),(131,'und',1,25,'permissions_by_term__uid_5',1,1,1),(131,'und',1,113,'permissions_by_term__uid_6',1,1,1),(131,'und',1,114,'permissions_by_term__uid_3',1,1,1),(131,'und',1,117,'permissions_by_term__uid_0',1,1,1),(131,'und',1,119,'permissions_by_term__uid_7',1,1,1),(132,'und',1,26,'permissions_by_term__uid_1',1,1,1),(132,'und',1,26,'permissions_by_term__uid_18',1,1,1),(132,'und',1,26,'permissions_by_term__uid_4',1,1,1),(132,'und',1,26,'permissions_by_term__uid_5',1,1,1),(132,'und',1,120,'permissions_by_term__uid_6',1,1,1),(132,'und',1,121,'permissions_by_term__uid_3',1,1,1),(132,'und',1,124,'permissions_by_term__uid_0',1,1,1),(132,'und',1,126,'permissions_by_term__uid_7',1,1,1),(133,'und',1,27,'permissions_by_term__uid_1',1,1,1),(133,'und',1,27,'permissions_by_term__uid_18',1,1,1),(133,'und',1,27,'permissions_by_term__uid_4',1,1,1),(133,'und',1,27,'permissions_by_term__uid_5',1,1,1),(133,'und',1,127,'permissions_by_term__uid_6',1,1,1),(133,'und',1,128,'permissions_by_term__uid_3',1,1,1),(133,'und',1,131,'permissions_by_term__uid_0',1,1,1),(133,'und',1,133,'permissions_by_term__uid_7',1,1,1),(134,'und',1,28,'permissions_by_term__uid_1',1,1,1),(134,'und',1,28,'permissions_by_term__uid_18',1,1,1),(134,'und',1,28,'permissions_by_term__uid_4',1,1,1),(134,'und',1,28,'permissions_by_term__uid_5',1,1,1),(134,'und',1,134,'permissions_by_term__uid_6',1,1,1),(134,'und',1,135,'permissions_by_term__uid_3',1,1,1),(134,'und',1,138,'permissions_by_term__uid_0',1,1,1),(134,'und',1,140,'permissions_by_term__uid_7',1,1,1),(135,'und',1,1,'permissions_by_term__uid_6',1,1,1),(135,'und',1,2,'permissions_by_term__uid_3',1,1,1),(135,'und',1,5,'permissions_by_term__uid_0',1,0,0),(135,'und',1,7,'permissions_by_term__uid_7',1,1,1),(135,'und',1,29,'permissions_by_term__uid_1',1,1,1),(135,'und',1,29,'permissions_by_term__uid_18',1,1,1),(135,'und',1,29,'permissions_by_term__uid_4',1,1,1),(135,'und',1,29,'permissions_by_term__uid_5',1,1,1),(136,'und',1,8,'permissions_by_term__uid_6',1,1,1),(136,'und',1,9,'permissions_by_term__uid_3',1,1,1),(136,'und',1,12,'permissions_by_term__uid_0',1,1,1),(136,'und',1,14,'permissions_by_term__uid_7',1,1,1),(136,'und',1,30,'permissions_by_term__uid_1',1,1,1),(136,'und',1,30,'permissions_by_term__uid_18',1,1,1),(136,'und',1,30,'permissions_by_term__uid_4',1,1,1),(136,'und',1,30,'permissions_by_term__uid_5',1,1,1),(137,'und',1,15,'permissions_by_term__uid_6',1,1,1),(137,'und',1,16,'permissions_by_term__uid_3',1,1,1),(137,'und',1,19,'permissions_by_term__uid_0',1,1,1),(137,'und',1,21,'permissions_by_term__uid_7',1,1,1),(137,'und',1,31,'permissions_by_term__uid_1',1,1,1),(137,'und',1,31,'permissions_by_term__uid_18',1,1,1),(137,'und',1,31,'permissions_by_term__uid_4',1,1,1),(137,'und',1,31,'permissions_by_term__uid_5',1,1,1),(169,'und',1,22,'permissions_by_term__uid_6',1,1,1),(169,'und',1,23,'permissions_by_term__uid_3',1,1,1),(169,'und',1,26,'permissions_by_term__uid_0',1,1,1),(169,'und',1,28,'permissions_by_term__uid_7',1,1,1),(169,'und',1,32,'permissions_by_term__uid_1',1,1,1),(169,'und',1,32,'permissions_by_term__uid_18',1,1,1),(169,'und',1,32,'permissions_by_term__uid_4',1,1,1),(169,'und',1,32,'permissions_by_term__uid_5',1,1,1),(196,'und',1,29,'permissions_by_term__uid_6',1,1,1),(196,'und',1,30,'permissions_by_term__uid_3',1,1,1),(196,'und',1,33,'permissions_by_term__uid_0',1,1,1),(196,'und',1,33,'permissions_by_term__uid_1',1,1,1),(196,'und',1,33,'permissions_by_term__uid_18',1,1,1),(196,'und',1,33,'permissions_by_term__uid_4',1,1,1),(196,'und',1,33,'permissions_by_term__uid_5',1,1,1),(196,'und',1,35,'permissions_by_term__uid_7',1,1,1),(265,'und',1,34,'permissions_by_term__uid_1',1,1,1),(265,'und',1,34,'permissions_by_term__uid_18',1,1,1),(265,'und',1,34,'permissions_by_term__uid_4',1,1,1),(265,'und',1,34,'permissions_by_term__uid_5',1,1,1),(265,'und',1,36,'permissions_by_term__uid_6',1,1,1),(265,'und',1,37,'permissions_by_term__uid_3',1,1,1),(265,'und',1,40,'permissions_by_term__uid_0',1,1,1),(265,'und',1,42,'permissions_by_term__uid_7',1,1,1),(271,'und',1,35,'permissions_by_term__uid_1',1,1,1),(271,'und',1,35,'permissions_by_term__uid_18',1,1,1),(271,'und',1,35,'permissions_by_term__uid_4',1,1,1),(271,'und',1,35,'permissions_by_term__uid_5',1,1,1),(271,'und',1,43,'permissions_by_term__uid_6',1,1,1),(271,'und',1,44,'permissions_by_term__uid_3',1,1,1),(271,'und',1,47,'permissions_by_term__uid_0',1,1,1),(271,'und',1,49,'permissions_by_term__uid_7',1,1,1),(274,'und',1,36,'permissions_by_term__uid_1',1,1,1),(274,'und',1,36,'permissions_by_term__uid_18',1,1,1),(274,'und',1,36,'permissions_by_term__uid_4',1,1,1),(274,'und',1,36,'permissions_by_term__uid_5',1,1,1),(274,'und',1,50,'permissions_by_term__uid_6',1,1,1),(274,'und',1,51,'permissions_by_term__uid_3',1,1,1),(274,'und',1,54,'permissions_by_term__uid_0',1,1,1),(274,'und',1,56,'permissions_by_term__uid_7',1,1,1),(285,'und',1,37,'permissions_by_term__uid_1',1,1,1),(285,'und',1,37,'permissions_by_term__uid_18',1,1,1),(285,'und',1,37,'permissions_by_term__uid_4',1,1,1),(285,'und',1,37,'permissions_by_term__uid_5',1,1,1),(285,'und',1,64,'permissions_by_term__uid_6',1,1,1),(285,'und',1,65,'permissions_by_term__uid_3',1,1,1),(285,'und',1,68,'permissions_by_term__uid_0',1,1,1),(285,'und',1,70,'permissions_by_term__uid_7',1,1,1),(323,'und',1,38,'permissions_by_term__uid_1',1,1,1),(323,'und',1,38,'permissions_by_term__uid_18',1,1,1),(323,'und',1,38,'permissions_by_term__uid_4',1,1,1),(323,'und',1,38,'permissions_by_term__uid_5',1,1,1),(323,'und',1,71,'permissions_by_term__uid_6',1,1,1),(323,'und',1,72,'permissions_by_term__uid_3',1,1,1),(323,'und',1,75,'permissions_by_term__uid_0',1,1,1),(323,'und',1,77,'permissions_by_term__uid_7',1,1,1),(325,'und',1,39,'permissions_by_term__uid_1',1,1,1),(325,'und',1,39,'permissions_by_term__uid_18',1,1,1),(325,'und',1,39,'permissions_by_term__uid_4',1,1,1),(325,'und',1,39,'permissions_by_term__uid_5',1,1,1),(325,'und',1,78,'permissions_by_term__uid_6',1,1,1),(325,'und',1,79,'permissions_by_term__uid_3',1,1,1),(325,'und',1,82,'permissions_by_term__uid_0',1,1,1),(325,'und',1,84,'permissions_by_term__uid_7',1,1,1),(342,'und',1,1,'permissions_by_term__uid_6',1,1,1),(342,'und',1,2,'permissions_by_term__uid_3',1,1,1),(342,'und',1,5,'permissions_by_term__uid_0',1,0,0),(342,'und',1,7,'permissions_by_term__uid_7',1,1,1),(342,'und',1,105,'permissions_by_term__uid_5',1,1,1),(342,'und',1,106,'permissions_by_term__uid_1',1,1,1),(342,'und',1,107,'permissions_by_term__uid_18',1,1,1),(342,'und',1,107,'permissions_by_term__uid_4',1,1,1),(344,'und',1,1,'permissions_by_term__uid_6',1,1,1),(344,'und',1,2,'permissions_by_term__uid_3',1,1,1),(344,'und',1,5,'permissions_by_term__uid_0',1,0,0),(344,'und',1,7,'permissions_by_term__uid_7',1,1,1),(344,'und',1,106,'permissions_by_term__uid_5',1,1,1),(344,'und',1,107,'permissions_by_term__uid_1',1,1,1),(344,'und',1,108,'permissions_by_term__uid_18',1,1,1),(344,'und',1,108,'permissions_by_term__uid_4',1,1,1),(345,'und',1,1,'permissions_by_term__uid_6',1,1,1),(345,'und',1,2,'permissions_by_term__uid_3',1,1,1),(345,'und',1,5,'permissions_by_term__uid_0',1,0,0),(345,'und',1,7,'permissions_by_term__uid_7',1,1,1),(345,'und',1,123,'permissions_by_term__uid_5',1,1,1),(345,'und',1,125,'permissions_by_term__uid_1',1,1,1),(345,'und',1,126,'permissions_by_term__uid_18',1,1,1),(345,'und',1,126,'permissions_by_term__uid_4',1,1,1),(347,'und',1,40,'permissions_by_term__uid_1',1,1,1),(347,'und',1,40,'permissions_by_term__uid_18',1,1,1),(347,'und',1,40,'permissions_by_term__uid_4',1,1,1),(347,'und',1,40,'permissions_by_term__uid_5',1,1,1),(347,'und',1,113,'permissions_by_term__uid_6',1,1,1),(347,'und',1,114,'permissions_by_term__uid_3',1,1,1),(347,'und',1,117,'permissions_by_term__uid_0',1,1,1),(347,'und',1,119,'permissions_by_term__uid_7',1,1,1),(348,'und',1,41,'permissions_by_term__uid_1',1,1,1),(348,'und',1,41,'permissions_by_term__uid_18',1,1,1),(348,'und',1,41,'permissions_by_term__uid_4',1,1,1),(348,'und',1,41,'permissions_by_term__uid_5',1,1,1),(348,'und',1,120,'permissions_by_term__uid_6',1,1,1),(348,'und',1,121,'permissions_by_term__uid_3',1,1,1),(348,'und',1,124,'permissions_by_term__uid_0',1,1,1),(348,'und',1,126,'permissions_by_term__uid_7',1,1,1),(351,'und',1,42,'permissions_by_term__uid_1',1,1,1),(351,'und',1,42,'permissions_by_term__uid_18',1,1,1),(351,'und',1,42,'permissions_by_term__uid_4',1,1,1),(351,'und',1,42,'permissions_by_term__uid_5',1,1,1),(351,'und',1,127,'permissions_by_term__uid_6',1,1,1),(351,'und',1,128,'permissions_by_term__uid_3',1,1,1),(351,'und',1,131,'permissions_by_term__uid_0',1,1,1),(351,'und',1,133,'permissions_by_term__uid_7',1,1,1),(353,'und',1,1,'permissions_by_term__uid_6',1,1,1),(353,'und',1,2,'permissions_by_term__uid_3',1,1,1),(353,'und',1,5,'permissions_by_term__uid_0',1,0,0),(353,'und',1,7,'permissions_by_term__uid_7',1,1,1),(353,'und',1,107,'permissions_by_term__uid_5',1,1,1),(353,'und',1,108,'permissions_by_term__uid_1',1,1,1),(353,'und',1,109,'permissions_by_term__uid_18',1,1,1),(353,'und',1,109,'permissions_by_term__uid_4',1,1,1),(357,'und',1,1,'permissions_by_term__uid_6',1,1,1),(357,'und',1,2,'permissions_by_term__uid_3',1,1,1),(357,'und',1,5,'permissions_by_term__uid_0',1,0,0),(357,'und',1,7,'permissions_by_term__uid_7',1,1,1),(357,'und',1,108,'permissions_by_term__uid_5',1,1,1),(357,'und',1,109,'permissions_by_term__uid_1',1,1,1),(357,'und',1,110,'permissions_by_term__uid_18',1,1,1),(357,'und',1,110,'permissions_by_term__uid_4',1,1,1),(358,'und',1,8,'permissions_by_term__uid_6',1,1,1),(358,'und',1,9,'permissions_by_term__uid_3',1,1,1),(358,'und',1,12,'permissions_by_term__uid_0',1,1,1),(358,'und',1,14,'permissions_by_term__uid_7',1,1,1),(358,'und',1,94,'permissions_by_term__uid_1',1,1,1),(358,'und',1,94,'permissions_by_term__uid_18',1,1,1),(358,'und',1,94,'permissions_by_term__uid_4',1,1,1),(358,'und',1,94,'permissions_by_term__uid_5',1,1,1),(359,'und',1,1,'permissions_by_term__uid_6',1,1,1),(359,'und',1,2,'permissions_by_term__uid_3',1,1,1),(359,'und',1,5,'permissions_by_term__uid_0',1,0,0),(359,'und',1,7,'permissions_by_term__uid_7',1,1,1),(359,'und',1,109,'permissions_by_term__uid_5',1,1,1),(359,'und',1,110,'permissions_by_term__uid_1',1,1,1),(359,'und',1,111,'permissions_by_term__uid_18',1,1,1),(359,'und',1,111,'permissions_by_term__uid_4',1,1,1),(360,'und',1,1,'permissions_by_term__uid_6',1,1,1),(360,'und',1,2,'permissions_by_term__uid_3',1,1,1),(360,'und',1,5,'permissions_by_term__uid_0',1,0,0),(360,'und',1,7,'permissions_by_term__uid_7',1,1,1),(360,'und',1,110,'permissions_by_term__uid_5',1,1,1),(360,'und',1,111,'permissions_by_term__uid_1',1,1,1),(360,'und',1,112,'permissions_by_term__uid_18',1,1,1),(360,'und',1,112,'permissions_by_term__uid_4',1,1,1),(363,'und',1,29,'permissions_by_term__uid_6',1,1,1),(363,'und',1,30,'permissions_by_term__uid_3',1,1,1),(363,'und',1,33,'permissions_by_term__uid_0',1,1,1),(363,'und',1,35,'permissions_by_term__uid_7',1,1,1),(363,'und',1,43,'permissions_by_term__uid_1',1,1,1),(363,'und',1,43,'permissions_by_term__uid_18',1,1,1),(363,'und',1,43,'permissions_by_term__uid_4',1,1,1),(363,'und',1,43,'permissions_by_term__uid_5',1,1,1),(365,'und',1,36,'permissions_by_term__uid_6',1,1,1),(365,'und',1,37,'permissions_by_term__uid_3',1,1,1),(365,'und',1,40,'permissions_by_term__uid_0',1,1,1),(365,'und',1,42,'permissions_by_term__uid_7',1,1,1),(365,'und',1,44,'permissions_by_term__uid_1',1,1,1),(365,'und',1,44,'permissions_by_term__uid_18',1,1,1),(365,'und',1,44,'permissions_by_term__uid_4',1,1,1),(365,'und',1,44,'permissions_by_term__uid_5',1,1,1),(366,'und',1,43,'permissions_by_term__uid_6',1,1,1),(366,'und',1,44,'permissions_by_term__uid_3',1,1,1),(366,'und',1,45,'permissions_by_term__uid_1',1,1,1),(366,'und',1,45,'permissions_by_term__uid_18',1,1,1),(366,'und',1,45,'permissions_by_term__uid_4',1,1,1),(366,'und',1,45,'permissions_by_term__uid_5',1,1,1),(366,'und',1,47,'permissions_by_term__uid_0',1,1,1),(366,'und',1,49,'permissions_by_term__uid_7',1,1,1),(367,'und',1,1,'permissions_by_term__uid_6',1,1,1),(367,'und',1,2,'permissions_by_term__uid_3',1,1,1),(367,'und',1,5,'permissions_by_term__uid_0',1,0,0),(367,'und',1,7,'permissions_by_term__uid_7',1,1,1),(367,'und',1,120,'permissions_by_term__uid_5',1,1,1),(367,'und',1,121,'permissions_by_term__uid_1',1,1,1),(367,'und',1,122,'permissions_by_term__uid_18',1,1,1),(367,'und',1,122,'permissions_by_term__uid_4',1,1,1),(368,'und',1,46,'permissions_by_term__uid_1',1,1,1),(368,'und',1,46,'permissions_by_term__uid_18',1,1,1),(368,'und',1,46,'permissions_by_term__uid_4',1,1,1),(368,'und',1,46,'permissions_by_term__uid_5',1,1,1),(368,'und',1,57,'permissions_by_term__uid_6',1,1,1),(368,'und',1,58,'permissions_by_term__uid_3',1,1,1),(368,'und',1,61,'permissions_by_term__uid_0',1,1,1),(368,'und',1,63,'permissions_by_term__uid_7',1,1,1),(369,'und',1,1,'permissions_by_term__uid_6',1,1,1),(369,'und',1,2,'permissions_by_term__uid_3',1,1,1),(369,'und',1,5,'permissions_by_term__uid_0',1,0,0),(369,'und',1,7,'permissions_by_term__uid_7',1,1,1),(369,'und',1,111,'permissions_by_term__uid_5',1,1,1),(369,'und',1,112,'permissions_by_term__uid_1',1,1,1),(369,'und',1,113,'permissions_by_term__uid_18',1,1,1),(369,'und',1,113,'permissions_by_term__uid_4',1,1,1),(370,'und',1,47,'permissions_by_term__uid_1',1,1,1),(370,'und',1,47,'permissions_by_term__uid_18',1,1,1),(370,'und',1,47,'permissions_by_term__uid_4',1,1,1),(370,'und',1,47,'permissions_by_term__uid_5',1,1,1),(370,'und',1,71,'permissions_by_term__uid_6',1,1,1),(370,'und',1,72,'permissions_by_term__uid_3',1,1,1),(370,'und',1,75,'permissions_by_term__uid_0',1,1,1),(370,'und',1,77,'permissions_by_term__uid_7',1,1,1),(371,'und',1,48,'permissions_by_term__uid_1',1,1,1),(371,'und',1,48,'permissions_by_term__uid_18',1,1,1),(371,'und',1,48,'permissions_by_term__uid_4',1,1,1),(371,'und',1,48,'permissions_by_term__uid_5',1,1,1),(371,'und',1,78,'permissions_by_term__uid_6',1,1,1),(371,'und',1,79,'permissions_by_term__uid_3',1,1,1),(371,'und',1,82,'permissions_by_term__uid_0',1,1,1),(371,'und',1,84,'permissions_by_term__uid_7',1,1,1),(372,'und',1,49,'permissions_by_term__uid_1',1,1,1),(372,'und',1,49,'permissions_by_term__uid_18',1,1,1),(372,'und',1,49,'permissions_by_term__uid_4',1,1,1),(372,'und',1,49,'permissions_by_term__uid_5',1,1,1),(372,'und',1,85,'permissions_by_term__uid_6',1,1,1),(372,'und',1,86,'permissions_by_term__uid_3',1,1,1),(372,'und',1,89,'permissions_by_term__uid_0',1,1,1),(372,'und',1,91,'permissions_by_term__uid_7',1,1,1),(374,'und',1,50,'permissions_by_term__uid_1',1,1,1),(374,'und',1,50,'permissions_by_term__uid_18',1,1,1),(374,'und',1,50,'permissions_by_term__uid_4',1,1,1),(374,'und',1,50,'permissions_by_term__uid_5',1,1,1),(374,'und',1,92,'permissions_by_term__uid_6',1,1,1),(374,'und',1,93,'permissions_by_term__uid_3',1,1,1),(374,'und',1,96,'permissions_by_term__uid_0',1,1,1),(374,'und',1,98,'permissions_by_term__uid_7',1,1,1),(376,'und',1,51,'permissions_by_term__uid_1',1,1,1),(376,'und',1,51,'permissions_by_term__uid_18',1,1,1),(376,'und',1,51,'permissions_by_term__uid_4',1,1,1),(376,'und',1,51,'permissions_by_term__uid_5',1,1,1),(376,'und',1,99,'permissions_by_term__uid_6',1,1,1),(376,'und',1,100,'permissions_by_term__uid_3',1,1,1),(376,'und',1,103,'permissions_by_term__uid_0',1,1,1),(376,'und',1,105,'permissions_by_term__uid_7',1,1,1),(377,'und',1,52,'permissions_by_term__uid_1',1,1,1),(377,'und',1,52,'permissions_by_term__uid_18',1,1,1),(377,'und',1,52,'permissions_by_term__uid_4',1,1,1),(377,'und',1,52,'permissions_by_term__uid_5',1,1,1),(377,'und',1,106,'permissions_by_term__uid_6',1,1,1),(377,'und',1,107,'permissions_by_term__uid_3',1,1,1),(377,'und',1,110,'permissions_by_term__uid_0',1,1,1),(377,'und',1,112,'permissions_by_term__uid_7',1,1,1),(380,'und',1,53,'permissions_by_term__uid_1',1,1,1),(380,'und',1,53,'permissions_by_term__uid_18',1,1,1),(380,'und',1,53,'permissions_by_term__uid_4',1,1,1),(380,'und',1,53,'permissions_by_term__uid_5',1,1,1),(380,'und',1,113,'permissions_by_term__uid_6',1,1,1),(380,'und',1,114,'permissions_by_term__uid_3',1,1,1),(380,'und',1,117,'permissions_by_term__uid_0',1,1,1),(380,'und',1,119,'permissions_by_term__uid_7',1,1,1),(382,'und',1,1,'permissions_by_term__uid_18',1,1,1),(382,'und',1,2,'permissions_by_term__uid_6',1,1,1),(382,'und',1,3,'permissions_by_term__uid_3',1,1,1),(382,'und',1,4,'permissions_by_term__uid_1',1,1,1),(382,'und',1,5,'permissions_by_term__uid_4',1,1,1),(382,'und',1,6,'permissions_by_term__uid_0',1,0,0),(382,'und',1,8,'permissions_by_term__uid_7',1,1,1),(382,'und',1,133,'permissions_by_term__uid_5',1,1,1),(384,'und',1,1,'permissions_by_term__uid_6',1,1,1),(384,'und',1,2,'permissions_by_term__uid_3',1,1,1),(384,'und',1,5,'permissions_by_term__uid_0',1,0,0),(384,'und',1,7,'permissions_by_term__uid_7',1,1,1),(384,'und',1,54,'permissions_by_term__uid_1',1,1,1),(384,'und',1,54,'permissions_by_term__uid_18',1,1,1),(384,'und',1,54,'permissions_by_term__uid_4',1,1,1),(384,'und',1,54,'permissions_by_term__uid_5',1,1,1),(385,'und',1,1,'permissions_by_term__uid_6',1,1,1),(385,'und',1,2,'permissions_by_term__uid_3',1,1,1),(385,'und',1,5,'permissions_by_term__uid_0',1,0,0),(385,'und',1,7,'permissions_by_term__uid_7',1,1,1),(385,'und',1,55,'permissions_by_term__uid_1',1,1,1),(385,'und',1,55,'permissions_by_term__uid_18',1,1,1),(385,'und',1,55,'permissions_by_term__uid_4',1,1,1),(385,'und',1,55,'permissions_by_term__uid_5',1,1,1),(388,'und',1,1,'permissions_by_term__uid_6',1,1,1),(388,'und',1,2,'permissions_by_term__uid_3',1,1,1),(388,'und',1,5,'permissions_by_term__uid_0',1,0,0),(388,'und',1,7,'permissions_by_term__uid_7',1,1,1),(388,'und',1,56,'permissions_by_term__uid_1',1,1,1),(388,'und',1,56,'permissions_by_term__uid_18',1,1,1),(388,'und',1,56,'permissions_by_term__uid_4',1,1,1),(388,'und',1,56,'permissions_by_term__uid_5',1,1,1),(389,'und',1,1,'permissions_by_term__uid_6',1,1,1),(389,'und',1,2,'permissions_by_term__uid_3',1,1,1),(389,'und',1,5,'permissions_by_term__uid_0',1,0,0),(389,'und',1,7,'permissions_by_term__uid_7',1,1,1),(389,'und',1,57,'permissions_by_term__uid_1',1,1,1),(389,'und',1,57,'permissions_by_term__uid_18',1,1,1),(389,'und',1,57,'permissions_by_term__uid_4',1,1,1),(389,'und',1,57,'permissions_by_term__uid_5',1,1,1),(390,'und',1,15,'permissions_by_term__uid_6',1,1,1),(390,'und',1,16,'permissions_by_term__uid_3',1,1,1),(390,'und',1,19,'permissions_by_term__uid_0',1,1,1),(390,'und',1,21,'permissions_by_term__uid_7',1,1,1),(390,'und',1,58,'permissions_by_term__uid_1',1,1,1),(390,'und',1,58,'permissions_by_term__uid_18',1,1,1),(390,'und',1,58,'permissions_by_term__uid_4',1,1,1),(390,'und',1,58,'permissions_by_term__uid_5',1,1,1),(391,'und',1,22,'permissions_by_term__uid_6',1,1,1),(391,'und',1,23,'permissions_by_term__uid_3',1,1,1),(391,'und',1,26,'permissions_by_term__uid_0',1,1,1),(391,'und',1,28,'permissions_by_term__uid_7',1,1,1),(391,'und',1,59,'permissions_by_term__uid_1',1,1,1),(391,'und',1,59,'permissions_by_term__uid_18',1,1,1),(391,'und',1,59,'permissions_by_term__uid_4',1,1,1),(391,'und',1,59,'permissions_by_term__uid_5',1,1,1),(397,'und',1,1,'permissions_by_term__uid_6',1,1,1),(397,'und',1,2,'permissions_by_term__uid_3',1,1,1),(397,'und',1,5,'permissions_by_term__uid_0',1,0,0),(397,'und',1,7,'permissions_by_term__uid_7',1,1,1),(397,'und',1,60,'permissions_by_term__uid_1',1,1,1),(397,'und',1,60,'permissions_by_term__uid_18',1,1,1),(397,'und',1,60,'permissions_by_term__uid_4',1,1,1),(397,'und',1,60,'permissions_by_term__uid_5',1,1,1),(398,'und',1,1,'permissions_by_term__uid_6',1,1,1),(398,'und',1,2,'permissions_by_term__uid_3',1,1,1),(398,'und',1,5,'permissions_by_term__uid_0',1,0,0),(398,'und',1,7,'permissions_by_term__uid_7',1,1,1),(398,'und',1,61,'permissions_by_term__uid_1',1,1,1),(398,'und',1,61,'permissions_by_term__uid_18',1,1,1),(398,'und',1,61,'permissions_by_term__uid_4',1,1,1),(398,'und',1,61,'permissions_by_term__uid_5',1,1,1),(399,'und',1,36,'permissions_by_term__uid_6',1,1,1),(399,'und',1,37,'permissions_by_term__uid_3',1,1,1),(399,'und',1,40,'permissions_by_term__uid_0',1,1,1),(399,'und',1,42,'permissions_by_term__uid_7',1,1,1),(399,'und',1,62,'permissions_by_term__uid_1',1,1,1),(399,'und',1,62,'permissions_by_term__uid_18',1,1,1),(399,'und',1,62,'permissions_by_term__uid_4',1,1,1),(399,'und',1,62,'permissions_by_term__uid_5',1,1,1),(400,'und',1,22,'permissions_by_term__uid_6',1,1,1),(400,'und',1,23,'permissions_by_term__uid_3',1,1,1),(400,'und',1,26,'permissions_by_term__uid_0',1,1,1),(400,'und',1,28,'permissions_by_term__uid_7',1,1,1),(400,'und',1,63,'permissions_by_term__uid_1',1,1,1),(400,'und',1,63,'permissions_by_term__uid_18',1,1,1),(400,'und',1,63,'permissions_by_term__uid_4',1,1,1),(400,'und',1,63,'permissions_by_term__uid_5',1,1,1),(401,'und',1,1,'permissions_by_term__uid_6',1,1,1),(401,'und',1,2,'permissions_by_term__uid_3',1,1,1),(401,'und',1,5,'permissions_by_term__uid_0',1,0,0),(401,'und',1,7,'permissions_by_term__uid_7',1,1,1),(401,'und',1,64,'permissions_by_term__uid_1',1,1,1),(401,'und',1,64,'permissions_by_term__uid_18',1,1,1),(401,'und',1,64,'permissions_by_term__uid_4',1,1,1),(401,'und',1,64,'permissions_by_term__uid_5',1,1,1),(407,'und',1,1,'permissions_by_term__uid_6',1,1,1),(407,'und',1,2,'permissions_by_term__uid_3',1,1,1),(407,'und',1,5,'permissions_by_term__uid_0',1,0,0),(407,'und',1,7,'permissions_by_term__uid_7',1,1,1),(407,'und',1,65,'permissions_by_term__uid_1',1,1,1),(407,'und',1,65,'permissions_by_term__uid_18',1,1,1),(407,'und',1,65,'permissions_by_term__uid_4',1,1,1),(407,'und',1,65,'permissions_by_term__uid_5',1,1,1),(408,'und',1,1,'permissions_by_term__uid_6',1,1,1),(408,'und',1,2,'permissions_by_term__uid_3',1,1,1),(408,'und',1,5,'permissions_by_term__uid_0',1,0,0),(408,'und',1,7,'permissions_by_term__uid_7',1,1,1),(408,'und',1,66,'permissions_by_term__uid_1',1,1,1),(408,'und',1,66,'permissions_by_term__uid_18',1,1,1),(408,'und',1,66,'permissions_by_term__uid_4',1,1,1),(408,'und',1,66,'permissions_by_term__uid_5',1,1,1),(409,'und',1,1,'permissions_by_term__uid_6',1,1,1),(409,'und',1,2,'permissions_by_term__uid_3',1,1,1),(409,'und',1,5,'permissions_by_term__uid_0',1,0,0),(409,'und',1,7,'permissions_by_term__uid_7',1,1,1),(409,'und',1,125,'permissions_by_term__uid_5',1,1,1),(409,'und',1,127,'permissions_by_term__uid_1',1,1,1),(409,'und',1,130,'permissions_by_term__uid_18',1,1,1),(409,'und',1,130,'permissions_by_term__uid_4',1,1,1),(411,'und',1,67,'permissions_by_term__uid_1',1,1,1),(411,'und',1,67,'permissions_by_term__uid_18',1,1,1),(411,'und',1,67,'permissions_by_term__uid_4',1,1,1),(411,'und',1,67,'permissions_by_term__uid_5',1,1,1),(411,'und',1,85,'permissions_by_term__uid_6',1,1,1),(411,'und',1,86,'permissions_by_term__uid_3',1,1,1),(411,'und',1,89,'permissions_by_term__uid_0',1,1,1),(411,'und',1,91,'permissions_by_term__uid_7',1,1,1),(412,'und',1,68,'permissions_by_term__uid_1',1,1,1),(412,'und',1,68,'permissions_by_term__uid_18',1,1,1),(412,'und',1,68,'permissions_by_term__uid_4',1,1,1),(412,'und',1,68,'permissions_by_term__uid_5',1,1,1),(412,'und',1,92,'permissions_by_term__uid_6',1,1,1),(412,'und',1,93,'permissions_by_term__uid_3',1,1,1),(412,'und',1,96,'permissions_by_term__uid_0',1,1,1),(412,'und',1,98,'permissions_by_term__uid_7',1,1,1),(413,'und',1,69,'permissions_by_term__uid_1',1,1,1),(413,'und',1,69,'permissions_by_term__uid_18',1,1,1),(413,'und',1,69,'permissions_by_term__uid_4',1,1,1),(413,'und',1,69,'permissions_by_term__uid_5',1,1,1),(413,'und',1,99,'permissions_by_term__uid_6',1,1,1),(413,'und',1,100,'permissions_by_term__uid_3',1,1,1),(413,'und',1,103,'permissions_by_term__uid_0',1,1,1),(413,'und',1,105,'permissions_by_term__uid_7',1,1,1),(414,'und',1,1,'permissions_by_term__uid_6',1,1,1),(414,'und',1,2,'permissions_by_term__uid_3',1,1,1),(414,'und',1,5,'permissions_by_term__uid_0',1,0,0),(414,'und',1,7,'permissions_by_term__uid_7',1,1,1),(414,'und',1,70,'permissions_by_term__uid_1',1,1,1),(414,'und',1,70,'permissions_by_term__uid_18',1,1,1),(414,'und',1,70,'permissions_by_term__uid_4',1,1,1),(414,'und',1,70,'permissions_by_term__uid_5',1,1,1),(415,'und',1,1,'permissions_by_term__uid_6',1,1,1),(415,'und',1,2,'permissions_by_term__uid_3',1,1,1),(415,'und',1,5,'permissions_by_term__uid_0',1,0,0),(415,'und',1,7,'permissions_by_term__uid_7',1,1,1),(415,'und',1,71,'permissions_by_term__uid_1',1,1,1),(415,'und',1,71,'permissions_by_term__uid_18',1,1,1),(415,'und',1,71,'permissions_by_term__uid_4',1,1,1),(415,'und',1,71,'permissions_by_term__uid_5',1,1,1),(416,'und',1,1,'permissions_by_term__uid_6',1,1,1),(416,'und',1,2,'permissions_by_term__uid_3',1,1,1),(416,'und',1,5,'permissions_by_term__uid_0',1,0,0),(416,'und',1,7,'permissions_by_term__uid_7',1,1,1),(416,'und',1,72,'permissions_by_term__uid_1',1,1,1),(416,'und',1,72,'permissions_by_term__uid_18',1,1,1),(416,'und',1,72,'permissions_by_term__uid_4',1,1,1),(416,'und',1,72,'permissions_by_term__uid_5',1,1,1),(417,'und',1,1,'permissions_by_term__uid_6',1,1,1),(417,'und',1,2,'permissions_by_term__uid_3',1,1,1),(417,'und',1,5,'permissions_by_term__uid_0',1,0,0),(417,'und',1,7,'permissions_by_term__uid_7',1,1,1),(417,'und',1,73,'permissions_by_term__uid_1',1,1,1),(417,'und',1,73,'permissions_by_term__uid_18',1,1,1),(417,'und',1,73,'permissions_by_term__uid_4',1,1,1),(417,'und',1,73,'permissions_by_term__uid_5',1,1,1),(418,'und',1,1,'permissions_by_term__uid_6',1,1,1),(418,'und',1,2,'permissions_by_term__uid_3',1,1,1),(418,'und',1,5,'permissions_by_term__uid_0',1,0,0),(418,'und',1,7,'permissions_by_term__uid_7',1,1,1),(418,'und',1,74,'permissions_by_term__uid_1',1,1,1),(418,'und',1,74,'permissions_by_term__uid_18',1,1,1),(418,'und',1,74,'permissions_by_term__uid_4',1,1,1),(418,'und',1,74,'permissions_by_term__uid_5',1,1,1),(420,'und',1,1,'permissions_by_term__uid_6',1,1,1),(420,'und',1,2,'permissions_by_term__uid_3',1,1,1),(420,'und',1,5,'permissions_by_term__uid_0',1,0,0),(420,'und',1,7,'permissions_by_term__uid_7',1,1,1),(420,'und',1,116,'permissions_by_term__uid_5',1,1,1),(420,'und',1,117,'permissions_by_term__uid_1',1,1,1),(420,'und',1,118,'permissions_by_term__uid_18',1,1,1),(420,'und',1,118,'permissions_by_term__uid_4',1,1,1),(426,'und',1,1,'permissions_by_term__uid_6',1,1,1),(426,'und',1,2,'permissions_by_term__uid_3',1,1,1),(426,'und',1,5,'permissions_by_term__uid_0',1,0,0),(426,'und',1,7,'permissions_by_term__uid_7',1,1,1),(426,'und',1,75,'permissions_by_term__uid_1',1,1,1),(426,'und',1,75,'permissions_by_term__uid_18',1,1,1),(426,'und',1,75,'permissions_by_term__uid_4',1,1,1),(426,'und',1,75,'permissions_by_term__uid_5',1,1,1),(427,'und',1,1,'permissions_by_term__uid_6',1,1,1),(427,'und',1,2,'permissions_by_term__uid_3',1,1,1),(427,'und',1,5,'permissions_by_term__uid_0',1,0,0),(427,'und',1,7,'permissions_by_term__uid_7',1,1,1),(427,'und',1,76,'permissions_by_term__uid_1',1,1,1),(427,'und',1,76,'permissions_by_term__uid_18',1,1,1),(427,'und',1,76,'permissions_by_term__uid_4',1,1,1),(427,'und',1,76,'permissions_by_term__uid_5',1,1,1),(428,'und',1,1,'permissions_by_term__uid_6',1,1,1),(428,'und',1,2,'permissions_by_term__uid_3',1,1,1),(428,'und',1,5,'permissions_by_term__uid_0',1,0,0),(428,'und',1,7,'permissions_by_term__uid_7',1,1,1),(428,'und',1,77,'permissions_by_term__uid_1',1,1,1),(428,'und',1,77,'permissions_by_term__uid_18',1,1,1),(428,'und',1,77,'permissions_by_term__uid_4',1,1,1),(428,'und',1,77,'permissions_by_term__uid_5',1,1,1),(430,'und',1,29,'permissions_by_term__uid_6',1,1,1),(430,'und',1,30,'permissions_by_term__uid_3',1,1,1),(430,'und',1,33,'permissions_by_term__uid_0',1,1,1),(430,'und',1,35,'permissions_by_term__uid_7',1,1,1),(430,'und',1,78,'permissions_by_term__uid_1',1,1,1),(430,'und',1,78,'permissions_by_term__uid_18',1,1,1),(430,'und',1,78,'permissions_by_term__uid_4',1,1,1),(430,'und',1,78,'permissions_by_term__uid_5',1,1,1),(431,'und',1,36,'permissions_by_term__uid_6',1,1,1),(431,'und',1,37,'permissions_by_term__uid_3',1,1,1),(431,'und',1,40,'permissions_by_term__uid_0',1,1,1),(431,'und',1,42,'permissions_by_term__uid_7',1,1,1),(431,'und',1,79,'permissions_by_term__uid_1',1,1,1),(431,'und',1,79,'permissions_by_term__uid_18',1,1,1),(431,'und',1,79,'permissions_by_term__uid_4',1,1,1),(431,'und',1,79,'permissions_by_term__uid_5',1,1,1),(432,'und',1,43,'permissions_by_term__uid_6',1,1,1),(432,'und',1,44,'permissions_by_term__uid_3',1,1,1),(432,'und',1,47,'permissions_by_term__uid_0',1,1,1),(432,'und',1,49,'permissions_by_term__uid_7',1,1,1),(432,'und',1,80,'permissions_by_term__uid_1',1,1,1),(432,'und',1,80,'permissions_by_term__uid_18',1,1,1),(432,'und',1,80,'permissions_by_term__uid_4',1,1,1),(432,'und',1,80,'permissions_by_term__uid_5',1,1,1),(433,'und',1,50,'permissions_by_term__uid_6',1,1,1),(433,'und',1,51,'permissions_by_term__uid_3',1,1,1),(433,'und',1,54,'permissions_by_term__uid_0',1,1,1),(433,'und',1,56,'permissions_by_term__uid_7',1,1,1),(433,'und',1,81,'permissions_by_term__uid_1',1,1,1),(433,'und',1,81,'permissions_by_term__uid_18',1,1,1),(433,'und',1,81,'permissions_by_term__uid_4',1,1,1),(433,'und',1,81,'permissions_by_term__uid_5',1,1,1),(434,'und',1,57,'permissions_by_term__uid_6',1,1,1),(434,'und',1,58,'permissions_by_term__uid_3',1,1,1),(434,'und',1,61,'permissions_by_term__uid_0',1,1,1),(434,'und',1,63,'permissions_by_term__uid_7',1,1,1),(434,'und',1,82,'permissions_by_term__uid_1',1,1,1),(434,'und',1,82,'permissions_by_term__uid_18',1,1,1),(434,'und',1,82,'permissions_by_term__uid_4',1,1,1),(434,'und',1,82,'permissions_by_term__uid_5',1,1,1),(435,'und',1,64,'permissions_by_term__uid_6',1,1,1),(435,'und',1,65,'permissions_by_term__uid_3',1,1,1),(435,'und',1,68,'permissions_by_term__uid_0',1,1,1),(435,'und',1,70,'permissions_by_term__uid_7',1,1,1),(435,'und',1,83,'permissions_by_term__uid_1',1,1,1),(435,'und',1,83,'permissions_by_term__uid_18',1,1,1),(435,'und',1,83,'permissions_by_term__uid_4',1,1,1),(435,'und',1,83,'permissions_by_term__uid_5',1,1,1),(436,'und',1,71,'permissions_by_term__uid_6',1,1,1),(436,'und',1,72,'permissions_by_term__uid_3',1,1,1),(436,'und',1,75,'permissions_by_term__uid_0',1,1,1),(436,'und',1,77,'permissions_by_term__uid_7',1,1,1),(436,'und',1,84,'permissions_by_term__uid_1',1,1,1),(436,'und',1,84,'permissions_by_term__uid_18',1,1,1),(436,'und',1,84,'permissions_by_term__uid_4',1,1,1),(436,'und',1,84,'permissions_by_term__uid_5',1,1,1),(448,'und',1,1,'permissions_by_term__uid_6',1,1,1),(448,'und',1,2,'permissions_by_term__uid_3',1,1,1),(448,'und',1,5,'permissions_by_term__uid_0',1,0,0),(448,'und',1,7,'permissions_by_term__uid_7',1,1,1),(448,'und',1,112,'permissions_by_term__uid_5',1,1,1),(448,'und',1,113,'permissions_by_term__uid_1',1,1,1),(448,'und',1,114,'permissions_by_term__uid_18',1,1,1),(448,'und',1,114,'permissions_by_term__uid_4',1,1,1),(451,'und',1,1,'permissions_by_term__uid_6',1,1,1),(451,'und',1,2,'permissions_by_term__uid_3',1,1,1),(451,'und',1,5,'permissions_by_term__uid_0',1,0,0),(451,'und',1,7,'permissions_by_term__uid_7',1,1,1),(451,'und',1,126,'permissions_by_term__uid_5',1,1,1),(451,'und',1,128,'permissions_by_term__uid_1',1,1,1),(451,'und',1,131,'permissions_by_term__uid_18',1,1,1),(451,'und',1,131,'permissions_by_term__uid_4',1,1,1),(452,'und',1,1,'permissions_by_term__uid_6',1,1,1),(452,'und',1,2,'permissions_by_term__uid_3',1,1,1),(452,'und',1,5,'permissions_by_term__uid_0',1,0,0),(452,'und',1,7,'permissions_by_term__uid_7',1,1,1),(452,'und',1,85,'permissions_by_term__uid_1',1,1,1),(452,'und',1,85,'permissions_by_term__uid_18',1,1,1),(452,'und',1,85,'permissions_by_term__uid_4',1,1,1),(452,'und',1,85,'permissions_by_term__uid_5',1,1,1),(453,'und',1,1,'permissions_by_term__uid_6',1,1,1),(453,'und',1,2,'permissions_by_term__uid_3',1,1,1),(453,'und',1,5,'permissions_by_term__uid_0',1,0,0),(453,'und',1,7,'permissions_by_term__uid_7',1,1,1),(453,'und',1,117,'permissions_by_term__uid_5',1,1,1),(453,'und',1,118,'permissions_by_term__uid_1',1,1,1),(453,'und',1,119,'permissions_by_term__uid_18',1,1,1),(453,'und',1,119,'permissions_by_term__uid_4',1,1,1),(454,'und',1,1,'permissions_by_term__uid_6',1,1,1),(454,'und',1,2,'permissions_by_term__uid_3',1,1,1),(454,'und',1,5,'permissions_by_term__uid_0',1,0,0),(454,'und',1,7,'permissions_by_term__uid_7',1,1,1),(454,'und',1,118,'permissions_by_term__uid_5',1,1,1),(454,'und',1,119,'permissions_by_term__uid_1',1,1,1),(454,'und',1,120,'permissions_by_term__uid_18',1,1,1),(454,'und',1,120,'permissions_by_term__uid_4',1,1,1),(455,'und',1,1,'permissions_by_term__uid_6',1,1,1),(455,'und',1,2,'permissions_by_term__uid_3',1,1,1),(455,'und',1,5,'permissions_by_term__uid_0',1,0,0),(455,'und',1,7,'permissions_by_term__uid_7',1,1,1),(455,'und',1,119,'permissions_by_term__uid_5',1,1,1),(455,'und',1,120,'permissions_by_term__uid_1',1,1,1),(455,'und',1,121,'permissions_by_term__uid_18',1,1,1),(455,'und',1,121,'permissions_by_term__uid_4',1,1,1),(456,'und',1,1,'permissions_by_term__uid_6',1,1,1),(456,'und',1,2,'permissions_by_term__uid_3',1,1,1),(456,'und',1,5,'permissions_by_term__uid_0',1,0,0),(456,'und',1,7,'permissions_by_term__uid_7',1,1,1),(456,'und',1,87,'permissions_by_term__uid_1',1,1,1),(456,'und',1,87,'permissions_by_term__uid_18',1,1,1),(456,'und',1,87,'permissions_by_term__uid_4',1,1,1),(456,'und',1,87,'permissions_by_term__uid_5',1,1,1),(457,'und',1,1,'permissions_by_term__uid_6',1,1,1),(457,'und',1,2,'permissions_by_term__uid_3',1,1,1),(457,'und',1,5,'permissions_by_term__uid_0',1,0,0),(457,'und',1,7,'permissions_by_term__uid_7',1,1,1),(457,'und',1,88,'permissions_by_term__uid_1',1,1,1),(457,'und',1,88,'permissions_by_term__uid_18',1,1,1),(457,'und',1,88,'permissions_by_term__uid_4',1,1,1),(457,'und',1,88,'permissions_by_term__uid_5',1,1,1),(458,'und',1,1,'permissions_by_term__uid_6',1,1,1),(458,'und',1,2,'permissions_by_term__uid_3',1,1,1),(458,'und',1,5,'permissions_by_term__uid_0',1,0,0),(458,'und',1,7,'permissions_by_term__uid_7',1,1,1),(458,'und',1,89,'permissions_by_term__uid_1',1,1,1),(458,'und',1,89,'permissions_by_term__uid_18',1,1,1),(458,'und',1,89,'permissions_by_term__uid_4',1,1,1),(458,'und',1,89,'permissions_by_term__uid_5',1,1,1),(459,'und',1,1,'permissions_by_term__uid_6',1,1,1),(459,'und',1,2,'permissions_by_term__uid_3',1,1,1),(459,'und',1,5,'permissions_by_term__uid_0',1,0,0),(459,'und',1,7,'permissions_by_term__uid_7',1,1,1),(459,'und',1,90,'permissions_by_term__uid_1',1,1,1),(459,'und',1,90,'permissions_by_term__uid_18',1,1,1),(459,'und',1,90,'permissions_by_term__uid_4',1,1,1),(459,'und',1,90,'permissions_by_term__uid_5',1,1,1),(460,'und',1,1,'permissions_by_term__uid_6',1,1,1),(460,'und',1,2,'permissions_by_term__uid_3',1,1,1),(460,'und',1,5,'permissions_by_term__uid_0',1,0,0),(460,'und',1,7,'permissions_by_term__uid_7',1,1,1),(460,'und',1,91,'permissions_by_term__uid_1',1,1,1),(460,'und',1,91,'permissions_by_term__uid_18',1,1,1),(460,'und',1,91,'permissions_by_term__uid_4',1,1,1),(460,'und',1,91,'permissions_by_term__uid_5',1,1,1),(461,'und',1,1,'permissions_by_term__uid_6',1,1,1),(461,'und',1,2,'permissions_by_term__uid_3',1,1,1),(461,'und',1,5,'permissions_by_term__uid_0',1,0,0),(461,'und',1,7,'permissions_by_term__uid_7',1,1,1),(461,'und',1,113,'permissions_by_term__uid_5',1,1,1),(461,'und',1,114,'permissions_by_term__uid_1',1,1,1),(461,'und',1,115,'permissions_by_term__uid_18',1,1,1),(461,'und',1,115,'permissions_by_term__uid_4',1,1,1),(462,'und',1,1,'permissions_by_term__uid_6',1,1,1),(462,'und',1,2,'permissions_by_term__uid_3',1,1,1),(462,'und',1,5,'permissions_by_term__uid_0',1,0,0),(462,'und',1,7,'permissions_by_term__uid_7',1,1,1),(462,'und',1,114,'permissions_by_term__uid_5',1,1,1),(462,'und',1,115,'permissions_by_term__uid_1',1,1,1),(462,'und',1,116,'permissions_by_term__uid_18',1,1,1),(462,'und',1,116,'permissions_by_term__uid_4',1,1,1),(466,'und',1,1,'permissions_by_term__uid_18',1,1,1),(466,'und',1,2,'permissions_by_term__uid_6',1,1,1),(466,'und',1,3,'permissions_by_term__uid_3',1,1,1),(466,'und',1,4,'permissions_by_term__uid_1',1,1,1),(466,'und',1,5,'permissions_by_term__uid_4',1,1,1),(466,'und',1,6,'permissions_by_term__uid_0',1,0,0),(466,'und',1,8,'permissions_by_term__uid_7',1,1,1),(466,'und',1,131,'permissions_by_term__uid_5',1,1,1),(479,'und',1,1,'permissions_by_term__uid_6',1,1,1),(479,'und',1,2,'permissions_by_term__uid_3',1,1,1),(479,'und',1,5,'permissions_by_term__uid_0',1,0,0),(479,'und',1,7,'permissions_by_term__uid_7',1,1,1),(479,'und',1,115,'permissions_by_term__uid_5',1,1,1),(479,'und',1,116,'permissions_by_term__uid_1',1,1,1),(479,'und',1,117,'permissions_by_term__uid_18',1,1,1),(479,'und',1,117,'permissions_by_term__uid_4',1,1,1),(481,'en',1,1,'permissions_by_term__uid_18',1,1,1),(481,'en',1,2,'permissions_by_term__uid_6',1,1,1),(481,'en',1,3,'permissions_by_term__uid_3',1,1,1),(481,'en',1,5,'permissions_by_term__uid_4',1,1,1),(481,'en',1,7,'permissions_by_term__uid_7',1,1,1),(481,'en',1,127,'permissions_by_term__uid_5',1,1,1),(481,'en',1,129,'permissions_by_term__uid_1',1,1,1),(487,'en',1,1,'permissions_by_term__uid_18',1,1,1),(487,'en',1,2,'permissions_by_term__uid_6',1,1,1),(487,'en',1,3,'permissions_by_term__uid_3',1,1,1),(487,'en',1,4,'permissions_by_term__uid_1',1,1,1),(487,'en',1,5,'permissions_by_term__uid_4',1,1,1),(487,'en',1,6,'permissions_by_term__uid_0',1,0,0),(487,'en',1,8,'permissions_by_term__uid_7',1,1,1),(487,'en',1,130,'permissions_by_term__uid_5',1,1,1),(488,'en',1,57,'permissions_by_term__uid_6',1,1,1),(488,'en',1,58,'permissions_by_term__uid_3',1,1,1),(488,'en',1,61,'permissions_by_term__uid_0',1,1,1),(488,'en',1,63,'permissions_by_term__uid_7',1,1,1),(488,'en',1,92,'permissions_by_term__uid_1',1,1,1),(488,'en',1,92,'permissions_by_term__uid_18',1,1,1),(488,'en',1,92,'permissions_by_term__uid_4',1,1,1),(488,'en',1,92,'permissions_by_term__uid_5',1,1,1),(489,'en',1,64,'permissions_by_term__uid_6',1,1,1),(489,'en',1,65,'permissions_by_term__uid_3',1,1,1),(489,'en',1,68,'permissions_by_term__uid_0',1,1,1),(489,'en',1,70,'permissions_by_term__uid_7',1,1,1),(489,'en',1,93,'permissions_by_term__uid_1',1,1,1),(489,'en',1,93,'permissions_by_term__uid_18',1,1,1),(489,'en',1,93,'permissions_by_term__uid_4',1,1,1),(489,'en',1,93,'permissions_by_term__uid_5',1,1,1),(497,'en',1,1,'permissions_by_term__uid_6',1,1,1),(497,'en',1,2,'permissions_by_term__uid_3',1,1,1),(497,'en',1,5,'permissions_by_term__uid_0',1,0,0),(497,'en',1,7,'permissions_by_term__uid_7',1,1,1),(497,'en',1,100,'permissions_by_term__uid_1',1,1,1),(497,'en',1,100,'permissions_by_term__uid_5',1,1,1),(497,'en',1,101,'permissions_by_term__uid_18',1,1,1),(497,'en',1,101,'permissions_by_term__uid_4',1,1,1),(498,'en',1,1,'permissions_by_term__uid_6',1,1,1),(498,'en',1,2,'permissions_by_term__uid_3',1,1,1),(498,'en',1,5,'permissions_by_term__uid_0',1,0,0),(498,'en',1,7,'permissions_by_term__uid_7',1,1,1),(498,'en',1,8,'permissions_by_term__uid_6',1,1,1),(498,'en',1,9,'permissions_by_term__uid_3',1,1,1),(498,'en',1,12,'permissions_by_term__uid_0',1,1,1),(498,'en',1,14,'permissions_by_term__uid_7',1,1,1),(498,'en',1,121,'permissions_by_term__uid_5',1,1,1),(498,'en',1,123,'permissions_by_term__uid_1',1,1,1),(498,'en',1,124,'permissions_by_term__uid_18',1,1,1),(498,'en',1,124,'permissions_by_term__uid_4',1,1,1),(499,'en',1,1,'permissions_by_term__uid_6',1,1,1),(499,'en',1,2,'permissions_by_term__uid_3',1,1,1),(499,'en',1,5,'permissions_by_term__uid_0',1,0,0),(499,'en',1,7,'permissions_by_term__uid_7',1,1,1),(499,'en',1,8,'permissions_by_term__uid_6',1,1,1),(499,'en',1,9,'permissions_by_term__uid_3',1,1,1),(499,'en',1,12,'permissions_by_term__uid_0',1,1,1),(499,'en',1,14,'permissions_by_term__uid_7',1,1,1),(499,'en',1,122,'permissions_by_term__uid_5',1,1,1),(499,'en',1,124,'permissions_by_term__uid_1',1,1,1),(499,'en',1,125,'permissions_by_term__uid_18',1,1,1),(499,'en',1,125,'permissions_by_term__uid_4',1,1,1),(501,'en',1,1,'permissions_by_term__uid_18',1,1,1),(501,'en',1,2,'permissions_by_term__uid_6',1,1,1),(501,'en',1,3,'permissions_by_term__uid_3',1,1,1),(501,'en',1,5,'permissions_by_term__uid_4',1,1,1),(501,'en',1,6,'permissions_by_term__uid_0',1,0,0),(501,'en',1,8,'permissions_by_term__uid_7',1,1,1),(501,'en',1,9,'permissions_by_term__uid_18',1,1,1),(501,'en',1,10,'permissions_by_term__uid_6',1,1,1),(501,'en',1,11,'permissions_by_term__uid_3',1,1,1),(501,'en',1,13,'permissions_by_term__uid_4',1,1,1),(501,'en',1,14,'permissions_by_term__uid_0',1,1,1),(501,'en',1,16,'permissions_by_term__uid_7',1,1,1),(501,'en',1,129,'permissions_by_term__uid_5',1,1,1),(501,'en',1,133,'permissions_by_term__uid_1',1,1,1),(502,'en',1,1,'permissions_by_term__uid_18',1,1,1),(502,'en',1,2,'permissions_by_term__uid_6',1,1,1),(502,'en',1,3,'permissions_by_term__uid_3',1,1,1),(502,'en',1,4,'permissions_by_term__uid_1',1,1,1),(502,'en',1,5,'permissions_by_term__uid_4',1,1,1),(502,'en',1,6,'permissions_by_term__uid_0',1,0,0),(502,'en',1,7,'permissions_by_term__uid_5',1,1,1),(502,'en',1,8,'permissions_by_term__uid_7',1,1,1),(502,'en',1,9,'permissions_by_term__uid_18',1,1,1),(502,'en',1,10,'permissions_by_term__uid_6',1,1,1),(502,'en',1,11,'permissions_by_term__uid_3',1,1,1),(502,'en',1,12,'permissions_by_term__uid_1',1,1,1),(502,'en',1,13,'permissions_by_term__uid_4',1,1,1),(502,'en',1,14,'permissions_by_term__uid_0',1,1,1),(502,'en',1,15,'permissions_by_term__uid_5',1,1,1),(502,'en',1,16,'permissions_by_term__uid_7',1,1,1),(503,'en',1,1,'permissions_by_term__uid_18',1,1,1),(503,'en',1,2,'permissions_by_term__uid_6',1,1,1),(503,'en',1,3,'permissions_by_term__uid_3',1,1,1),(503,'en',1,4,'permissions_by_term__uid_1',1,1,1),(503,'en',1,5,'permissions_by_term__uid_4',1,1,1),(503,'en',1,6,'permissions_by_term__uid_0',1,0,0),(503,'en',1,7,'permissions_by_term__uid_5',1,1,1),(503,'en',1,8,'permissions_by_term__uid_7',1,1,1);
commit;

--
-- Table structure for table `node_field_data`
--

CREATE TABLE `node_field_data` (
  `nid` int(10) unsigned NOT NULL,
  `vid` int(10) unsigned NOT NULL,
  `type` varchar(32) CHARACTER SET ascii NOT NULL COMMENT 'The ID of the target entity.',
  `langcode` varchar(12) CHARACTER SET ascii NOT NULL,
  `title` varchar(255) NOT NULL,
  `uid` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
  `status` tinyint(4) NOT NULL,
  `created` int(11) NOT NULL,
  `changed` int(11) NOT NULL,
  `promote` tinyint(4) NOT NULL,
  `sticky` tinyint(4) NOT NULL,
  `revision_translation_affected` tinyint(4) DEFAULT NULL,
  `default_langcode` tinyint(4) NOT NULL,
  PRIMARY KEY (`nid`,`langcode`),
  KEY `node__id__default_langcode__langcode` (`nid`,`default_langcode`,`langcode`),
  KEY `node__vid` (`vid`),
  KEY `node_field__type__target_id` (`type`),
  KEY `node_field__uid__target_id` (`uid`),
  KEY `node_field__created` (`created`),
  KEY `node_field__changed` (`changed`),
  KEY `node__frontpage` (`promote`,`status`,`sticky`,`created`),
  KEY `node__status_type` (`status`,`type`,`nid`),
  KEY `node__title_type` (`title`(191),`type`(4))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='The data table for node entities.';

--
-- Dumping data for table `node_field_data`
--

set autocommit=0;
INSERT INTO `node_field_data` VALUES (31,645,'page','und','Legal',1,1,1116797232,1504708684,0,0,1,1),(32,633,'page','und','Yaffs Licence Sample',1,1,1116799730,1498730566,0,0,1,1),(37,570,'page','und','Yaffs Original Specification',1,1,1116847901,1496361508,0,1,1,1),(38,571,'page','und','Yaffs 2 Specification',3,1,1116848038,1496365861,0,1,1,1),(39,572,'page','und','Yaffs (Yaffs1) Development Notes',1,1,1116848206,1496365925,0,1,1,1),(40,551,'page','und','HOWTO incorporate YAFFS in Linux',1,1,1116848477,1495718291,0,1,1,1),(41,567,'page','und','JFFS2 and NAND study',4,1,1149597275,1496142831,0,0,NULL,1),(42,573,'page','und','State of NAND MTD driver at start of project',1,1,1116849036,1496365989,0,0,1,1),(43,553,'page','und','Yaffs History',1,1,1116849117,1495718333,0,0,NULL,1),(44,44,'page','und','YAFFS and ARM Linux support',1,0,1116849266,1363089692,0,0,1,1),(61,556,'page','und','(Anti) Software patents talk - 2003',1,0,1116857946,1495718447,0,0,NULL,1),(62,557,'page','und','Updated software patents talk',1,0,1116858148,1495718474,0,0,1,1),(73,73,'page','und','Contact',1,1,1119480717,1453818953,0,0,1,1),(77,473,'book','und','YAFFS talk - slides from a presentation to FOSDEM in 2004',1,1,1120658663,1344432401,0,0,1,1),(79,79,'book','und','YAFFS talk - Slide 1 - Title',1,1,1120670265,1129598505,1,0,1,1),(110,110,'book','und','YAFFS talk - Slide 2 - Intro',1,1,1120696310,1183480423,1,0,1,1),(111,111,'book','und','YAFFS talk - Slide 3 - Project Genesis',1,1,1120696839,1129598559,1,0,1,1),(112,112,'book','und','YAFFS talk - Slide 4 - History',1,1,1120696981,1129598581,1,0,1,1),(113,113,'book','und','YAFFS talk - Slide 5 - Flash Primer',1,1,1120697241,1129598601,1,0,1,1),(114,114,'book','und','YAFFS talk - Slide 6 - Design Approach',1,1,1120697383,1129598623,1,0,1,1),(115,115,'book','und','YAFFS talk - Slide 7 - Architecture',1,1,1120697463,1129598643,1,0,1,1),(116,116,'book','und','YAFFS talk - Slide 8 - Terminology',1,1,1120697602,1129598662,1,0,1,1),(117,117,'book','und','YAFFS talk - Slide 9 - Filesystem Design',1,1,1120697747,1129598687,1,0,1,1),(118,118,'book','und','YAFFS talk - Slide 10 - Filesystem Limits',1,1,1120697827,1129598707,1,0,1,1),(119,119,'book','und','YAFFS talk - Slide 11 - OOB Data',1,1,1120697966,1129598726,1,0,1,1),(120,120,'book','und','YAFFS talk - Slide 12 - Filesystem Data Structures',1,1,1120698103,1129600003,1,0,1,1),(121,121,'book','und','YAFFS talk - Slide 13 - Filesystem RAM Data Structures',1,1,1120698346,1129600486,1,0,1,1),(122,122,'book','und','YAFFS talk - Slide 14 - Partitioning',1,1,1120698522,1129598802,1,0,1,1),(123,123,'book','und','YAFFS talk - Slide 15 - Garbage Collection and Threads',1,1,1120698585,1129598865,1,0,1,1),(124,124,'book','und','YAFFS talk - Slide 16 - ECC',1,1,1120698601,1129598881,1,0,1,1),(125,125,'book','und','YAFFS talk - Slide 17 - OS Portability',1,1,1120698682,1129598902,1,0,1,1),(126,126,'book','und','YAFFS talk - Slide 18 - YAFFS in Use',1,1,1120698822,1129598922,1,0,1,1),(127,127,'book','und','YAFFS talk - Slide 19 - Embedded System Use',1,1,1120738864,1129598944,1,0,1,1),(128,128,'book','und','YAFFS talk - Slide 20 - Embedded System Use',1,1,1120738968,1129599348,1,0,1,1),(129,129,'book','und','YAFFS talk - Slide 21 - Embedded System Use',1,1,1120739424,1129599324,1,0,1,1),(130,130,'book','und','YAFFS talk - Slide 22 - Embedded System Use',1,1,1120739494,1129599394,1,0,1,1),(131,131,'book','und','YAFFS talk - Slide 23 - Performance - Examples',1,1,1120739612,1129600892,1,0,1,1),(132,132,'book','und','YAFFS talk - Slide 24 - Performance - Caching',1,1,1120739653,1129599433,1,0,1,1),(133,133,'book','und','YAFFS talk - Slide 25 - JFFS2 and YAFFS Comparison',1,1,1120739718,1129600938,1,0,1,1),(134,134,'book','und','YAFFS talk - Slide 26 - Licensing',1,1,1120739796,1129601016,1,0,1,1),(135,135,'book','und','YAFFS talk - Slide 27 - YAFFS2',1,1,1120739859,1129599459,1,0,1,1),(136,136,'book','und','YAFFS talk - Slide 28 - YAFFS2 Comparison with YAFFS1',1,1,1120739973,1129601074,1,0,1,1),(137,137,'book','und','YAFFS talk - Slide 29 - Fin',1,1,1120740127,1129599487,1,0,1,1),(169,169,'book','und','Emdebsys talk - Slide 1 - Title',1,1,1129736238,1129736718,1,0,1,1),(196,196,'book','und','ARM-Linux talk - Slide 1 - Title',1,1,1129764462,1129764702,1,0,1,1),(265,265,'book','und','Creating a Filesystem on your Compact Flash',1,0,1131733983,1131744243,1,0,1,1),(271,271,'book','und','JTAG and Jflash-linux',1,0,1131734397,1131734397,1,0,1,1),(274,274,'book','und','Compiling a Kernel',1,0,1131734493,1131734553,1,0,1,1),(285,285,'book','und','The Filesystem',1,0,1131735111,1131745131,1,0,1,1),(323,323,'page','und','Maps',1,1,1132679889,1339888362,1,0,1,1),(325,325,'page','und','About us',1,1,1133366647,1347895942,1,0,1,1),(342,574,'page','und','FUEL Embedded Database for use with YAFFS',4,1,1138703943,1496397622,0,0,1,1),(344,576,'page','und','Yaffs Overview',3,1,1151544621,1496397858,0,1,1,1),(345,619,'page','und','Yaffs - GPL Licence',4,1,1152534903,1497348780,0,0,1,1),(347,347,'book','und','YAFFS: the NAND-specific flash file system - Introductory Article',3,1,1153919492,1495718512,1,1,1,1),(348,348,'book','und','Yaffs1 memory footprint',3,1,1153925836,1495718524,1,0,1,1),(351,351,'page','und','YAFFS Debugging',3,1,1158355933,1201700928,1,1,1,1),(353,577,'page','und','Yaffs Licence FAQs',4,1,1179420859,1496398001,1,0,1,1),(357,578,'article','und','Yaffs - A Flash File System For Embedded Use',1,1,1183194112,1496398070,0,0,1,1),(358,544,'article','und','The Internal History of YAFFS',1,1,1183224534,1495717209,1,0,1,1),(359,579,'article','und','Comparison between Yaffs (Yaffs2) and JFFS2',1,1,1183329435,1496398143,1,0,1,1),(360,580,'article','und','Paper investigating a log management & crash recovery mechanism',1,1,1183375135,1496398229,0,0,1,1),(363,364,'image','und','The Old Courthouse',1,1,1192033311,1192033311,0,0,1,1),(365,366,'page','und','Paying us',4,1,1197995334,1197995334,0,0,1,1),(366,367,'image','und','YAFFS embedded structure',1,1,1198150224,1198177808,1,0,1,1),(367,610,'page','und','Yaffs Talk - PDF of slides from CELF, 2007',1,1,1201746081,1496924893,0,0,1,1),(368,369,'book','und','IDEAS List',4,1,1204732266,1205289965,1,0,1,1),(369,582,'page','und','Yaffs Porting Guide',5,1,1240841747,1496398411,0,0,1,1),(370,371,'image','und','yaffs_porting_guide_html_2de490f8.png',5,1,1244212305,1244212473,1,0,1,1),(371,372,'image','und','yaffs_porting_guide_html_m11b1f893.png',5,1,1244212305,1244214689,1,0,1,1),(372,373,'image','und','yaffs_porting_guide_html_m4650262f.png',5,1,1244212305,1244214744,1,0,1,1),(374,375,'image','und','YAFFS Tnode tree',1,1,1263783089,1263783268,1,0,1,1),(376,377,'image','und','YAFFS - directory structure example',1,1,1263783335,1263783445,1,0,1,1),(377,378,'image','und','YAFFS - Block states',1,1,1263783506,1263783571,1,0,1,1),(380,381,'page','und','Support',1,1,1330383366,1441709157,0,0,1,1),(382,639,'page','und','Get Yaffs',1,1,1330444044,1502716247,0,0,1,1),(384,385,'what_is_special_about_yaffs','und','Royalty Free... ',1,1,1330455802,1498518115,1,0,1,1),(385,386,'what_is_special_about_yaffs','und','A robust flash file system...',1,1,1330456244,1496412025,1,0,1,1),(388,389,'what_is_special_about_yaffs','und','Yaffs is Open Source...',1,1,1330467790,1496401931,1,0,1,1),(389,390,'what_is_special_about_yaffs','und','Tried and tested in millions of devices...',1,1,1330468194,1496407203,1,0,1,1),(390,391,'image','und','Get YAFFS now',1,1,1330473626,1330473626,0,0,1,1),(391,392,'image','und','Get YAFFS now',1,1,1330522429,1330522429,0,0,1,1),(397,398,'yaffs_user_logo','und','Design Electronics',1,1,1336589997,1496412075,0,0,1,1),(398,399,'yaffs_user_logo','und','Eaton',1,1,1336605810,1496412157,0,0,1,1),(399,400,'yaffs_user_logo','und','LANCOM Sytems',1,1,1336605955,1494601211,0,0,1,1),(400,401,'yaffs_user_logo','und','Bernina',1,1,1336606047,1494601697,0,0,1,1),(401,402,'yaffs_user_logo','und','Gallagher',1,1,1336606102,1496412218,0,0,1,1),(407,408,'what_is_special_about_yaffs','und','Booting is fast...',1,1,1338515490,1496402093,1,0,1,1),(408,409,'what_is_special_about_yaffs','und','An active community...',1,1,1338515545,1496402147,1,0,1,1),(409,627,'paper','und','How Yaffs works',6,1,1338593328,1498530801,1,0,1,1),(411,412,'image','und','HowYaffsWorks_directories_0.gif',1,1,1338949299,1338949299,0,0,1,1),(412,413,'image','und','HowYaffsWorks_tnode_tree_0.gif',1,1,1338949356,1338949356,0,0,1,1),(413,414,'image','und','HowYaffsWorks_block_states_0.gif',1,1,1338949403,1338949403,0,0,1,1),(414,415,'what_is_special_about_yaffs','und','Suitable for open and closed source projects...',1,1,1339010643,1496402329,1,0,1,1),(415,416,'what_is_special_about_yaffs','und','For closed source projects - try before you buy...',1,1,1339066508,1496402417,1,0,1,1),(416,417,'what_is_special_about_yaffs','und','Yaffs is a safe choice...',1,1,1339071522,1496402459,1,0,1,1),(417,418,'what_is_special_about_yaffs','und','Yaffs is fully supported...',1,1,1339095743,1496407318,1,0,1,1),(418,419,'what_is_special_about_yaffs','und','Data is safe with Yaffs...',1,1,1339097688,1496407385,1,0,1,1),(420,605,'paper','und','YAFFS Robustness and Testing',6,1,1339119318,1496873154,1,0,1,1),(426,427,'what_is_special_about_yaffs','und','High and low level interfaces...',1,1,1339875040,1496407743,1,0,1,1),(427,428,'what_is_special_about_yaffs','und','Cross-platform and portable...',1,1,1339875620,1496408088,1,0,1,1),(428,429,'what_is_special_about_yaffs','und','A file system designed for Flash memory...',1,1,1339884680,1496408130,1,0,1,1),(430,431,'image','und','get yaffs now.png',1,1,1340645767,1340645767,0,0,1,1),(431,432,'image','und','get yaffs now.png',1,1,1340645837,1340645837,0,0,1,1),(432,433,'image','und','yaffs-robustness-structure.png',1,1,1340819524,1340819524,0,0,1,1),(433,434,'what_is_special_about_yaffs','und','Predictable and performance oriented',1,1,1341564526,1494935941,1,0,1,1),(434,435,'what_is_special_about_yaffs','und','Memory efficiency',1,1,1341566593,1494872502,1,0,1,1),(435,436,'what_is_special_about_yaffs','und','Highly configurable - matches your Flash memory',1,1,1341567095,1494888515,1,0,1,1),(436,437,'what_is_special_about_yaffs','und','Simple to integrate',1,1,1341567314,1495711914,1,0,1,1),(448,584,'paper','und','FAQ',1,1,1341786644,1496408204,0,0,1,1),(451,628,'paper','und','Yaffs Tuning',1,1,1342985022,1498531073,1,0,1,1),(452,468,'help_video','und','Yaffs introduction and overview video',1,1,1199059200,1496408407,1,0,1,1),(453,606,'paper','und','Yaffs Direct Interface',1,1,1343000234,1496875984,1,0,1,1),(454,607,'article','und','Running Yaffs Direct Tests',1,1,1343001796,1496922769,1,0,1,1),(455,608,'paper','und','Yaffs NAND flash failure mitigation',1,1,1343003341,1496923141,1,0,1,1),(456,474,'image','und','Yaffs structure diagram',1,1,1344992980,1496408784,0,0,1,1),(457,475,'yaffs_user_logo','und','Google Android',1,1,1345044409,1496410129,0,1,1,1),(458,476,'help_video','und','Preparing to build Linux with Yaffs',1,1,1345255081,1497046070,0,0,1,1),(459,477,'help_video','und','Building Yaffs into Linux',1,1,1345341072,1497046569,0,0,1,1),(460,478,'yaffs_user_logo','und','Leica Geosystems',1,1,1345477881,1496410357,0,0,1,1),(461,589,'article','und','Sample Licence - 2014',4,0,1345555545,1496410431,1,0,1,1),(462,590,'page','und','Licences - more background and detail',4,1,1352909131,1496410536,0,0,1,1),(466,637,'paper','und','Considerations in Choosing a Flash File System',4,1,1401281609,1500990045,1,0,NULL,1),(479,592,'paper','und','Yaffs for VxWorks',1,1,1452526135,1496410804,1,0,1,1),(481,630,'restr','en','Yaffs Admin Dashboard',1,1,1491347756,1498611221,0,0,1,1),(487,636,'page','en','A Robust Flash File System Since 2002',1,1,1493124112,1500985777,0,0,1,1),(488,512,'page','en','Documents - old',1,0,1495073158,1495073190,0,0,1,1),(489,516,'page','en','Test Yaffs under Linux using Virtualbox and Vagrant',1,1,1495625853,1495625903,0,0,1,1),(497,568,'article','en','Test article',1,1,1496249509,1496314192,0,0,1,1),(498,615,'page','en','Commercial Licences',1,1,1497343156,1497343646,0,0,1,1),(499,616,'page','en','Yaffs Licences',1,0,1497270636,1497343733,0,0,1,1),(501,634,'book','en','Case history',4,1,1500201747,1500201902,0,0,1,1),(502,640,'case_study','en','Yaffs in space!',1,1,1504267155,1504267397,1,0,1,1),(503,643,'case_study','en','“Almost 15 years …never seen a failure...”',1,1,1504267408,1504268448,1,0,1,1);
commit;

--
-- Table structure for table `node_field_revision`
--

CREATE TABLE `node_field_revision` (
  `nid` int(10) unsigned NOT NULL,
  `vid` int(10) unsigned NOT NULL,
  `langcode` varchar(12) CHARACTER SET ascii NOT NULL,
  `title` varchar(255) DEFAULT NULL,
  `uid` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
  `status` tinyint(4) NOT NULL,
  `created` int(11) DEFAULT NULL,
  `changed` int(11) DEFAULT NULL,
  `promote` tinyint(4) DEFAULT NULL,
  `sticky` tinyint(4) DEFAULT NULL,
  `revision_translation_affected` tinyint(4) DEFAULT NULL,
  `default_langcode` tinyint(4) NOT NULL,
  PRIMARY KEY (`vid`,`langcode`),
  KEY `node__id__default_langcode__langcode` (`nid`,`default_langcode`,`langcode`),
  KEY `node_field__uid__target_id` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='The revision data table for node entities.';

--
-- Dumping data for table `node_field_revision`
--

set autocommit=0;
INSERT INTO `node_field_revision` VALUES (31,31,'und','Legal',1,1,1116797232,1495041997,0,0,1,1),(32,32,'und','Yaffs Licence Sample',1,1,1116799730,1475152147,0,0,1,1),(37,37,'und','Yaffs Original Specification',1,1,1116847901,1341794506,0,1,1,1),(38,38,'und','Yaffs 2 Specification',3,1,1116848038,1341799920,0,1,1,1),(39,39,'und','Yaffs (Yaffs1) Development Notes',1,1,1116848206,1344434684,0,1,1,1),(40,40,'und','HOWTO incorporate YAFFS in Linux',1,1,1116848477,1275520993,0,1,1,1),(41,41,'und','JFFS2 and NAND study',4,1,1149597275,1149695255,0,0,1,1),(42,42,'und','State of NAND MTD driver at start of project',1,1,1116849036,1341795526,0,0,1,1),(43,43,'und','Yaffs History',1,1,1116849117,1341798646,0,0,1,1),(44,44,'und','YAFFS and ARM Linux support',1,0,1116849266,1363089692,0,0,1,1),(61,61,'und','(Anti) Software patents talk - 2003',1,0,1116857946,1336958429,0,0,1,1),(62,62,'und','Updated software patents talk',1,0,1116858148,1336958461,0,0,1,1),(73,73,'und','Contact',1,1,1119480717,1453818953,0,0,1,1),(77,77,'und','YAFFS talk - slides from a presentation to FOSDEM in 2004',1,1,1120658663,1489533039,0,0,1,1),(79,79,'und','YAFFS talk - Slide 1 - Title',1,1,1120670265,1129598505,1,0,1,1),(110,110,'und','YAFFS talk - Slide 2 - Intro',1,1,1120696310,1183480423,1,0,1,1),(111,111,'und','YAFFS talk - Slide 3 - Project Genesis',1,1,1120696839,1129598559,1,0,1,1),(112,112,'und','YAFFS talk - Slide 4 - History',1,1,1120696981,1129598581,1,0,1,1),(113,113,'und','YAFFS talk - Slide 5 - Flash Primer',1,1,1120697241,1129598601,1,0,1,1),(114,114,'und','YAFFS talk - Slide 6 - Design Approach',1,1,1120697383,1129598623,1,0,1,1),(115,115,'und','YAFFS talk - Slide 7 - Architecture',1,1,1120697463,1129598643,1,0,1,1),(116,116,'und','YAFFS talk - Slide 8 - Terminology',1,1,1120697602,1129598662,1,0,1,1),(117,117,'und','YAFFS talk - Slide 9 - Filesystem Design',1,1,1120697747,1129598687,1,0,1,1),(118,118,'und','YAFFS talk - Slide 10 - Filesystem Limits',1,1,1120697827,1129598707,1,0,1,1),(119,119,'und','YAFFS talk - Slide 11 - OOB Data',1,1,1120697966,1129598726,1,0,1,1),(120,120,'und','YAFFS talk - Slide 12 - Filesystem Data Structures',1,1,1120698103,1129600003,1,0,1,1),(121,121,'und','YAFFS talk - Slide 13 - Filesystem RAM Data Structures',1,1,1120698346,1129600486,1,0,1,1),(122,122,'und','YAFFS talk - Slide 14 - Partitioning',1,1,1120698522,1129598802,1,0,1,1),(123,123,'und','YAFFS talk - Slide 15 - Garbage Collection and Threads',1,1,1120698585,1129598865,1,0,1,1),(124,124,'und','YAFFS talk - Slide 16 - ECC',1,1,1120698601,1129598881,1,0,1,1),(125,125,'und','YAFFS talk - Slide 17 - OS Portability',1,1,1120698682,1129598902,1,0,1,1),(126,126,'und','YAFFS talk - Slide 18 - YAFFS in Use',1,1,1120698822,1129598922,1,0,1,1),(127,127,'und','YAFFS talk - Slide 19 - Embedded System Use',1,1,1120738864,1129598944,1,0,1,1),(128,128,'und','YAFFS talk - Slide 20 - Embedded System Use',1,1,1120738968,1129599348,1,0,1,1),(129,129,'und','YAFFS talk - Slide 21 - Embedded System Use',1,1,1120739424,1129599324,1,0,1,1),(130,130,'und','YAFFS talk - Slide 22 - Embedded System Use',1,1,1120739494,1129599394,1,0,1,1),(131,131,'und','YAFFS talk - Slide 23 - Performance - Examples',1,1,1120739612,1129600892,1,0,1,1),(132,132,'und','YAFFS talk - Slide 24 - Performance - Caching',1,1,1120739653,1129599433,1,0,1,1),(133,133,'und','YAFFS talk - Slide 25 - JFFS2 and YAFFS Comparison',1,1,1120739718,1129600938,1,0,1,1),(134,134,'und','YAFFS talk - Slide 26 - Licensing',1,1,1120739796,1129601016,1,0,1,1),(135,135,'und','YAFFS talk - Slide 27 - YAFFS2',1,1,1120739859,1129599459,1,0,1,1),(136,136,'und','YAFFS talk - Slide 28 - YAFFS2 Comparison with YAFFS1',1,1,1120739973,1129601074,1,0,1,1),(137,137,'und','YAFFS talk - Slide 29 - Fin',1,1,1120740127,1129599487,1,0,1,1),(169,169,'und','Emdebsys talk - Slide 1 - Title',1,1,1129736238,1129736718,1,0,1,1),(196,196,'und','ARM-Linux talk - Slide 1 - Title',1,1,1129764462,1129764702,1,0,1,1),(265,265,'und','Creating a Filesystem on your Compact Flash',1,0,1131733983,1131744243,1,0,1,1),(271,271,'und','JTAG and Jflash-linux',1,0,1131734397,1131734397,1,0,1,1),(274,274,'und','Compiling a Kernel',1,0,1131734493,1131734553,1,0,1,1),(285,285,'und','The Filesystem',1,0,1131735111,1131745131,1,0,1,1),(323,323,'und','Maps',1,1,1132679889,1339888362,1,0,1,1),(325,325,'und','About us',1,1,1133366647,1347895942,1,0,1,1),(342,342,'und','FUEL Embedded Database for use with YAFFS',4,1,1138703943,1342992641,0,0,1,1),(344,344,'und','Yaffs Overview',3,1,1151544621,1495660570,0,1,1,1),(345,345,'und','Yaffs - GPL',4,1,1152534903,1430387828,0,0,1,1),(347,347,'und','YAFFS: the NAND-specific flash file system - Introductory Article',3,1,1153919492,1495718512,1,1,1,1),(348,348,'und','Yaffs1 memory footprint',3,1,1153925836,1495718524,1,0,1,1),(351,351,'und','YAFFS Debugging',3,1,1158355933,1201700928,1,1,1,1),(353,353,'und','Yaffs Licence FAQs',4,1,1179420859,1495660707,1,0,1,1),(357,358,'und','Yaffs - A Flash File System For Embedded Use',1,1,1183194112,1490156068,0,0,1,1),(358,359,'und','The Internal History of YAFFS',1,1,1183224534,1183224600,1,0,1,1),(359,360,'und','Comparison between Yaffs (Yaffs2) and JFFS2',1,1,1183329435,1341800896,1,0,1,1),(360,361,'und','Paper investigating a log management & crash recovery mechanism',1,1,1183375135,1344431818,0,0,1,1),(363,364,'und','The Old Courthouse',1,1,1192033311,1192033311,0,0,1,1),(365,366,'und','Paying us',4,1,1197995334,1197995334,0,0,1,1),(366,367,'und','YAFFS embedded structure',1,1,1198150224,1198177808,1,0,1,1),(367,368,'und','Yaffs Talk - PDF of slides from CELF, 2007',1,1,1201746081,1345450864,0,0,1,1),(368,369,'und','IDEAS List',4,1,1204732266,1205289965,1,0,1,1),(369,370,'und','Yaffs Porting Guide',5,1,1240841747,1342996181,0,0,1,1),(370,371,'und','yaffs_porting_guide_html_2de490f8.png',5,1,1244212305,1244212473,1,0,1,1),(371,372,'und','yaffs_porting_guide_html_m11b1f893.png',5,1,1244212305,1244214689,1,0,1,1),(372,373,'und','yaffs_porting_guide_html_m4650262f.png',5,1,1244212305,1244214744,1,0,1,1),(374,375,'und','YAFFS Tnode tree',1,1,1263783089,1263783268,1,0,1,1),(376,377,'und','YAFFS - directory structure example',1,1,1263783335,1263783445,1,0,1,1),(377,378,'und','YAFFS - Block states',1,1,1263783506,1263783571,1,0,1,1),(380,381,'und','Support',1,1,1330383366,1441709157,0,0,1,1),(382,383,'und','Get Yaffs',1,1,1330444044,1489533044,0,0,1,1),(384,385,'und','Royalty Free... ',1,1,1330455802,1498518115,1,0,1,1),(385,386,'und','A robust flash file system...',1,1,1330456244,1496412025,1,0,1,1),(388,389,'und','Yaffs is Open Source...',1,1,1330467790,1496401931,1,0,1,1),(389,390,'und','Tried and tested in millions of devices...',1,1,1330468194,1496407203,1,0,1,1),(390,391,'und','Get YAFFS now',1,1,1330473626,1330473626,0,0,1,1),(391,392,'und','Get YAFFS now',1,1,1330522429,1330522429,0,0,1,1),(397,398,'und','Design Electronics',1,1,1336589997,1496412075,0,0,1,1),(398,399,'und','Eaton',1,1,1336605810,1496412157,0,0,1,1),(399,400,'und','LANCOM Sytems',1,1,1336605955,1494601211,0,0,1,1),(400,401,'und','Bernina',1,1,1336606047,1494601697,0,0,1,1),(401,402,'und','Gallagher',1,1,1336606102,1496412218,0,0,1,1),(407,408,'und','Booting is fast...',1,1,1338515490,1496402093,1,0,1,1),(408,409,'und','An active community...',1,1,1338515545,1496402147,1,0,1,1),(409,410,'und','How Yaffs works',6,1,1338593328,1495203213,1,0,1,1),(411,412,'und','HowYaffsWorks_directories_0.gif',1,1,1338949299,1338949299,0,0,1,1),(412,413,'und','HowYaffsWorks_tnode_tree_0.gif',1,1,1338949356,1338949356,0,0,1,1),(413,414,'und','HowYaffsWorks_block_states_0.gif',1,1,1338949403,1338949403,0,0,1,1),(414,415,'und','Suitable for open and closed source projects...',1,1,1339010643,1496402329,1,0,1,1),(415,416,'und','For closed source projects - try before you buy...',1,1,1339066508,1496402417,1,0,1,1),(416,417,'und','Yaffs is a safe choice...',1,1,1339071522,1496402459,1,0,1,1),(417,418,'und','Yaffs is fully supported...',1,1,1339095743,1496407318,1,0,1,1),(418,419,'und','Data is safe with Yaffs...',1,1,1339097688,1496407385,1,0,1,1),(420,421,'und','YAFFS Robustness and Testing',6,1,1339119318,1489533044,1,0,1,1),(426,427,'und','High and low level interfaces...',1,1,1339875040,1496407743,1,0,1,1),(427,428,'und','Cross-platform and portable...',1,1,1339875620,1496408088,1,0,1,1),(428,429,'und','A file system designed for Flash memory...',1,1,1339884680,1496408130,1,0,1,1),(430,431,'und','get yaffs now.png',1,1,1340645767,1340645767,0,0,1,1),(431,432,'und','get yaffs now.png',1,1,1340645837,1340645837,0,0,1,1),(432,433,'und','yaffs-robustness-structure.png',1,1,1340819524,1340819524,0,0,1,1),(433,434,'und','Predictable and performance oriented',1,1,1341564526,1494935941,1,0,1,1),(434,435,'und','Memory efficiency',1,1,1341566593,1494872502,1,0,1,1),(435,436,'und','Highly configurable - matches your Flash memory',1,1,1341567095,1494888515,1,0,1,1),(436,437,'und','Simple to integrate',1,1,1341567314,1495711914,1,0,1,1),(448,464,'und','FAQ',1,1,1341786644,1495660691,0,0,1,1),(451,467,'und','Yaffs Tuning',1,1,1342985022,1342985043,1,0,1,1),(452,468,'und','Yaffs introduction and overview video',1,1,1199059200,1496408407,1,0,1,1),(453,469,'und','Yaffs Direct Interface',1,1,1343000234,1343000801,1,0,1,1),(454,470,'und','Running Yaffs Direct Tests',1,1,1343001796,1343001796,1,0,1,1),(455,471,'und','Yaffs NAND flash failure mitigation',1,1,1343003341,1495207423,1,0,1,1),(77,473,'und','YAFFS talk - slides from a presentation to FOSDEM in 2004',1,1,1120658663,1344432401,0,0,1,1),(456,474,'und','Yaffs structure diagram',1,1,1344992980,1496408784,0,0,1,1),(457,475,'und','Google Android',1,1,1345044409,1496410129,0,1,1,1),(458,476,'und','Preparing to build Linux with Yaffs',1,1,1345255081,1497046070,0,0,1,1),(459,477,'und','Building Yaffs into Linux',1,1,1345341072,1497046569,0,0,1,1),(460,478,'und','Leica Geosystems',1,1,1345477881,1496410357,0,0,1,1),(461,479,'und','Sample Licence',4,0,1345555545,1422456477,1,0,1,1),(420,480,'und','YAFFS Robustness and Testing',6,1,1339119318,1452538265,1,0,1,1),(382,481,'und','Get Yaffs',1,1,1330444044,1430388564,0,0,1,1),(462,482,'und','Licences - more background and detail',4,1,1352909131,1495660905,0,0,1,1),(466,486,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1495415009,1,0,1,1),(479,499,'und','Yaffs for VxWorks',1,1,1452526135,1452647354,1,0,1,1),(481,501,'en','Dashboard',1,1,1491347756,1491347824,0,0,1,1),(481,505,'en','Dashboard',1,1,1491347756,1492857955,0,0,1,1),(481,506,'en','Dashboard',1,1,1491347756,1492858124,0,0,1,1),(481,507,'en','Dashboard',1,1,1491347756,1492858550,0,0,1,1),(481,508,'en','Dashboard',1,1,1491347756,1492858662,0,0,1,1),(487,511,'en','Robust Flash Storage Since 2002',1,1,1493124112,1493127397,0,0,1,1),(488,512,'en','Documents - old',1,0,1495073158,1495073190,0,0,1,1),(481,513,'en','Dashboard',1,1,1491347756,1495117783,0,0,NULL,1),(481,514,'en','Yaffs Admin Dashboard',1,1,1491347756,1495117836,0,0,1,1),(481,515,'en','Yaffs Admin Dashboard',1,1,1491347756,1495117945,0,0,1,1),(489,516,'en','Test Yaffs under Linux using Virtualbox and Vagrant',1,1,1495625853,1495625903,0,0,1,1),(461,522,'und','Sample Licence - 2014',4,0,1345555545,1495660964,1,0,1,1),(32,523,'und','Yaffs Licence Sample',1,1,1116799730,1495660982,0,0,1,1),(409,524,'und','How Yaffs works',6,1,1338593328,1495703644,1,0,1,1),(479,525,'und','Yaffs for VxWorks',1,1,1452526135,1495703669,1,0,1,1),(451,526,'und','Yaffs Tuning',1,1,1342985022,1495703875,1,0,1,1),(454,527,'und','Running Yaffs Direct Tests',1,1,1343001796,1495703895,1,0,1,1),(453,528,'und','Yaffs Direct Interface',1,1,1343000234,1495703908,1,0,1,1),(454,529,'und','Running Yaffs Direct Tests',1,1,1343001796,1495705523,1,0,1,1),(455,530,'und','Yaffs NAND flash failure mitigation',1,1,1343003341,1495705537,1,0,1,1),(420,532,'und','YAFFS Robustness and Testing',6,1,1339119318,1495715911,1,0,1,1),(38,533,'und','Yaffs 2 Specification',3,1,1116848038,1495715920,0,1,1,1),(359,534,'und','Comparison between Yaffs (Yaffs2) and JFFS2',1,1,1183329435,1495715931,1,0,1,1),(369,535,'und','Yaffs Porting Guide',5,1,1240841747,1495715984,0,0,1,1),(367,536,'und','Yaffs Talk - PDF of slides from CELF, 2007',1,1,1201746081,1495716652,0,0,1,1),(367,537,'und','Yaffs Talk - PDF of slides from CELF, 2007',1,1,1201746081,1495716710,0,0,NULL,1),(62,538,'und','Updated software patents talk',1,0,1116858148,1495716845,0,0,1,1),(61,539,'und','(Anti) Software patents talk - 2003',1,0,1116857946,1495716893,0,0,1,1),(360,540,'und','Paper investigating a log management & crash recovery mechanism',1,1,1183375135,1495716922,0,0,1,1),(37,541,'und','Yaffs Original Specification',1,1,1116847901,1495716955,0,1,1,1),(42,542,'und','State of NAND MTD driver at start of project',1,1,1116849036,1495717066,0,0,1,1),(43,543,'und','Yaffs History',1,1,1116849117,1495717098,0,0,1,1),(358,544,'und','The Internal History of YAFFS',1,1,1183224534,1495717209,1,0,1,1),(40,545,'und','HOWTO incorporate YAFFS in Linux',1,1,1116848477,1495717406,0,1,1,1),(39,546,'und','Yaffs (Yaffs1) Development Notes',1,1,1116848206,1495717454,0,1,1,1),(342,548,'und','FUEL Embedded Database for use with YAFFS',4,1,1138703943,1495718124,0,0,1,1),(37,549,'und','Yaffs Original Specification',1,1,1116847901,1495718256,0,1,NULL,1),(39,550,'und','Yaffs (Yaffs1) Development Notes',1,1,1116848206,1495718273,0,1,NULL,1),(40,551,'und','HOWTO incorporate YAFFS in Linux',1,1,1116848477,1495718291,0,1,1,1),(42,552,'und','State of NAND MTD driver at start of project',1,1,1116849036,1495718311,0,0,NULL,1),(43,553,'und','Yaffs History',1,1,1116849117,1495718333,0,0,NULL,1),(367,554,'und','Yaffs Talk - PDF of slides from CELF, 2007',1,1,1201746081,1495718371,0,0,NULL,1),(360,555,'und','Paper investigating a log management & crash recovery mechanism',1,1,1183375135,1495718389,0,0,NULL,1),(61,556,'und','(Anti) Software patents talk - 2003',1,0,1116857946,1495718447,0,0,NULL,1),(62,557,'und','Updated software patents talk',1,0,1116858148,1495718474,0,0,1,1),(481,561,'en','Yaffs Admin Dashboard',1,1,1491347756,1495760825,0,0,NULL,1),(481,562,'en','Yaffs Admin Dashboard',1,1,1491347756,1495760899,0,0,1,1),(481,563,'en','Yaffs Admin Dashboard',1,1,1491347756,1495761212,0,0,1,1),(466,564,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1496072106,1,0,1,1),(41,565,'und','JFFS2 and NAND study',4,1,1149597275,1496101239,0,0,1,1),(41,566,'und','JFFS2 and NAND study',4,1,1149597275,1496142801,0,0,1,1),(41,567,'und','JFFS2 and NAND study',4,1,1149597275,1496142831,0,0,NULL,1),(497,568,'en','Test article',1,1,1496249509,1496314192,0,0,1,1),(31,569,'und','Legal',1,1,1116797232,1496361414,0,0,1,1),(37,570,'und','Yaffs Original Specification',1,1,1116847901,1496361508,0,1,1,1),(38,571,'und','Yaffs 2 Specification',3,1,1116848038,1496365861,0,1,1,1),(39,572,'und','Yaffs (Yaffs1) Development Notes',1,1,1116848206,1496365925,0,1,1,1),(42,573,'und','State of NAND MTD driver at start of project',1,1,1116849036,1496365989,0,0,1,1),(342,574,'und','FUEL Embedded Database for use with YAFFS',4,1,1138703943,1496397622,0,0,1,1),(344,575,'und','Yaffs Overview',3,1,1151544621,1496397679,0,1,1,1),(344,576,'und','Yaffs Overview',3,1,1151544621,1496397858,0,1,1,1),(353,577,'und','Yaffs Licence FAQs',4,1,1179420859,1496398001,1,0,1,1),(357,578,'und','Yaffs - A Flash File System For Embedded Use',1,1,1183194112,1496398070,0,0,1,1),(359,579,'und','Comparison between Yaffs (Yaffs2) and JFFS2',1,1,1183329435,1496398143,1,0,1,1),(360,580,'und','Paper investigating a log management & crash recovery mechanism',1,1,1183375135,1496398229,0,0,1,1),(367,581,'und','Yaffs Talk - PDF of slides from CELF, 2007',1,1,1201746081,1496398289,0,0,1,1),(369,582,'und','Yaffs Porting Guide',5,1,1240841747,1496398411,0,0,1,1),(409,583,'und','How Yaffs works',6,1,1338593328,1496402230,1,0,1,1),(448,584,'und','FAQ',1,1,1341786644,1496408204,0,0,1,1),(451,585,'und','Yaffs Tuning',1,1,1342985022,1496408298,1,0,1,1),(453,586,'und','Yaffs Direct Interface',1,1,1343000234,1496408475,1,0,1,1),(454,587,'und','Running Yaffs Direct Tests',1,1,1343001796,1496408556,1,0,1,1),(455,588,'und','Yaffs NAND flash failure mitigation',1,1,1343003341,1496408673,1,0,1,1),(461,589,'und','Sample Licence - 2014',4,0,1345555545,1496410431,1,0,1,1),(462,590,'und','Licences - more background and detail',4,1,1352909131,1496410536,0,0,1,1),(466,591,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1496410592,1,0,1,1),(479,592,'und','Yaffs for VxWorks',1,1,1452526135,1496410804,1,0,1,1),(409,593,'und','How Yaffs works',6,1,1338593328,1496776964,1,0,1,1),(409,594,'und','How Yaffs works',6,1,1338593328,1496793499,1,0,1,1),(409,595,'und','How Yaffs works',6,1,1338593328,1496776964,1,0,1,1),(409,596,'und','How Yaffs works',6,1,1338593328,1496842197,1,0,1,1),(409,597,'und','How Yaffs works',6,1,1338593328,1496844869,1,0,1,1),(409,598,'und','How Yaffs works',6,1,1338593328,1496852338,1,0,1,1),(409,599,'und','How Yaffs works',6,1,1338593328,1496852438,1,0,1,1),(409,600,'und','How Yaffs works',6,1,1338593328,1496852456,1,0,NULL,1),(409,601,'und','How Yaffs works',6,1,1338593328,1496852593,1,0,NULL,1),(466,602,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1496853416,1,0,1,1),(420,603,'und','YAFFS Robustness and Testing',6,1,1339119318,1496872963,1,0,1,1),(420,604,'und','YAFFS Robustness and Testing',6,1,1339119318,1496872972,1,0,1,1),(420,605,'und','YAFFS Robustness and Testing',6,1,1339119318,1496873154,1,0,1,1),(453,606,'und','Yaffs Direct Interface',1,1,1343000234,1496875984,1,0,1,1),(454,607,'und','Running Yaffs Direct Tests',1,1,1343001796,1496922769,1,0,1,1),(455,608,'und','Yaffs NAND flash failure mitigation',1,1,1343003341,1496923141,1,0,1,1),(451,609,'und','Yaffs Tuning',1,1,1342985022,1496924843,1,0,1,1),(367,610,'und','Yaffs Talk - PDF of slides from CELF, 2007',1,1,1201746081,1496924893,0,0,1,1),(466,611,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1496924936,1,0,1,1),(409,612,'und','How Yaffs works',6,1,1338593328,1496924967,1,0,1,1),(382,613,'und','Get Yaffs',1,1,1330444044,1497314275,0,0,1,1),(382,614,'und','Get Yaffs',1,1,1330444044,1497343111,0,0,1,1),(498,615,'en','Commercial Licences',1,1,1497343156,1497343646,0,0,1,1),(499,616,'en','Yaffs Licences',1,0,1497270636,1497343733,0,0,1,1),(345,617,'und','Yaffs - GPL Licence',4,1,1152534903,1497347161,0,0,1,1),(345,618,'und','Yaffs - GPL Licence',4,1,1152534903,1497347544,0,0,1,1),(345,619,'und','Yaffs - GPL Licence',4,1,1152534903,1497348780,0,0,1,1),(487,620,'en','Robust Flash Storage Since 2002',1,1,1493124112,1497460913,0,0,1,1),(32,622,'und','Yaffs Licence Sample',1,1,1116799730,1498518247,0,0,1,1),(32,623,'und','Yaffs Licence Sample',1,1,1116799730,1498518361,0,0,1,1),(409,624,'und','How Yaffs works',6,1,1338593328,1498521274,1,0,1,1),(409,625,'und','How Yaffs works',6,1,1338593328,1498529494,1,0,NULL,1),(409,626,'und','How Yaffs works',6,1,1338593328,1498530157,1,0,1,1),(409,627,'und','How Yaffs works',6,1,1338593328,1498530801,1,0,1,1),(451,628,'und','Yaffs Tuning',1,1,1342985022,1498531073,1,0,1,1),(466,629,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1498531189,1,0,1,1),(481,630,'en','Yaffs Admin Dashboard',1,1,1491347756,1498611221,0,0,1,1),(487,631,'en','Robust Flash Storage Since 2002',1,1,1493124112,1498655526,0,0,1,1),(466,632,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1498658027,1,0,1,1),(32,633,'und','Yaffs Licence Sample',1,1,1116799730,1498730566,0,0,1,1),(501,634,'en','Case history',4,1,1500201747,1500201902,0,0,1,1),(487,635,'en','Robust Flash Storage Since 2002',1,1,1493124112,1500981193,0,0,NULL,1),(487,636,'en','A Robust Flash File System Since 2002',1,1,1493124112,1500985777,0,0,1,1),(466,637,'und','Considerations in Choosing a Flash File System',4,1,1401281609,1500990045,1,0,NULL,1),(31,638,'und','Legal',1,1,1116797232,1501770074,0,0,1,1),(382,639,'und','Get Yaffs',1,1,1330444044,1502716247,0,0,1,1),(502,640,'en','Yaffs in space!',1,1,1504267155,1504267397,1,0,1,1),(503,641,'en','“Almost 15 years …never seen a failure...”',1,1,1504267408,1504267698,1,0,1,1),(503,642,'en','“Almost 15 years …never seen a failure...”',1,1,1504267408,1504268000,1,0,1,1),(503,643,'en','“Almost 15 years …never seen a failure...”',1,1,1504267408,1504268448,1,0,1,1),(31,644,'und','Legal',1,1,1116797232,1504708558,0,0,1,1),(31,645,'und','Legal',1,1,1116797232,1504708684,0,0,1,1);
commit;

--
-- Table structure for table `node_revision`
--

CREATE TABLE `node_revision` (
  `nid` int(10) unsigned NOT NULL,
  `vid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `langcode` varchar(12) CHARACTER SET ascii NOT NULL,
  `revision_timestamp` int(11) DEFAULT NULL,
  `revision_uid` int(10) unsigned DEFAULT NULL COMMENT 'The ID of the target entity.',
  `revision_log` longtext,
  PRIMARY KEY (`vid`),
  KEY `node__nid` (`nid`),
  KEY `node_field__langcode` (`langcode`),
  KEY `node_field__revision_uid__target_id` (`revision_uid`)
) ENGINE=InnoDB AUTO_INCREMENT=646 DEFAULT CHARSET=utf8mb4 COMMENT='The revision table for node entities.';

--
-- Dumping data for table `node_revision`
--

set autocommit=0;
INSERT INTO `node_revision` VALUES (31,31,'und',1338339118,1,NULL),(32,32,'und',1475152147,5,'Change of order'),(37,37,'und',1341794506,1,NULL),(38,38,'und',1341799920,1,NULL),(39,39,'und',1344434684,1,NULL),(40,40,'und',1275520993,6,NULL),(41,41,'und',1149695255,4,NULL),(42,42,'und',1341795526,1,NULL),(43,43,'und',1341798646,1,NULL),(44,44,'und',1363089692,4,NULL),(61,61,'und',1336958429,1,NULL),(62,62,'und',1336958461,1,NULL),(73,73,'und',1453818953,4,NULL),(77,77,'und',1336958549,1,NULL),(79,79,'und',1129598505,1,NULL),(110,110,'und',1183480423,1,NULL),(111,111,'und',1129598559,1,NULL),(112,112,'und',1129598581,1,NULL),(113,113,'und',1129598601,1,NULL),(114,114,'und',1129598623,1,NULL),(115,115,'und',1129598643,1,NULL),(116,116,'und',1129598662,1,NULL),(117,117,'und',1129598687,1,NULL),(118,118,'und',1129598707,1,NULL),(119,119,'und',1129598726,1,NULL),(120,120,'und',1129600003,1,NULL),(121,121,'und',1129600486,1,NULL),(122,122,'und',1129598802,1,NULL),(123,123,'und',1129598865,1,NULL),(124,124,'und',1129598881,1,NULL),(125,125,'und',1129598902,1,NULL),(126,126,'und',1129598922,1,NULL),(127,127,'und',1129598944,1,NULL),(128,128,'und',1129599348,1,NULL),(129,129,'und',1129599324,1,NULL),(130,130,'und',1129599394,1,NULL),(131,131,'und',1129600892,1,NULL),(132,132,'und',1129599433,1,NULL),(133,133,'und',1129600938,1,NULL),(134,134,'und',1129601016,1,NULL),(135,135,'und',1129599459,1,NULL),(136,136,'und',1129601074,1,NULL),(137,137,'und',1129599487,1,NULL),(169,169,'und',1129736718,1,NULL),(196,196,'und',1129764702,1,NULL),(265,265,'und',1131744243,1,NULL),(271,271,'und',1131734397,1,NULL),(274,274,'und',1131734553,1,NULL),(285,285,'und',1131745131,1,NULL),(323,323,'und',1339888362,1,NULL),(325,325,'und',1347895942,4,NULL),(342,342,'und',1342992641,1,NULL),(344,344,'und',1341802545,1,NULL),(345,345,'und',1430387828,4,NULL),(347,347,'und',1268911764,5,'Change CVS ref to GIT'),(348,348,'und',1342996514,1,NULL),(351,351,'und',1201700928,1,NULL),(353,353,'und',1430387504,4,'Update to reorder in list'),(357,358,'und',1344935972,4,NULL),(358,359,'und',1183224600,1,NULL),(359,360,'und',1341800896,1,NULL),(360,361,'und',1344431818,1,NULL),(363,364,'und',1192033311,1,NULL),(365,366,'und',1197995334,4,NULL),(366,367,'und',1198177808,1,NULL),(367,368,'und',1345450864,4,NULL),(368,369,'und',1205289965,6,NULL),(369,370,'und',1342996181,1,'Page from Laurie relating to porting YAFFS'),(370,371,'und',1244212473,5,'Not sure where images from porting page have gone so seeing if I need to add them separately like this'),(371,372,'und',1244214689,5,'Not sure where images from porting page have gone so seeing if I need to add them separately like this'),(372,373,'und',1244214744,5,'Not sure where images from porting page have gone so seeing if I need to add them separately like this'),(374,375,'und',1263783268,1,NULL),(376,377,'und',1263783445,1,NULL),(377,378,'und',1263783571,1,NULL),(380,381,'und',1441709157,5,NULL),(382,383,'und',1343869637,1,NULL),(384,385,'und',1430391793,4,NULL),(385,386,'und',1354548038,4,NULL),(388,389,'und',1430391671,4,NULL),(389,390,'und',1378306103,1,NULL),(390,391,'und',1330473626,1,NULL),(391,392,'und',1330522429,1,NULL),(397,398,'und',1336591220,1,NULL),(398,399,'und',1336605810,1,NULL),(399,400,'und',1336605985,1,NULL),(400,401,'und',1342416153,1,NULL),(401,402,'und',1336606157,1,NULL),(407,408,'und',1344939309,4,NULL),(408,409,'und',1344936557,4,NULL),(409,410,'und',1342921051,1,NULL),(411,412,'und',1338949299,1,NULL),(412,413,'und',1338949356,1,NULL),(413,414,'und',1338949403,1,NULL),(414,415,'und',1430391217,4,NULL),(415,416,'und',1430391377,4,NULL),(416,417,'und',1430392039,4,NULL),(417,418,'und',1341880534,1,NULL),(418,419,'und',1344939735,4,NULL),(420,421,'und',1345820300,1,NULL),(426,427,'und',1344939996,4,NULL),(427,428,'und',1354548179,4,NULL),(428,429,'und',1395573949,4,NULL),(430,431,'und',1340645767,1,NULL),(431,432,'und',1340645837,1,NULL),(432,433,'und',1340819524,1,NULL),(433,434,'und',1344941764,4,NULL),(434,435,'und',1344942007,4,NULL),(435,436,'und',1344942371,4,NULL),(436,437,'und',1341567314,1,NULL),(448,464,'und',1345470435,4,NULL),(451,467,'und',1342985043,1,NULL),(452,468,'und',1345341621,1,NULL),(453,469,'und',1343000801,1,NULL),(454,470,'und',1343001796,1,NULL),(455,471,'und',1343003341,1,NULL),(77,473,'und',1344432401,1,NULL),(456,474,'und',1371773385,1,NULL),(457,475,'und',1345044728,1,NULL),(458,476,'und',1430391523,4,NULL),(459,477,'und',1345473183,1,NULL),(460,478,'und',1345477881,1,NULL),(461,479,'und',1422456477,4,NULL),(420,480,'und',1452538265,1,NULL),(382,481,'und',1430388564,4,NULL),(462,482,'und',1430388314,4,NULL),(466,486,'und',1408410951,1,NULL),(479,499,'und',1452647354,1,NULL),(481,501,'en',1491347824,1,NULL),(481,505,'en',1492857955,1,NULL),(481,506,'en',1492858124,1,NULL),(481,507,'en',1492858550,1,NULL),(481,508,'en',1492858662,1,NULL),(487,511,'en',1493127209,1,NULL),(488,512,'en',1495073190,1,NULL),(481,513,'en',1495117783,1,NULL),(481,514,'en',1495117836,1,NULL),(481,515,'en',1495117945,1,NULL),(489,516,'en',1495625903,1,NULL),(461,522,'und',1495660964,1,NULL),(32,523,'und',1495660982,1,NULL),(409,524,'und',1495703644,1,NULL),(479,525,'und',1495703669,1,NULL),(451,526,'und',1495703875,1,NULL),(454,527,'und',1495703895,1,NULL),(453,528,'und',1495703908,1,NULL),(454,529,'und',1495705523,1,NULL),(455,530,'und',1495705537,1,NULL),(420,532,'und',1495715911,1,NULL),(38,533,'und',1495715920,1,NULL),(359,534,'und',1495715931,1,NULL),(369,535,'und',1495715984,1,NULL),(367,536,'und',1495716652,1,NULL),(367,537,'und',1495716710,1,NULL),(62,538,'und',1495716845,1,NULL),(61,539,'und',1495716893,1,NULL),(360,540,'und',1495716922,1,NULL),(37,541,'und',1495716955,1,NULL),(42,542,'und',1495717066,1,NULL),(43,543,'und',1495717098,1,NULL),(358,544,'und',1495717209,1,NULL),(40,545,'und',1495717406,1,NULL),(39,546,'und',1495717454,1,NULL),(342,548,'und',1495718124,1,NULL),(37,549,'und',1495718256,1,NULL),(39,550,'und',1495718273,1,NULL),(40,551,'und',1495718291,1,NULL),(42,552,'und',1495718311,1,NULL),(43,553,'und',1495718333,1,NULL),(367,554,'und',1495718371,1,NULL),(360,555,'und',1495718389,1,NULL),(61,556,'und',1495718447,1,NULL),(62,557,'und',1495718474,1,NULL),(481,561,'en',1495760825,1,NULL),(481,562,'en',1495760899,1,NULL),(481,563,'en',1495761212,1,NULL),(466,564,'und',1496072106,1,NULL),(41,565,'und',1496101239,1,NULL),(41,566,'und',1496142801,1,NULL),(41,567,'und',1496142831,1,NULL),(497,568,'en',1496314192,1,NULL),(31,569,'und',1496361414,1,NULL),(37,570,'und',1496361508,1,NULL),(38,571,'und',1496365861,1,NULL),(39,572,'und',1496365925,1,NULL),(42,573,'und',1496365989,1,NULL),(342,574,'und',1496397622,1,NULL),(344,575,'und',1496397679,1,NULL),(344,576,'und',1496397858,1,NULL),(353,577,'und',1496398001,1,NULL),(357,578,'und',1496398070,1,NULL),(359,579,'und',1496398143,1,NULL),(360,580,'und',1496398229,1,NULL),(367,581,'und',1496398289,1,NULL),(369,582,'und',1496398411,1,NULL),(409,583,'und',1496402230,1,NULL),(448,584,'und',1496408204,1,NULL),(451,585,'und',1496408298,1,NULL),(453,586,'und',1496408475,1,NULL),(454,587,'und',1496408556,1,NULL),(455,588,'und',1496408673,1,NULL),(461,589,'und',1496410431,1,NULL),(462,590,'und',1496410536,1,NULL),(466,591,'und',1496410592,1,NULL),(479,592,'und',1496410804,1,NULL),(409,593,'und',1496776964,1,NULL),(409,594,'und',1496793499,1,NULL),(409,595,'und',1496776964,1,'Copy of the revision from <em class=\"placeholder\">6 June, 2017 - 8:22pm</em>.'),(409,596,'und',1496842197,1,NULL),(409,597,'und',1496844869,1,NULL),(409,598,'und',1496852338,1,NULL),(409,599,'und',1496852438,1,NULL),(409,600,'und',1496852456,1,NULL),(409,601,'und',1496852593,1,NULL),(466,602,'und',1496853416,1,NULL),(420,603,'und',1496872963,1,NULL),(420,604,'und',1496872972,1,NULL),(420,605,'und',1496873154,1,NULL),(453,606,'und',1496875984,1,NULL),(454,607,'und',1496922769,1,NULL),(455,608,'und',1496923141,1,NULL),(451,609,'und',1496924843,1,NULL),(367,610,'und',1496924893,1,NULL),(466,611,'und',1496924936,1,NULL),(409,612,'und',1496924967,1,NULL),(382,613,'und',1497314192,1,NULL),(382,614,'und',1497342599,1,NULL),(498,615,'en',1497343646,1,NULL),(499,616,'en',1497343733,1,NULL),(345,617,'und',1497347161,1,NULL),(345,618,'und',1497347544,1,NULL),(345,619,'und',1497348780,1,NULL),(487,620,'en',1497460821,1,NULL),(32,622,'und',1498518247,1,NULL),(32,623,'und',1498518361,1,NULL),(409,624,'und',1498521240,1,NULL),(409,625,'und',1498529494,1,NULL),(409,626,'und',1498530157,1,NULL),(409,627,'und',1498530801,1,NULL),(451,628,'und',1498531073,1,NULL),(466,629,'und',1498531189,1,NULL),(481,630,'en',1498611221,1,NULL),(487,631,'en',1498655526,4,NULL),(466,632,'und',1498658027,4,NULL),(32,633,'und',1498730566,4,NULL),(501,634,'en',1500201902,4,NULL),(487,635,'en',1500981193,1,'Update to ensure a cache clear.'),(487,636,'en',1500985777,1,NULL),(466,637,'und',1500990045,1,NULL),(31,638,'und',1501770074,4,NULL),(382,639,'und',1502716247,1,NULL),(502,640,'en',1504267397,1,NULL),(503,641,'en',1504267698,1,NULL),(503,642,'en',1504268000,1,NULL),(503,643,'en',1504268448,1,NULL),(31,644,'und',1504708558,1,NULL),(31,645,'und',1504708684,1,NULL);
commit;

--
-- Table structure for table `node_revision__body`
--

CREATE TABLE `node_revision__body` (
  `bundle` varchar(128) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The field instance bundle to which this row belongs, used when deleting a field instance',
  `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'A boolean indicating whether this data item has been deleted',
  `entity_id` int(10) unsigned NOT NULL COMMENT 'The entity id this data is attached to',
  `revision_id` int(10) unsigned NOT NULL COMMENT 'The entity revision id this data is attached to',
  `langcode` varchar(32) CHARACTER SET ascii NOT NULL DEFAULT '' COMMENT 'The language code for this data item.',
  `delta` int(10) unsigned NOT NULL COMMENT 'The sequence number for this data item, used for multi-value fields',
  `body_value` longtext NOT NULL,
  `body_summary` longtext,
  `body_format` varchar(255) CHARACTER SET ascii DEFAULT NULL,
  PRIMARY KEY (`entity_id`,`revision_id`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `body_format` (`body_format`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Revision archive storage for node field body.';

--
-- Dumping data for table `node_revision__body`
--

set autocommit=0;
INSERT INTO `node_revision__body` VALUES ('page',0,31,31,'und',0,'<h3><a>Cookies</a></h3>\r\n\r\n<p>We may store information about you using cookies (files which are sent by us to your computer or other access device) which we can access when you visit our site in future. We do this to enable functions like the text resize in the right hand column. If you want to delete any cookies that are already on your computer, please refer to the instructions for your file management software to locate the file or directory that stores cookies. Our cookies will have file names starting yaffs.net. These may be found among the Privacy settings for your web browser. Information on deleting or controlling cookies is available at the excellent and informative site:www.AboutCookies.org. Please note that by deleting our cookies or disabling future cookies you may not be able to access certain areas or features of our site.</p>\r\n\r\n<h3><a>Privacy</a></h3>\r\n\r\n<p>We, like all British companies handling data on computers, are registered under the Data Protection Act, which requires us (amongst many other things) to describe what use we shall make of the data we keep, and have the authorities record and accept that use, and permits you access to the data about you (for a reasonable fee).</p>\r\n\r\n<p>In practice when we write an Invoice we do it on a computer and we keep the invoice details for a few months (and our paper copy much longer).</p>\r\n\r\n<p>We DO NOT EVER pass this information on, or sell it, to any other company. We never have done so and we expect never to do so in the future. Details of your transaction with us remain private to us and you can expect them to be seen only by our staff and possibly by our professional Auditors.</p>\r\n\r\n<p>We suffer enough from junk mail and junk email to wish not to inflict any of it on anyone else!</p>\r\n\r\n<p>We do not promise not to tell you if we have a new product we think you might be interested in. We very rarely do this, but as our product range develops and changes for the better we might at some future time want to tell you about what was both new and likely to be relevant to you.</p>\r\n\r\n<p>If you tell us not to send you any mail about new developments then we will not do so.</p>\r\n\r\n<p>We do also run Email lists for some types of product, but you only receive emails if you ask to do so. Where such a list exists you will find details on the page about that product.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3><a>Guarantee of goods</a></h3>\r\n\r\n<p>Our policy has always been to provide all the information a buyer needs to make an informed choice among our products. If you have questions to which you do not see answers we are happy to try to answer those specific questions, if you make clear to what product they relate.</p>\r\n\r\n<p>For this reason our Guarantee is as follows:-</p>\r\n\r\n<p>Our hardware products (except Balloon boards) and instruments are guaranteed against defects in materials or workmanship for a period of twelve months from date of purchase.</p>\r\n\r\n<p>Our software products and Balloon Boards and related hardware are offered only on an \"as is\" basis without any warranty as to their suitability for any particular purpose. This may seem unfair, but it follows from the terms of the GNU Public Licence and the Licence for the hardware designs. In practice we stand behind our products, and exchange them if they prove faulty.</p>\r\n\r\n<p>In all cases the company shall not be liable for any losses, damage, costs, expenses including (without limitation) any loss of profits, any loss or damage to property and any indirect or consequential loss howsoever caused including any liability to third parties.</p>\r\n\r\n<p>This Guarantee does not alter your statutory rights, which are described in more detail, for private buyers (not businesses) within the EC, at <a href=\"http://www.dti.gov.uk/cacp/ca/policy/distanceselling/newregs.htm\">http://www.dti.gov.uk/cacp/ca/policy/distanceselling/newregs.htm</a></p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3><a>Title to goods</a></h3>\r\n\r\n<p>Title to goods (that is, ownership) passes to the buyer only when we have received full payment for the goods.</p>\r\n','Details of our privacy policy and our conditions of sale.','filtered_html'),('page',0,31,569,'und',0,'<h3><a>Cookies</a></h3>\r\n\r\n<p>We may store information about you using cookies (files which are sent by us to your computer or other access device) which we can access when you visit our site in future. We do this to enable functions like the text resize in the right hand column. If you want to delete any cookies that are already on your computer, please refer to the instructions for your file management software to locate the file or directory that stores cookies. Our cookies will have file names starting yaffs.net. These may be found among the Privacy settings for your web browser. Information on deleting or controlling cookies is available at the excellent and informative site:www.AboutCookies.org. Please note that by deleting our cookies or disabling future cookies you may not be able to access certain areas or features of our site.</p>\r\n\r\n<h3><a>Privacy</a></h3>\r\n\r\n<p>We, like all British companies handling data on computers, are registered under the Data Protection Act, which requires us (amongst many other things) to describe what use we shall make of the data we keep, and have the authorities record and accept that use, and permits you access to the data about you (for a reasonable fee).</p>\r\n\r\n<p>In practice when we write an Invoice we do it on a computer and we keep the invoice details for a few months (and our paper copy much longer).</p>\r\n\r\n<p>We DO NOT EVER pass this information on, or sell it, to any other company. We never have done so and we expect never to do so in the future. Details of your transaction with us remain private to us and you can expect them to be seen only by our staff and possibly by our professional Auditors.</p>\r\n\r\n<p>We suffer enough from junk mail and junk email to wish not to inflict any of it on anyone else!</p>\r\n\r\n<p>We do not promise not to tell you if we have a new product we think you might be interested in. We very rarely do this, but as our product range develops and changes for the better we might at some future time want to tell you about what was both new and likely to be relevant to you.</p>\r\n\r\n<p>If you tell us not to send you any mail about new developments then we will not do so.</p>\r\n\r\n<p>We do also run Email lists for some types of product, but you only receive emails if you ask to do so. Where such a list exists you will find details on the page about that product.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3><a>Guarantee of goods</a></h3>\r\n\r\n<p>Our policy has always been to provide all the information a buyer needs to make an informed choice among our products. If you have questions to which you do not see answers we are happy to try to answer those specific questions, if you make clear to what product they relate.</p>\r\n\r\n<p>For this reason our Guarantee is as follows:-</p>\r\n\r\n<p>Our hardware products (except Balloon boards) and instruments are guaranteed against defects in materials or workmanship for a period of twelve months from date of purchase.</p>\r\n\r\n<p>Our software products and Balloon Boards and related hardware are offered only on an \"as is\" basis without any warranty as to their suitability for any particular purpose. This may seem unfair, but it follows from the terms of the GNU Public Licence and the Licence for the hardware designs. In practice we stand behind our products, and exchange them if they prove faulty.</p>\r\n\r\n<p>In all cases the company shall not be liable for any losses, damage, costs, expenses including (without limitation) any loss of profits, any loss or damage to property and any indirect or consequential loss howsoever caused including any liability to third parties.</p>\r\n\r\n<p>This Guarantee does not alter your statutory rights, which are described in more detail, for private buyers (not businesses) within the EC, at <a href=\"http://www.dti.gov.uk/cacp/ca/policy/distanceselling/newregs.htm\">http://www.dti.gov.uk/cacp/ca/policy/distanceselling/newregs.htm</a></p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3><a>Title to goods</a></h3>\r\n\r\n<p>Title to goods (that is, ownership) passes to the buyer only when we have received full payment for the goods.</p>\r\n','Details of our privacy policy and our conditions of sale.','basic_html'),('page',0,31,638,'und',0,'<h3><a>Cookies</a></h3>\r\n\r\n<p>We may store information about you using cookies (files which are sent by us to your computer or other access device) which we can access when you visit our site in future. We do this to enable functions like the text resize in the right hand column. If you want to delete any cookies that are already on your computer, please refer to the instructions for your file management software to locate the file or directory that stores cookies. Our cookies will have file names starting yaffs.net. These may be found among the Privacy settings for your web browser. Information on deleting or controlling cookies is available at the excellent and informative site:www.AboutCookies.org. Please note that by deleting our cookies or disabling future cookies you may not be able to access certain areas or features of our site.</p>\r\n\r\n<h3><a>Privacy</a></h3>\r\n\r\n<p>We, like all British companies handling data on computers, are registered under the Data Protection Act, which requires us (amongst many other things) to describe what use we shall make of the data we keep, and have the authorities record and accept that use, and permits you access to the data about you.</p>\r\n\r\n<p>In practice when we write an Invoice we do it on a computer and we keep the invoice details for a few months (and a paper copy much longer).</p>\r\n\r\n<p>We DO NOT EVER pass this information on, or sell it, to any other company. We never have done so and we expect never to do so in the future. Details of your transaction with us remain private to us and you can expect them to be seen only by our staff and possibly by our professional Auditors.</p>\r\n\r\n<p>We suffer enough from junk mail and junk email to wish not to inflict any of it on anyone else!</p>\r\n\r\n<p>We do not promise not to tell you if we have a new product we think you might be interested in. We very rarely do this but we might at some future time want to tell you about what is both new and likely to be relevant to you.</p>\r\n\r\n<p>We do also run an Email list for Yaffs, but you only receive emails if you ask to do so by going to:-&nbsp; http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs&nbsp; to join in.</p>\r\n\r\n<h3><a>Guarantee</a></h3>\r\n\r\n<p>Our policy has always been to provide all the information a buyer needs to make an informed choice of our products. If you have questions to which you do not see answers we are happy to try to answer those specific questions; they are much more likely to be answered if you provide information about the software context in which you are using Yaffs and details of the kind of difficulty you have</p>\r\n\r\n<p>Yaffs is provided on an \"as is\" basis without any warranty as to its suitability for any particular purpose. This may seem unfair, but it follows from the terms of the GNU Public Licence and the Licence for the hardware designs.&nbsp; Yaffs is unique in our experience in that you can try it without charge, and satisfy yourself that it works for your product before you buy a Licence to use it.</p>\r\n\r\n<p>In any case the company shall not be liable for any losses, damage, costs, expenses including (without limitation) any loss of profits, any loss or damage to property and any indirect or consequential loss howsoever caused including any liability to third parties.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n','Details of our privacy policy and our conditions of sale.','basic_html'),('page',0,31,644,'und',0,'<h3><a>Cookies</a></h3>\r\n\r\n<p>We may store information about you using cookies (files which are sent by us to your computer or other access device) which we can access when you visit our site in future. We do this to enable functions like the text resize in the right hand column. If you want to delete any cookies that are already on your computer, please refer to the instructions for your file management software to locate the file or directory that stores cookies. Our cookies will have file names starting yaffs.net. These may be found among the Privacy settings for your web browser. Information on deleting or controlling cookies is available at the excellent and informative site:www.AboutCookies.org. Please note that by deleting our cookies or disabling future cookies you may not be able to access certain areas or features of our site.</p>\r\n\r\n<h3><a>Privacy</a></h3>\r\n\r\n<p>We, like all British companies handling data on computers, are registered under the Data Protection Act, which requires us (amongst many other things) to describe what use we shall make of the data we keep, and have the authorities record and accept that use, and permits you access to the data about you.</p>\r\n\r\n<p>In practice when we write an Invoice we do it on a computer and we keep the invoice details for a few months (and a paper copy much longer).</p>\r\n\r\n<p>We DO NOT EVER pass this information on, or sell it, to any other company. We never have done so and we expect never to do so in the future. Details of your transaction with us remain private to us and you can expect them to be seen only by our staff and possibly by our professional Auditors.</p>\r\n\r\n<p>We suffer enough from junk mail and junk email to wish not to inflict any of it on anyone else!</p>\r\n\r\n<p>We do not promise not to tell you if we have a new product we think you might be interested in. We very rarely do this but we might at some future time want to tell you about what is both new and likely to be relevant to you.</p>\r\n\r\n<p>We do also run an Email list for Yaffs, but you only receive emails if you ask to do so by going to:-&nbsp; http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs&nbsp; to join in.</p>\r\n\r\n<h3><a>Guarantee</a></h3>\r\n\r\n<p>Our policy has always been to provide all the information a buyer needs to make an informed choice of our products. If you have questions to which you do not see answers we are happy to try to answer those specific questions; they are much more likely to be answered if you provide information about the software context in which you are using Yaffs and details of the kind of difficulty you have</p>\r\n\r\n<p>Yaffs is provided on an \"as is\" basis without any warranty as to its suitability for any particular purpose. This may seem unfair, but it follows from the terms of the GNU Public Licence and the Licence for the hardware designs.&nbsp; Yaffs is unique in our experience in that you can try it without charge, and satisfy yourself that it works for your product before you buy a Licence to use it.</p>\r\n\r\n<p>In any case the company shall not be liable for any losses, damage, costs, expenses including (without limitation) any loss of profits, any loss or damage to property and any indirect or consequential loss howsoever caused including any liability to third parties.</p>\r\n\r\n<h3>Legal</h3>\r\n\r\n<p>We provide the Source Code to Yaffs and any derived file systems without any warranty&nbsp;but <strong>AS IS</strong>&nbsp;save that (to the best of Aleph One\'s knowledge) the use of the Source&nbsp;Code does not infringe the intellectual property rights of any third party.</p>\r\n\r\n<p>We provide certain pieces of software, with different licences associated with them:</p>\r\n\r\n<ul>\r\n	<li>Source Code for Yaffs1, Yaffs2 and Yaffs/direct and Bootloader, being the subject of this Licence Agreement, for incorporation in a Product.</li>\r\n	<li>Yaffs&nbsp;Development Tools</li>\r\n</ul>\r\n\r\n<p>Images created with the tools may be incorporated into a Product. The images are not affected by the licence status of the Tools. When these Tool files are supplied in the tarball we send they appear with a header saying they are used under the GNU Public Licence, GPL. That term applies only to the Tools.</p>\r\n\r\n<p>The other files in the tarball have headers making clear they are used under a paid licence from Aleph One Ltd.</p>\r\n\r\n<p>The Licence also permits access to all information on Yaffs&nbsp;published by Aleph One Ltd at http://www.yaffs.net - now and at any time in the future.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n','Details of our privacy policy and our conditions of sale.','basic_html'),('page',0,31,645,'und',0,'<h3>Cookies</h3>\r\n\r\n<p>We may store information about you using cookies (files which are sent by us to your computer or other access device) which we can access when you visit our site in future. We do this to enable functions like the text resize in the right hand column. If you want to delete any cookies that are already on your computer, please refer to the instructions for your file management software to locate the file or directory that stores cookies. Our cookies will have file names starting yaffs.net. These may be found among the Privacy settings for your web browser. Information on deleting or controlling cookies is available at the excellent and informative site:www.AboutCookies.org. Please note that by deleting our cookies or disabling future cookies you may not be able to access certain areas or features of our site.</p>\r\n\r\n<h3>Privacy</h3>\r\n\r\n<p>We, like all British companies handling data on computers, are registered under the Data Protection Act, which requires us (amongst many other things) to describe what use we shall make of the data we keep, and have the authorities record and accept that use, and permits you access to the data about you.</p>\r\n\r\n<p>In practice when we write an Invoice we do it on a computer and we keep the invoice details for a few months (and a paper copy much longer).</p>\r\n\r\n<p>We DO NOT EVER pass this information on, or sell it, to any other company. We never have done so and we expect never to do so in the future. Details of your transaction with us remain private to us and you can expect them to be seen only by our staff and possibly by our professional Auditors.</p>\r\n\r\n<p>We suffer enough from junk mail and junk email to wish not to inflict any of it on anyone else!</p>\r\n\r\n<p>We do not promise not to tell you if we have a new product we think you might be interested in. We very rarely do this but we might at some future time want to tell you about what is both new and likely to be relevant to you.</p>\r\n\r\n<p>We do also run an Email list for Yaffs, but you only receive emails if you ask to do so by going to:-&nbsp; http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs&nbsp; to join in.</p>\r\n\r\n<h3>Guarantee</h3>\r\n\r\n<p>Our policy has always been to provide all the information a buyer needs to make an informed choice of our products. If you have questions to which you do not see answers we are happy to try to answer those specific questions; they are much more likely to be answered if you provide information about the software context in which you are using Yaffs and details of the kind of difficulty you have</p>\r\n\r\n<p>Yaffs is provided on an \"as is\" basis without any warranty as to its suitability for any particular purpose. This may seem unfair, but it follows from the terms of the GNU Public Licence and the Licence for the hardware designs.&nbsp; Yaffs is unique in our experience in that you can try it without charge, and satisfy yourself that it works for your product before you buy a Licence to use it.</p>\r\n\r\n<p>In any case the company shall not be liable for any losses, damage, costs, expenses including (without limitation) any loss of profits, any loss or damage to property and any indirect or consequential loss howsoever caused including any liability to third parties.</p>\r\n\r\n<h3>Legal</h3>\r\n\r\n<p>We provide the Source Code to Yaffs and any derived file systems without any warranty&nbsp;but <strong>AS IS</strong>&nbsp;save that (to the best of Aleph One\'s knowledge) the use of the Source&nbsp;Code does not infringe the intellectual property rights of any third party.</p>\r\n\r\n<p>We provide certain pieces of software, with different licences associated with them:</p>\r\n\r\n<ul>\r\n	<li>Source Code for Yaffs1, Yaffs2 and Yaffs/direct and Bootloader, being the subject of this Licence Agreement, for incorporation in a Product.</li>\r\n	<li>Yaffs&nbsp;Development Tools</li>\r\n</ul>\r\n\r\n<p>Images created with the tools may be incorporated into a Product. The images are not affected by the licence status of the Tools. When these Tool files are supplied in the tarball we send they appear with a header saying they are used under the GNU Public Licence, GPL. That term applies only to the Tools.</p>\r\n\r\n<p>The other files in the tarball have headers making clear they are used under a paid licence from Aleph One Ltd.</p>\r\n\r\n<p>The Licence also permits access to all information on Yaffs&nbsp;published by Aleph One Ltd at http://www.yaffs.net - now and at any time in the future.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n','Details of our privacy policy and our conditions of sale.','basic_html'),('page',0,32,32,'und',0,'<p>1. Definitions:</p><p>ALEPH ONE LIMITED - An English company, Registered Number 1017960, of The Old Courthouse, 123 High Street, Bottisham, Cambridge CB25 9BA UK.</p><p>SOURCE CODE - Code owned by Aleph One Ltd and supplied under this Licence</p><p>BINARY CODE - Code which has been compiled from SOURCE CODE</p><p>LICENCE-HOLDER - The firm represented by the person who signs this Agreement. Each Licence bears the Name and Address of a particular LICENCE HOLDER.</p><p>YAFFS FILESYSTEMS - any Filesystem Images made using YAFFS SOURCE CODE or YAFFS BINARY CODE.</p><p>PRODUCT will be defined precisely at the time of negotiation of the sale of the Licence. See section 3 for the principles used in defining PRODUCT</p><p>2. The Licence:</p><p>Allows the LICENCE-HOLDER to use Aleph One\'s software to create the File System, FS and incorporate the FS in the defined Products.</p><p>Entitles the LICENCE-HOLDER to distribute BINARY CODE compiled from the SOURCE CODE provided.</p><p>Does not entail any obligation to reveal the BINARY CODE.</p><p>Prohibits the LICENCE-HOLDER from releasing the SOURCE CODE to other parties, except to the extent necessary to permit sub-contractors to work with the LICENCE-HOLDER on a project using the code. The LICENCE-HOLDER is responsible for ensuring compliance with all the terms of this Licence by any sub-contractor used.</p><p>Is only available in a non-exclusive form.</p><p>Is applicable worldwide.</p><p>Has no time limit or per-unit royalty, but a fixed price paid upon signature of the Licence Agreement.&nbsp; From 1 August 2012 the base price (for one Product) is GB£10,000. Sterling</p><p>Applies to use of the FS for one PRODUCT rather than to a company/user/person. It cannot be transferred to another PRODUCT.</p><p>Provides the SOURCE CODE and any derived FILESYSTEMS without any warranty but &gt;AS IS&lt; save that (to the best of Aleph One\'s knowledge) the use of the SOURCE CODE does not infringe the intellectual propert rights of any third party.</p><p>3. Supporting information and Terms relating to use:</p><p>Aleph One Ltd supplies:</p><p>Free access to all documentation written for YAFFS by Aleph One, at http://www.yaffs.net</p><p>Certain pieces of software, with different Licences attached to them:-</p><p>SOURCE CODE for YAFFS/direct and Bootloader, being the subject of this Licence agreement, for incorporation in a PRODUCT.</p><p>YAFFS Development Tools; images created with the tools may be incorporated into a product. The images are not affected by the licence status of the tools.&nbsp; When these Tool files are supplied in the tarball we send, they will appear with a header saying they are used under the GNU General Public Licence, version 2.&nbsp; That term applies only to the Tools; the other files in the tarball will have headers making clear they are used under a paid Licence from Aleph One Ltd.</p><p>Source code modifications and enhancements made by the LICENCE-HOLDER remain the property of LICENCE-HOLDER, but may not be redistributed or sold to third parties by LICENCE-HOLDER without the consent of Aleph One.</p><p>PRODUCT DEFINITION<br><br>A Yaffs Licence Agreement requires the definition of the Product to which it applies.&nbsp; We do this with a brief description of its purpose, and the hardware in terms of the type or family of chips used as CPU or MCU, and any internal Code Name or Product name or SKU that you use for it.<br>Later changes to the PCB which are evolutionary do not create a fresh Product, nor do changes in the size or speed of those chips or of the I/O technology.</p><p>Discussion with Aleph One about licensing further Products is required where:<br>&nbsp;&nbsp;&nbsp; A new PCB or key CPU or MCU is used, or<br>&nbsp;&nbsp;&nbsp; You sell chip designs and no hardware, or<br>&nbsp;&nbsp;&nbsp; You sell a Development Board with SDK to customers who will integrate&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Yaffs into their Products, or<br>&nbsp;&nbsp;&nbsp; Changes in the brand name or badge are made, or<br>&nbsp;&nbsp;&nbsp; Your rights to the Product pass to a new owner.<br><br>Following payment for the Licence Aleph One will provide a tarball with file headers showing that the code is being used by the LICENCE-HOLDER under a paid Licence from Aleph One.</p><ul><li>Version 24 - September 2015</li></ul>','While the Yaffs code is available free of charge under GNU General Public Licence, version 2, that entails the obligation to disclose Source Code for your application using Yaffs. An Aleph One Licence does not impose that obligation and so is attractive for proprietary projects.  This provides an example of the points we expect a Licence to cover.','full_html'),('page',0,32,523,'und',0,'<p>1. Definitions:</p><p>ALEPH ONE LIMITED - An English company, Registered Number 1017960, of The Old Courthouse, 123 High Street, Bottisham, Cambridge CB25 9BA UK.</p><p>SOURCE CODE - Code owned by Aleph One Ltd and supplied under this Licence</p><p>BINARY CODE - Code which has been compiled from SOURCE CODE</p><p>LICENCE-HOLDER - The firm represented by the person who signs this Agreement. Each Licence bears the Name and Address of a particular LICENCE HOLDER.</p><p>YAFFS FILESYSTEMS - any Filesystem Images made using YAFFS SOURCE CODE or YAFFS BINARY CODE.</p><p>PRODUCT will be defined precisely at the time of negotiation of the sale of the Licence. See section 3 for the principles used in defining PRODUCT</p><p>2. The Licence:</p><p>Allows the LICENCE-HOLDER to use Aleph One\'s software to create the File System, FS and incorporate the FS in the defined Products.</p><p>Entitles the LICENCE-HOLDER to distribute BINARY CODE compiled from the SOURCE CODE provided.</p><p>Does not entail any obligation to reveal the BINARY CODE.</p><p>Prohibits the LICENCE-HOLDER from releasing the SOURCE CODE to other parties, except to the extent necessary to permit sub-contractors to work with the LICENCE-HOLDER on a project using the code. The LICENCE-HOLDER is responsible for ensuring compliance with all the terms of this Licence by any sub-contractor used.</p><p>Is only available in a non-exclusive form.</p><p>Is applicable worldwide.</p><p>Has no time limit or per-unit royalty, but a fixed price paid upon signature of the Licence Agreement.&nbsp; From 1 August 2012 the base price (for one Product) is GB£10,000. Sterling</p><p>Applies to use of the FS for one PRODUCT rather than to a company/user/person. It cannot be transferred to another PRODUCT.</p><p>Provides the SOURCE CODE and any derived FILESYSTEMS without any warranty but &gt;AS IS&lt; save that (to the best of Aleph One\'s knowledge) the use of the SOURCE CODE does not infringe the intellectual propert rights of any third party.</p><p>3. Supporting information and Terms relating to use:</p><p>Aleph One Ltd supplies:</p><p>Free access to all documentation written for YAFFS by Aleph One, at http://www.yaffs.net</p><p>Certain pieces of software, with different Licences attached to them:-</p><p>SOURCE CODE for YAFFS/direct and Bootloader, being the subject of this Licence agreement, for incorporation in a PRODUCT.</p><p>YAFFS Development Tools; images created with the tools may be incorporated into a product. The images are not affected by the licence status of the tools.&nbsp; When these Tool files are supplied in the tarball we send, they will appear with a header saying they are used under the GNU General Public Licence, version 2.&nbsp; That term applies only to the Tools; the other files in the tarball will have headers making clear they are used under a paid Licence from Aleph One Ltd.</p><p>Source code modifications and enhancements made by the LICENCE-HOLDER remain the property of LICENCE-HOLDER, but may not be redistributed or sold to third parties by LICENCE-HOLDER without the consent of Aleph One.</p><p>PRODUCT DEFINITION<br><br>A Yaffs Licence Agreement requires the definition of the Product to which it applies.&nbsp; We do this with a brief description of its purpose, and the hardware in terms of the type or family of chips used as CPU or MCU, and any internal Code Name or Product name or SKU that you use for it.<br>Later changes to the PCB which are evolutionary do not create a fresh Product, nor do changes in the size or speed of those chips or of the I/O technology.</p><p>Discussion with Aleph One about licensing further Products is required where:<br>&nbsp;&nbsp;&nbsp; A new PCB or key CPU or MCU is used, or<br>&nbsp;&nbsp;&nbsp; You sell chip designs and no hardware, or<br>&nbsp;&nbsp;&nbsp; You sell a Development Board with SDK to customers who will integrate&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Yaffs into their Products, or<br>&nbsp;&nbsp;&nbsp; Changes in the brand name or badge are made, or<br>&nbsp;&nbsp;&nbsp; Your rights to the Product pass to a new owner.<br><br>Following payment for the Licence Aleph One will provide a tarball with file headers showing that the code is being used by the LICENCE-HOLDER under a paid Licence from Aleph One.</p><ul><li>Version 24 - September 2015</li></ul>','While the Yaffs code is available free of charge under GNU General Public Licence, version 2, that entails the obligation to disclose Source Code for your application using Yaffs. An Aleph One Licence does not impose that obligation and so is attractive for proprietary projects.  This provides an example of the points we expect a Licence to cover.','full_html'),('page',0,32,622,'und',0,'<p>1. Definitions:</p>\r\n\r\n<p>ALEPH ONE LIMITED - An English company, Registered Number 1017960, of The Old Courthouse, 123 High Street, Bottisham, Cambridge CB25 9BA UK.</p>\r\n\r\n<p>SOURCE CODE - Code owned by Aleph One Ltd and supplied under this Licence</p>\r\n\r\n<p>BINARY CODE - Code which has been compiled from SOURCE CODE</p>\r\n\r\n<p>LICENCE-HOLDER - The firm represented by the person who signs this Agreement. Each Licence bears the Name and Address of a particular LICENCE HOLDER.</p>\r\n\r\n<p>YAFFS FILESYSTEMS - any Filesystem Images made using YAFFS SOURCE CODE or YAFFS BINARY CODE.</p>\r\n\r\n<p>PRODUCT will be defined precisely at the time of negotiation of the sale of the Licence. See section 3 for the principles used in defining PRODUCT</p>\r\n\r\n<p>2. The Licence:</p>\r\n\r\n<p>Allows the LICENCE-HOLDER to use Aleph One\'s software to create the File System, FS and incorporate the FS in the defined Products.</p>\r\n\r\n<p>Entitles the LICENCE-HOLDER to distribute BINARY CODE compiled from the SOURCE CODE provided.</p>\r\n\r\n<p>Does not entail any obligation to reveal the BINARY CODE.</p>\r\n\r\n<p>Prohibits the LICENCE-HOLDER from releasing the SOURCE CODE to other parties, except to the extent necessary to permit sub-contractors to work with the LICENCE-HOLDER on a project using the code. The LICENCE-HOLDER is responsible for ensuring compliance with all the terms of this Licence by any sub-contractor used.</p>\r\n\r\n<p>Is only available in a non-exclusive form.</p>\r\n\r\n<p>Is applicable worldwide.</p>\r\n\r\n<p>Has no time limit or per-unit royalty, but a fixed price paid upon signature of the Licence Agreement.&nbsp; From 1 August 2012 the base price (for one Product) is GB£10,000. Sterling</p>\r\n\r\n<p>Applies to use of the FS for one PRODUCT rather than to a company/user/person. It cannot be transferred to another PRODUCT.</p>\r\n\r\n<p>Provides the SOURCE CODE and any derived FILESYSTEMS without any warranty but &gt;AS IS&lt; save that (to the best of Aleph One\'s knowledge) the use of the SOURCE CODE does not infringe the intellectual propert rights of any third party.</p>\r\n\r\n<p>3. Supporting information and Terms relating to use:</p>\r\n\r\n<p>Aleph One Ltd supplies:</p>\r\n\r\n<p>Free access to all documentation written for YAFFS by Aleph One, at http://www.yaffs.net</p>\r\n\r\n<p>Certain pieces of software, with different Licences attached to them:-</p>\r\n\r\n<p>SOURCE CODE for YAFFS/direct and Bootloader, being the subject of this Licence agreement, for incorporation in a PRODUCT.</p>\r\n\r\n<p>YAFFS Development Tools; images created with the tools may be incorporated into a product. The images are not affected by the licence status of the tools.&nbsp; When these Tool files are supplied in the tarball we send, they will appear with a header saying they are used under the GNU General Public Licence, version 2.&nbsp; That term applies only to the Tools; the other files in the tarball will have headers making clear they are used under a paid Licence from Aleph One Ltd.</p>\r\n\r\n<p>Source code modifications and enhancements made by the LICENCE-HOLDER remain the property of LICENCE-HOLDER, but may not be redistributed or sold to third parties by LICENCE-HOLDER without the consent of Aleph One.</p>\r\n\r\n<p>PRODUCT DEFINITION<br />\r\n<br />\r\nA Yaffs Licence Agreement requires the definition of the Product to which it applies.&nbsp; We do this with a brief description of its purpose, and the hardware in terms of the type or family of chips used as CPU or MCU, and any internal Code Name or Product name or SKU that you use for it.<br />\r\nLater changes to the PCB which are evolutionary do not create a fresh Product, nor do changes in the size or speed of those chips or of the I/O technology.</p>\r\n\r\n<p>Discussion with Aleph One about licensing further Products is required where:<br />\r\n&nbsp;&nbsp;&nbsp; A new PCB or key CPU or MCU is used, or<br />\r\n&nbsp;&nbsp;&nbsp; You sell chip designs and no hardware, or<br />\r\n&nbsp;&nbsp;&nbsp; You sell a Development Board with SDK to customers who will integrate&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Yaffs into their Products, or<br />\r\n&nbsp;&nbsp;&nbsp; Changes in the brand name or badge are made, or<br />\r\n&nbsp;&nbsp;&nbsp; Your rights to the Product pass to a new owner.<br />\r\n<br />\r\nFollowing payment for the Licence Aleph One will provide a tarball with file headers showing that the code is being used by the LICENCE-HOLDER under a paid Licence from Aleph One.</p>\r\n\r\n<ul>\r\n	<li>Version 24 - September 2015</li>\r\n</ul>\r\n','While the Yaffs code is available free of charge under GNU General Public Licence, version 2, that entails the obligation to disclose Source Code for your application using Yaffs. An Aleph One Licence does not impose that obligation and so is attractive for proprietary projects.  This sample Licence provides an example of the points we expect a Licence to cover.','full_html'),('page',0,32,623,'und',0,'<p>1. Definitions:</p>\r\n\r\n<p>ALEPH ONE LIMITED - An English company, Registered Number 1017960, of The Old Courthouse, 123 High Street, Bottisham, Cambridge CB25 9BA UK.</p>\r\n\r\n<p>SOURCE CODE - Code owned by Aleph One Ltd and supplied under this Licence</p>\r\n\r\n<p>BINARY CODE - Code which has been compiled from SOURCE CODE</p>\r\n\r\n<p>LICENCE-HOLDER - The firm represented by the person who signs this Agreement. Each Licence bears the Name and Address of a particular LICENCE HOLDER.</p>\r\n\r\n<p>YAFFS FILESYSTEMS - any Filesystem Images made using YAFFS SOURCE CODE or YAFFS BINARY CODE.</p>\r\n\r\n<p>PRODUCT will be defined precisely at the time of negotiation of the sale of the Licence. See section 3 for the principles used in defining PRODUCT</p>\r\n\r\n<p>2. The Licence:</p>\r\n\r\n<p>Allows the LICENCE-HOLDER to use Aleph One\'s software to create the File System, FS and incorporate the FS in the defined Products.</p>\r\n\r\n<p>Entitles the LICENCE-HOLDER to distribute BINARY CODE compiled from the SOURCE CODE provided.</p>\r\n\r\n<p>Does not entail any obligation to reveal the BINARY CODE.</p>\r\n\r\n<p>Prohibits the LICENCE-HOLDER from releasing the SOURCE CODE to other parties, except to the extent necessary to permit sub-contractors to work with the LICENCE-HOLDER on a project using the code. The LICENCE-HOLDER is responsible for ensuring compliance with all the terms of this Licence by any sub-contractor used.</p>\r\n\r\n<p>Is only available in a non-exclusive form.</p>\r\n\r\n<p>Is applicable worldwide.</p>\r\n\r\n<p>Has no time limit or per-unit royalty, but a fixed price paid upon signature of the Licence Agreement.&nbsp; From 1 August 2012 the base price (for one Product) is GB£10,000. Sterling</p>\r\n\r\n<p>Applies to use of the FS for one PRODUCT rather than to a company/user/person. It cannot be transferred to another PRODUCT.</p>\r\n\r\n<p>Provides the SOURCE CODE and any derived FILESYSTEMS without any warranty but &gt;AS IS&lt; save that (to the best of Aleph One\'s knowledge) the use of the SOURCE CODE does not infringe the intellectual propert rights of any third party.</p>\r\n\r\n<p>3. Supporting information and Terms relating to use:</p>\r\n\r\n<p>Aleph One Ltd supplies:</p>\r\n\r\n<p>Free access to all documentation written for YAFFS by Aleph One, at http://www.yaffs.net</p>\r\n\r\n<p>Certain pieces of software, with different Licences attached to them:-</p>\r\n\r\n<p>SOURCE CODE for YAFFS/direct and Bootloader, being the subject of this Licence agreement, for incorporation in a PRODUCT.</p>\r\n\r\n<p>YAFFS Development Tools; images created with the tools may be incorporated into a product. The images are not affected by the licence status of the tools.&nbsp; When these Tool files are supplied in the tarball we send, they will appear with a header saying they are used under the GNU General Public Licence, version 2.&nbsp; That term applies only to the Tools; the other files in the tarball will have headers making clear they are used under a paid Licence from Aleph One Ltd.</p>\r\n\r\n<p>Source code modifications and enhancements made by the LICENCE-HOLDER remain the property of LICENCE-HOLDER, but may not be redistributed or sold to third parties by LICENCE-HOLDER without the consent of Aleph One.</p>\r\n\r\n<p>PRODUCT DEFINITION<br />\r\n<br />\r\nA Yaffs Licence Agreement requires the definition of the Product to which it applies.&nbsp; We do this with a brief description of its purpose, and the hardware in terms of the type or family of chips used as CPU or MCU, and any internal Code Name or Product name or SKU that you use for it.<br />\r\nLater changes to the PCB which are evolutionary do not create a fresh Product, nor do changes in the size or speed of those chips or of the I/O technology.</p>\r\n\r\n<p>Discussion with Aleph One about licensing further Products is required where:</p>\r\n\r\n<ul>\r\n	<li>A new PCB or key CPU or MCU is used, or</li>\r\n	<li>You sell chip designs and no hardware, or</li>\r\n	<li>You sell a Development Board with SDK to customers who will integrate&nbsp;Yaffs into their Products, or</li>\r\n	<li>Changes in the brand name or badge are made, or</li>\r\n	<li>Your rights to the Product pass to a new owner.</li>\r\n</ul>\r\n\r\n<p>Following payment for the Licence Aleph One will provide a tarball with file headers showing that the code is being used by the LICENCE-HOLDER under a paid Licence from Aleph One.</p>\r\n\r\n<ul>\r\n	<li>Version 24 - September 2015</li>\r\n</ul>\r\n','While the Yaffs code is available free of charge under GNU General Public Licence, version 2, that entails the obligation to disclose Source Code for your application using Yaffs. An Aleph One Licence does not impose that obligation and so is attractive for proprietary projects.  This sample Licence provides an example of the points we expect a Licence to cover.','full_html'),('page',0,32,633,'und',0,'<p>1. Definitions:</p>\r\n\r\n<p>ALEPH ONE LIMITED - An English company, Registered Number 1017960, of The Old Courthouse, 123 High Street, Bottisham, Cambridge CB25 9BA UK.</p>\r\n\r\n<p>SOURCE CODE - Code owned by Aleph One Ltd and supplied under this Licence</p>\r\n\r\n<p>BINARY CODE - Code which has been compiled from SOURCE CODE</p>\r\n\r\n<p>LICENCE-HOLDER - The firm represented by the person who signs this Agreement. Each Licence bears the Name and Address of a particular LICENCE HOLDER.</p>\r\n\r\n<p>YAFFS FILESYSTEMS - any Filesystem Images made using YAFFS SOURCE CODE or YAFFS BINARY CODE.</p>\r\n\r\n<p>PRODUCT will be defined precisely at the time of negotiation of the sale of the Licence. See section 3 for the principles used in defining PRODUCT</p>\r\n\r\n<p>2. The Licence:</p>\r\n\r\n<p>Allows the LICENCE-HOLDER to use Aleph One\'s software to create the File System, FS and incorporate the FS in the defined Products.</p>\r\n\r\n<p>Entitles the LICENCE-HOLDER to distribute BINARY CODE compiled from the SOURCE CODE provided.</p>\r\n\r\n<p>Does not entail any obligation to reveal the BINARY CODE.</p>\r\n\r\n<p>Prohibits the LICENCE-HOLDER from releasing the SOURCE CODE to other parties, except to the extent necessary to permit sub-contractors to work with the LICENCE-HOLDER on a project using the code. The LICENCE-HOLDER is responsible for ensuring compliance with all the terms of this Licence by any sub-contractor used.</p>\r\n\r\n<p>Is only available in a non-exclusive form.</p>\r\n\r\n<p>Is applicable worldwide.</p>\r\n\r\n<p>Has no time limit or per-unit royalty, but a fixed price paid upon signature of the Licence Agreement.&nbsp; From 1 August 2012 the base price (for one Product) is GB£10,000. Sterling</p>\r\n\r\n<p>Applies to use of the FS for one PRODUCT rather than to a company/user/person. It cannot be transferred to another PRODUCT.</p>\r\n\r\n<p>Provides the SOURCE CODE and any derived FILESYSTEMS without any warranty but &gt;AS IS&lt; save that (to the best of Aleph One\'s knowledge) the use of the SOURCE CODE does not infringe the intellectual propert rights of any third party.</p>\r\n\r\n<p>3. Supporting information and Terms relating to use:</p>\r\n\r\n<p>This Licence supplies:</p>\r\n\r\n<p>Free access to all documentation written for YAFFS by Aleph One, at http://www.yaffs.net</p>\r\n\r\n<p>Certain pieces of software, with different Licences attached to them:-</p>\r\n\r\n<p>SOURCE CODE for YAFFS/direct and Bootloader, being the subject of this Licence agreement, for incorporation in a PRODUCT.</p>\r\n\r\n<p>YAFFS Development Tools; images created with the tools may be incorporated into a product. The images are not affected by the licence status of the tools.&nbsp; When these Tool files are supplied in the tarball we send, they will appear with a header saying they are used under the GNU General Public Licence, version 2.&nbsp; That term applies only to the Tools; the other files in the tarball will have headers making clear they are used under a paid Licence from Aleph One Ltd.</p>\r\n\r\n<p>Source code modifications and enhancements made by the LICENCE-HOLDER remain the property of LICENCE-HOLDER, but may not be redistributed or sold to third parties by LICENCE-HOLDER without the consent of Aleph One.</p>\r\n\r\n<p>PRODUCT DEFINITION<br />\r\n<br />\r\nA Yaffs Licence Agreement requires the definition of the Product to which it applies.&nbsp; We do this with a brief description of its purpose, and the hardware in terms of the type or family of chips used as CPU or MCU, and any internal Code Name or Product name or SKU that you use for it.<br />\r\nLater changes to the PCB which are evolutionary do not create a fresh Product, nor do changes in the size or speed of those chips or of the I/O technology.</p>\r\n\r\n<p>Discussion with Aleph One about licensing further Products is required where:</p>\r\n\r\n<ul>\r\n	<li>A new PCB or key CPU or MCU is used, or</li>\r\n	<li>You sell chip designs and no hardware, or</li>\r\n	<li>You sell a Development Board with SDK to customers who will integrate&nbsp;Yaffs into their Products, or</li>\r\n	<li>Changes in the brand name or badge are made, or</li>\r\n	<li>Your rights to the Product pass to a new owner.</li>\r\n</ul>\r\n\r\n<p>Following payment for the Licence Aleph One will provide a tarball with file headers showing that the code is being used by the LICENCE-HOLDER under a paid Licence from Aleph One.</p>\r\n\r\n<ul>\r\n	<li>Version 24 - September 2015</li>\r\n</ul>\r\n','While the Yaffs code is available free of charge under GNU General Public Licence, version 2, that entails the obligation to disclose Source Code for your application using Yaffs. An Aleph One Licence does not impose that obligation and so is attractive for proprietary projects.  This sample Licence provides an example of the points we expect a Licence to cover.','full_html'),('page',0,37,37,'und',0,'<h1 align=\"center\">YAFFS (Yet Another Flash File System)</h1><h4 align=\"left\">Version 0.3</h4><h4 align=\"left\">Charles Manning (and Wookey), December 2001</h4><p align=\"left\"><br>&nbsp;</p><h2>Revision History</h2><p>V0.0 20/12/01 First Draft</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" style=\"width: 548px;\"><tbody><tr><td valign=\"top\" width=\"88\"><p align=\"left\">V0.1</p></td><td valign=\"bottom\" width=\"72\"><p align=\"left\">11/01/02</p></td><td valign=\"top\" width=\"350\"><p align=\"left\">Minor corrections &amp; cosmetics.<br>Change use of data status byte.</p></td></tr><tr><td valign=\"top\" width=\"88\"><p align=\"left\">V0.2</p></td><td valign=\"bottom\" width=\"72\"><p align=\"right\">28/01/02</p></td><td valign=\"top\" width=\"350\"><p align=\"left\">Added observations about inodes, file headers and hard links.</p></td></tr><tr><td valign=\"top\" width=\"88\"><p align=\"left\">V0.3</p></td><td valign=\"bottom\" width=\"72\"><p align=\"right\">26/02/02</p></td><td valign=\"top\" width=\"350\"><p align=\"left\">W:Added some general observations on compatibility, partitions and bootloading.</p></td></tr></tbody></table><p align=\"left\"><br>&nbsp;</p><h2>Scope</h2><p>The purpose of this document is to outline a potential NAND-friendly file system for Linux.</p><h2>Background</h2><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><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><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><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><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><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><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><p>The intentions of the design sketched here are:</p><ul><li><p>Be NAND-flash friendly.</p></li><li><p>Robustness through journaling strategies.</p></li><li><p>Significantly reduce the RAM overheads and boot times associated with JFFSx.</p></li></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><h2>Overview</h2><p>Here follows a simplified overview of YAFFS.</p><p>YAFFS uses a physical flash format similar to SmartMedia. This is done for various reasons:</p><ul><li><p>Some of the formatting, eg placement of bad block markers is determined by the NAND manufacturers and can\'t be changed.</p></li><li><p>Potential to reuse code.</p></li><li><p>If it ain\'t broke don\'t fix.</p></li></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><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><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><p>File \"headers\" are stored as a single page, marked so as to be differentiated from data pages.</p><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><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><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 2<sup>18</sup> 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><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><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><p><br>&nbsp;</p><h3>Spare area details</h3><p>The following table summarizes the layout of the spare area of each page.</p><p>Byte #SmartMedia usageYAFFS usage</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" style=\"width: 674px;\"><tbody><tr valign=\"top\"><td width=\"96\"><p>0..511</p></td><td width=\"249\"><p>Data</p></td><td width=\"291\"><p>Data. either file data or file header depending on tags</p></td></tr><tr valign=\"top\"><td width=\"96\"><p>512..515</p></td><td width=\"249\"><p>Reserved</p></td><td width=\"291\"><p>Tags</p></td></tr><tr><td valign=\"bottom\" width=\"96\"><p align=\"right\">516</p></td><td valign=\"top\" width=\"249\"><p>Data status byte. Not used in SM code from Samsung</p></td><td valign=\"top\" width=\"291\"><p>Data status byte. If more than 4 bits are zero, then this page is discarded.</p></td></tr><tr><td valign=\"bottom\" width=\"96\"><p align=\"right\">517</p></td><td valign=\"top\" width=\"249\"><p>Block status byte</p></td><td valign=\"top\" width=\"291\"><p>Block status byte</p></td></tr><tr valign=\"top\"><td width=\"96\"><p align=\"left\">518..519</p></td><td width=\"249\"><p>Block address</p></td><td width=\"291\"><p>Tags</p></td></tr><tr valign=\"top\"><td width=\"96\"><p align=\"left\">520..522</p></td><td width=\"249\"><p>ECC on second 256 bytes part of data</p></td><td width=\"291\"><p>ECC on second 256 bytes of data</p></td></tr><tr valign=\"top\"><td width=\"96\"><p align=\"left\">523..524</p></td><td width=\"249\"><p>Block address</p></td><td width=\"291\"><p>Tags</p></td></tr><tr valign=\"top\"><td width=\"96\"><p align=\"left\">525..527</p></td><td width=\"249\"><p>ECC on first 256 bytes part of data</p></td><td width=\"291\"><p>ECC on first 256 bytes part of data</p></td></tr></tbody></table><p><br>&nbsp;</p><p>The block status is a reserved value that shows whether the block is damaged.</p><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><p>There are 8 bytes (64 bits) for use by YAFFS tags. This is partitioned as follows:</p><p>Number of bitsUsage</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" style=\"width: 596px;\"><tbody><tr><td valign=\"bottom\" width=\"146\"><p align=\"right\">18</p></td><td valign=\"top\" width=\"423\"><p>18-bit file id. ie. Limit of 2<sup>18</sup> (over 260000) files. File id 0 is not valid and indicates a deleted page. File Id 0x3FFFF i is also not valid.</p></td></tr><tr><td valign=\"bottom\" width=\"146\"><p align=\"right\">2</p></td><td valign=\"top\" width=\"423\"><p align=\"left\">2-bit serial number.</p></td></tr><tr><td valign=\"bottom\" width=\"146\"><p align=\"right\">20</p></td><td valign=\"top\" width=\"423\"><p>20-bit page id within file. Limit of 2<sup>20</sup> pages per file. ie. over 500MB file max size. Page id 0 means the file header for this file.</p></td></tr><tr><td valign=\"bottom\" width=\"146\"><p align=\"right\">10</p></td><td valign=\"top\" width=\"423\"><p>10-bit counter of the number of bytes used in the page.</p></td></tr><tr><td valign=\"bottom\" width=\"146\"><p align=\"right\">12</p></td><td valign=\"top\" width=\"423\"><p>12-bit ECC on tags.</p></td></tr><tr><td valign=\"bottom\" width=\"146\"><p align=\"right\">2</p></td><td valign=\"top\" width=\"423\"><p>Unused. Keep as 1.</p></td></tr><tr><td valign=\"bottom\" width=\"146\"><p align=\"right\"><strong>64</strong></p></td><td valign=\"top\" width=\"423\"><p><strong>Total</strong></p></td></tr></tbody></table><p><br>&nbsp;</p><p>A bit of explanation on the usage of some of these fields:</p><p>file Id is synonymous with inode.</p><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><p>When the page is rewritten, the file id, these data status byte and the 12-bit ECC are all written to zero.</p><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><p>File \"headers\" come in two flavours:</p><ul><li><p>file info ( the mode, ower id, group id, length,...)</p></li><li><p>the hard link(s) that refers to the file.</p></li></ul><p>A directory also appears as a file (ie. has an inode and hard link(s)) but has no data.</p><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><h3>RAM data details</h3><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><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><h3>Page allocation and garbage collection</h3><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><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><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><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><h3>Flash writing</h3><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><h3>Wear levelling</h3><p>No wear levelling is explicitly used here. Instead we rely on two \"strategies\":</p><ul><li><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></li><li><p>The infrequent random block selection should prevent low-wear blocks getting \"stuck\".</p></li></ul><h3>Partitioning</h3><p>Partitioning is not included in this spec, but could be added if required.</p><h3>Bootloading</h3><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><h3>Conclusion</h3><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><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><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><p>&nbsp;</p><h1 align=\"center\">YAFFS Development Notes</h1><h3>Build options</h3><p>Yaffs can be built as either a kernel module (ie. a Linux file system) or as an application.</p><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><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><h3>Trying it out</h3><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><ol><li><p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p></li><li><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></li><li><p>Type <strong>make clean; make</strong> to build yaffs</p></li><li><p>Load yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p></li><li><p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p></li><li><p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p></li><li><p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p></li></ol><p><br>&nbsp;</p><h3>YAFFS Data structures</h3><p>All data types are defined in yaffs_guts.h</p><p>Yaffs uses the following major objects:</p><ul><li><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></li><li><p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p></li><li><p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p></li><li><p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p></li><li><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></li><li><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></li></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><h3>yaffs_Object</h3><p><br>&nbsp;</p><p>struct yaffs_ObjectStruct</p><p>{</p><p>__u8 fake:1; // A fake object has no presence on NAND.</p><p>__u8 renameAllowed:1; // Are we allowed to rename it?</p><p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p><p>__u8 dirty:1; // the object needs to be written to flash</p><p>__u8 valid:1; // When the file system is being loaded up, this</p><p>// object might be created before the data</p><p>// is available (ie. file data records appear before the header).</p><p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p><p>// read back the old one to update.</p><p>__u16 sum; // sum of the name to speed searching</p><p>&nbsp;</p><p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p><p>&nbsp;</p><p>&nbsp;</p><p>struct list_head hashLink; // list of objects in this hash bucket</p><p>&nbsp;</p><p>&nbsp;</p><p>struct list_head hardLinks; // all the equivalent hard linked objects</p><p>// live on this list</p><p>// directory structure stuff</p><p>struct yaffs_ObjectStruct *parent; //my parent directory</p><p>struct list_head siblings; // siblings in a directory</p><p>// also used for linking up the free list</p><p>&nbsp;</p><p>// Where\'s my data in NAND?</p><p>int chunkId; // where it lives</p><p>&nbsp;</p><p>__u32 objectId; // the object id value</p><p>&nbsp;</p><p>&nbsp;</p><p>__u32 st_mode; // protection</p><p>__u32 st_uid; // user ID of owner</p><p>__u32 st_gid; // group ID of owner</p><p>__u32 st_atime; // time of last access</p><p>__u32 st_mtime; // time of last modification</p><p>__u32 st_ctime; // time of last change</p><p>&nbsp;</p><p>&nbsp;</p><p>yaffs_ObjectType variantType;</p><p>&nbsp;</p><p>yaffs_ObjectVariant variant;</p><p>&nbsp;</p><p>};</p><p><br>&nbsp;</p><p>Obvious stuff skipped....</p><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><p>serial, sum: see yaffs_ObjectHeader.</p><p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p><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><p>hashlink is a list of Objects in the same hash bucket.</p><p>The four variants hold extra info:</p><p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p><p>Directories hold a list of children objects.</p><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><p>Hardlinks hold information to identify the equivalent object.</p><p><br>&nbsp;</p><p><br>&nbsp;</p><h3>File structure (tnodes)</h3><p>File structures are done with a tiered indexing structure</p><p><br>&nbsp;</p><p><img align=\"left\" border=\"0\" height=\"294\" src=\"yaffs/sv9349341.gif\" width=\"491\"><br><br>&nbsp;</p><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><ul><li><p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p></li><li><p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p></li></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><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><p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p><p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p><p>LevelBitsSelected value</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" style=\"width: 496px;\"><tbody><tr valign=\"top\"><td width=\"140\"><p>3 or more if they exist</p></td><td width=\"160\"><p>&gt;= 10</p></td><td width=\"158\"><p>Zero</p></td></tr><tr><td valign=\"bottom\" width=\"140\"><p align=\"right\">2</p></td><td valign=\"top\" width=\"160\"><p align=\"left\">9 to 7</p></td><td valign=\"top\" width=\"158\"><p>100 binary = 4</p></td></tr><tr><td valign=\"bottom\" width=\"140\"><p align=\"right\">1</p></td><td valign=\"top\" width=\"160\"><p align=\"left\">6 to 4</p></td><td valign=\"top\" width=\"158\"><p>011 binary = 3</p></td></tr><tr><td valign=\"bottom\" width=\"140\"><p align=\"right\">0</p></td><td valign=\"top\" width=\"160\"><p align=\"left\">3 to 0</p></td><td valign=\"top\" width=\"158\"><p>0101 binary = 5</p></td></tr></tbody></table><p><br>&nbsp;</p><p>Free tnodes are stored in a list. When the list is exhausted, more are allocated.</p><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><p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p><p><br>&nbsp;</p><h3>NAND data</h3><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><ul><li><p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p></li><li><p>A chunk of file data.</p></li></ul><p>The 16 byte spare area contains:</p><ul><li><p>8 bytes of tags,</p></li><li><p>6 bytes of ECC data</p></li><li><p>1 byte block status (used to identify damaged blocks)</p></li><li><p>1 byte data status (currently unused).</p></li></ul><p>The tags are made up as follows:</p><p>typedef struct</p><p>{</p><p>unsigned chunkId:20; //chunk number in file</p><p>unsigned serialNumber:2; //serial number for chunk</p><p>unsigned byteCount:10; //number of bytes of data used in this chunk</p><p>unsigned objectId:18; //the object id that this chunk belongs to.</p><p>unsigned ecc:12; //ECC on tags</p><p>unsigned unusedStuff:2; //unused</p><p>} yaffs_Tags;</p><p>&nbsp;</p><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><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><p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p><p>objectId says which object this chunk belongs to.</p><p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p><p><br>&nbsp;</p><h3>yaffs_ObjectHeader</h3><p>typedef struct</p><p>{</p><p>yaffs_ObjectType type;</p><p>&nbsp;</p><p>// Apply to everything</p><p>int parentObjectId;</p><p>__u16 sum; // checksum of name</p><p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p><p>&nbsp;</p><p>// Thes following apply to directories, files, symlinks - not hard links</p><p>__u32 st_mode; // protection</p><p>__u32 st_uid; // user ID of owner</p><p>__u32 st_gid; // group ID of owner</p><p>__u32 st_atime; // time of last access</p><p>__u32 st_mtime; // time of last modification</p><p>__u32 st_ctime; // time of last change</p><p>&nbsp;</p><p>// File size applies to files only</p><p>int fileSize;</p><p>&nbsp;</p><p>// Equivalent object id applies to hard links only.</p><p>int equivalentObjectId;</p><p>// alias only applies to symlinks</p><p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p><p>&nbsp;</p><p>&nbsp;</p><p>} yaffs_ObjectHeader;</p><p>&nbsp;</p><p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p><p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p><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><p>Obvious stuff skipped....</p><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><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><p><br>&nbsp;</p><h3>NAND Interface</h3><p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p><ul><li><p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p></li><li><p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p></li><li><p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p></li><li><p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p></li></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><p>A quick note about NAND:</p><ul><li><p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p></li><li><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></li><li><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></li><li><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></li><li><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></li><li><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></li></ul><p><br>&nbsp;</p><h3>mkyaffs</h3><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><p><br>&nbsp;</p><h2>Expected performance</h2><p>The following numbers should give an indication of the performance we should expect from YAFFS.</p><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><p>Seek10uS/page</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" style=\"width: 233px;\"><tbody><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Read</p></td><td width=\"103\"><p align=\"left\">100nS/byte</p></td></tr><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Write</p></td><td width=\"103\"><p align=\"left\">100nS/byte</p></td></tr><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Program</p></td><td width=\"103\"><p align=\"left\">200uS/page</p></td></tr><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Erase</p></td><td width=\"103\"><p align=\"left\">2mS/block</p></td></tr></tbody></table><p><br>&nbsp;</p><p>From this we can derive some higher-level numbers:</p><p>OperationTimeCalculation</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" style=\"width: 706px;\"><tbody><tr valign=\"top\"><td width=\"204\"><p>Read spare</p></td><td width=\"160\"><p>12uS</p></td><td width=\"304\"><p>seek + 16 * read</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Read page</p></td><td width=\"160\"><p>63 uS</p></td><td width=\"304\"><p>seek + 528 * read</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Write page</p></td><td width=\"160\"><p>326 uS</p></td><td width=\"304\"><p>seek + 528 * write + program + read page (for verification)</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Discard page</p></td><td width=\"160\"><p>212 uS</p></td><td width=\"304\"><p>seek + 16 * write + program</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Overwrite page</p></td><td width=\"160\"><p>538 uS</p></td><td width=\"304\"><p>write page + discard page</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Erase overhead per page</p></td><td width=\"160\"><p>63uS</p></td><td width=\"304\"><p>erase/32</p></td></tr></tbody></table><p><br>&nbsp;</p><p>From this we can infer the following flash access times:</p><p>OperationTimeCalculation</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" style=\"width: 704px;\"><tbody><tr valign=\"top\"><td width=\"196\"><p>Read 1MB file</p></td><td width=\"167\"><p>0.13s (about 7.5 MB/s)</p></td><td width=\"303\"><p>2000 * read page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Write 1MB (clean system)</p></td><td width=\"167\"><p>0.53s (about 1.8 MB/s)</p></td><td width=\"303\"><p>2000 * write page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Overwrite 1MB file (no gc)</p></td><td width=\"167\"><p>1.08s (about 0.9MB/s)</p></td><td width=\"303\"><p>2000 * overwrite page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Overwrite 1MB with 50% gc</p></td><td width=\"167\"><p>2.4s (about 0.4 MB/s)</p></td><td width=\"303\"><p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Delete 1MB file</p></td><td width=\"167\"><p>0.43s (about 2.2 MB/s)</p></td><td width=\"303\"><p>2000 * discard page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Delete 1MB file with 50% gc</p></td><td width=\"167\"><p>0.49s (about 2.0MB/s)</p></td><td width=\"303\"><p>2000 * discard page + 1000 * erase overhead</p></td></tr></tbody></table><p>&nbsp;</p>','The initial specification for Yaffs. Circa 2002. Details of the filing system, including short backgrounder. Read this if you want to know what it is, what it does and how it works. This specification does not cover Yaffs2.','filtered_html'),('page',0,37,541,'und',0,'<p>YAFFS (Yet Another Flash File System)</p>\r\n\r\n<h4>Version 0.3</h4>\r\n\r\n<h4>Charles Manning (and Wookey), December 2001</h4>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Revision History</h2>\r\n\r\n<p>V0.0 20/12/01 First Draft</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>V0.1</p>\r\n			</td>\r\n			<td>\r\n			<p>11/01/02</p>\r\n			</td>\r\n			<td>\r\n			<p>Minor corrections &amp; cosmetics.<br />\r\n			Change use of data status byte.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>V0.2</p>\r\n			</td>\r\n			<td>\r\n			<p>28/01/02</p>\r\n			</td>\r\n			<td>\r\n			<p>Added observations about inodes, file headers and hard links.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>V0.3</p>\r\n			</td>\r\n			<td>\r\n			<p>26/02/02</p>\r\n			</td>\r\n			<td>\r\n			<p>W:Added some general observations on compatibility, partitions and bootloading.</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Scope</h2>\r\n\r\n<p>The purpose of this document is to outline a potential NAND-friendly file system for Linux.</p>\r\n\r\n<h2>Background</h2>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>The intentions of the design sketched here are:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Be NAND-flash friendly.</p>\r\n	</li>\r\n	<li>\r\n	<p>Robustness through journaling strategies.</p>\r\n	</li>\r\n	<li>\r\n	<p>Significantly reduce the RAM overheads and boot times associated with JFFSx.</p>\r\n	</li>\r\n</ul>\r\n\r\n<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>\r\n\r\n<h2>Overview</h2>\r\n\r\n<p>Here follows a simplified overview of YAFFS.</p>\r\n\r\n<p>YAFFS uses a physical flash format similar to SmartMedia. This is done for various reasons:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Some of the formatting, eg placement of bad block markers is determined by the NAND manufacturers and can\'t be changed.</p>\r\n	</li>\r\n	<li>\r\n	<p>Potential to reuse code.</p>\r\n	</li>\r\n	<li>\r\n	<p>If it ain\'t broke don\'t fix.</p>\r\n	</li>\r\n</ul>\r\n\r\n<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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>File \"headers\" are stored as a single page, marked so as to be differentiated from data pages.</p>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>Spare area details</h3>\r\n\r\n<p>The following table summarizes the layout of the spare area of each page.</p>\r\n\r\n<p>Byte #SmartMedia usageYAFFS usage</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>0..511</p>\r\n			</td>\r\n			<td>\r\n			<p>Data</p>\r\n			</td>\r\n			<td>\r\n			<p>Data. either file data or file header depending on tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>512..515</p>\r\n			</td>\r\n			<td>\r\n			<p>Reserved</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>516</p>\r\n			</td>\r\n			<td>\r\n			<p>Data status byte. Not used in SM code from Samsung</p>\r\n			</td>\r\n			<td>\r\n			<p>Data status byte. If more than 4 bits are zero, then this page is discarded.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>517</p>\r\n			</td>\r\n			<td>\r\n			<p>Block status byte</p>\r\n			</td>\r\n			<td>\r\n			<p>Block status byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>518..519</p>\r\n			</td>\r\n			<td>\r\n			<p>Block address</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>520..522</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on second 256 bytes part of data</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on second 256 bytes of data</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>523..524</p>\r\n			</td>\r\n			<td>\r\n			<p>Block address</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>525..527</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on first 256 bytes part of data</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on first 256 bytes part of data</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>The block status is a reserved value that shows whether the block is damaged.</p>\r\n\r\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>\r\n\r\n<p>There are 8 bytes (64 bits) for use by YAFFS tags. This is partitioned as follows:</p>\r\n\r\n<p>Number of bitsUsage</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>18</p>\r\n			</td>\r\n			<td>\r\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>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>2-bit serial number.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>20</p>\r\n			</td>\r\n			<td>\r\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>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10-bit counter of the number of bytes used in the page.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>12</p>\r\n			</td>\r\n			<td>\r\n			<p>12-bit ECC on tags.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>Unused. Keep as 1.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p><strong>64</strong></p>\r\n			</td>\r\n			<td>\r\n			<p><strong>Total</strong></p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>A bit of explanation on the usage of some of these fields:</p>\r\n\r\n<p>file Id is synonymous with inode.</p>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>File \"headers\" come in two flavours:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>file info ( the mode, ower id, group id, length,...)</p>\r\n	</li>\r\n	<li>\r\n	<p>the hard link(s) that refers to the file.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>A directory also appears as a file (ie. has an inode and hard link(s)) but has no data.</p>\r\n\r\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>\r\n\r\n<h3>RAM data details</h3>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Page allocation and garbage collection</h3>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Flash writing</h3>\r\n\r\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>\r\n\r\n<h3>Wear levelling</h3>\r\n\r\n<p>No wear levelling is explicitly used here. Instead we rely on two \"strategies\":</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>The infrequent random block selection should prevent low-wear blocks getting \"stuck\".</p>\r\n	</li>\r\n</ul>\r\n\r\n<h3>Partitioning</h3>\r\n\r\n<p>Partitioning is not included in this spec, but could be added if required.</p>\r\n\r\n<h3>Bootloading</h3>\r\n\r\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>\r\n\r\n<h3>Conclusion</h3>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>YAFFS Development Notes</p>\r\n\r\n<h3>Build options</h3>\r\n\r\n<p>Yaffs can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Trying it out</h3>\r\n\r\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>\r\n\r\n<ol>\r\n	<li>\r\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\r\n	</li>\r\n	<li>\r\n	<p>Load yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\r\n	</li>\r\n	<li>\r\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\r\n	</li>\r\n</ol>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>YAFFS Data structures</h3>\r\n\r\n<p>All data types are defined in yaffs_guts.h</p>\r\n\r\n<p>Yaffs uses the following major objects:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\r\n	</li>\r\n	<li>\r\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\r\n	</li>\r\n	<li>\r\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h3>yaffs_Object</h3>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>struct yaffs_ObjectStruct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\r\n\r\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\r\n\r\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\r\n\r\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\r\n\r\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\r\n\r\n<p>// object might be created before the data</p>\r\n\r\n<p>// is available (ie. file data records appear before the header).</p>\r\n\r\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\r\n\r\n<p>// read back the old one to update.</p>\r\n\r\n<p>__u16 sum; // sum of the name to speed searching</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\r\n\r\n<p>// live on this list</p>\r\n\r\n<p>// directory structure stuff</p>\r\n\r\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\r\n\r\n<p>struct list_head siblings; // siblings in a directory</p>\r\n\r\n<p>// also used for linking up the free list</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Where\'s my data in NAND?</p>\r\n\r\n<p>int chunkId; // where it lives</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>__u32 objectId; // the object id value</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>yaffs_ObjectType variantType;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>yaffs_ObjectVariant variant;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>};</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\n<p>serial, sum: see yaffs_ObjectHeader.</p>\r\n\r\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\r\n\r\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>\r\n\r\n<p>hashlink is a list of Objects in the same hash bucket.</p>\r\n\r\n<p>The four variants hold extra info:</p>\r\n\r\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\r\n\r\n<p>Directories hold a list of children objects.</p>\r\n\r\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>\r\n\r\n<p>Hardlinks hold information to identify the equivalent object.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>File structure (tnodes)</h3>\r\n\r\n<p>File structures are done with a tiered indexing structure</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><img alt=\"\" height=\"294\" src=\"yaffs/sv9349341.gif\" width=\"491\" /><br />\r\n<br />\r\n&nbsp;</p>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\r\n	</li>\r\n	<li>\r\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\r\n\r\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\r\n\r\n<p>LevelBitsSelected value</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>3 or more if they exist</p>\r\n			</td>\r\n			<td>\r\n			<p>&gt;= 10</p>\r\n			</td>\r\n			<td>\r\n			<p>Zero</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>9 to 7</p>\r\n			</td>\r\n			<td>\r\n			<p>100 binary = 4</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>6 to 4</p>\r\n			</td>\r\n			<td>\r\n			<p>011 binary = 3</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>3 to 0</p>\r\n			</td>\r\n			<td>\r\n			<p>0101 binary = 5</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Free tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\r\n\r\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>\r\n\r\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>NAND data</h3>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\r\n	</li>\r\n	<li>\r\n	<p>A chunk of file data.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The 16 byte spare area contains:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>8 bytes of tags,</p>\r\n	</li>\r\n	<li>\r\n	<p>6 bytes of ECC data</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte block status (used to identify damaged blocks)</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte data status (currently unused).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The tags are made up as follows:</p>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>unsigned chunkId:20; //chunk number in file</p>\r\n\r\n<p>unsigned serialNumber:2; //serial number for chunk</p>\r\n\r\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\r\n\r\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\r\n\r\n<p>unsigned ecc:12; //ECC on tags</p>\r\n\r\n<p>unsigned unusedStuff:2; //unused</p>\r\n\r\n<p>} yaffs_Tags;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\r\n\r\n<p>objectId says which object this chunk belongs to.</p>\r\n\r\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>yaffs_ObjectHeader</h3>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>yaffs_ObjectType type;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Apply to everything</p>\r\n\r\n<p>int parentObjectId;</p>\r\n\r\n<p>__u16 sum; // checksum of name</p>\r\n\r\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// File size applies to files only</p>\r\n\r\n<p>int fileSize;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Equivalent object id applies to hard links only.</p>\r\n\r\n<p>int equivalentObjectId;</p>\r\n\r\n<p>// alias only applies to symlinks</p>\r\n\r\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>} yaffs_ObjectHeader;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\r\n\r\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\r\n\r\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>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>NAND Interface</h3>\r\n\r\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\r\n	</li>\r\n	<li>\r\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\r\n	</li>\r\n	<li>\r\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\r\n	</li>\r\n	<li>\r\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<p>A quick note about NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>mkyaffs</h3>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Expected performance</h2>\r\n\r\n<p>The following numbers should give an indication of the performance we should expect from YAFFS.</p>\r\n\r\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>\r\n\r\n<p>Seek10uS/page</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>200uS/page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>2mS/block</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can derive some higher-level numbers:</p>\r\n\r\n<p>OperationTimeCalculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read spare</p>\r\n			</td>\r\n			<td>\r\n			<p>12uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read page</p>\r\n			</td>\r\n			<td>\r\n			<p>63 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write page</p>\r\n			</td>\r\n			<td>\r\n			<p>326 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * write + program + read page (for verification)</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Discard page</p>\r\n			</td>\r\n			<td>\r\n			<p>212 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * write + program</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite page</p>\r\n			</td>\r\n			<td>\r\n			<p>538 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>write page + discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase overhead per page</p>\r\n			</td>\r\n			<td>\r\n			<p>63uS</p>\r\n			</td>\r\n			<td>\r\n			<p>erase/32</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can infer the following flash access times:</p>\r\n\r\n<p>OperationTimeCalculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.13s (about 7.5 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * read page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 1MB (clean system)</p>\r\n			</td>\r\n			<td>\r\n			<p>0.53s (about 1.8 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * write page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB file (no gc)</p>\r\n			</td>\r\n			<td>\r\n			<p>1.08s (about 0.9MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>2.4s (about 0.4 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.43s (about 2.2 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>0.49s (about 2.0MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page + 1000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n','The initial specification for Yaffs. Circa 2002. Details of the filing system, including short backgrounder. Read this if you want to know what it is, what it does and how it works. This specification does not cover Yaffs2.','filtered_html'),('page',0,37,549,'und',0,'<p>YAFFS (Yet Another Flash File System)</p>\r\n\r\n<h4>Version 0.3</h4>\r\n\r\n<h4>Charles Manning (and Wookey), December 2001</h4>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Revision History</h2>\r\n\r\n<p>V0.0 20/12/01 First Draft</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>V0.1</p>\r\n			</td>\r\n			<td>\r\n			<p>11/01/02</p>\r\n			</td>\r\n			<td>\r\n			<p>Minor corrections &amp; cosmetics.<br />\r\n			Change use of data status byte.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>V0.2</p>\r\n			</td>\r\n			<td>\r\n			<p>28/01/02</p>\r\n			</td>\r\n			<td>\r\n			<p>Added observations about inodes, file headers and hard links.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>V0.3</p>\r\n			</td>\r\n			<td>\r\n			<p>26/02/02</p>\r\n			</td>\r\n			<td>\r\n			<p>W:Added some general observations on compatibility, partitions and bootloading.</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Scope</h2>\r\n\r\n<p>The purpose of this document is to outline a potential NAND-friendly file system for Linux.</p>\r\n\r\n<h2>Background</h2>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>The intentions of the design sketched here are:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Be NAND-flash friendly.</p>\r\n	</li>\r\n	<li>\r\n	<p>Robustness through journaling strategies.</p>\r\n	</li>\r\n	<li>\r\n	<p>Significantly reduce the RAM overheads and boot times associated with JFFSx.</p>\r\n	</li>\r\n</ul>\r\n\r\n<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>\r\n\r\n<h2>Overview</h2>\r\n\r\n<p>Here follows a simplified overview of YAFFS.</p>\r\n\r\n<p>YAFFS uses a physical flash format similar to SmartMedia. This is done for various reasons:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Some of the formatting, eg placement of bad block markers is determined by the NAND manufacturers and can\'t be changed.</p>\r\n	</li>\r\n	<li>\r\n	<p>Potential to reuse code.</p>\r\n	</li>\r\n	<li>\r\n	<p>If it ain\'t broke don\'t fix.</p>\r\n	</li>\r\n</ul>\r\n\r\n<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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>File \"headers\" are stored as a single page, marked so as to be differentiated from data pages.</p>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>Spare area details</h3>\r\n\r\n<p>The following table summarizes the layout of the spare area of each page.</p>\r\n\r\n<p>Byte #SmartMedia usageYAFFS usage</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>0..511</p>\r\n			</td>\r\n			<td>\r\n			<p>Data</p>\r\n			</td>\r\n			<td>\r\n			<p>Data. either file data or file header depending on tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>512..515</p>\r\n			</td>\r\n			<td>\r\n			<p>Reserved</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>516</p>\r\n			</td>\r\n			<td>\r\n			<p>Data status byte. Not used in SM code from Samsung</p>\r\n			</td>\r\n			<td>\r\n			<p>Data status byte. If more than 4 bits are zero, then this page is discarded.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>517</p>\r\n			</td>\r\n			<td>\r\n			<p>Block status byte</p>\r\n			</td>\r\n			<td>\r\n			<p>Block status byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>518..519</p>\r\n			</td>\r\n			<td>\r\n			<p>Block address</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>520..522</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on second 256 bytes part of data</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on second 256 bytes of data</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>523..524</p>\r\n			</td>\r\n			<td>\r\n			<p>Block address</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>525..527</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on first 256 bytes part of data</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on first 256 bytes part of data</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>The block status is a reserved value that shows whether the block is damaged.</p>\r\n\r\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>\r\n\r\n<p>There are 8 bytes (64 bits) for use by YAFFS tags. This is partitioned as follows:</p>\r\n\r\n<p>Number of bitsUsage</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>18</p>\r\n			</td>\r\n			<td>\r\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>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>2-bit serial number.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>20</p>\r\n			</td>\r\n			<td>\r\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>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10-bit counter of the number of bytes used in the page.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>12</p>\r\n			</td>\r\n			<td>\r\n			<p>12-bit ECC on tags.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>Unused. Keep as 1.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p><strong>64</strong></p>\r\n			</td>\r\n			<td>\r\n			<p><strong>Total</strong></p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>A bit of explanation on the usage of some of these fields:</p>\r\n\r\n<p>file Id is synonymous with inode.</p>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>File \"headers\" come in two flavours:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>file info ( the mode, ower id, group id, length,...)</p>\r\n	</li>\r\n	<li>\r\n	<p>the hard link(s) that refers to the file.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>A directory also appears as a file (ie. has an inode and hard link(s)) but has no data.</p>\r\n\r\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>\r\n\r\n<h3>RAM data details</h3>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Page allocation and garbage collection</h3>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Flash writing</h3>\r\n\r\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>\r\n\r\n<h3>Wear levelling</h3>\r\n\r\n<p>No wear levelling is explicitly used here. Instead we rely on two \"strategies\":</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>The infrequent random block selection should prevent low-wear blocks getting \"stuck\".</p>\r\n	</li>\r\n</ul>\r\n\r\n<h3>Partitioning</h3>\r\n\r\n<p>Partitioning is not included in this spec, but could be added if required.</p>\r\n\r\n<h3>Bootloading</h3>\r\n\r\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>\r\n\r\n<h3>Conclusion</h3>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>YAFFS Development Notes</p>\r\n\r\n<h3>Build options</h3>\r\n\r\n<p>Yaffs can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Trying it out</h3>\r\n\r\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>\r\n\r\n<ol>\r\n	<li>\r\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\r\n	</li>\r\n	<li>\r\n	<p>Load yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\r\n	</li>\r\n	<li>\r\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\r\n	</li>\r\n</ol>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>YAFFS Data structures</h3>\r\n\r\n<p>All data types are defined in yaffs_guts.h</p>\r\n\r\n<p>Yaffs uses the following major objects:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\r\n	</li>\r\n	<li>\r\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\r\n	</li>\r\n	<li>\r\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h3>yaffs_Object</h3>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>struct yaffs_ObjectStruct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\r\n\r\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\r\n\r\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\r\n\r\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\r\n\r\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\r\n\r\n<p>// object might be created before the data</p>\r\n\r\n<p>// is available (ie. file data records appear before the header).</p>\r\n\r\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\r\n\r\n<p>// read back the old one to update.</p>\r\n\r\n<p>__u16 sum; // sum of the name to speed searching</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\r\n\r\n<p>// live on this list</p>\r\n\r\n<p>// directory structure stuff</p>\r\n\r\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\r\n\r\n<p>struct list_head siblings; // siblings in a directory</p>\r\n\r\n<p>// also used for linking up the free list</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Where\'s my data in NAND?</p>\r\n\r\n<p>int chunkId; // where it lives</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>__u32 objectId; // the object id value</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>yaffs_ObjectType variantType;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>yaffs_ObjectVariant variant;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>};</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\n<p>serial, sum: see yaffs_ObjectHeader.</p>\r\n\r\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\r\n\r\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>\r\n\r\n<p>hashlink is a list of Objects in the same hash bucket.</p>\r\n\r\n<p>The four variants hold extra info:</p>\r\n\r\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\r\n\r\n<p>Directories hold a list of children objects.</p>\r\n\r\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>\r\n\r\n<p>Hardlinks hold information to identify the equivalent object.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>File structure (tnodes)</h3>\r\n\r\n<p>File structures are done with a tiered indexing structure</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><img alt=\"\" height=\"294\" src=\"yaffs/sv9349341.gif\" width=\"491\" /><br />\r\n<br />\r\n&nbsp;</p>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\r\n	</li>\r\n	<li>\r\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\r\n\r\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\r\n\r\n<p>LevelBitsSelected value</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>3 or more if they exist</p>\r\n			</td>\r\n			<td>\r\n			<p>&gt;= 10</p>\r\n			</td>\r\n			<td>\r\n			<p>Zero</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>9 to 7</p>\r\n			</td>\r\n			<td>\r\n			<p>100 binary = 4</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>6 to 4</p>\r\n			</td>\r\n			<td>\r\n			<p>011 binary = 3</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>3 to 0</p>\r\n			</td>\r\n			<td>\r\n			<p>0101 binary = 5</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Free tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\r\n\r\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>\r\n\r\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>NAND data</h3>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\r\n	</li>\r\n	<li>\r\n	<p>A chunk of file data.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The 16 byte spare area contains:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>8 bytes of tags,</p>\r\n	</li>\r\n	<li>\r\n	<p>6 bytes of ECC data</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte block status (used to identify damaged blocks)</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte data status (currently unused).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The tags are made up as follows:</p>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>unsigned chunkId:20; //chunk number in file</p>\r\n\r\n<p>unsigned serialNumber:2; //serial number for chunk</p>\r\n\r\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\r\n\r\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\r\n\r\n<p>unsigned ecc:12; //ECC on tags</p>\r\n\r\n<p>unsigned unusedStuff:2; //unused</p>\r\n\r\n<p>} yaffs_Tags;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\r\n\r\n<p>objectId says which object this chunk belongs to.</p>\r\n\r\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>yaffs_ObjectHeader</h3>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>yaffs_ObjectType type;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Apply to everything</p>\r\n\r\n<p>int parentObjectId;</p>\r\n\r\n<p>__u16 sum; // checksum of name</p>\r\n\r\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// File size applies to files only</p>\r\n\r\n<p>int fileSize;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Equivalent object id applies to hard links only.</p>\r\n\r\n<p>int equivalentObjectId;</p>\r\n\r\n<p>// alias only applies to symlinks</p>\r\n\r\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>} yaffs_ObjectHeader;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\r\n\r\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\r\n\r\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>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>NAND Interface</h3>\r\n\r\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\r\n	</li>\r\n	<li>\r\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\r\n	</li>\r\n	<li>\r\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\r\n	</li>\r\n	<li>\r\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<p>A quick note about NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>mkyaffs</h3>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Expected performance</h2>\r\n\r\n<p>The following numbers should give an indication of the performance we should expect from YAFFS.</p>\r\n\r\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>\r\n\r\n<p>Seek10uS/page</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>200uS/page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>2mS/block</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can derive some higher-level numbers:</p>\r\n\r\n<p>OperationTimeCalculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read spare</p>\r\n			</td>\r\n			<td>\r\n			<p>12uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read page</p>\r\n			</td>\r\n			<td>\r\n			<p>63 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write page</p>\r\n			</td>\r\n			<td>\r\n			<p>326 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * write + program + read page (for verification)</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Discard page</p>\r\n			</td>\r\n			<td>\r\n			<p>212 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * write + program</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite page</p>\r\n			</td>\r\n			<td>\r\n			<p>538 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>write page + discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase overhead per page</p>\r\n			</td>\r\n			<td>\r\n			<p>63uS</p>\r\n			</td>\r\n			<td>\r\n			<p>erase/32</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can infer the following flash access times:</p>\r\n\r\n<p>OperationTimeCalculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.13s (about 7.5 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * read page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 1MB (clean system)</p>\r\n			</td>\r\n			<td>\r\n			<p>0.53s (about 1.8 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * write page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB file (no gc)</p>\r\n			</td>\r\n			<td>\r\n			<p>1.08s (about 0.9MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>2.4s (about 0.4 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.43s (about 2.2 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>0.49s (about 2.0MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page + 1000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n','The initial specification for Yaffs. Circa 2002. Details of the filing system, including short backgrounder. Read this if you want to know what it is, what it does and how it works. This specification does not cover Yaffs2.','filtered_html'),('page',0,37,570,'und',0,'<p>YAFFS (Yet Another Flash File System)</p>\r\n\r\n<h4>Version 0.3</h4>\r\n\r\n<h4>Charles Manning (and Wookey), December 2001</h4>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Revision History</h2>\r\n\r\n<p>V0.0 20/12/01 First Draft</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>V0.1</p>\r\n			</td>\r\n			<td>\r\n			<p>11/01/02</p>\r\n			</td>\r\n			<td>\r\n			<p>Minor corrections &amp; cosmetics.<br />\r\n			Change use of data status byte.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>V0.2</p>\r\n			</td>\r\n			<td>\r\n			<p>28/01/02</p>\r\n			</td>\r\n			<td>\r\n			<p>Added observations about inodes, file headers and hard links.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>V0.3</p>\r\n			</td>\r\n			<td>\r\n			<p>26/02/02</p>\r\n			</td>\r\n			<td>\r\n			<p>W:Added some general observations on compatibility, partitions and bootloading.</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Scope</h2>\r\n\r\n<p>The purpose of this document is to outline a potential NAND-friendly file system for Linux.</p>\r\n\r\n<h2>Background</h2>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>The intentions of the design sketched here are:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Be NAND-flash friendly.</p>\r\n	</li>\r\n	<li>\r\n	<p>Robustness through journaling strategies.</p>\r\n	</li>\r\n	<li>\r\n	<p>Significantly reduce the RAM overheads and boot times associated with JFFSx.</p>\r\n	</li>\r\n</ul>\r\n\r\n<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>\r\n\r\n<h2>Overview</h2>\r\n\r\n<p>Here follows a simplified overview of YAFFS.</p>\r\n\r\n<p>YAFFS uses a physical flash format similar to SmartMedia. This is done for various reasons:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Some of the formatting, eg placement of bad block markers is determined by the NAND manufacturers and can\'t be changed.</p>\r\n	</li>\r\n	<li>\r\n	<p>Potential to reuse code.</p>\r\n	</li>\r\n	<li>\r\n	<p>If it ain\'t broke don\'t fix.</p>\r\n	</li>\r\n</ul>\r\n\r\n<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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>File \"headers\" are stored as a single page, marked so as to be differentiated from data pages.</p>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>Spare area details</h3>\r\n\r\n<p>The following table summarizes the layout of the spare area of each page.</p>\r\n\r\n<p>Byte #SmartMedia usageYAFFS usage</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>0..511</p>\r\n			</td>\r\n			<td>\r\n			<p>Data</p>\r\n			</td>\r\n			<td>\r\n			<p>Data. either file data or file header depending on tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>512..515</p>\r\n			</td>\r\n			<td>\r\n			<p>Reserved</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>516</p>\r\n			</td>\r\n			<td>\r\n			<p>Data status byte. Not used in SM code from Samsung</p>\r\n			</td>\r\n			<td>\r\n			<p>Data status byte. If more than 4 bits are zero, then this page is discarded.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>517</p>\r\n			</td>\r\n			<td>\r\n			<p>Block status byte</p>\r\n			</td>\r\n			<td>\r\n			<p>Block status byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>518..519</p>\r\n			</td>\r\n			<td>\r\n			<p>Block address</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>520..522</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on second 256 bytes part of data</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on second 256 bytes of data</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>523..524</p>\r\n			</td>\r\n			<td>\r\n			<p>Block address</p>\r\n			</td>\r\n			<td>\r\n			<p>Tags</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>525..527</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on first 256 bytes part of data</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on first 256 bytes part of data</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>The block status is a reserved value that shows whether the block is damaged.</p>\r\n\r\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>\r\n\r\n<p>There are 8 bytes (64 bits) for use by YAFFS tags. This is partitioned as follows:</p>\r\n\r\n<p>Number of bitsUsage</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>18</p>\r\n			</td>\r\n			<td>\r\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>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>2-bit serial number.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>20</p>\r\n			</td>\r\n			<td>\r\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>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10-bit counter of the number of bytes used in the page.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>12</p>\r\n			</td>\r\n			<td>\r\n			<p>12-bit ECC on tags.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>Unused. Keep as 1.</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p><strong>64</strong></p>\r\n			</td>\r\n			<td>\r\n			<p><strong>Total</strong></p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>A bit of explanation on the usage of some of these fields:</p>\r\n\r\n<p>file Id is synonymous with inode.</p>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>File \"headers\" come in two flavours:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>file info ( the mode, ower id, group id, length,...)</p>\r\n	</li>\r\n	<li>\r\n	<p>the hard link(s) that refers to the file.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>A directory also appears as a file (ie. has an inode and hard link(s)) but has no data.</p>\r\n\r\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>\r\n\r\n<h3>RAM data details</h3>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Page allocation and garbage collection</h3>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Flash writing</h3>\r\n\r\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>\r\n\r\n<h3>Wear levelling</h3>\r\n\r\n<p>No wear levelling is explicitly used here. Instead we rely on two \"strategies\":</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>The infrequent random block selection should prevent low-wear blocks getting \"stuck\".</p>\r\n	</li>\r\n</ul>\r\n\r\n<h3>Partitioning</h3>\r\n\r\n<p>Partitioning is not included in this spec, but could be added if required.</p>\r\n\r\n<h3>Bootloading</h3>\r\n\r\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>\r\n\r\n<h3>Conclusion</h3>\r\n\r\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>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>YAFFS Development Notes</p>\r\n\r\n<h3>Build options</h3>\r\n\r\n<p>Yaffs can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Trying it out</h3>\r\n\r\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>\r\n\r\n<ol>\r\n	<li>\r\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\r\n	</li>\r\n	<li>\r\n	<p>Load yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\r\n	</li>\r\n	<li>\r\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\r\n	</li>\r\n</ol>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>YAFFS Data structures</h3>\r\n\r\n<p>All data types are defined in yaffs_guts.h</p>\r\n\r\n<p>Yaffs uses the following major objects:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\r\n	</li>\r\n	<li>\r\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\r\n	</li>\r\n	<li>\r\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h3>yaffs_Object</h3>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>struct yaffs_ObjectStruct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\r\n\r\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\r\n\r\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\r\n\r\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\r\n\r\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\r\n\r\n<p>// object might be created before the data</p>\r\n\r\n<p>// is available (ie. file data records appear before the header).</p>\r\n\r\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\r\n\r\n<p>// read back the old one to update.</p>\r\n\r\n<p>__u16 sum; // sum of the name to speed searching</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\r\n\r\n<p>// live on this list</p>\r\n\r\n<p>// directory structure stuff</p>\r\n\r\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\r\n\r\n<p>struct list_head siblings; // siblings in a directory</p>\r\n\r\n<p>// also used for linking up the free list</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Where\'s my data in NAND?</p>\r\n\r\n<p>int chunkId; // where it lives</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>__u32 objectId; // the object id value</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>yaffs_ObjectType variantType;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>yaffs_ObjectVariant variant;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>};</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\n<p>serial, sum: see yaffs_ObjectHeader.</p>\r\n\r\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\r\n\r\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>\r\n\r\n<p>hashlink is a list of Objects in the same hash bucket.</p>\r\n\r\n<p>The four variants hold extra info:</p>\r\n\r\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\r\n\r\n<p>Directories hold a list of children objects.</p>\r\n\r\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>\r\n\r\n<p>Hardlinks hold information to identify the equivalent object.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>File structure (tnodes)</h3>\r\n\r\n<p>File structures are done with a tiered indexing structure</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><img alt=\"\" height=\"294\" src=\"yaffs/sv9349341.gif\" width=\"491\" /><br />\r\n<br />\r\n&nbsp;</p>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\r\n	</li>\r\n	<li>\r\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\r\n\r\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\r\n\r\n<p>LevelBitsSelected value</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>3 or more if they exist</p>\r\n			</td>\r\n			<td>\r\n			<p>&gt;= 10</p>\r\n			</td>\r\n			<td>\r\n			<p>Zero</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>9 to 7</p>\r\n			</td>\r\n			<td>\r\n			<p>100 binary = 4</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>6 to 4</p>\r\n			</td>\r\n			<td>\r\n			<p>011 binary = 3</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>3 to 0</p>\r\n			</td>\r\n			<td>\r\n			<p>0101 binary = 5</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Free tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\r\n\r\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>\r\n\r\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>NAND data</h3>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\r\n	</li>\r\n	<li>\r\n	<p>A chunk of file data.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The 16 byte spare area contains:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>8 bytes of tags,</p>\r\n	</li>\r\n	<li>\r\n	<p>6 bytes of ECC data</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte block status (used to identify damaged blocks)</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte data status (currently unused).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The tags are made up as follows:</p>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>unsigned chunkId:20; //chunk number in file</p>\r\n\r\n<p>unsigned serialNumber:2; //serial number for chunk</p>\r\n\r\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\r\n\r\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\r\n\r\n<p>unsigned ecc:12; //ECC on tags</p>\r\n\r\n<p>unsigned unusedStuff:2; //unused</p>\r\n\r\n<p>} yaffs_Tags;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\r\n\r\n<p>objectId says which object this chunk belongs to.</p>\r\n\r\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>yaffs_ObjectHeader</h3>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>yaffs_ObjectType type;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Apply to everything</p>\r\n\r\n<p>int parentObjectId;</p>\r\n\r\n<p>__u16 sum; // checksum of name</p>\r\n\r\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// File size applies to files only</p>\r\n\r\n<p>int fileSize;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Equivalent object id applies to hard links only.</p>\r\n\r\n<p>int equivalentObjectId;</p>\r\n\r\n<p>// alias only applies to symlinks</p>\r\n\r\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>} yaffs_ObjectHeader;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\r\n\r\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\r\n\r\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>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>NAND Interface</h3>\r\n\r\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\r\n	</li>\r\n	<li>\r\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\r\n	</li>\r\n	<li>\r\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\r\n	</li>\r\n	<li>\r\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<p>A quick note about NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>mkyaffs</h3>\r\n\r\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>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h2>Expected performance</h2>\r\n\r\n<p>The following numbers should give an indication of the performance we should expect from YAFFS.</p>\r\n\r\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>\r\n\r\n<p>Seek10uS/page</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>200uS/page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>2mS/block</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can derive some higher-level numbers:</p>\r\n\r\n<p>OperationTimeCalculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read spare</p>\r\n			</td>\r\n			<td>\r\n			<p>12uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read page</p>\r\n			</td>\r\n			<td>\r\n			<p>63 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write page</p>\r\n			</td>\r\n			<td>\r\n			<p>326 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * write + program + read page (for verification)</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Discard page</p>\r\n			</td>\r\n			<td>\r\n			<p>212 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * write + program</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite page</p>\r\n			</td>\r\n			<td>\r\n			<p>538 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>write page + discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase overhead per page</p>\r\n			</td>\r\n			<td>\r\n			<p>63uS</p>\r\n			</td>\r\n			<td>\r\n			<p>erase/32</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can infer the following flash access times:</p>\r\n\r\n<p>OperationTimeCalculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n			<td>\r\n			<p>Read 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.13s (about 7.5 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * read page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 1MB (clean system)</p>\r\n			</td>\r\n			<td>\r\n			<p>0.53s (about 1.8 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * write page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB file (no gc)</p>\r\n			</td>\r\n			<td>\r\n			<p>1.08s (about 0.9MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>2.4s (about 0.4 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.43s (about 2.2 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>0.49s (about 2.0MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page + 1000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n','The initial specification for Yaffs. Circa 2002. Details of the filing system, including short backgrounder. Read this if you want to know what it is, what it does and how it works. This specification does not cover Yaffs2.','basic_html'),('page',0,38,38,'und',0,'<h2>Summary</h2><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><p>To achieve this, a new design is used which also realises the following benefits:</p><ul><li><p>Zero page rewrites means faster operation. (Yaffs1 uses a single rewrite in the spare area to delete a page).</p></li><li><p>Ability to exploit simultaneous page programming on some chips.</p></li><li><p>Improves performance relative to Yaffs1 speed(write:1.5x to 5x, delete: 4x, garbage collection: 2x)</p></li><li><p>Lower RAM footprint (approx. 25% to 50% of Yaffs1).</p></li><li><p>Can support Toshiba/Sandisk MLC parts.</p></li></ul><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><h4>Method</h4><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><p>Instead Yaffs2 uses two mechanisms to resolve data state.</p><ul><li><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></li><li><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></li><li><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></li></ul><p>This changes erasure slightly:</p><ul><li><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></li></ul><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><h4>Tag structure</h4><p>Each chunk in Yaffs2 has the following information:</p><p>Field</p><p>Comment</p><p>Size for 1kb chunks</p><p>Size for 2kB chunks</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"100%\"><tbody><tr valign=\"top\"></tr><tr valign=\"top\"><td width=\"18%\"><p>blockState</p></td><td width=\"32%\"><p>Block state. non-0xFF for bad block</p></td><td width=\"25%\"><p>1 byte</p></td><td width=\"25%\"><p>1 byte</p></td></tr><tr valign=\"top\"><td width=\"18%\"><p>chunkId</p></td><td width=\"32%\"><p>32-bit chunk Id</p></td><td width=\"25%\"><p>4 bytes</p></td><td width=\"25%\"><p>4 bytes</p></td></tr><tr valign=\"top\"><td width=\"18%\"><p>objectId</p></td><td width=\"32%\"><p>32-bit object Id</p></td><td width=\"25%\"><p>4 bytes</p></td><td width=\"25%\"><p>4 bytes</p></td></tr><tr valign=\"top\"><td width=\"18%\"><p>nBytes</p></td><td width=\"32%\"><p>Number of data bytes in this chunk</p></td><td width=\"25%\"><p>2 bytes</p></td><td width=\"25%\"><p>2 bytes</p></td></tr><tr valign=\"top\"><td width=\"18%\"><p>blockSequence</p></td><td width=\"32%\"><p>sequence number for this block</p></td><td width=\"25%\"><p>4 bytes</p></td><td width=\"25%\"><p>4 bytes</p></td></tr><tr valign=\"top\"><td width=\"18%\"><p>tagsEcc</p></td><td width=\"32%\"><p>ECC on tags area</p></td><td width=\"25%\"><p>3 bytes</p></td><td width=\"25%\"><p>3 bytes</p></td></tr><tr valign=\"top\"><td width=\"18%\"><p>ecc</p></td><td width=\"32%\"><p>ECC, 3 bytes/256 bytes of data</p></td><td width=\"25%\"><p>12 bytes</p></td><td width=\"25%\"><p>24 bytes</p></td></tr><tr valign=\"top\"><td width=\"18%\"><p><b>Total</b></p></td><td width=\"32%\"><p>&nbsp;</p></td><td width=\"25%\"><p align=\"left\"><b>30 bytes</b></p></td><td width=\"25%\"><p><b>42 bytes</b></p></td></tr></tbody></table><p><br>&nbsp;</p><p>To get enough spare bytes for this tagging structure requires a chunk-size of at least 1kB.</p><p>The blockSequence increments each time a block is allocated. (ie. the first block allocated is block 1, and so on).</p><h4>Scanning</h4><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><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><h4>Performance</h4><p>Times for 2kB read(units of 1uS).</p><p>Operation</p><p>Yaffs1</p><p>Yaffs2 (512b pages)</p><p>Yaffs2 (2kB pages)</p><p>Yaffs2(2kB pages, x16)</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"937\"><tbody><tr valign=\"top\"></tr><tr><td valign=\"top\" width=\"175\"><p>Seek</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">40</p></td><td valign=\"bottom\" width=\"177\"><p align=\"right\">40</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">10</p></td><td valign=\"bottom\" width=\"173\"><p align=\"right\">10</p></td></tr><tr><td valign=\"top\" width=\"175\"><p>Read</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">220</p></td><td valign=\"bottom\" width=\"177\"><p align=\"right\">220</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">220</p></td><td valign=\"bottom\" width=\"173\"><p align=\"right\">110</p></td></tr><tr><td valign=\"top\" width=\"175\"><p>Total</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">260</p></td><td valign=\"bottom\" width=\"177\"><p align=\"right\">260</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">230</p></td><td valign=\"bottom\" width=\"173\"><p align=\"right\">120</p></td></tr><tr><td valign=\"top\" width=\"175\"><p>MB/s</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">7.6</p></td><td valign=\"bottom\" width=\"177\"><p align=\"right\">7.6</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">8.7</p></td><td valign=\"bottom\" width=\"173\"><p align=\"right\">16.7</p></td></tr><tr><td valign=\"top\" width=\"175\"><p>Relative speed</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">1</p></td><td valign=\"bottom\" width=\"177\"><p align=\"right\">1</p></td><td valign=\"bottom\" width=\"176\"><p align=\"right\">1.1</p></td><td valign=\"bottom\" width=\"173\"><p align=\"right\">2.2</p></td></tr></tbody></table><p><br>&nbsp;</p><p>Times for 2kB writes(units of 1uS).</p><p>Operation</p><p>Yaffs1</p><p>Yaffs2 (512b pages)</p><p>Yaffs2 (2kB pages)</p><p>Yaffs2(2kB pages, x16)</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"100%\"><tbody><tr valign=\"top\"></tr><tr><td valign=\"top\" width=\"20%\"><p>Seek</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">40</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">40</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">10</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">10</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Program</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">800</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">800</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">200</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">200</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Seek</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">40</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">40</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">10</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">10</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Read</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">220</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">220</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">220</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">110</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Total</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1320</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1320</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">660</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">440</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>MB/s</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1.5</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1.5</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">3</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">4.5</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Relative speed</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">2</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">3</p></td></tr></tbody></table><p><br>&nbsp;</p><p>Times for 1MB delete (units of 1uS).</p><p>Operation</p><p>Yaffs1</p><p>Yaffs2 (512b pages)</p><p>Yaffs2 (2kB pages)</p><p>Yaffs2(2kB pages, x16)</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"100%\"><tbody><tr valign=\"top\"></tr><tr><td valign=\"top\" width=\"20%\"><p>Seek</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">20480</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">0</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">0</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">0</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Program</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">409600</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">0</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">0</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">0</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Erase</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">128000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">128000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">16000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">16000</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Total</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">558080</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">128000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">16000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">16000</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>MB/s</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1.8</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">7.8</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">62.5</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">62.5</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Relative speed</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">4</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">34</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">34</p></td></tr></tbody></table><p><br>&nbsp;</p><p>Times for 1MB of garbage collection at 50% dirty (units of 1uS).</p><p>Operation</p><p>Yaffs1</p><p>Yaffs2 (512b pages)</p><p>Yaffs2 (2kB pages)</p><p>Yaffs2(2kB pages, x16)</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"100%\"><tbody><tr valign=\"top\"></tr><tr><td valign=\"top\" width=\"20%\"><p>Delete 1MB</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">558080</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">128000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">16000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">16000</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Write 0.5MB</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">337920</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">337920</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">168960</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">112640</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Total</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">896000</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">465920</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">184960</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">128640</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>MB/s</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1.1</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">2.1</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">5.4</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">7.7</p></td></tr><tr><td valign=\"top\" width=\"20%\"><p>Relative speed</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">1.9</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">4.9</p></td><td valign=\"bottom\" width=\"20%\"><p align=\"right\">7</p></td></tr></tbody></table><p><br>&nbsp;</p>','<p>The initial specification for Yaffs version 2. Describes the development of Yaffs to deal with next-generation NAND chips which have larger (2Kb) pages and don\'t allow page rewrites. This newer design is be significantly faster (write: 1.5x-5x, delete: 4x, garbage collection: 2x) and has 25-50% lower RAM footfrint.</p>','filtered_html'),('page',0,38,533,'und',0,'<h2>Summary</h2>\r\n\r\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>\r\n\r\n<p>To achieve this, a new design is used which also realises the following benefits:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Zero page rewrites means faster operation. (Yaffs1 uses a single rewrite in the spare area to delete a page).</p>\r\n	</li>\r\n	<li>\r\n	<p>Ability to exploit simultaneous page programming on some chips.</p>\r\n	</li>\r\n	<li>\r\n	<p>Improves performance relative to Yaffs1 speed(write:1.5x to 5x, delete: 4x, garbage collection: 2x)</p>\r\n	</li>\r\n	<li>\r\n	<p>Lower RAM footprint (approx. 25% to 50% of Yaffs1).</p>\r\n	</li>\r\n	<li>\r\n	<p>Can support Toshiba/Sandisk MLC parts.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h4>Method</h4>\r\n\r\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>\r\n\r\n<p>Instead Yaffs2 uses two mechanisms to resolve data state.</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<p>This changes erasure slightly:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h4>Tag structure</h4>\r\n\r\n<p>Each chunk in Yaffs2 has the following information:</p>\r\n\r\n<p>Field</p>\r\n\r\n<p>Comment</p>\r\n\r\n<p>Size for 1kb chunks</p>\r\n\r\n<p>Size for 2kB chunks</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>blockState</p>\r\n			</td>\r\n			<td>\r\n			<p>Block state. non-0xFF for bad block</p>\r\n			</td>\r\n			<td>\r\n			<p>1 byte</p>\r\n			</td>\r\n			<td>\r\n			<p>1 byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>chunkId</p>\r\n			</td>\r\n			<td>\r\n			<p>32-bit chunk Id</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>objectId</p>\r\n			</td>\r\n			<td>\r\n			<p>32-bit object Id</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>nBytes</p>\r\n			</td>\r\n			<td>\r\n			<p>Number of data bytes in this chunk</p>\r\n			</td>\r\n			<td>\r\n			<p>2 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>2 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>blockSequence</p>\r\n			</td>\r\n			<td>\r\n			<p>sequence number for this block</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>tagsEcc</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on tags area</p>\r\n			</td>\r\n			<td>\r\n			<p>3 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>3 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>ecc</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC, 3 bytes/256 bytes of data</p>\r\n			</td>\r\n			<td>\r\n			<p>12 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>24 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p><strong>Total</strong></p>\r\n			</td>\r\n			<td>\r\n			<p>&nbsp;</p>\r\n			</td>\r\n			<td>\r\n			<p><strong>30 bytes</strong></p>\r\n			</td>\r\n			<td>\r\n			<p><strong>42 bytes</strong></p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>To get enough spare bytes for this tagging structure requires a chunk-size of at least 1kB.</p>\r\n\r\n<p>The blockSequence increments each time a block is allocated. (ie. the first block allocated is block 1, and so on).</p>\r\n\r\n<h4>Scanning</h4>\r\n\r\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>\r\n\r\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>\r\n\r\n<h4>Performance</h4>\r\n\r\n<p>Times for 2kB read(units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>110</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>260</p>\r\n			</td>\r\n			<td>\r\n			<p>260</p>\r\n			</td>\r\n			<td>\r\n			<p>230</p>\r\n			</td>\r\n			<td>\r\n			<p>120</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>7.6</p>\r\n			</td>\r\n			<td>\r\n			<p>7.6</p>\r\n			</td>\r\n			<td>\r\n			<p>8.7</p>\r\n			</td>\r\n			<td>\r\n			<p>16.7</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1.1</p>\r\n			</td>\r\n			<td>\r\n			<p>2.2</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Times for 2kB writes(units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>800</p>\r\n			</td>\r\n			<td>\r\n			<p>800</p>\r\n			</td>\r\n			<td>\r\n			<p>200</p>\r\n			</td>\r\n			<td>\r\n			<p>200</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>110</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>1320</p>\r\n			</td>\r\n			<td>\r\n			<p>1320</p>\r\n			</td>\r\n			<td>\r\n			<p>660</p>\r\n			</td>\r\n			<td>\r\n			<p>440</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>1.5</p>\r\n			</td>\r\n			<td>\r\n			<p>1.5</p>\r\n			</td>\r\n			<td>\r\n			<p>3</p>\r\n			</td>\r\n			<td>\r\n			<p>4.5</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>3</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Times for 1MB delete (units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>20480</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>409600</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>558080</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>1.8</p>\r\n			</td>\r\n			<td>\r\n			<p>7.8</p>\r\n			</td>\r\n			<td>\r\n			<p>62.5</p>\r\n			</td>\r\n			<td>\r\n			<p>62.5</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>4</p>\r\n			</td>\r\n			<td>\r\n			<p>34</p>\r\n			</td>\r\n			<td>\r\n			<p>34</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Times for 1MB of garbage collection at 50% dirty (units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB</p>\r\n			</td>\r\n			<td>\r\n			<p>558080</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 0.5MB</p>\r\n			</td>\r\n			<td>\r\n			<p>337920</p>\r\n			</td>\r\n			<td>\r\n			<p>337920</p>\r\n			</td>\r\n			<td>\r\n			<p>168960</p>\r\n			</td>\r\n			<td>\r\n			<p>112640</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>896000</p>\r\n			</td>\r\n			<td>\r\n			<p>465920</p>\r\n			</td>\r\n			<td>\r\n			<p>184960</p>\r\n			</td>\r\n			<td>\r\n			<p>128640</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>1.1</p>\r\n			</td>\r\n			<td>\r\n			<p>2.1</p>\r\n			</td>\r\n			<td>\r\n			<p>5.4</p>\r\n			</td>\r\n			<td>\r\n			<p>7.7</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1.9</p>\r\n			</td>\r\n			<td>\r\n			<p>4.9</p>\r\n			</td>\r\n			<td>\r\n			<p>7</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n','<p>The initial specification for Yaffs version 2. Describes the development of Yaffs to deal with next-generation NAND chips which have larger (2Kb) pages and don\'t allow page rewrites. This newer design is be significantly faster (write: 1.5x-5x, delete: 4x, garbage collection: 2x) and has 25-50% lower RAM footfrint.</p>','filtered_html'),('page',0,38,571,'und',0,'<h2>Summary</h2>\r\n\r\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>\r\n\r\n<p>To achieve this, a new design is used which also realises the following benefits:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Zero page rewrites means faster operation. (Yaffs1 uses a single rewrite in the spare area to delete a page).</p>\r\n	</li>\r\n	<li>\r\n	<p>Ability to exploit simultaneous page programming on some chips.</p>\r\n	</li>\r\n	<li>\r\n	<p>Improves performance relative to Yaffs1 speed(write:1.5x to 5x, delete: 4x, garbage collection: 2x)</p>\r\n	</li>\r\n	<li>\r\n	<p>Lower RAM footprint (approx. 25% to 50% of Yaffs1).</p>\r\n	</li>\r\n	<li>\r\n	<p>Can support Toshiba/Sandisk MLC parts.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h4>Method</h4>\r\n\r\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>\r\n\r\n<p>Instead Yaffs2 uses two mechanisms to resolve data state.</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<p>This changes erasure slightly:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h4>Tag structure</h4>\r\n\r\n<p>Each chunk in Yaffs2 has the following information:</p>\r\n\r\n<p>Field</p>\r\n\r\n<p>Comment</p>\r\n\r\n<p>Size for 1kb chunks</p>\r\n\r\n<p>Size for 2kB chunks</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>blockState</p>\r\n			</td>\r\n			<td>\r\n			<p>Block state. non-0xFF for bad block</p>\r\n			</td>\r\n			<td>\r\n			<p>1 byte</p>\r\n			</td>\r\n			<td>\r\n			<p>1 byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>chunkId</p>\r\n			</td>\r\n			<td>\r\n			<p>32-bit chunk Id</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>objectId</p>\r\n			</td>\r\n			<td>\r\n			<p>32-bit object Id</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>nBytes</p>\r\n			</td>\r\n			<td>\r\n			<p>Number of data bytes in this chunk</p>\r\n			</td>\r\n			<td>\r\n			<p>2 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>2 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>blockSequence</p>\r\n			</td>\r\n			<td>\r\n			<p>sequence number for this block</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>4 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>tagsEcc</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC on tags area</p>\r\n			</td>\r\n			<td>\r\n			<p>3 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>3 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>ecc</p>\r\n			</td>\r\n			<td>\r\n			<p>ECC, 3 bytes/256 bytes of data</p>\r\n			</td>\r\n			<td>\r\n			<p>12 bytes</p>\r\n			</td>\r\n			<td>\r\n			<p>24 bytes</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p><strong>Total</strong></p>\r\n			</td>\r\n			<td>\r\n			<p>&nbsp;</p>\r\n			</td>\r\n			<td>\r\n			<p><strong>30 bytes</strong></p>\r\n			</td>\r\n			<td>\r\n			<p><strong>42 bytes</strong></p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>To get enough spare bytes for this tagging structure requires a chunk-size of at least 1kB.</p>\r\n\r\n<p>The blockSequence increments each time a block is allocated. (ie. the first block allocated is block 1, and so on).</p>\r\n\r\n<h4>Scanning</h4>\r\n\r\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>\r\n\r\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>\r\n\r\n<h4>Performance</h4>\r\n\r\n<p>Times for 2kB read(units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>110</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>260</p>\r\n			</td>\r\n			<td>\r\n			<p>260</p>\r\n			</td>\r\n			<td>\r\n			<p>230</p>\r\n			</td>\r\n			<td>\r\n			<p>120</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>7.6</p>\r\n			</td>\r\n			<td>\r\n			<p>7.6</p>\r\n			</td>\r\n			<td>\r\n			<p>8.7</p>\r\n			</td>\r\n			<td>\r\n			<p>16.7</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1.1</p>\r\n			</td>\r\n			<td>\r\n			<p>2.2</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Times for 2kB writes(units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>800</p>\r\n			</td>\r\n			<td>\r\n			<p>800</p>\r\n			</td>\r\n			<td>\r\n			<p>200</p>\r\n			</td>\r\n			<td>\r\n			<p>200</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>40</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n			<td>\r\n			<p>10</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>220</p>\r\n			</td>\r\n			<td>\r\n			<p>110</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>1320</p>\r\n			</td>\r\n			<td>\r\n			<p>1320</p>\r\n			</td>\r\n			<td>\r\n			<p>660</p>\r\n			</td>\r\n			<td>\r\n			<p>440</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>1.5</p>\r\n			</td>\r\n			<td>\r\n			<p>1.5</p>\r\n			</td>\r\n			<td>\r\n			<p>3</p>\r\n			</td>\r\n			<td>\r\n			<p>4.5</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>3</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Times for 1MB delete (units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Seek</p>\r\n			</td>\r\n			<td>\r\n			<p>20480</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>409600</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>558080</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>1.8</p>\r\n			</td>\r\n			<td>\r\n			<p>7.8</p>\r\n			</td>\r\n			<td>\r\n			<p>62.5</p>\r\n			</td>\r\n			<td>\r\n			<p>62.5</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>4</p>\r\n			</td>\r\n			<td>\r\n			<p>34</p>\r\n			</td>\r\n			<td>\r\n			<p>34</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Times for 1MB of garbage collection at 50% dirty (units of 1uS).</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Yaffs1</p>\r\n\r\n<p>Yaffs2 (512b pages)</p>\r\n\r\n<p>Yaffs2 (2kB pages)</p>\r\n\r\n<p>Yaffs2(2kB pages, x16)</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB</p>\r\n			</td>\r\n			<td>\r\n			<p>558080</p>\r\n			</td>\r\n			<td>\r\n			<p>128000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n			<td>\r\n			<p>16000</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 0.5MB</p>\r\n			</td>\r\n			<td>\r\n			<p>337920</p>\r\n			</td>\r\n			<td>\r\n			<p>337920</p>\r\n			</td>\r\n			<td>\r\n			<p>168960</p>\r\n			</td>\r\n			<td>\r\n			<p>112640</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Total</p>\r\n			</td>\r\n			<td>\r\n			<p>896000</p>\r\n			</td>\r\n			<td>\r\n			<p>465920</p>\r\n			</td>\r\n			<td>\r\n			<p>184960</p>\r\n			</td>\r\n			<td>\r\n			<p>128640</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>MB/s</p>\r\n			</td>\r\n			<td>\r\n			<p>1.1</p>\r\n			</td>\r\n			<td>\r\n			<p>2.1</p>\r\n			</td>\r\n			<td>\r\n			<p>5.4</p>\r\n			</td>\r\n			<td>\r\n			<p>7.7</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Relative speed</p>\r\n			</td>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>1.9</p>\r\n			</td>\r\n			<td>\r\n			<p>4.9</p>\r\n			</td>\r\n			<td>\r\n			<p>7</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n','<p>The initial specification for Yaffs version 2. Describes the development of Yaffs to deal with next-generation NAND chips which have larger (2Kb) pages and don\'t allow page rewrites. This newer design is be significantly faster (write: 1.5x-5x, delete: 4x, garbage collection: 2x) and has 25-50% lower RAM footfrint.</p>','full_html'),('page',0,39,39,'und',0,'<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><p>&nbsp;</p><h2>Build options</h2><p>Yaffs1 can be built as either a kernel module (ie. a Linux file system) or as an application.</p><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><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><h3>Trying it out</h3><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><ol><li><p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p></li><li><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></li><li><p>Type <strong>make clean; make</strong> to build yaffs</p></li><li><p>Load Yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p></li><li><p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p></li><li><p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p></li><li><p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p></li></ol><p><br>&nbsp;</p><h3>Yaffs1 Data structures</h3><p>All data types are defined in yaffs_guts.h</p><p>Yaffs1 uses the following major objects:</p><ul><li><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></li><li><p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p></li><li><p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p></li><li><p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p></li><li><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></li><li><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></li></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><h3>yaffs_Object</h3><p>struct yaffs_ObjectStruct</p><p>{</p><p>__u8 fake:1; // A fake object has no presence on NAND.</p><p>__u8 renameAllowed:1; // Are we allowed to rename it?</p><p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p><p>__u8 dirty:1; // the object needs to be written to flash</p><p>__u8 valid:1; // When the file system is being loaded up, this</p><p>// object might be created before the data</p><p>// is available (ie. file data records appear before the header).</p><p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p><p>// read back the old one to update.</p><p>__u16 sum; // sum of the name to speed searching</p><p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p><p>struct list_head hashLink; // list of objects in this hash bucket</p><p>struct list_head hardLinks; // all the equivalent hard linked objects</p><p>// live on this list</p><p>// directory structure stuff</p><p>struct yaffs_ObjectStruct *parent; //my parent directory</p><p>struct list_head siblings; // siblings in a directory</p><p>// also used for linking up the free list</p><p>// Where\'s my data in NAND?</p><p>int chunkId; // where it lives</p><p>__u32 objectId; // the object id value</p><p>__u32 st_mode; // protection</p><p>__u32 st_uid; // user ID of owner</p><p>__u32 st_gid; // group ID of owner</p><p>__u32 st_atime; // time of last access</p><p>__u32 st_mtime; // time of last modification</p><p>__u32 st_ctime; // time of last change</p><p>yaffs_ObjectType variantType;</p><p>yaffs_ObjectVariant variant;</p><p>};</p><p><br>&nbsp;</p><p>Obvious stuff skipped....</p><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><p>serial, sum: see yaffs_ObjectHeader.</p><p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p><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><p>hashlink is a list of Objects in the same hash bucket.</p><p>The four variants hold extra info:</p><p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p><p>Directories hold a list of children objects.</p><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><p>Hardlinks hold information to identify the equivalent object.</p><p><br>&nbsp;</p><h3>File structure (tnodes)</h3><p>File structures are done with a tiered indexing structure</p><p><br>&nbsp;</p><p><img align=\"left\" border=\"0\" height=\"294\" src=\"http://www.aleph1.co.uk/yaffs/sv9349341.gif\" width=\"491\"><br><br>&nbsp;</p><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><ul><li><p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p></li><li><p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p></li></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><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><p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p><p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p><p>Level</p><p>Bits</p><p>Selected value</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"496\"><tbody><tr valign=\"top\"></tr><tr valign=\"top\"><td width=\"140\"><p>3 or more if they exist</p></td><td width=\"160\"><p>&gt;= 10</p></td><td width=\"158\"><p>Zero</p></td></tr><tr><td valign=\"bottom\" width=\"140\"><p align=\"right\">2</p></td><td valign=\"top\" width=\"160\"><p align=\"left\">9 to 7</p></td><td valign=\"top\" width=\"158\"><p>100 binary = 4</p></td></tr><tr><td valign=\"bottom\" width=\"140\"><p align=\"right\">1</p></td><td valign=\"top\" width=\"160\"><p align=\"left\">6 to 4</p></td><td valign=\"top\" width=\"158\"><p>011 binary = 3</p></td></tr><tr><td valign=\"bottom\" width=\"140\"><p align=\"right\">0</p></td><td valign=\"top\" width=\"160\"><p align=\"left\">3 to 0</p></td><td valign=\"top\" width=\"158\"><p>0101 binary = 5</p></td></tr></tbody></table><p><br>Free tnodes are stored in a list. When the list is exhausted, more are allocated.</p><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><p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p><h3>NAND data</h3><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><ul><li><p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p></li><li><p>A chunk of file data.</p></li></ul><p>The 16 byte spare area contains:</p><ul><li><p>8 bytes of tags,</p></li><li><p>6 bytes of ECC data</p></li><li><p>1 byte block status (used to identify damaged blocks)</p></li><li><p>1 byte data status (currently unused).</p></li></ul><p>The tags are made up as follows:</p><p>typedef struct</p><p>{</p><p>unsigned chunkId:20; //chunk number in file</p><p>unsigned serialNumber:2; //serial number for chunk</p><p>unsigned byteCount:10; //number of bytes of data used in this chunk</p><p>unsigned objectId:18; //the object id that this chunk belongs to.</p><p>unsigned ecc:12; //ECC on tags</p><p>unsigned unusedStuff:2; //unused</p><p>} yaffs_Tags;</p><p>&nbsp;</p><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><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><p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p><p>objectId says which object this chunk belongs to.</p><p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p><h3>yaffs_ObjectHeader</h3><p>typedef struct</p><p>{</p><p>yaffs_ObjectType type;</p><p>&nbsp;</p><p>// Apply to everything</p><p>int parentObjectId;</p><p>__u16 sum; // checksum of name</p><p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p><p>&nbsp;</p><p>// Thes following apply to directories, files, symlinks - not hard links</p><p>__u32 st_mode; // protection</p><p>__u32 st_uid; // user ID of owner</p><p>__u32 st_gid; // group ID of owner</p><p>__u32 st_atime; // time of last access</p><p>__u32 st_mtime; // time of last modification</p><p>__u32 st_ctime; // time of last change</p><p>&nbsp;</p><p>// File size applies to files only</p><p>int fileSize;</p><p>&nbsp;</p><p>// Equivalent object id applies to hard links only.</p><p>int equivalentObjectId;</p><p>// alias only applies to symlinks</p><p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p><p>&nbsp;</p><p>&nbsp;</p><p>} yaffs_ObjectHeader;</p><p>&nbsp;</p><p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p><p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p><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><p>Obvious stuff skipped....</p><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><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><h3>NAND Interface</h3><p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p><ul><li><p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p></li><li><p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p></li><li><p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p></li><li><p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p></li></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><p>A quick note about NAND:</p><ul><li><p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p></li><li><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></li><li><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></li><li><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></li><li><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></li><li><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></li></ul><h3>mkyaffs</h3><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><h2>Expected performance</h2><p>The following numbers should give an indication of the performance we should expect from Yaffs1.</p><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><p align=\"left\">Seek</p><p align=\"left\">10uS/page</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"233\"><tbody><tr valign=\"top\"></tr><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Read</p></td><td width=\"103\"><p align=\"left\">100nS/byte</p></td></tr><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Write</p></td><td width=\"103\"><p align=\"left\">100nS/byte</p></td></tr><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Program</p></td><td width=\"103\"><p align=\"left\">200uS/page</p></td></tr><tr valign=\"top\"><td width=\"103\"><p align=\"left\">Erase</p></td><td width=\"103\"><p align=\"left\">2mS/block</p></td></tr></tbody></table><p>&nbsp;</p><p>From this we can derive some higher-level numbers:</p><p>Operation</p><p>Time</p><p>Calculation</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"706\"><tbody><tr valign=\"top\"></tr><tr valign=\"top\"><td width=\"204\"><p>Read spare</p></td><td width=\"160\"><p>12uS</p></td><td width=\"304\"><p>seek + 16 * read</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Read page</p></td><td width=\"160\"><p>63 uS</p></td><td width=\"304\"><p>seek + 528 * read</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Write page</p></td><td width=\"160\"><p>326 uS</p></td><td width=\"304\"><p>seek + 528 * write + program + read page (for verification)</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Discard page</p></td><td width=\"160\"><p>212 uS</p></td><td width=\"304\"><p>seek + 16 * write + program</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Overwrite page</p></td><td width=\"160\"><p>538 uS</p></td><td width=\"304\"><p>write page + discard page</p></td></tr><tr valign=\"top\"><td width=\"204\"><p>Erase overhead per page</p></td><td width=\"160\"><p>63uS</p></td><td width=\"304\"><p>erase/32</p></td></tr></tbody></table><p><br>&nbsp;</p><p>From this we can infer the following flash access times:</p><p>Operation</p><p>Time</p><p>Calculation</p><table border=\"1\" cellpadding=\"4\" cellspacing=\"3\" width=\"704\"><tbody><tr valign=\"top\"></tr><tr valign=\"top\"><td width=\"196\"><p>Read 1MB file</p></td><td width=\"167\"><p>0.13s (about 7.5 MB/s)</p></td><td width=\"303\"><p>2000 * read page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Write 1MB (clean system)</p></td><td width=\"167\"><p>0.53s (about 1.8 MB/s)</p></td><td width=\"303\"><p>2000 * write page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Overwrite 1MB file (no gc)</p></td><td width=\"167\"><p>1.08s (about 0.9MB/s)</p></td><td width=\"303\"><p>2000 * overwrite page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Overwrite 1MB with 50% gc</p></td><td width=\"167\"><p>2.4s (about 0.4 MB/s)</p></td><td width=\"303\"><p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Delete 1MB file</p></td><td width=\"167\"><p>0.43s (about 2.2 MB/s)</p></td><td width=\"303\"><p>2000 * discard page</p></td></tr><tr valign=\"top\"><td width=\"196\"><p>Delete 1MB file with 50% gc</p></td><td width=\"167\"><p>0.49s (about 2.0MB/s)</p></td><td width=\"303\"><p>2000 * discard page + 1000 * erase overhead</p></td></tr></tbody></table><p>&nbsp;</p>','<p>Notes on how to use Yaffs (Yaffs1) and some details of the internal structures - useful if you want to mess with the code. This document is included in the Yaffs1 download.</p>','filtered_html'),('page',0,39,546,'und',0,'<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>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h2>Build options</h2>\r\n\r\n<p>Yaffs1 can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Trying it out</h3>\r\n\r\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>\r\n\r\n<ol>\r\n	<li>\r\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\r\n	</li>\r\n	<li>\r\n	<p>Load Yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\r\n	</li>\r\n	<li>\r\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\r\n	</li>\r\n</ol>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>Yaffs1 Data structures</h3>\r\n\r\n<p>All data types are defined in yaffs_guts.h</p>\r\n\r\n<p>Yaffs1 uses the following major objects:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\r\n	</li>\r\n	<li>\r\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\r\n	</li>\r\n	<li>\r\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h3>yaffs_Object</h3>\r\n\r\n<p>struct yaffs_ObjectStruct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\r\n\r\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\r\n\r\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\r\n\r\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\r\n\r\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\r\n\r\n<p>// object might be created before the data</p>\r\n\r\n<p>// is available (ie. file data records appear before the header).</p>\r\n\r\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\r\n\r\n<p>// read back the old one to update.</p>\r\n\r\n<p>__u16 sum; // sum of the name to speed searching</p>\r\n\r\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\r\n\r\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\r\n\r\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\r\n\r\n<p>// live on this list</p>\r\n\r\n<p>// directory structure stuff</p>\r\n\r\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\r\n\r\n<p>struct list_head siblings; // siblings in a directory</p>\r\n\r\n<p>// also used for linking up the free list</p>\r\n\r\n<p>// Where\'s my data in NAND?</p>\r\n\r\n<p>int chunkId; // where it lives</p>\r\n\r\n<p>__u32 objectId; // the object id value</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>yaffs_ObjectType variantType;</p>\r\n\r\n<p>yaffs_ObjectVariant variant;</p>\r\n\r\n<p>};</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\n<p>serial, sum: see yaffs_ObjectHeader.</p>\r\n\r\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\r\n\r\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>\r\n\r\n<p>hashlink is a list of Objects in the same hash bucket.</p>\r\n\r\n<p>The four variants hold extra info:</p>\r\n\r\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\r\n\r\n<p>Directories hold a list of children objects.</p>\r\n\r\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>\r\n\r\n<p>Hardlinks hold information to identify the equivalent object.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>File structure (tnodes)</h3>\r\n\r\n<p>File structures are done with a tiered indexing structure</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><img alt=\"\" height=\"294\" src=\"http://www.aleph1.co.uk/yaffs/sv9349341.gif\" width=\"491\" /><br />\r\n<br />\r\n&nbsp;</p>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\r\n	</li>\r\n	<li>\r\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\r\n\r\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\r\n\r\n<p>Level</p>\r\n\r\n<p>Bits</p>\r\n\r\n<p>Selected value</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>3 or more if they exist</p>\r\n			</td>\r\n			<td>\r\n			<p>&gt;= 10</p>\r\n			</td>\r\n			<td>\r\n			<p>Zero</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>9 to 7</p>\r\n			</td>\r\n			<td>\r\n			<p>100 binary = 4</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>6 to 4</p>\r\n			</td>\r\n			<td>\r\n			<p>011 binary = 3</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>3 to 0</p>\r\n			</td>\r\n			<td>\r\n			<p>0101 binary = 5</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\nFree tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\r\n\r\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>\r\n\r\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\r\n\r\n<h3>NAND data</h3>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\r\n	</li>\r\n	<li>\r\n	<p>A chunk of file data.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The 16 byte spare area contains:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>8 bytes of tags,</p>\r\n	</li>\r\n	<li>\r\n	<p>6 bytes of ECC data</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte block status (used to identify damaged blocks)</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte data status (currently unused).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The tags are made up as follows:</p>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>unsigned chunkId:20; //chunk number in file</p>\r\n\r\n<p>unsigned serialNumber:2; //serial number for chunk</p>\r\n\r\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\r\n\r\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\r\n\r\n<p>unsigned ecc:12; //ECC on tags</p>\r\n\r\n<p>unsigned unusedStuff:2; //unused</p>\r\n\r\n<p>} yaffs_Tags;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\r\n\r\n<p>objectId says which object this chunk belongs to.</p>\r\n\r\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\r\n\r\n<h3>yaffs_ObjectHeader</h3>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>yaffs_ObjectType type;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Apply to everything</p>\r\n\r\n<p>int parentObjectId;</p>\r\n\r\n<p>__u16 sum; // checksum of name</p>\r\n\r\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// File size applies to files only</p>\r\n\r\n<p>int fileSize;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Equivalent object id applies to hard links only.</p>\r\n\r\n<p>int equivalentObjectId;</p>\r\n\r\n<p>// alias only applies to symlinks</p>\r\n\r\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>} yaffs_ObjectHeader;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\r\n\r\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\r\n\r\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>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>NAND Interface</h3>\r\n\r\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\r\n	</li>\r\n	<li>\r\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\r\n	</li>\r\n	<li>\r\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\r\n	</li>\r\n	<li>\r\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<p>A quick note about NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<h3>mkyaffs</h3>\r\n\r\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>\r\n\r\n<h2>Expected performance</h2>\r\n\r\n<p>The following numbers should give an indication of the performance we should expect from Yaffs1.</p>\r\n\r\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>\r\n\r\n<p>Seek</p>\r\n\r\n<p>10uS/page</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>200uS/page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>2mS/block</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>From this we can derive some higher-level numbers:</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Time</p>\r\n\r\n<p>Calculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read spare</p>\r\n			</td>\r\n			<td>\r\n			<p>12uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read page</p>\r\n			</td>\r\n			<td>\r\n			<p>63 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write page</p>\r\n			</td>\r\n			<td>\r\n			<p>326 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * write + program + read page (for verification)</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Discard page</p>\r\n			</td>\r\n			<td>\r\n			<p>212 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * write + program</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite page</p>\r\n			</td>\r\n			<td>\r\n			<p>538 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>write page + discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase overhead per page</p>\r\n			</td>\r\n			<td>\r\n			<p>63uS</p>\r\n			</td>\r\n			<td>\r\n			<p>erase/32</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can infer the following flash access times:</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Time</p>\r\n\r\n<p>Calculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.13s (about 7.5 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * read page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 1MB (clean system)</p>\r\n			</td>\r\n			<td>\r\n			<p>0.53s (about 1.8 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * write page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB file (no gc)</p>\r\n			</td>\r\n			<td>\r\n			<p>1.08s (about 0.9MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>2.4s (about 0.4 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.43s (about 2.2 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>0.49s (about 2.0MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page + 1000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n','<p>Notes on how to use Yaffs (Yaffs1) and some details of the internal structures - useful if you want to mess with the code. This document is included in the Yaffs1 download.</p>','filtered_html'),('page',0,39,550,'und',0,'<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>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h2>Build options</h2>\r\n\r\n<p>Yaffs1 can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Trying it out</h3>\r\n\r\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>\r\n\r\n<ol>\r\n	<li>\r\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\r\n	</li>\r\n	<li>\r\n	<p>Load Yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\r\n	</li>\r\n	<li>\r\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\r\n	</li>\r\n</ol>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>Yaffs1 Data structures</h3>\r\n\r\n<p>All data types are defined in yaffs_guts.h</p>\r\n\r\n<p>Yaffs1 uses the following major objects:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\r\n	</li>\r\n	<li>\r\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\r\n	</li>\r\n	<li>\r\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h3>yaffs_Object</h3>\r\n\r\n<p>struct yaffs_ObjectStruct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\r\n\r\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\r\n\r\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\r\n\r\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\r\n\r\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\r\n\r\n<p>// object might be created before the data</p>\r\n\r\n<p>// is available (ie. file data records appear before the header).</p>\r\n\r\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\r\n\r\n<p>// read back the old one to update.</p>\r\n\r\n<p>__u16 sum; // sum of the name to speed searching</p>\r\n\r\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\r\n\r\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\r\n\r\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\r\n\r\n<p>// live on this list</p>\r\n\r\n<p>// directory structure stuff</p>\r\n\r\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\r\n\r\n<p>struct list_head siblings; // siblings in a directory</p>\r\n\r\n<p>// also used for linking up the free list</p>\r\n\r\n<p>// Where\'s my data in NAND?</p>\r\n\r\n<p>int chunkId; // where it lives</p>\r\n\r\n<p>__u32 objectId; // the object id value</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>yaffs_ObjectType variantType;</p>\r\n\r\n<p>yaffs_ObjectVariant variant;</p>\r\n\r\n<p>};</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\n<p>serial, sum: see yaffs_ObjectHeader.</p>\r\n\r\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\r\n\r\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>\r\n\r\n<p>hashlink is a list of Objects in the same hash bucket.</p>\r\n\r\n<p>The four variants hold extra info:</p>\r\n\r\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\r\n\r\n<p>Directories hold a list of children objects.</p>\r\n\r\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>\r\n\r\n<p>Hardlinks hold information to identify the equivalent object.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>File structure (tnodes)</h3>\r\n\r\n<p>File structures are done with a tiered indexing structure</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><img alt=\"\" height=\"294\" src=\"http://www.aleph1.co.uk/yaffs/sv9349341.gif\" width=\"491\" /><br />\r\n<br />\r\n&nbsp;</p>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\r\n	</li>\r\n	<li>\r\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\r\n\r\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\r\n\r\n<p>Level</p>\r\n\r\n<p>Bits</p>\r\n\r\n<p>Selected value</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>3 or more if they exist</p>\r\n			</td>\r\n			<td>\r\n			<p>&gt;= 10</p>\r\n			</td>\r\n			<td>\r\n			<p>Zero</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>9 to 7</p>\r\n			</td>\r\n			<td>\r\n			<p>100 binary = 4</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>6 to 4</p>\r\n			</td>\r\n			<td>\r\n			<p>011 binary = 3</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>3 to 0</p>\r\n			</td>\r\n			<td>\r\n			<p>0101 binary = 5</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\nFree tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\r\n\r\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>\r\n\r\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\r\n\r\n<h3>NAND data</h3>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\r\n	</li>\r\n	<li>\r\n	<p>A chunk of file data.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The 16 byte spare area contains:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>8 bytes of tags,</p>\r\n	</li>\r\n	<li>\r\n	<p>6 bytes of ECC data</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte block status (used to identify damaged blocks)</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte data status (currently unused).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The tags are made up as follows:</p>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>unsigned chunkId:20; //chunk number in file</p>\r\n\r\n<p>unsigned serialNumber:2; //serial number for chunk</p>\r\n\r\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\r\n\r\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\r\n\r\n<p>unsigned ecc:12; //ECC on tags</p>\r\n\r\n<p>unsigned unusedStuff:2; //unused</p>\r\n\r\n<p>} yaffs_Tags;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\r\n\r\n<p>objectId says which object this chunk belongs to.</p>\r\n\r\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\r\n\r\n<h3>yaffs_ObjectHeader</h3>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>yaffs_ObjectType type;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Apply to everything</p>\r\n\r\n<p>int parentObjectId;</p>\r\n\r\n<p>__u16 sum; // checksum of name</p>\r\n\r\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// File size applies to files only</p>\r\n\r\n<p>int fileSize;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Equivalent object id applies to hard links only.</p>\r\n\r\n<p>int equivalentObjectId;</p>\r\n\r\n<p>// alias only applies to symlinks</p>\r\n\r\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>} yaffs_ObjectHeader;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\r\n\r\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\r\n\r\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>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>NAND Interface</h3>\r\n\r\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\r\n	</li>\r\n	<li>\r\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\r\n	</li>\r\n	<li>\r\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\r\n	</li>\r\n	<li>\r\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<p>A quick note about NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<h3>mkyaffs</h3>\r\n\r\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>\r\n\r\n<h2>Expected performance</h2>\r\n\r\n<p>The following numbers should give an indication of the performance we should expect from Yaffs1.</p>\r\n\r\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>\r\n\r\n<p>Seek</p>\r\n\r\n<p>10uS/page</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>200uS/page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>2mS/block</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>From this we can derive some higher-level numbers:</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Time</p>\r\n\r\n<p>Calculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read spare</p>\r\n			</td>\r\n			<td>\r\n			<p>12uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read page</p>\r\n			</td>\r\n			<td>\r\n			<p>63 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write page</p>\r\n			</td>\r\n			<td>\r\n			<p>326 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * write + program + read page (for verification)</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Discard page</p>\r\n			</td>\r\n			<td>\r\n			<p>212 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * write + program</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite page</p>\r\n			</td>\r\n			<td>\r\n			<p>538 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>write page + discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase overhead per page</p>\r\n			</td>\r\n			<td>\r\n			<p>63uS</p>\r\n			</td>\r\n			<td>\r\n			<p>erase/32</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can infer the following flash access times:</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Time</p>\r\n\r\n<p>Calculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.13s (about 7.5 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * read page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 1MB (clean system)</p>\r\n			</td>\r\n			<td>\r\n			<p>0.53s (about 1.8 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * write page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB file (no gc)</p>\r\n			</td>\r\n			<td>\r\n			<p>1.08s (about 0.9MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>2.4s (about 0.4 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.43s (about 2.2 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>0.49s (about 2.0MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page + 1000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n','<p>Notes on how to use Yaffs (Yaffs1) and some details of the internal structures - useful if you want to mess with the code. This document is included in the Yaffs1 download.</p>','filtered_html'),('page',0,39,572,'und',0,'<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>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h2>Build options</h2>\r\n\r\n<p>Yaffs1 can be built as either a kernel module (ie. a Linux file system) or as an application.</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>Trying it out</h3>\r\n\r\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>\r\n\r\n<ol>\r\n	<li>\r\n	<p>Hack the Makefile and change the KERNELDIR define to your kernel directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>Type <strong>make clean; make</strong> to build yaffs</p>\r\n	</li>\r\n	<li>\r\n	<p>Load Yaffs as a module by typing <strong>/sbin/insmod yaffs.o</strong> (ya gotta be root!).</p>\r\n	</li>\r\n	<li>\r\n	<p>Create a mount point eg. <strong>mkdir /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>To mount the RAM emulation version of yaffs, <strong>mount -t yaffsram none /mnt/y</strong></p>\r\n	</li>\r\n	<li>\r\n	<p>Alternatively, to mount the mtd version of yaffs,<strong> mount -t yaffs /dev/mtd0 /mnt/y</strong></p>\r\n	</li>\r\n</ol>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>Yaffs1 Data structures</h3>\r\n\r\n<p>All data types are defined in yaffs_guts.h</p>\r\n\r\n<p>Yaffs1 uses the following major objects:</p>\r\n\r\n<ul>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\n	<p>parent: pointer to the yaffs_Object that is a parent of this yaffs_Object in the directory structure.</p>\r\n	</li>\r\n	<li>\r\n	<p>siblings: this field is used to link together a list of all the yaffs_Objects in the same directory.</p>\r\n	</li>\r\n	<li>\r\n	<p>children: if the object is a directory, then children holds the head of the list of objects in the directory.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<h3>yaffs_Object</h3>\r\n\r\n<p>struct yaffs_ObjectStruct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>__u8 fake:1; // A fake object has no presence on NAND.</p>\r\n\r\n<p>__u8 renameAllowed:1; // Are we allowed to rename it?</p>\r\n\r\n<p>__u8 unlinkAllowed:1; // Are we allowed to unlink it?</p>\r\n\r\n<p>__u8 dirty:1; // the object needs to be written to flash</p>\r\n\r\n<p>__u8 valid:1; // When the file system is being loaded up, this</p>\r\n\r\n<p>// object might be created before the data</p>\r\n\r\n<p>// is available (ie. file data records appear before the header).</p>\r\n\r\n<p>__u8 serial; // serial number of chunk in NAND. Store here so we don\'t have to</p>\r\n\r\n<p>// read back the old one to update.</p>\r\n\r\n<p>__u16 sum; // sum of the name to speed searching</p>\r\n\r\n<p>struct yaffs_DeviceStruct *myDev; // The device I\'m on</p>\r\n\r\n<p>struct list_head hashLink; // list of objects in this hash bucket</p>\r\n\r\n<p>struct list_head hardLinks; // all the equivalent hard linked objects</p>\r\n\r\n<p>// live on this list</p>\r\n\r\n<p>// directory structure stuff</p>\r\n\r\n<p>struct yaffs_ObjectStruct *parent; //my parent directory</p>\r\n\r\n<p>struct list_head siblings; // siblings in a directory</p>\r\n\r\n<p>// also used for linking up the free list</p>\r\n\r\n<p>// Where\'s my data in NAND?</p>\r\n\r\n<p>int chunkId; // where it lives</p>\r\n\r\n<p>__u32 objectId; // the object id value</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>yaffs_ObjectType variantType;</p>\r\n\r\n<p>yaffs_ObjectVariant variant;</p>\r\n\r\n<p>};</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\n<p>serial, sum: see yaffs_ObjectHeader.</p>\r\n\r\n<p>dirty indicates that the object\'s contents has changed and a new yaffs_ObjectHeader must be written to flash.</p>\r\n\r\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>\r\n\r\n<p>hashlink is a list of Objects in the same hash bucket.</p>\r\n\r\n<p>The four variants hold extra info:</p>\r\n\r\n<p>Files hold the file size and the top level and pointer to the tnode tree for the file.</p>\r\n\r\n<p>Directories hold a list of children objects.</p>\r\n\r\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>\r\n\r\n<p>Hardlinks hold information to identify the equivalent object.</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<h3>File structure (tnodes)</h3>\r\n\r\n<p>File structures are done with a tiered indexing structure</p>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p><img alt=\"\" height=\"294\" src=\"http://www.aleph1.co.uk/yaffs/sv9349341.gif\" width=\"491\" /><br />\r\n<br />\r\n&nbsp;</p>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>.... if it is at the lowest level, then 16 __u16s which identify the page.</p>\r\n	</li>\r\n	<li>\r\n	<p>.... if it is at a higher level (ie an internal tnode), then 8 pointers to lowest-level tnodes.</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>For example, finding page 0x235 (ie. the one starting at file position 0x46800 would proceed as follows:</p>\r\n\r\n<p>0x235 is 0000001000110101, partitioned as follows. 000.000.100.011.0101</p>\r\n\r\n<p>Level</p>\r\n\r\n<p>Bits</p>\r\n\r\n<p>Selected value</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>3 or more if they exist</p>\r\n			</td>\r\n			<td>\r\n			<p>&gt;= 10</p>\r\n			</td>\r\n			<td>\r\n			<p>Zero</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>2</p>\r\n			</td>\r\n			<td>\r\n			<p>9 to 7</p>\r\n			</td>\r\n			<td>\r\n			<p>100 binary = 4</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>1</p>\r\n			</td>\r\n			<td>\r\n			<p>6 to 4</p>\r\n			</td>\r\n			<td>\r\n			<p>011 binary = 3</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>0</p>\r\n			</td>\r\n			<td>\r\n			<p>3 to 0</p>\r\n			</td>\r\n			<td>\r\n			<p>0101 binary = 5</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\nFree tnodes are stored in a list. When the list is exhausted, more are allocated.</p>\r\n\r\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>\r\n\r\n<p>The tree grows as required. When the file is resized to a smaller size then it is pruned.</p>\r\n\r\n<h3>NAND data</h3>\r\n\r\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>\r\n\r\n<ul>\r\n	<li>\r\n	<p>A yaffs_ObjectHeader. This is the way a yaffs_Object gets stored on NAND.</p>\r\n	</li>\r\n	<li>\r\n	<p>A chunk of file data.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The 16 byte spare area contains:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>8 bytes of tags,</p>\r\n	</li>\r\n	<li>\r\n	<p>6 bytes of ECC data</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte block status (used to identify damaged blocks)</p>\r\n	</li>\r\n	<li>\r\n	<p>1 byte data status (currently unused).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>The tags are made up as follows:</p>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>unsigned chunkId:20; //chunk number in file</p>\r\n\r\n<p>unsigned serialNumber:2; //serial number for chunk</p>\r\n\r\n<p>unsigned byteCount:10; //number of bytes of data used in this chunk</p>\r\n\r\n<p>unsigned objectId:18; //the object id that this chunk belongs to.</p>\r\n\r\n<p>unsigned ecc:12; //ECC on tags</p>\r\n\r\n<p>unsigned unusedStuff:2; //unused</p>\r\n\r\n<p>} yaffs_Tags;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<p>bytecount applies only to data chunks and tells how many of the data bytes are valid.</p>\r\n\r\n<p>objectId says which object this chunk belongs to.</p>\r\n\r\n<p>ecc is used to perform error correction on the tags. Another ecc field is used to error correct the data.</p>\r\n\r\n<h3>yaffs_ObjectHeader</h3>\r\n\r\n<p>typedef struct</p>\r\n\r\n<p>{</p>\r\n\r\n<p>yaffs_ObjectType type;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Apply to everything</p>\r\n\r\n<p>int parentObjectId;</p>\r\n\r\n<p>__u16 sum; // checksum of name</p>\r\n\r\n<p>char name[YAFFS_MAX_NAME_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Thes following apply to directories, files, symlinks - not hard links</p>\r\n\r\n<p>__u32 st_mode; // protection</p>\r\n\r\n<p>__u32 st_uid; // user ID of owner</p>\r\n\r\n<p>__u32 st_gid; // group ID of owner</p>\r\n\r\n<p>__u32 st_atime; // time of last access</p>\r\n\r\n<p>__u32 st_mtime; // time of last modification</p>\r\n\r\n<p>__u32 st_ctime; // time of last change</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// File size applies to files only</p>\r\n\r\n<p>int fileSize;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>// Equivalent object id applies to hard links only.</p>\r\n\r\n<p>int equivalentObjectId;</p>\r\n\r\n<p>// alias only applies to symlinks</p>\r\n\r\n<p>char alias[YAFFS_MAX_ALIAS_LENGTH + 1];</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>} yaffs_ObjectHeader;</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>A yaffs_ObjectHeader is stored in NAND for every yaffs_Object.</p>\r\n\r\n<p>type holds the type of yaffs_Object (file,directory,hardlink or symlink).</p>\r\n\r\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>\r\n\r\n<p>Obvious stuff skipped....</p>\r\n\r\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>\r\n\r\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>\r\n\r\n<h3>NAND Interface</h3>\r\n\r\n<p>All NAND access is performed via four functions pointed to by yaffs_Device. At the moment a chunk is a page.</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>int WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)</p>\r\n	</li>\r\n	<li>\r\n	<p>int ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare);</p>\r\n	</li>\r\n	<li>\r\n	<p>int EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND);</p>\r\n	</li>\r\n	<li>\r\n	<p>int InitialiseNAND(struct yaffs_DeviceStruct *dev);</p>\r\n	</li>\r\n</ul>\r\n\r\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>\r\n\r\n<p>A quick note about NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND is not random access, but page oriented. Thus, we do all reads &amp; writes in pages.</p>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n	<li>\r\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>\r\n	</li>\r\n</ul>\r\n\r\n<h3>mkyaffs</h3>\r\n\r\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>\r\n\r\n<h2>Expected performance</h2>\r\n\r\n<p>The following numbers should give an indication of the performance we should expect from Yaffs1.</p>\r\n\r\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>\r\n\r\n<p>Seek</p>\r\n\r\n<p>10uS/page</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write</p>\r\n			</td>\r\n			<td>\r\n			<p>100nS/byte</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Program</p>\r\n			</td>\r\n			<td>\r\n			<p>200uS/page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase</p>\r\n			</td>\r\n			<td>\r\n			<p>2mS/block</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>From this we can derive some higher-level numbers:</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Time</p>\r\n\r\n<p>Calculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read spare</p>\r\n			</td>\r\n			<td>\r\n			<p>12uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read page</p>\r\n			</td>\r\n			<td>\r\n			<p>63 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * read</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write page</p>\r\n			</td>\r\n			<td>\r\n			<p>326 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 528 * write + program + read page (for verification)</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Discard page</p>\r\n			</td>\r\n			<td>\r\n			<p>212 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>seek + 16 * write + program</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite page</p>\r\n			</td>\r\n			<td>\r\n			<p>538 uS</p>\r\n			</td>\r\n			<td>\r\n			<p>write page + discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Erase overhead per page</p>\r\n			</td>\r\n			<td>\r\n			<p>63uS</p>\r\n			</td>\r\n			<td>\r\n			<p>erase/32</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p><br />\r\n&nbsp;</p>\r\n\r\n<p>From this we can infer the following flash access times:</p>\r\n\r\n<p>Operation</p>\r\n\r\n<p>Time</p>\r\n\r\n<p>Calculation</p>\r\n\r\n<table>\r\n	<tbody>\r\n		<tr>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Read 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.13s (about 7.5 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * read page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Write 1MB (clean system)</p>\r\n			</td>\r\n			<td>\r\n			<p>0.53s (about 1.8 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * write page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB file (no gc)</p>\r\n			</td>\r\n			<td>\r\n			<p>1.08s (about 0.9MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Overwrite 1MB with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>2.4s (about 0.4 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * overwrite page + 2000 * page copy (== overwrite page) + 4000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file</p>\r\n			</td>\r\n			<td>\r\n			<p>0.43s (about 2.2 MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page</p>\r\n			</td>\r\n		</tr>\r\n		<tr>\r\n			<td>\r\n			<p>Delete 1MB file with 50% gc</p>\r\n			</td>\r\n			<td>\r\n			<p>0.49s (about 2.0MB/s)</p>\r\n			</td>\r\n			<td>\r\n			<p>2000 * discard page + 1000 * erase overhead</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n','<p>Notes on how to use Yaffs (Yaffs1) and some details of the internal structures - useful if you want to mess with the code. This document is included in the Yaffs1 download.</p>','full_html'),('page',0,40,40,'und',0,'<h1>Brief HOWTO on incorporating yaffs as a root fs.</h1>\r\n<h4>By N C Bane &lt;nick@cecomputing.co.uk&gt;</h4>\r\n<h3>Document status</h3>\r\n<p>\r\nThis document is very much work in progress. It currently refers to YAFFS1 and needs updating for YAFFS2. It has been edited by different people with no attempt to keep a consistent style. Beauty will come with age.\r\n</p>\r\n<h2>What is yaffs?</h2>\r\n<p>\r\nYaffs stands for Yet Another Flash Filing System.\r\n</p>\r\n<p>\r\nIt is a journaling filesystem designed to run on NAND flash with special reference to embedded systems.\r\n</p>\r\n<h2>Why would I want to use it?</h2>\r\n<p>\r\nNAND flash (SmartMedia cards are repackaged raw NAND chips) is cheap and has a fast erase time as compared with NOR flash.\r\n</p>\r\n<p>\r\nThe NAND physical interface is very simple.\r\n</p>\r\n<p>\r\nThe small size and low current requirements make it very suitable for embedded systems.\r\n</p>\r\n<p>\r\nHowever, NAND has its problems. These are mainly due to bad block management as blocks of memory can be bad when the device is shipped and further blocks can become unusable over time.\r\n</p>\r\n<p>\r\nPower can die unpredictably in embedded systems leading to data loss and possibly file system corruption.\r\n</p>\r\n<p>\r\nThis is where yaffs comes in; it handles bad blocks and uses formats which are resistant to corruption.\r\n</p>\r\n<h2>What do I need to know?</h2>\r\n<p>\r\nIt is assumed that the reader has a development system with direct access to NAND flash (ie not a CF/SmartMedia adaptor which).\r\n</p>\r\n<p>\r\nThe user should be familiar with building linux kernels and patching build trees.\r\n</p>\r\n<p>\r\nIt is strongly suggested that you also read more about NAND flash on the Linux mtd site.\r\n</p>\r\n<h3>Assumptions:</h3>\r\n<p>\r\nYou have already downloaded the yaffs sources from the cvs at Aleph1.\r\n</p>\r\n<p>\r\nYou have mtd code that exposes NAND as an mtdblock device.\r\n</p>\r\n<h3>Nand interface:</h3>\r\n<p>\r\nFor yaffs to function, it must be able to be the only code that writes to the oob area on the NAND device.\r\n</p>\r\n<p>\r\nThe existing NAND driver in kernel 2.4.19 assumes that it will do the ecc/oob management for the host fs. For yaffs, this is quite wrong.\r\n</p>\r\n<p>\r\nYou can disable ecc/oob calculations either by hand patching the mtd code to bypass ecc calculations or by merging the latest mtd cvs.\r\n</p>\r\n<p>\r\nThe patches at http://www.toby-churchill.org have done the latter.\r\n</p>\r\n<h3>Including yaffs as a kernel fs:</h3>\r\n<p>\r\n1) Create [linux]/fs/yaffs directory in your kernel test source.\r\n</p>\r\n<p>\r\n2) Copy devextras.h yaffs_fs.c yaffs_gets.c yaffs_guts.h yaffs_mtdif.c yaffs_mtdif.h yaffsinterface.h and yportenv.h from the yaffs sources to that directory.\r\n</p>\r\n<p>\r\n3) Copy the Makefile from either the yaffs sources (Makefile.kernel) or the Balloon download site below to [linux]/fs/yaffs/Makefile.\r\n</p>\r\n<p>\r\n4) Modify [linux]/fs/Config.in to include the 3 lines\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\nif [ &quot;CONFIG_MTD_NAND&quot; = &quot;y&quot; ]; then\r\n</p>\r\n<p>\r\n    tristate &quot;Yaffs filesystem on NAND&quot; CONFIG_YAFFS_FS\r\n</p>\r\n<p>\r\nfi\r\n</p>\r\n<p>\r\n5) Modify [linux]/fs/Makefile to include the yaffs fs reference\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\n subdir-$(CONFIG_YAFFS_FS) +=yaffs\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\n6) Configure the kernel to include (not modules) all the mtd nand code (incl nand_ecc and mtdblock device) and yaffs fs.\r\n</p>\r\n<p>\r\nYou should now be able to build a kernel with yaffs as a root fs using the normal tools.\r\n</p>\r\n<h3>Creating a bootable yaffs partition:</h3>\r\n<p>\r\nYou can\r\n</p>\r\n<p>\r\n1) Create the partition by mounting it from a running linux os and copying the data there. The mkyaffs utility in the yaffs source simply erases a NAND mtdblock device without removing bad block data.\r\n</p>\r\n<p>\r\n2) Make and download a filesystem image. The mkyaffsimage utility that came with the sources will create a YAFFS block list in a file from a root tree. This is a list of 512+16 byte blocks that need to be placed (in any order) on a NAND device.\r\n</p>\r\n<p>\r\nYou will need to write code to copy these data blocks and add in the block numbers in the oob areas.\r\n</p>\r\n<p>\r\nExamples of a modified handhelds.org bootldr for the Balloon board can be found on the toby-churchill.org website.\r\n</p>\r\n<h3>Booting into yaffs:</h3>\r\n<p>\r\nModify your bootloader to pass a  command line to linux to specifying the mtdblock/n that refers to the root partition.\r\n</p>\r\n<p>\r\n&nbsp;\r\n</p>\r\n<p>\r\nBalloon page at http://www.toby-churchill.org.uk\r\n</p>\r\n<p>\r\nYaffs mailing list - to join go to http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs and enter your email address\r\n\r\n</p>\r\n<p>\r\nLinux MTD http://www.linux-mtd.infradead.org/\r\n</p>\r\n<p>\r\n$Id$\r\n</p>\r\n','Simple HOWTO for getting started with YAFFS and using it as a root filesystem. If you just want the <i>quick start</i> info - read this.','obsolete_tinymce'),('page',0,40,545,'und',0,'<h1>Brief HOWTO on incorporating yaffs as a root fs.</h1>\r\n<h4>By N C Bane &lt;nick@cecomputing.co.uk&gt;</h4>\r\n<h3>Document status</h3>\r\n<p>\r\nThis document is very much work in progress. It currently refers to YAFFS1 and needs updating for YAFFS2. It has been edited by different people with no attempt to keep a consistent style. Beauty will come with age.\r\n</p>\r\n<h2>What is yaffs?</h2>\r\n<p>\r\nYaffs stands for Yet Another Flash Filing System.\r\n</p>\r\n<p>\r\nIt is a journaling filesystem designed to run on NAND flash with special reference to embedded systems.\r\n</p>\r\n<h2>Why would I want to use it?</h2>\r\n<p>\r\nNAND flash (SmartMedia cards are repackaged raw NAND chips) is cheap and has a fast erase time as compared with NOR flash.\r\n</p>\r\n<p>\r\nThe NAND physical interface is very simple.\r\n</p>\r\n<p>\r\nThe small size and low current requirements make it very suitable for embedded systems.\r\n</p>\r\n<p>\r\nHowever, NAND has its problems. These are mainly due to bad block management as blocks of memory can be bad when the device is shipped and further blocks can become unusable over time.\r\n</p>\r\n<p>\r\nPower can die unpredictably in embedded systems leading to data loss and possibly file system corruption.\r\n</p>\r\n<p>\r\nThis is where yaffs comes in; it handles bad blocks and uses formats which are resistant to corruption.\r\n</p>\r\n<h2>What do I need to know?</h2>\r\n<p>\r\nIt is assumed that the reader has a development system with direct access to NAND flash (ie not a CF/SmartMedia adaptor which).\r\n</p>\r\n<p>\r\nThe user should be familiar with building linux kernels and patching build trees.\r\n</p>\r\n<p>\r\nIt is strongly suggested that you also read more about NAND flash on the Linux mtd site.\r\n</p>\r\n<h3>Assumptions:</h3>\r\n<p>\r\nYou have already downloaded the yaffs sources from the cvs at Aleph1.\r\n</p>\r\n<p>\r\nYou have mtd code that exposes NAND as an mtdblock device.\r\n</p>\r\n<h3>Nand interface:</h3>\r\n<p>\r\nFor yaffs to function, it must be able to be the only code that writes to the oob area on the NAND device.\r\n</p>\r\n<p>\r\nThe existing NAND driver in kernel 2.4.19 assumes that it will do the ecc/oob management for the host fs. For yaffs, this is quite wrong.\r\n</p>\r\n<p>\r\nYou can disable ecc/oob calculations either by hand patching the mtd code to bypass ecc calculations or by merging the latest mtd cvs.\r\n</p>\r\n<p>\r\nThe patches at http://www.toby-churchill.org have done the latter.\r\n</p>\r\n<h3>Including yaffs as a kernel fs:</h3>\r\n<p>\r\n1) Create [linux]/fs/yaffs directory in your kernel test source.\r\n</p>\r\n<p>\r\n2) Copy devextras.h yaffs_fs.c yaffs_gets.c yaffs_guts.h yaffs_mtdif.c yaffs_mtdif.h yaffsinterface.h and yportenv.h from the yaffs sources to that directory.\r\n</p>\r\n<p>\r\n3) Copy the Makefile from either the yaffs sources (Makefile.kernel) or the Balloon download site below to [linux]/fs/yaffs/Makefile.\r\n</p>\r\n<p>\r\n4) Modify [linux]/fs/Config.in to include the 3 lines\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\nif [ &quot;CONFIG_MTD_NAND&quot; = &quot;y&quot; ]; then\r\n</p>\r\n<p>\r\n    tristate &quot;Yaffs filesystem on NAND&quot; CONFIG_YAFFS_FS\r\n</p>\r\n<p>\r\nfi\r\n</p>\r\n<p>\r\n5) Modify [linux]/fs/Makefile to include the yaffs fs reference\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\n subdir-$(CONFIG_YAFFS_FS) +=yaffs\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\n6) Configure the kernel to include (not modules) all the mtd nand code (incl nand_ecc and mtdblock device) and yaffs fs.\r\n</p>\r\n<p>\r\nYou should now be able to build a kernel with yaffs as a root fs using the normal tools.\r\n</p>\r\n<h3>Creating a bootable yaffs partition:</h3>\r\n<p>\r\nYou can\r\n</p>\r\n<p>\r\n1) Create the partition by mounting it from a running linux os and copying the data there. The mkyaffs utility in the yaffs source simply erases a NAND mtdblock device without removing bad block data.\r\n</p>\r\n<p>\r\n2) Make and download a filesystem image. The mkyaffsimage utility that came with the sources will create a YAFFS block list in a file from a root tree. This is a list of 512+16 byte blocks that need to be placed (in any order) on a NAND device.\r\n</p>\r\n<p>\r\nYou will need to write code to copy these data blocks and add in the block numbers in the oob areas.\r\n</p>\r\n<p>\r\nExamples of a modified handhelds.org bootldr for the Balloon board can be found on the toby-churchill.org website.\r\n</p>\r\n<h3>Booting into yaffs:</h3>\r\n<p>\r\nModify your bootloader to pass a  command line to linux to specifying the mtdblock/n that refers to the root partition.\r\n</p>\r\n<p>\r\n&nbsp;\r\n</p>\r\n<p>\r\nBalloon page at http://www.toby-churchill.org.uk\r\n</p>\r\n<p>\r\nYaffs mailing list - to join go to http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs and enter your email address\r\n\r\n</p>\r\n<p>\r\nLinux MTD http://www.linux-mtd.infradead.org/\r\n</p>\r\n<p>\r\n$Id$\r\n</p>\r\n','Simple HOWTO for getting started with YAFFS and using it as a root filesystem. If you just want the <i>quick start</i> info - read this.','obsolete_tinymce'),('page',0,40,551,'und',0,'<h1>Brief HOWTO on incorporating yaffs as a root fs.</h1>\r\n<h4>By N C Bane &lt;nick@cecomputing.co.uk&gt;</h4>\r\n<h3>Document status</h3>\r\n<p>\r\nThis document is very much work in progress. It currently refers to YAFFS1 and needs updating for YAFFS2. It has been edited by different people with no attempt to keep a consistent style. Beauty will come with age.\r\n</p>\r\n<h2>What is yaffs?</h2>\r\n<p>\r\nYaffs stands for Yet Another Flash Filing System.\r\n</p>\r\n<p>\r\nIt is a journaling filesystem designed to run on NAND flash with special reference to embedded systems.\r\n</p>\r\n<h2>Why would I want to use it?</h2>\r\n<p>\r\nNAND flash (SmartMedia cards are repackaged raw NAND chips) is cheap and has a fast erase time as compared with NOR flash.\r\n</p>\r\n<p>\r\nThe NAND physical interface is very simple.\r\n</p>\r\n<p>\r\nThe small size and low current requirements make it very suitable for embedded systems.\r\n</p>\r\n<p>\r\nHowever, NAND has its problems. These are mainly due to bad block management as blocks of memory can be bad when the device is shipped and further blocks can become unusable over time.\r\n</p>\r\n<p>\r\nPower can die unpredictably in embedded systems leading to data loss and possibly file system corruption.\r\n</p>\r\n<p>\r\nThis is where yaffs comes in; it handles bad blocks and uses formats which are resistant to corruption.\r\n</p>\r\n<h2>What do I need to know?</h2>\r\n<p>\r\nIt is assumed that the reader has a development system with direct access to NAND flash (ie not a CF/SmartMedia adaptor which).\r\n</p>\r\n<p>\r\nThe user should be familiar with building linux kernels and patching build trees.\r\n</p>\r\n<p>\r\nIt is strongly suggested that you also read more about NAND flash on the Linux mtd site.\r\n</p>\r\n<h3>Assumptions:</h3>\r\n<p>\r\nYou have already downloaded the yaffs sources from the cvs at Aleph1.\r\n</p>\r\n<p>\r\nYou have mtd code that exposes NAND as an mtdblock device.\r\n</p>\r\n<h3>Nand interface:</h3>\r\n<p>\r\nFor yaffs to function, it must be able to be the only code that writes to the oob area on the NAND device.\r\n</p>\r\n<p>\r\nThe existing NAND driver in kernel 2.4.19 assumes that it will do the ecc/oob management for the host fs. For yaffs, this is quite wrong.\r\n</p>\r\n<p>\r\nYou can disable ecc/oob calculations either by hand patching the mtd code to bypass ecc calculations or by merging the latest mtd cvs.\r\n</p>\r\n<p>\r\nThe patches at http://www.toby-churchill.org have done the latter.\r\n</p>\r\n<h3>Including yaffs as a kernel fs:</h3>\r\n<p>\r\n1) Create [linux]/fs/yaffs directory in your kernel test source.\r\n</p>\r\n<p>\r\n2) Copy devextras.h yaffs_fs.c yaffs_gets.c yaffs_guts.h yaffs_mtdif.c yaffs_mtdif.h yaffsinterface.h and yportenv.h from the yaffs sources to that directory.\r\n</p>\r\n<p>\r\n3) Copy the Makefile from either the yaffs sources (Makefile.kernel) or the Balloon download site below to [linux]/fs/yaffs/Makefile.\r\n</p>\r\n<p>\r\n4) Modify [linux]/fs/Config.in to include the 3 lines\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\nif [ &quot;CONFIG_MTD_NAND&quot; = &quot;y&quot; ]; then\r\n</p>\r\n<p>\r\n    tristate &quot;Yaffs filesystem on NAND&quot; CONFIG_YAFFS_FS\r\n</p>\r\n<p>\r\nfi\r\n</p>\r\n<p>\r\n5) Modify [linux]/fs/Makefile to include the yaffs fs reference\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\n subdir-$(CONFIG_YAFFS_FS) +=yaffs\r\n</p>\r\n<p>\r\n<br />\r\n</p>\r\n<p>\r\n6) Configure the kernel to include (not modules) all the mtd nand code (incl nand_ecc and mtdblock device) and yaffs fs.\r\n</p>\r\n<p>\r\nYou should now be able to build a kernel with yaffs as a root fs using the normal tools.\r\n</p>\r\n<h3>Creating a bootable yaffs partition:</h3>\r\n<p>\r\nYou can\r\n</p>\r\n<p>\r\n1) Create the partition by mounting it from a running linux os and copying the data there. The mkyaffs utility in the yaffs source simply erases a NAND mtdblock device without removing bad block data.\r\n</p>\r\n<p>\r\n2) Make and download a filesystem image. The mkyaffsimage utility that came with the sources will create a YAFFS block list in a file from a root tree. This is a list of 512+16 byte blocks that need to be placed (in any order) on a NAND device.\r\n</p>\r\n<p>\r\nYou will need to write code to copy these data blocks and add in the block numbers in the oob areas.\r\n</p>\r\n<p>\r\nExamples of a modified handhelds.org bootldr for the Balloon board can be found on the toby-churchill.org website.\r\n</p>\r\n<h3>Booting into yaffs:</h3>\r\n<p>\r\nModify your bootloader to pass a  command line to linux to specifying the mtdblock/n that refers to the root partition.\r\n</p>\r\n<p>\r\n&nbsp;\r\n</p>\r\n<p>\r\nBalloon page at http://www.toby-churchill.org.uk\r\n</p>\r\n<p>\r\nYaffs mailing list - to join go to http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs and enter your email address\r\n\r\n</p>\r\n<p>\r\nLinux MTD http://www.linux-mtd.infradead.org/\r\n</p>\r\n<p>\r\n$Id$\r\n</p>\r\n','Simple HOWTO for getting started with YAFFS and using it as a root filesystem. If you just want the <i>quick start</i> info - read this.','full_html'),('page',0,41,41,'und',0,'For  the purposes of this discussion, the term NAND will mean both AND and NAND type flash memories, both sharing similar properties from a system perspective.    <h3>A bit of history -</h3> History on my perspective, not the history of JFFS2.</p>   <p>Some years ago I wrote a flash file system for Trimble. Trimble patented this system. This FFS runs on NOR flash and uses a concepts very similar to JFFS to overcome problems associated with Flash Translation Layers, FTLs and flash. This FFS was rigorously tested for block failure, stress tested in various ways and deliberately crashed with an emulator at critical stages to attempt to damage data integrity. The FFS held up to all this.</p>   <p>Thus, when looking at JFFS2 I can immediately understand why certain things are being done and various benefits of this approach over FTLs.</p>   <p>At first I thought that using  an FTL would be better than JFFS2 for NAND because NAND has a different set of constraints. After a bit of analysis, I came around to thinking that using JFFS2 would still be better than an FTL mainly because JFFS2 dispenses with the need for a logical to physical translation layer.</p>  <p>&nbsp;</p> <h3>NOR and NAND</h3>   <p>The following table highlights some of the important properties of NOR and NAND flash. This table holds true for most devices, though there are some odd-ball devices out there.</p>  <p><br /> </p>   <table width=\"568\" cellspacing=\"0\" cellpadding=\"1\" border=\"1\">  	 	 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p><strong>NOR</strong></p> 		</td> 		<td width=\"281\"> 			<p><strong>NAND</strong></p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Cost $HIGHER</p> 		</td> 		<td width=\"281\"> 			<p>Cost LOWER</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Low density (approx 8MB max device size)</p> 		</td> 		<td width=\"281\"> 			<p>Higher density (approx 256MB max device size)</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Linear random access:</p> 			<ul><li><p>Like RAM</p> 				</li><li><p>Can be used for XIP</p> 			</li></ul> 		</td> 		<td width=\"281\"> 			<p>Sector read/write:</p> 			<ul><li><p>Almost like a disk.</p> 				</li><li><p>Can\'t be used for XIP</p> 			</li></ul> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Structured as erasable blocks of 8kB to 128kB typical.</p> 		</td> 		<td width=\"281\"> 			<p>Structured as erasable blocks of 32x512-byte pages. Each page 			has 16-bytes of extra management data.</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Endurance 100k to 1M erasures</p> 		</td> 		<td width=\"281\"> 			<p>Endurance 100k to 1M erasures</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Erase time 1second/erasable block</p> 		</td> 		<td width=\"281\"> 			<p>Erase time 2ms</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Designed as ROM replacements</p> 		</td> 		<td width=\"281\"> 			<p>Designed as mass storage replacements</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Byte-by-byte programming allowing single-bit modification. Any 			single bit can be modified from a 1 to a 0 by programming that 			byte. However, the only way to modify a 0 to a 1 is to erase the 			entire erasable block.</p> 		</td> 		<td width=\"281\"> 			<p>Page or partial-page programming. A page may be programmed a 			maximum number of times. After that number of times, the erasable 			block must be erased to allow further programming. Write 			operations can only modify 1s to 0s. Changing 0s to 1s requires an 			erasure.</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>Random access programming.  			</p> 		</td> 		<td width=\"281\"> 			<p>Pages must be written sequentially within a block.</p> 		</td> 	</tr> 	<tr valign=\"top\"> 		<td width=\"281\"> 			<p>No bad blocks when delivered, but the devices wear out. Thus 			file systems should be fault tolerant.</p> 		</td> 		<td width=\"281\"> 			<p>Bad blocks are expected when the devices are delivered. Further 			degradation is expected with use. Thus fault tolerance is an 			absolute necessity.  			</p> 		</td> 	</tr>  </table>  <p><br /> </p>   <p>It is important to note the various differences between NOR and NAND flash, because these are material in choosing the appropriate file systems for each. In particular:</p>  <ul> <li><p>The erasure times are very 	different. This impacts on the selection of appropriate garbage 	collection and erasure strategies. NOR\'s 1 second erasure time is 	significant and needs to be considered; NAND\'s 2msec erasure time is 	virtually insignificant.</p> </li> </ul>  <ul> <li><p>The programming access 	restrictions that apply to NAND do not apply to NOR.</p> 	</li><li><p>Errors are far more likely in NAND 	devices, therefore error detection and correction is highly 	desirable.</p> 	</li><li><p>NAND flash is arranged in 	pages/sectors of 512b and is inherently block structured.</p> </li> </ul>   <p>Both families of flash technology have significant usage restrictions which require special consideration when using the devices for file storage:</p>  <ul> <li><p>All flash memory blocks can only 	endure a limited number of erasure cycles. Some wear levelling 	strategy is required to prevent often-used sectors wearing out 	faster.</p> 	</li><li><p>Sectors,  are smaller than an 	erasable block. Thus, some garbage collection strategy is required 	to reclaim deleted/dirty sectors. To accomplish this, the &quot;good 	data&quot; must be copied off the selected block so that the whole 	block can be erased without losing data.</p> 	</li><li><p>If a part of a file needs to be 	overwritten, it is a limitation of flash memory that the new data 	cannot just overwrite the data at the same physical location. 	Instead the data must be written at a new location. Thus, some sort 	of logical to physical mapping layer (ie. FTL) or alternative data 	storage approach is required (eg. JFFS2). Such logical to physical 	decoupling is also required to perform garbage collection.</p> </li> </ul>  <p>&nbsp;</p> <h3>Flash file systems in general</h3>  <p>Flash file systems can essentially be implemented in two possible ways:</p>  <ul> <li><p>Custom-built file system. ie. the 	whole file system is designed so as to operate with flash memory. An 	example of this is JFFS2 or Microsoft FFS2.</p> 	</li><li><p>Use a standard file system with a 	custom block driver (ie Flash Translation Layer - FTL).</p> </li> </ul>   <p>Each of these approaches have their pros and cons. FTLs are particularly suited to situations where the file system is pre-ordained; a custom file system is able to be more &quot;flash friendly&quot;.</p>   <h3>An appraisal of the JFFS2 file system</h3>  <p>JFFS, and JFFS2, achieve the logical decoupling between logical file positions and physical memory by using journaling. For this to work, the entire file system must be designed to support journaling - as appropriate to flash memory. This is not excessively restrictive with non-removable media and embedded systems since there is no need to conform to a legacy file system layout.</p>   <p>JFFS2 is designed to support NOR flash, but is currently not suited to NAND flash since it does not handle bad blocks. If this deficiency was addressed would it be a better choice for NAND than an FTL? Probably not directly, some other tweaks would be needed.</p>   <p>Journaling is particularly useful: Garbage collection, bad block handling and the restrictions which prevent flash sectors being overwritten mean that data in flash file systems is forever being moved around. For FTLs this means storing logical to physical mappings. Journaling neatly sidesteps this overhead.</p>   <p>One of the most thorny issues with flash file systems is that there are many patents covering both FTL-like block drivers and various approaches to custom file systems.</p>  <p>These patents are particularly restrictive in FTL-like block drivers (especially the M-Systems patents). JFFS2 does not violate any patents I am aware of, but it probably comes quite close to some - particularly the Trimble one.  Thus it is highly beneficial to have a GPL\'ed system that can be extended.</p>   <h3>Work needed</h3>   <p>The following effort is required to make JFFS2 work with NAND:</p>  <ul> <li><p>New MTDs for NAND flash. A new 	interface is probably required for NAND since many of the functions 	for NOR make no sense on NAND.</p> </li> </ul>  <ul> <li><p>Bad block handling. This could be 	handled in a NOR-specific layer, although it should really be 	generically supported since NOR can fail too.</p> 	</li><li><p>ECC for data security. Code 	available from Samsung www. This can be handled as part of the write 	and read. When a journaling node is written, it should be verified. 	If the data cannot be retrieved, then a new node is created.  	</p> 	</li><li><p>Fixed size journaling nodes (since 	NAND is page oriented with limited writes per page). This might make 	compression challenging - maybe compression can\'t be used with NAND? 	Anyway, fixed-size journaling nodes probably reduce fragmentation 	too (since there\'s an integer number of these per erasable block).</p> </li> </ul>   <p>&nbsp;</p> <p>The following are possible improvements:</p>  <ul> <li><p>Tuning garbage collection/erasure 	strategies to suite NAND (eg. NAND erasure time is much faster). 	Using fixed-size nodes will probably strip out a chunk of code too.</p> 	</li><li><p>Attempting to use the spare 16 	bytes per page for journalling tags (if there\'s a useful amount of 	space left after ECC and bad block management).</p> </li> </ul>   <p>Thus, my preliminary suggestion would be to add a NAND sub-system to JFFS2. This subsystem would use the same journaling file system core. Fixing the size of journaling nodes to &quot;pages&quot; of 512 bytes quite likely simplifies the interfaces, node management and garbage collection.</p>   <p>Error handling would fit within the NAND subsystem. Since NOR fails too, bad block handling is really required for NOR too. Whether the same management is appropriate for both is TBD. ECC is only required for NAND.</p>   <p><br /> </p>  <p align=\"center\"><a name=\"_1065327724\" /><a name=\"_1065291949\" /> <img width=\"227\" height=\"190\" border=\"0\" align=\"bottom\" src=\"http://www.aleph1.co.uk/yaffs/sv9379380.gif\" /></p>    <h3> References</h3>  <p>Samsung and  Toshiba NAND part data sheets and www. Samsung in particular has useful applications notes and code.</p>  <p>JFFS2 presentation materials. http://sources.redhat.com/jffs2/</p>','Discussion of the characteristics of NAND and NOR flash and how those interact with JFFS2 to produce significant boot-time delays and high RAM consumption, especially with large flash chips.','obsolete_tinymce'),('page',0,41,565,'und',0,'<p>For the purposes of this discussion, the term NAND will mean both AND and NAND type flash memories, both sharing similar properties from a system perspective.</p>\r\n\r\n<h3>A bit of history -</h3>\r\n\r\n<p>History on my perspective, not the history of JFFS2.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>Some years ago I wrote a flash file system for Trimble. Trimble patented this system. This FFS runs on NOR flash and uses a concepts very similar to JFFS to overcome problems associated with Flash Translation Layers, FTLs and flash. This FFS was rigorously tested for block failure, stress tested in various ways and deliberately crashed with an emulator at critical stages to attempt to damage data integrity. The FFS held up to all this.</p>\r\n\r\n<p>Thus, when looking at JFFS2 I can immediately understand why certain things are being done and various benefits of this approach over FTLs.</p>\r\n\r\n<p>At first I thought that using an FTL would be better than JFFS2 for NAND because NAND has a different set of constraints. After a bit of analysis, I came around to thinking that using JFFS2 would still be better than an FTL mainly because JFFS2 dispenses with the need for a logical to physical translation layer.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>NOR and NAND</h3>\r\n\r\n<p>The following table highlights some of the important properties of NOR and NAND flash. This table holds true for most devices, though there are some odd-ball devices out there.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" width=\"568\">\r\n	<tbody>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p><strong>NOR</strong></p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p><strong>NAND</strong></p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Cost $HIGHER</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Cost LOWER</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Low density (approx 8MB max device size)</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Higher density (approx 256MB max device size)</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Linear random access:</p>\r\n\r\n			<ul>\r\n				<li>\r\n				<p>Like RAM</p>\r\n				</li>\r\n				<li>\r\n				<p>Can be used for XIP</p>\r\n				</li>\r\n			</ul>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Sector read/write:</p>\r\n\r\n			<ul>\r\n				<li>\r\n				<p>Almost like a disk.</p>\r\n				</li>\r\n				<li>\r\n				<p>Can\'t be used for XIP</p>\r\n				</li>\r\n			</ul>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Structured as erasable blocks of 8kB to 128kB typical.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Structured as erasable blocks of 32x512-byte pages. Each page has 16-bytes of extra management data.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Endurance 100k to 1M erasures</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Endurance 100k to 1M erasures</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Erase time 1second/erasable block</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Erase time 2ms</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Designed as ROM replacements</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Designed as mass storage replacements</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Byte-by-byte programming allowing single-bit modification. Any single bit can be modified from a 1 to a 0 by programming that byte. However, the only way to modify a 0 to a 1 is to erase the entire erasable block.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Page or partial-page programming. A page may be programmed a maximum number of times. After that number of times, the erasable block must be erased to allow further programming. Write operations can only modify 1s to 0s. Changing 0s to 1s requires an erasure.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Random access programming.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Pages must be written sequentially within a block.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>No bad blocks when delivered, but the devices wear out. Thus file systems should be fault tolerant.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Bad blocks are expected when the devices are delivered. Further degradation is expected with use. Thus fault tolerance is an absolute necessity.</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>It is important to note the various differences between NOR and NAND flash, because these are material in choosing the appropriate file systems for each. In particular:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>The erasure times are very different. This impacts on the selection of appropriate garbage collection and erasure strategies. NOR\'s 1 second erasure time is significant and needs to be considered; NAND\'s 2msec erasure time is virtually insignificant.</p>\r\n	</li>\r\n</ul>\r\n\r\n<ul>\r\n	<li>\r\n	<p>The programming access restrictions that apply to NAND do not apply to NOR.</p>\r\n	</li>\r\n	<li>\r\n	<p>Errors are far more likely in NAND devices, therefore error detection and correction is highly desirable.</p>\r\n	</li>\r\n	<li>\r\n	<p>NAND flash is arranged in pages/sectors of 512b and is inherently block structured.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Both families of flash technology have significant usage restrictions which require special consideration when using the devices for file storage:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>All flash memory blocks can only endure a limited number of erasure cycles. Some wear levelling strategy is required to prevent often-used sectors wearing out faster.</p>\r\n	</li>\r\n	<li>\r\n	<p>Sectors, are smaller than an erasable block. Thus, some garbage collection strategy is required to reclaim deleted/dirty sectors. To accomplish this, the \"good data\" must be copied off the selected block so that the whole block can be erased without losing data.</p>\r\n	</li>\r\n	<li>\r\n	<p>If a part of a file needs to be overwritten, it is a limitation of flash memory that the new data cannot just overwrite the data at the same physical location. Instead the data must be written at a new location. Thus, some sort of logical to physical mapping layer (ie. FTL) or alternative data storage approach is required (eg. JFFS2). Such logical to physical decoupling is also required to perform garbage collection.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>Flash file systems in general</h3>\r\n\r\n<p>Flash file systems can essentially be implemented in two possible ways:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Custom-built file system. ie. the whole file system is designed so as to operate with flash memory. An example of this is JFFS2 or Microsoft FFS2.</p>\r\n	</li>\r\n	<li>\r\n	<p>Use a standard file system with a custom block driver (ie Flash Translation Layer - FTL).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Each of these approaches have their pros and cons. FTLs are particularly suited to situations where the file system is pre-ordained; a custom file system is able to be more \"flash friendly\".</p>\r\n\r\n<h3>An appraisal of the JFFS2 file system</h3>\r\n\r\n<p>JFFS, and JFFS2, achieve the logical decoupling between logical file positions and physical memory by using journaling. For this to work, the entire file system must be designed to support journaling - as appropriate to flash memory. This is not excessively restrictive with non-removable media and embedded systems since there is no need to conform to a legacy file system layout.</p>\r\n\r\n<p>JFFS2 is designed to support NOR flash, but is currently not suited to NAND flash since it does not handle bad blocks. If this deficiency was addressed would it be a better choice for NAND than an FTL? Probably not directly, some other tweaks would be needed.</p>\r\n\r\n<p>Journaling is particularly useful: Garbage collection, bad block handling and the restrictions which prevent flash sectors being overwritten mean that data in flash file systems is forever being moved around. For FTLs this means storing logical to physical mappings. Journaling neatly sidesteps this overhead.</p>\r\n\r\n<p>One of the most thorny issues with flash file systems is that there are many patents covering both FTL-like block drivers and various approaches to custom file systems.</p>\r\n\r\n<p>These patents are particularly restrictive in FTL-like block drivers (especially the M-Systems patents). JFFS2 does not violate any patents I am aware of, but it probably comes quite close to some - particularly the Trimble one. Thus it is highly beneficial to have a GPL\'ed system that can be extended.</p>\r\n\r\n<h3>Work needed</h3>\r\n\r\n<p>The following effort is required to make JFFS2 work with NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>New MTDs for NAND flash. A new interface is probably required for NAND since many of the functions for NOR make no sense on NAND.</p>\r\n	</li>\r\n</ul>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Bad block handling. This could be handled in a NOR-specific layer, although it should really be generically supported since NOR can fail too.</p>\r\n	</li>\r\n	<li>\r\n	<p>ECC for data security. Code available from Samsung www. This can be handled as part of the write and read. When a journaling node is written, it should be verified. If the data cannot be retrieved, then a new node is created.</p>\r\n	</li>\r\n	<li>\r\n	<p>Fixed size journaling nodes (since NAND is page oriented with limited writes per page). This might make compression challenging - maybe compression can\'t be used with NAND? Anyway, fixed-size journaling nodes probably reduce fragmentation too (since there\'s an integer number of these per erasable block).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>The following are possible improvements:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Tuning garbage collection/erasure strategies to suite NAND (eg. NAND erasure time is much faster). Using fixed-size nodes will probably strip out a chunk of code too.</p>\r\n	</li>\r\n	<li>\r\n	<p>Attempting to use the spare 16 bytes per page for journalling tags (if there\'s a useful amount of space left after ECC and bad block management).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Thus, my preliminary suggestion would be to add a NAND sub-system to JFFS2. This subsystem would use the same journaling file system core. Fixing the size of journaling nodes to \"pages\" of 512 bytes quite likely simplifies the interfaces, node management and garbage collection.</p>\r\n\r\n<p>Error handling would fit within the NAND subsystem. Since NOR fails too, bad block handling is really required for NOR too. Whether the same management is appropriate for both is TBD. ECC is only required for NAND.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p align=\"center\"><a name=\"_1065327724\"></a><a name=\"_1065291949\"> <img align=\"bottom\" border=\"0\" height=\"190\" src=\"/sites/yaffs.net/files/sv9379380.gif\" width=\"227\" /></a></p>\r\n\r\n<p><a name=\"_1065291949\"> </a></p>\r\n\r\n<h3><a name=\"_1065291949\">References</a></h3>\r\n\r\n<p><a name=\"_1065291949\">Samsung and Toshiba NAND part data sheets and www. Samsung in particular has useful applications notes and code.</a></p>\r\n\r\n<p><a name=\"_1065291949\">JFFS2 presentation materials. http://sources.redhat.com/jffs2/</a></p>\r\n','Discussion of the characteristics of NAND and NOR flash and how those interact with JFFS2 to produce significant boot-time delays and high RAM consumption, especially with large flash chips.','full_html'),('page',0,41,566,'und',0,'<p>For the purposes of this discussion, the term NAND will mean both AND and NAND type flash memories, both sharing similar properties from a system perspective.</p>\r\n\r\n<h3>A bit of history -</h3>\r\n\r\n<p>History on my perspective, not the history of JFFS2.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>Some years ago I wrote a flash file system for Trimble. Trimble patented this system. This FFS runs on NOR flash and uses a concepts very similar to JFFS to overcome problems associated with Flash Translation Layers, FTLs and flash. This FFS was rigorously tested for block failure, stress tested in various ways and deliberately crashed with an emulator at critical stages to attempt to damage data integrity. The FFS held up to all this.</p>\r\n\r\n<p>Thus, when looking at JFFS2 I can immediately understand why certain things are being done and various benefits of this approach over FTLs.</p>\r\n\r\n<p>At first I thought that using an FTL would be better than JFFS2 for NAND because NAND has a different set of constraints. After a bit of analysis, I came around to thinking that using JFFS2 would still be better than an FTL mainly because JFFS2 dispenses with the need for a logical to physical translation layer.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>NOR and NAND</h3>\r\n\r\n<p>The following table highlights some of the important properties of NOR and NAND flash. This table holds true for most devices, though there are some odd-ball devices out there.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" width=\"568\">\r\n	<tbody>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p><strong>NOR</strong></p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p><strong>NAND</strong></p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Cost $HIGHER</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Cost LOWER</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Low density (approx 8MB max device size)</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Higher density (approx 256MB max device size)</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Linear random access:</p>\r\n\r\n			<ul>\r\n				<li>\r\n				<p>Like RAM</p>\r\n				</li>\r\n				<li>\r\n				<p>Can be used for XIP</p>\r\n				</li>\r\n			</ul>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Sector read/write:</p>\r\n\r\n			<ul>\r\n				<li>\r\n				<p>Almost like a disk.</p>\r\n				</li>\r\n				<li>\r\n				<p>Can\'t be used for XIP</p>\r\n				</li>\r\n			</ul>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Structured as erasable blocks of 8kB to 128kB typical.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Structured as erasable blocks of 32x512-byte pages. Each page has 16-bytes of extra management data.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Endurance 100k to 1M erasures</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Endurance 100k to 1M erasures</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Erase time 1second/erasable block</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Erase time 2ms</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Designed as ROM replacements</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Designed as mass storage replacements</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Byte-by-byte programming allowing single-bit modification. Any single bit can be modified from a 1 to a 0 by programming that byte. However, the only way to modify a 0 to a 1 is to erase the entire erasable block.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Page or partial-page programming. A page may be programmed a maximum number of times. After that number of times, the erasable block must be erased to allow further programming. Write operations can only modify 1s to 0s. Changing 0s to 1s requires an erasure.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Random access programming.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Pages must be written sequentially within a block.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>No bad blocks when delivered, but the devices wear out. Thus file systems should be fault tolerant.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Bad blocks are expected when the devices are delivered. Further degradation is expected with use. Thus fault tolerance is an absolute necessity.</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>It is important to note the various differences between NOR and NAND flash, because these are material in choosing the appropriate file systems for each. In particular:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>The erasure times are very different. This impacts on the selection of appropriate garbage collection and erasure strategies. NOR\'s 1 second erasure time is significant and needs to be considered; NAND\'s 2msec erasure time is virtually insignificant.</p>\r\n	</li>\r\n</ul>\r\n\r\n<ul>\r\n	<li>\r\n	<p>The programming access restrictions that apply to NAND do not apply to NOR.</p>\r\n	</li>\r\n	<li>\r\n	<p>Errors are far more likely in NAND devices, therefore error detection and correction is highly desirable.</p>\r\n	</li>\r\n	<li>\r\n	<p>NAND flash is arranged in pages/sectors of 512b and is inherently block structured.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Both families of flash technology have significant usage restrictions which require special consideration when using the devices for file storage:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>All flash memory blocks can only endure a limited number of erasure cycles. Some wear levelling strategy is required to prevent often-used sectors wearing out faster.</p>\r\n	</li>\r\n	<li>\r\n	<p>Sectors, are smaller than an erasable block. Thus, some garbage collection strategy is required to reclaim deleted/dirty sectors. To accomplish this, the \"good data\" must be copied off the selected block so that the whole block can be erased without losing data.</p>\r\n	</li>\r\n	<li>\r\n	<p>If a part of a file needs to be overwritten, it is a limitation of flash memory that the new data cannot just overwrite the data at the same physical location. Instead the data must be written at a new location. Thus, some sort of logical to physical mapping layer (ie. FTL) or alternative data storage approach is required (eg. JFFS2). Such logical to physical decoupling is also required to perform garbage collection.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>Flash file systems in general</h3>\r\n\r\n<p>Flash file systems can essentially be implemented in two possible ways:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Custom-built file system. ie. the whole file system is designed so as to operate with flash memory. An example of this is JFFS2 or Microsoft FFS2.</p>\r\n	</li>\r\n	<li>\r\n	<p>Use a standard file system with a custom block driver (ie Flash Translation Layer - FTL).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Each of these approaches have their pros and cons. FTLs are particularly suited to situations where the file system is pre-ordained; a custom file system is able to be more \"flash friendly\".</p>\r\n\r\n<h3>An appraisal of the JFFS2 file system</h3>\r\n\r\n<p>JFFS, and JFFS2, achieve the logical decoupling between logical file positions and physical memory by using journaling. For this to work, the entire file system must be designed to support journaling - as appropriate to flash memory. This is not excessively restrictive with non-removable media and embedded systems since there is no need to conform to a legacy file system layout.</p>\r\n\r\n<p>JFFS2 is designed to support NOR flash, but is currently not suited to NAND flash since it does not handle bad blocks. If this deficiency was addressed would it be a better choice for NAND than an FTL? Probably not directly, some other tweaks would be needed.</p>\r\n\r\n<p>Journaling is particularly useful: Garbage collection, bad block handling and the restrictions which prevent flash sectors being overwritten mean that data in flash file systems is forever being moved around. For FTLs this means storing logical to physical mappings. Journaling neatly sidesteps this overhead.</p>\r\n\r\n<p>One of the most thorny issues with flash file systems is that there are many patents covering both FTL-like block drivers and various approaches to custom file systems.</p>\r\n\r\n<p>These patents are particularly restrictive in FTL-like block drivers (especially the M-Systems patents). JFFS2 does not violate any patents I am aware of, but it probably comes quite close to some - particularly the Trimble one. Thus it is highly beneficial to have a GPL\'ed system that can be extended.</p>\r\n\r\n<h3>Work needed</h3>\r\n\r\n<p>The following effort is required to make JFFS2 work with NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>New MTDs for NAND flash. A new interface is probably required for NAND since many of the functions for NOR make no sense on NAND.</p>\r\n	</li>\r\n</ul>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Bad block handling. This could be handled in a NOR-specific layer, although it should really be generically supported since NOR can fail too.</p>\r\n	</li>\r\n	<li>\r\n	<p>ECC for data security. Code available from Samsung www. This can be handled as part of the write and read. When a journaling node is written, it should be verified. If the data cannot be retrieved, then a new node is created.</p>\r\n	</li>\r\n	<li>\r\n	<p>Fixed size journaling nodes (since NAND is page oriented with limited writes per page). This might make compression challenging - maybe compression can\'t be used with NAND? Anyway, fixed-size journaling nodes probably reduce fragmentation too (since there\'s an integer number of these per erasable block).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>The following are possible improvements:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Tuning garbage collection/erasure strategies to suite NAND (eg. NAND erasure time is much faster). Using fixed-size nodes will probably strip out a chunk of code too.</p>\r\n	</li>\r\n	<li>\r\n	<p>Attempting to use the spare 16 bytes per page for journalling tags (if there\'s a useful amount of space left after ECC and bad block management).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Thus, my preliminary suggestion would be to add a NAND sub-system to JFFS2. This subsystem would use the same journaling file system core. Fixing the size of journaling nodes to \"pages\" of 512 bytes quite likely simplifies the interfaces, node management and garbage collection.</p>\r\n\r\n<p>Error handling would fit within the NAND subsystem. Since NOR fails too, bad block handling is really required for NOR too. Whether the same management is appropriate for both is TBD. ECC is only required for NAND.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p align=\"center\"><a name=\"_1065327724\"></a><a name=\"_1065291949\"> <img align=\"bottom\" border=\"0\" height=\"190\" src=\"/sites/yaffs.net/files/sv9379380.gif\" width=\"227\" /></a></p>\r\n\r\n<p><a name=\"_1065291949\"> </a></p>\r\n\r\n<h3><a name=\"_1065291949\">References</a></h3>\r\n\r\n<p><a name=\"_1065291949\">Samsung and Toshiba NAND part data sheets and www. Samsung in particular has useful applications notes and code.</a></p>\r\n\r\n<p><a name=\"_1065291949\">JFFS2 presentation materials. http://sources.redhat.com/jffs2/</a></p>\r\n','Discussion of the characteristics of NAND and NOR flash and how those interact with JFFS2 to produce significant boot-time delays and high RAM consumption, especially with large flash chips.','full_html'),('page',0,41,567,'und',0,'<p>For the purposes of this discussion, the term NAND will mean both AND and NAND type flash memories, both sharing similar properties from a system perspective.</p>\r\n\r\n<h3>A bit of history -</h3>\r\n\r\n<p>History on my perspective, not the history of JFFS2.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>Some years ago I wrote a flash file system for Trimble. Trimble patented this system. This FFS runs on NOR flash and uses a concepts very similar to JFFS to overcome problems associated with Flash Translation Layers, FTLs and flash. This FFS was rigorously tested for block failure, stress tested in various ways and deliberately crashed with an emulator at critical stages to attempt to damage data integrity. The FFS held up to all this.</p>\r\n\r\n<p>Thus, when looking at JFFS2 I can immediately understand why certain things are being done and various benefits of this approach over FTLs.</p>\r\n\r\n<p>At first I thought that using an FTL would be better than JFFS2 for NAND because NAND has a different set of constraints. After a bit of analysis, I came around to thinking that using JFFS2 would still be better than an FTL mainly because JFFS2 dispenses with the need for a logical to physical translation layer.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>NOR and NAND</h3>\r\n\r\n<p>The following table highlights some of the important properties of NOR and NAND flash. This table holds true for most devices, though there are some odd-ball devices out there.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" width=\"568\">\r\n	<tbody>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p><strong>NOR</strong></p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p><strong>NAND</strong></p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Cost $HIGHER</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Cost LOWER</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Low density (approx 8MB max device size)</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Higher density (approx 256MB max device size)</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Linear random access:</p>\r\n\r\n			<ul>\r\n				<li>\r\n				<p>Like RAM</p>\r\n				</li>\r\n				<li>\r\n				<p>Can be used for XIP</p>\r\n				</li>\r\n			</ul>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Sector read/write:</p>\r\n\r\n			<ul>\r\n				<li>\r\n				<p>Almost like a disk.</p>\r\n				</li>\r\n				<li>\r\n				<p>Can\'t be used for XIP</p>\r\n				</li>\r\n			</ul>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Structured as erasable blocks of 8kB to 128kB typical.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Structured as erasable blocks of 32x512-byte pages. Each page has 16-bytes of extra management data.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Endurance 100k to 1M erasures</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Endurance 100k to 1M erasures</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Erase time 1second/erasable block</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Erase time 2ms</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Designed as ROM replacements</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Designed as mass storage replacements</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Byte-by-byte programming allowing single-bit modification. Any single bit can be modified from a 1 to a 0 by programming that byte. However, the only way to modify a 0 to a 1 is to erase the entire erasable block.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Page or partial-page programming. A page may be programmed a maximum number of times. After that number of times, the erasable block must be erased to allow further programming. Write operations can only modify 1s to 0s. Changing 0s to 1s requires an erasure.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>Random access programming.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Pages must be written sequentially within a block.</p>\r\n			</td>\r\n		</tr>\r\n		<tr valign=\"top\">\r\n			<td width=\"281\">\r\n			<p>No bad blocks when delivered, but the devices wear out. Thus file systems should be fault tolerant.</p>\r\n			</td>\r\n			<td width=\"281\">\r\n			<p>Bad blocks are expected when the devices are delivered. Further degradation is expected with use. Thus fault tolerance is an absolute necessity.</p>\r\n			</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>It is important to note the various differences between NOR and NAND flash, because these are material in choosing the appropriate file systems for each. In particular:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>The erasure times are very different. This impacts on the selection of appropriate garbage collection and erasure strategies. NOR\'s 1 second erasure time is significant and needs to be considered; NAND\'s 2msec erasure time is virtually insignificant.</p>\r\n	</li>\r\n</ul>\r\n\r\n<ul>\r\n	<li>\r\n	<p>The programming access restrictions that apply to NAND do not apply to NOR.</p>\r\n	</li>\r\n	<li>\r\n	<p>Errors are far more likely in NAND devices, therefore error detection and correction is highly desirable.</p>\r\n	</li>\r\n	<li>\r\n	<p>NAND flash is arranged in pages/sectors of 512b and is inherently block structured.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Both families of flash technology have significant usage restrictions which require special consideration when using the devices for file storage:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>All flash memory blocks can only endure a limited number of erasure cycles. Some wear levelling strategy is required to prevent often-used sectors wearing out faster.</p>\r\n	</li>\r\n	<li>\r\n	<p>Sectors, are smaller than an erasable block. Thus, some garbage collection strategy is required to reclaim deleted/dirty sectors. To accomplish this, the \"good data\" must be copied off the selected block so that the whole block can be erased without losing data.</p>\r\n	</li>\r\n	<li>\r\n	<p>If a part of a file needs to be overwritten, it is a limitation of flash memory that the new data cannot just overwrite the data at the same physical location. Instead the data must be written at a new location. Thus, some sort of logical to physical mapping layer (ie. FTL) or alternative data storage approach is required (eg. JFFS2). Such logical to physical decoupling is also required to perform garbage collection.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>Flash file systems in general</h3>\r\n\r\n<p>Flash file systems can essentially be implemented in two possible ways:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Custom-built file system. ie. the whole file system is designed so as to operate with flash memory. An example of this is JFFS2 or Microsoft FFS2.</p>\r\n	</li>\r\n	<li>\r\n	<p>Use a standard file system with a custom block driver (ie Flash Translation Layer - FTL).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Each of these approaches have their pros and cons. FTLs are particularly suited to situations where the file system is pre-ordained; a custom file system is able to be more \"flash friendly\".</p>\r\n\r\n<h3>An appraisal of the JFFS2 file system</h3>\r\n\r\n<p>JFFS, and JFFS2, achieve the logical decoupling between logical file positions and physical memory by using journaling. For this to work, the entire file system must be designed to support journaling - as appropriate to flash memory. This is not excessively restrictive with non-removable media and embedded systems since there is no need to conform to a legacy file system layout.</p>\r\n\r\n<p>JFFS2 is designed to support NOR flash, but is currently not suited to NAND flash since it does not handle bad blocks. If this deficiency was addressed would it be a better choice for NAND than an FTL? Probably not directly, some other tweaks would be needed.</p>\r\n\r\n<p>Journaling is particularly useful: Garbage collection, bad block handling and the restrictions which prevent flash sectors being overwritten mean that data in flash file systems is forever being moved around. For FTLs this means storing logical to physical mappings. Journaling neatly sidesteps this overhead.</p>\r\n\r\n<p>One of the most thorny issues with flash file systems is that there are many patents covering both FTL-like block drivers and various approaches to custom file systems.</p>\r\n\r\n<p>These patents are particularly restrictive in FTL-like block drivers (especially the M-Systems patents). JFFS2 does not violate any patents I am aware of, but it probably comes quite close to some - particularly the Trimble one. Thus it is highly beneficial to have a GPL\'ed system that can be extended.</p>\r\n\r\n<h3>Work needed</h3>\r\n\r\n<p>The following effort is required to make JFFS2 work with NAND:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>New MTDs for NAND flash. A new interface is probably required for NAND since many of the functions for NOR make no sense on NAND.</p>\r\n	</li>\r\n</ul>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Bad block handling. This could be handled in a NOR-specific layer, although it should really be generically supported since NOR can fail too.</p>\r\n	</li>\r\n	<li>\r\n	<p>ECC for data security. Code available from Samsung www. This can be handled as part of the write and read. When a journaling node is written, it should be verified. If the data cannot be retrieved, then a new node is created.</p>\r\n	</li>\r\n	<li>\r\n	<p>Fixed size journaling nodes (since NAND is page oriented with limited writes per page). This might make compression challenging - maybe compression can\'t be used with NAND? Anyway, fixed-size journaling nodes probably reduce fragmentation too (since there\'s an integer number of these per erasable block).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>The following are possible improvements:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Tuning garbage collection/erasure strategies to suite NAND (eg. NAND erasure time is much faster). Using fixed-size nodes will probably strip out a chunk of code too.</p>\r\n	</li>\r\n	<li>\r\n	<p>Attempting to use the spare 16 bytes per page for journalling tags (if there\'s a useful amount of space left after ECC and bad block management).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Thus, my preliminary suggestion would be to add a NAND sub-system to JFFS2. This subsystem would use the same journaling file system core. Fixing the size of journaling nodes to \"pages\" of 512 bytes quite likely simplifies the interfaces, node management and garbage collection.</p>\r\n\r\n<p>Error handling would fit within the NAND subsystem. Since NOR fails too, bad block handling is really required for NOR too. Whether the same management is appropriate for both is TBD. ECC is only required for NAND.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p align=\"center\"><a name=\"_1065327724\"></a><a name=\"_1065291949\"> <img align=\"bottom\" border=\"0\" height=\"190\" src=\"/sites/yaffs.net/files/sv9379380.gif\" width=\"227\" /></a></p>\r\n\r\n<p><a name=\"_1065291949\"> </a></p>\r\n\r\n<h3><a name=\"_1065291949\">References</a></h3>\r\n\r\n<p><a name=\"_1065291949\">Samsung and Toshiba NAND part data sheets and www. Samsung in particular has useful applications notes and code.</a></p>\r\n\r\n<p><a name=\"_1065291949\">JFFS2 presentation materials. http://sources.redhat.com/jffs2/</a></p>\r\n','Discussion of the characteristics of NAND and NOR flash and how those interact with JFFS2 to produce significant boot-time delays and high RAM consumption, especially with large flash chips.','full_html'),('page',0,42,42,'und',0,'<h3>Current state of NAND MTD</h3><p>The current NAND MTD supports basic read/write functions. The code is hard-wired to support the NAND devices on a SPIA board. The ECC code supports 256 byte sectors.</p><p>There are 3 files:</p><p>nand.c: nand support algorithms. Unfortunately there is no hardware abstraction (ie. the hardware is assumed to be the SPIA board). but this is relatively easy to add.</p><p>spia.c: this initialises the spia hardware to set up the addresses for the hardware access.</p><p>ecc.c: ECC for 256 byte pages.</p><p>What needs to be done at this level:</p><ul><li><p>Hardware abstraction of nand.c. This allows this code to be used with different hardware configurations.</p></li><li><p>The larger memory sizes use 512 byte pages. The memory sizes supported by 256-byte pages are obsolete. 512-byte pages are treated as two sub-pages of 256 bytes each. The Samsung code is calculation based (ie. maybe slow). The Toshiba code is table based and probably faster. Check if they are equivalent.</p></li><li><p>Write a software emulation for a NAND device. The purpose of the software emulator is:</p><ul><li><p>Allow debugging without the need for hardware.</p></li><li><p>NAND file systems need to be fault tolerant. The hardware can\'t be forced to fail to test out bad block detection/handling etc. A software emulator can be forced to fail.</p></li></ul></li></ul><p>&nbsp;</p><h3>Overall flash system diagram<img align=\"bottom\" border=\"0\" height=\"402\" src=\"http://www.aleph1.co.uk/yaffs/sv16516600.gif\" width=\"399\"></h3><p>A diagrammatic representation of support for SmartMedia, NAND and NOR as well as both FAT16 and JFFS2 might look like the above.</p><p>The NAND flash sub-system uses common layers for:</p><ul><li><p>hardware access</p></li><li><p>ECC, bad block handling and low-level formatting. (based on Smart Media low-level specs). By using the same low level formatting and ECC as much as possible we gain some benefit in testing, reuse etc. The low-level formatting would differ in that fields used to store the LBA and reserved fields might be used for something else (??journaling tags??)</p></li></ul><h3>Concerns with using JFFS2 on NAND</h3><p>There are some reasons why JFFS and NAND might not work together that well.</p><p>Two particular concerns re booting</p><ul><li><p>NAND devices are typically much larger than NOR (eg. 128MB is currently a large NAND chip while 16MB would be considered a large NOR chip), thus the data structures associated with flash management are likely to be much larger. Also, JFFS2 scans the media on boot to build data structures representing the nodes in the system. This increases the boot time.</p></li><li><p>NAND is not random access but must be read serially. This means that the scanning routine can\'t just merrily skip through the flash, instead the whole flash must be read and ECC\'d first. This slows scanning and hence booting.</p></li></ul><p>Thus booting a 128MB NAND-based JFFS2 is likely to look something like this:</p><ul><li><p>Read and ECC every last byte on the device even if we only need a few bytes per page for journaling headers and digest the contents. At say 5MB/second this will take ~25 seconds.</p></li><li><p>Each node requires a 16-byte structure (struct jffs2_raw_node_ref). If nodes were 512-bytes then that\'s 4MB of RAM!</p></li></ul><p>These are probably unacceptable for the product being used. We therefore need to run something better than this.</p><p>Two approaches spring to mind:</p><ul><li><p>Just run FAT16. ie. Just treat all NAND as SmartMedia. Benefits: one code base. Down-side: reliability.</p></li><li><p>I\'m reluctant to store critical files in a FAT16 file system because these can be so unreliable. I\'m convinced that a journaling file system is superior. Maybe what we need is a light weight journaling file system (using common code with JFFS) modified in such a way as sidestep some of the nasty issues raised above.</p></li></ul><p>&nbsp;</p><h3>What I\'m working towards</h3><p>Right now I\'m investigating the idea of trying to do something more appropriate. My current avenue of exploration is to use a journaling approach as follows:</p><ul><li><p>The journaling records are stored in fixed-size 512-byte pages.</p></li><li><p>The journaling tags are stored in the 16-byte-per-page \"management space\", semi-consistent with SmartMedia, using the 8 bytes of reserved space and LBA space to store journaling tags. ie something like:</p></li><li><p>20 bits of page id within inode</p></li><li><p>20 bits of inode id</p></li><li><p>9 bits length (bytes used in this page).</p></li><li><p>7 bits flags etc.</p></li><li><p>8 bits of hamming code on this area.</p></li></ul><p>Each page id identifies where the page fits into the file. When a page is replaced (ie file data is overwritten) a new page with the same page id is written and the old one is wiped out. During garbage collection, the pages containing valid data are copied and the wiped out data is discarded.</p><p>The benefits of this approach are:</p><ul><li><p>NAND-friendly since it works within the write limitations of NAND.</p></li><li><p>Less stuff to read to reconstruct file structures (only read management data).</p></li></ul><p>Down sides:</p><ul><li><p>No compression. But is that an issue considering the target data is already compressed and NAND is far less precious than NOR (thanks to higher densities and lower price).</p></li></ul><p>Still need to see if a new data structure is going to reduce the overhead of jffs2_raw_node_ref somewhat.</p>','<p>Details of Dec 2001 state of nand driver, and overview of how drivers fit together for use with different hardware and filesystems. Not really intended for public consumption, but a useful backgrounder and explanation of the evolution of YAFFS.</p>','filtered_html'),('page',0,42,542,'und',0,'<h3>Current state of NAND MTD</h3>\r\n\r\n<p>The current NAND MTD supports basic read/write functions. The code is hard-wired to support the NAND devices on a SPIA board. The ECC code supports 256 byte sectors.</p>\r\n\r\n<p>There are 3 files:</p>\r\n\r\n<p>nand.c: nand support algorithms. Unfortunately there is no hardware abstraction (ie. the hardware is assumed to be the SPIA board). but this is relatively easy to add.</p>\r\n\r\n<p>spia.c: this initialises the spia hardware to set up the addresses for the hardware access.</p>\r\n\r\n<p>ecc.c: ECC for 256 byte pages.</p>\r\n\r\n<p>What needs to be done at this level:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Hardware abstraction of nand.c. This allows this code to be used with different hardware configurations.</p>\r\n	</li>\r\n	<li>\r\n	<p>The larger memory sizes use 512 byte pages. The memory sizes supported by 256-byte pages are obsolete. 512-byte pages are treated as two sub-pages of 256 bytes each. The Samsung code is calculation based (ie. maybe slow). The Toshiba code is table based and probably faster. Check if they are equivalent.</p>\r\n	</li>\r\n	<li>\r\n	<p>Write a software emulation for a NAND device. The purpose of the software emulator is:</p>\r\n\r\n	<ul>\r\n		<li>\r\n		<p>Allow debugging without the need for hardware.</p>\r\n		</li>\r\n		<li>\r\n		<p>NAND file systems need to be fault tolerant. The hardware can\'t be forced to fail to test out bad block detection/handling etc. A software emulator can be forced to fail.</p>\r\n		</li>\r\n	</ul>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>Overall flash system diagram<img alt=\"\" height=\"402\" src=\"/sites/yaffs.net/sv16516600.gif\" width=\"399\" /></h3>\r\n\r\n<p>A diagrammatic representation of support for SmartMedia, NAND and NOR as well as both FAT16 and JFFS2 might look like the above.</p>\r\n\r\n<p>The NAND flash sub-system uses common layers for:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>hardware access</p>\r\n	</li>\r\n	<li>\r\n	<p>ECC, bad block handling and low-level formatting. (based on Smart Media low-level specs). By using the same low level formatting and ECC as much as possible we gain some benefit in testing, reuse etc. The low-level formatting would differ in that fields used to store the LBA and reserved fields might be used for something else (??journaling tags??)</p>\r\n	</li>\r\n</ul>\r\n\r\n<h3>Concerns with using JFFS2 on NAND</h3>\r\n\r\n<p>There are some reasons why JFFS and NAND might not work together that well.</p>\r\n\r\n<p>Two particular concerns re booting</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND devices are typically much larger than NOR (eg. 128MB is currently a large NAND chip while 16MB would be considered a large NOR chip), thus the data structures associated with flash management are likely to be much larger. Also, JFFS2 scans the media on boot to build data structures representing the nodes in the system. This increases the boot time.</p>\r\n	</li>\r\n	<li>\r\n	<p>NAND is not random access but must be read serially. This means that the scanning routine can\'t just merrily skip through the flash, instead the whole flash must be read and ECC\'d first. This slows scanning and hence booting.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Thus booting a 128MB NAND-based JFFS2 is likely to look something like this:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Read and ECC every last byte on the device even if we only need a few bytes per page for journaling headers and digest the contents. At say 5MB/second this will take ~25 seconds.</p>\r\n	</li>\r\n	<li>\r\n	<p>Each node requires a 16-byte structure (struct jffs2_raw_node_ref). If nodes were 512-bytes then that\'s 4MB of RAM!</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>These are probably unacceptable for the product being used. We therefore need to run something better than this.</p>\r\n\r\n<p>Two approaches spring to mind:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>Just run FAT16. ie. Just treat all NAND as SmartMedia. Benefits: one code base. Down-side: reliability.</p>\r\n	</li>\r\n	<li>\r\n	<p>I\'m reluctant to store critical files in a FAT16 file system because these can be so unreliable. I\'m convinced that a journaling file system is superior. Maybe what we need is a light weight journaling file system (using common code with JFFS) modified in such a way as sidestep some of the nasty issues raised above.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>What I\'m working towards</h3>\r\n\r\n<p>Right now I\'m investigating the idea of trying to do something more appropriate. My current avenue of exploration is to use a journaling approach as follows:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>The journaling records are stored in fixed-size 512-byte pages.</p>\r\n	</li>\r\n	<li>\r\n	<p>The journaling tags are stored in the 16-byte-per-page \"management space\", semi-consistent with SmartMedia, using the 8 bytes of reserved space and LBA space to store journaling tags. ie something like:</p>\r\n	</li>\r\n	<li>\r\n	<p>20 bits of page id within inode</p>\r\n	</li>\r\n	<li>\r\n	<p>20 bits of inode id</p>\r\n	</li>\r\n	<li>\r\n	<p>9 bits length (bytes used in this page).</p>\r\n	</li>\r\n	<li>\r\n	<p>7 bits flags etc.</p>\r\n	</li>\r\n	<li>\r\n	<p>8 bits of hamming code on this area.</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Each page id identifies where the page fits into the file. When a page is replaced (ie file data is overwritten) a new page with the same page id is written and the old one is wiped out. During garbage collection, the pages containing valid data are copied and the wiped out data is discarded.</p>\r\n\r\n<p>The benefits of this approach are:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>NAND-friendly since it works within the write limitations of NAND.</p>\r\n	</li>\r\n	<li>\r\n	<p>Less stuff to read to reconstruct file structures (only read management data).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Down sides:</p>\r\n\r\n<ul>\r\n	<li>\r\n	<p>No compression. But is that an issue considering the target data is already compressed and NAND is far less precious than NOR (thanks to higher densities and lower price).</p>\r\n	</li>\r\n</ul>\r\n\r\n<p>Still need to see if a new data structure is going to reduce the overhead of jffs2_raw_node_ref somewhat.</p>\r\n','<p>Details of Dec 2001 state of nand driver, and overview of how drivers fit together for use with different hardware and filesystems. Not really intended for public consumption, but a useful backgrounder and explanation of the evolution of YAFFS.</p>','filtered_html'),