CREATE TABLE `migrate_message_d6_node__yaffs_user_logo` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node__yaffs_user_logo`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__article`
--

CREATE TABLE `migrate_message_d6_node_revision__article` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__article`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__book`
--

CREATE TABLE `migrate_message_d6_node_revision__book` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__book`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__download`
--

CREATE TABLE `migrate_message_d6_node_revision__download` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__download`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__faq_item`
--

CREATE TABLE `migrate_message_d6_node_revision__faq_item` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__faq_item`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__help_video`
--

CREATE TABLE `migrate_message_d6_node_revision__help_video` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__help_video`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__image`
--

CREATE TABLE `migrate_message_d6_node_revision__image` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__image`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__page`
--

CREATE TABLE `migrate_message_d6_node_revision__page` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__page`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__paper`
--

CREATE TABLE `migrate_message_d6_node_revision__paper` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__paper`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__what_is_special_about_yaffs`
--

CREATE TABLE `migrate_message_d6_node_revision__what_is_special_about_yaffs` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__what_is_special_about_yaffs`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_revision__yaffs_user_logo`
--

CREATE TABLE `migrate_message_d6_node_revision__yaffs_user_logo` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_revision__yaffs_user_logo`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_setting_promote`
--

CREATE TABLE `migrate_message_d6_node_setting_promote` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_setting_promote`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_setting_status`
--

CREATE TABLE `migrate_message_d6_node_setting_status` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_setting_status`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_setting_sticky`
--

CREATE TABLE `migrate_message_d6_node_setting_sticky` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_setting_sticky`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_settings`
--

CREATE TABLE `migrate_message_d6_node_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_node_type`
--

CREATE TABLE `migrate_message_d6_node_type` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_node_type`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_path_redirect`
--

CREATE TABLE `migrate_message_d6_path_redirect` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_path_redirect`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_profile_values`
--

CREATE TABLE `migrate_message_d6_profile_values` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_profile_values`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_search_settings`
--

CREATE TABLE `migrate_message_d6_search_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_search_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_system_cron`
--

CREATE TABLE `migrate_message_d6_system_cron` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_system_cron`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_system_date`
--

CREATE TABLE `migrate_message_d6_system_date` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_system_date`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_system_file`
--

CREATE TABLE `migrate_message_d6_system_file` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_system_file`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_system_performance`
--

CREATE TABLE `migrate_message_d6_system_performance` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_system_performance`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_term_node__10`
--

CREATE TABLE `migrate_message_d6_term_node__10` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_term_node__10`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_term_node__11`
--

CREATE TABLE `migrate_message_d6_term_node__11` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_term_node__11`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_term_node__8`
--

CREATE TABLE `migrate_message_d6_term_node__8` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_term_node__8`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_upload`
--

CREATE TABLE `migrate_message_d6_upload` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_upload`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_upload_entity_display`
--

CREATE TABLE `migrate_message_d6_upload_entity_display` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_upload_entity_display`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_upload_entity_form_display`
--

CREATE TABLE `migrate_message_d6_upload_entity_form_display` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_upload_entity_form_display`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_upload_field`
--

CREATE TABLE `migrate_message_d6_upload_field` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_upload_field`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_upload_field_instance`
--

CREATE TABLE `migrate_message_d6_upload_field_instance` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_upload_field_instance`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_url_alias`
--

CREATE TABLE `migrate_message_d6_url_alias` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_url_alias`
--

set autocommit=0;
INSERT INTO `migrate_message_d6_url_alias` VALUES (1,'45c711e81f606ec93c9a4fc7aff9e9b08e89a75033d354df49b2f1bb0c2b86ac',1,'Array index missing, extraction failed.');
commit;

--
-- Table structure for table `migrate_message_d6_user`
--

CREATE TABLE `migrate_message_d6_user` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_user`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_user_contact_settings`
--

CREATE TABLE `migrate_message_d6_user_contact_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_user_contact_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_user_mail`
--

CREATE TABLE `migrate_message_d6_user_mail` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_user_mail`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_user_picture_file`
--

CREATE TABLE `migrate_message_d6_user_picture_file` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_user_picture_file`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_user_role`
--

CREATE TABLE `migrate_message_d6_user_role` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_user_role`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_user_settings`
--

CREATE TABLE `migrate_message_d6_user_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_user_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_d6_view_modes`
--

CREATE TABLE `migrate_message_d6_view_modes` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_d6_view_modes`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_file_settings`
--

CREATE TABLE `migrate_message_file_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_file_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_menu_settings`
--

CREATE TABLE `migrate_message_menu_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_menu_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_search_page`
--

CREATE TABLE `migrate_message_search_page` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_search_page`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_system_image`
--

CREATE TABLE `migrate_message_system_image` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_system_image`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_system_image_gd`
--

CREATE TABLE `migrate_message_system_image_gd` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_system_image_gd`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_system_logging`
--

CREATE TABLE `migrate_message_system_logging` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_system_logging`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_system_maintenance`
--

CREATE TABLE `migrate_message_system_maintenance` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_system_maintenance`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_system_rss`
--

CREATE TABLE `migrate_message_system_rss` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_system_rss`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_system_site`
--

CREATE TABLE `migrate_message_system_site` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_system_site`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_taxonomy_settings`
--

CREATE TABLE `migrate_message_taxonomy_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_taxonomy_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_text_settings`
--

CREATE TABLE `migrate_message_text_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_text_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_update_settings`
--

CREATE TABLE `migrate_message_update_settings` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_update_settings`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_picture_entity_display`
--

CREATE TABLE `migrate_message_user_picture_entity_display` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_picture_entity_display`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_picture_entity_form_display`
--

CREATE TABLE `migrate_message_user_picture_entity_form_display` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_picture_entity_form_display`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_picture_field`
--

CREATE TABLE `migrate_message_user_picture_field` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_picture_field`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_picture_field_instance`
--

CREATE TABLE `migrate_message_user_picture_field_instance` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_picture_field_instance`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_profile_entity_display`
--

CREATE TABLE `migrate_message_user_profile_entity_display` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_profile_entity_display`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_profile_entity_form_display`
--

CREATE TABLE `migrate_message_user_profile_entity_form_display` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_profile_entity_form_display`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_profile_field`
--

CREATE TABLE `migrate_message_user_profile_field` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_profile_field`
--

set autocommit=0;
commit;

--
-- Table structure for table `migrate_message_user_profile_field_instance`
--

CREATE TABLE `migrate_message_user_profile_field_instance` (
  `msgid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source_ids_hash` varchar(64) NOT NULL COMMENT 'Hash of source ids. Used as primary key',
  `level` int(10) unsigned NOT NULL DEFAULT '1',
  `message` mediumtext NOT NULL,
  PRIMARY KEY (`msgid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Messages generated during a migration process';

--
-- Dumping data for table `migrate_message_user_profile_field_instance`
--

set autocommit=0;
commit;

--
-- Table structure for table `node`
--

CREATE TABLE `node` (
  `nid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `vid` int(10) unsigned DEFAULT NULL,
  `type` varchar(32) CHARACTER SET ascii NOT NULL COMMENT 'The ID of the target entity.',
  `uuid` varchar(128) CHARACTER SET ascii NOT NULL,
  `langcode` varchar(12) CHARACTER SET ascii NOT NULL,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `node_field__uuid__value` (`uuid`),
  UNIQUE KEY `node__vid` (`vid`),
  KEY `node_field__type__target_id` (`type`)
) ENGINE=InnoDB AUTO_INCREMENT=504 DEFAULT CHARSET=utf8mb4 COMMENT='The base table for node entities.';

--
-- Dumping data for table `node`
--

set autocommit=0;
INSERT INTO `node` VALUES (31,645,'page','e5204dda-42f3-41de-8427-1614eb565595','und'),(32,633,'page','054b3ebf-6a19-4ee7-8105-b7e465e33a3a','und'),(37,570,'page','5395b75f-7832-44a7-9a49-e57b466031b7','und'),(38,571,'page','10044baf-840c-421b-9888-e789cd7d53e3','und'),(39,572,'page','a403e5ec-a8d5-45be-aa0c-7201aabd03f2','und'),(40,551,'page','14126930-0e90-4638-b0bd-2d36a20eb26d','und'),(41,567,'page','d0453baf-7f75-451c-8711-b9c8d9efb201','und'),(42,573,'page','1561b774-226c-4c3f-96ff-6f08e210b3f9','und'),(43,553,'page','bc3ba208-5871-418a-9a87-bf3a96135fab','und'),(44,44,'page','466fba77-b49c-4ca5-957f-54ef1f6dec47','und'),(61,556,'page','125abeb6-0223-4c57-9599-e08941b6806d','und'),(62,557,'page','78357360-b8e7-4a9e-9020-3efc48ab7406','und'),(73,73,'page','ffbcfa43-17ae-4152-8d86-4e063dd0a022','und'),(77,473,'book','43f68aec-fc8e-4c2a-8b33-89e8be8192a9','und'),(79,79,'book','39aa8e11-35cd-4ed0-8275-985a0ad19f2b','und'),(110,110,'book','331d1ed0-ad80-4cab-8ec8-9ab85a004480','und'),(111,111,'book','612e8e4d-d821-47b7-a65e-fb07d6e8fb93','und'),(112,112,'book','891a976a-5e64-41b2-b7bc-13bf793d5c93','und'),(113,113,'book','186f18e7-e034-46de-8507-a206ffb02617','und'),(114,114,'book','7d6de0d1-b68c-4236-a89b-0fe924b6770e','und'),(115,115,'book','c4d1375a-ce84-4623-90dd-3ff62100fb82','und'),(116,116,'book','6ee2bb8d-18eb-4c08-9eb0-4f5945e76157','und'),(117,117,'book','a0e2fd0b-67cb-4e7c-80ae-7635c0f5a61e','und'),(118,118,'book','b0909ced-61c5-4e51-ac16-7db0e7b7c1fd','und'),(119,119,'book','b8dbffab-dad3-4fec-88e5-65b3a0aac0a4','und'),(120,120,'book','4655d888-92c7-48eb-b105-db40912308ad','und'),(121,121,'book','f30cdb78-f98e-4d7b-b730-3c6d5abe21e1','und'),(122,122,'book','5d0f8d9b-51a8-4ca0-9363-da3ac3233eb2','und'),(123,123,'book','a2fdec18-65ed-4352-a0cb-87fb091976d5','und'),(124,124,'book','b75026fa-c2ab-4bbe-9ab8-8fd76be87d40','und'),(125,125,'book','692badc4-1f17-4e6b-bd85-70af19e5e796','und'),(126,126,'book','f818da1a-8959-4612-9c0b-8665bf76ad14','und'),(127,127,'book','11b95230-931f-4f15-8a45-8fceef3d6ef4','und'),(128,128,'book','e0e026d2-d39a-4496-ba21-a0794338a8b2','und'),(129,129,'book','d92c9568-a5e9-4ae1-99bb-53d0e1b95838','und'),(130,130,'book','995b0e81-52ad-450c-8fab-cd44462f6fa2','und'),(131,131,'book','9bfd745c-c730-447b-bc24-4756c64834aa','und'),(132,132,'book','e03f20a6-fbe8-401f-9aa6-80a1d322e66e','und'),(133,133,'book','e3dd231c-aeae-4f89-bea2-bf3e408a78be','und'),(134,134,'book','47484ae7-ebcf-4934-b400-891c15130f97','und'),(135,135,'book','7acaffcc-7bec-4c28-bdfd-b7f5fbbd5839','und'),(136,136,'book','1a06ae17-b9e5-4139-a98a-fa16bad8deba','und'),(137,137,'book','38409dd3-8365-4e2b-a9d3-fcefd0bad3c2','und'),(169,169,'book','dec36112-2472-4ce8-8538-7ce494b2ac9d','und'),(196,196,'book','e8ec6b93-54f6-40ac-be56-374ab1b44770','und'),(265,265,'book','464540f6-b889-4004-a26f-96c29d3f8430','und'),(271,271,'book','550bb994-2a3e-4607-a84c-ebd02eb8b225','und'),(274,274,'book','e5faa4d0-bd3c-492d-8637-8686a6e2daec','und'),(285,285,'book','33215ee9-9790-4b17-a3af-4135010973cc','und'),(323,323,'page','09544b3d-d1f3-4396-a445-29d814ef7c2b','und'),(325,325,'page','9105bf07-2560-4937-b033-4a9658bb8060','und'),(342,574,'page','d4c596e1-a3d5-4e3f-a843-a43221caa0cb','und'),(344,576,'page','9c59b095-c279-4a56-b447-47f2e8a61ac7','und'),(345,619,'page','cc5a2008-bfec-4883-899f-d7000d4b5385','und'),(347,347,'book','bf609f47-2cdc-4b19-b0c2-1d2b1d8a2c6e','und'),(348,348,'book','1c05d477-dc77-4427-a152-7bcf3e1da0e9','und'),(351,351,'page','d81b81da-c2d8-408d-b12e-a3c54c42cf8b','und'),(353,577,'page','3536fa8c-76b9-42da-b17a-c942115833e8','und'),(357,578,'article','e92a70b6-7c68-4787-a69e-5707b8a21f0c','und'),(358,544,'article','9e71c43b-20dc-4f70-97ff-278cba50ed81','und'),(359,579,'article','67b9e056-f327-46fa-a7d7-72c08c645d85','und'),(360,580,'article','f06e4a06-bb8c-4419-8bb2-3e3001bde7cd','und'),(363,364,'image','f653b3ba-e66b-4ea7-9a37-16daedd7c06e','und'),(365,366,'page','50ab47d3-fa98-4a31-9bd6-485328e405a1','und'),(366,367,'image','c60fa288-8c7e-4c59-bce7-7ac5e3e5df7b','und'),(367,610,'page','7fb93f3e-503d-49ed-957d-936d7d4d0655','und'),(368,369,'book','cebbba58-ae99-4961-8eb7-2f45d3f7c6ac','und'),(369,582,'page','c5fbdd59-19eb-46b0-b431-2fdd6706881b','und'),(370,371,'image','4ddba847-c91b-4a04-95d9-80ed994cae87','und'),(371,372,'image','5accfa24-1487-463a-839b-ef98a18344fe','und'),(372,373,'image','eecbcfd1-c44e-4d8c-8117-7d0f65b5ddcd','und'),(374,375,'image','0adf7c47-37bc-424d-b254-3fd339c29144','und'),(376,377,'image','9b2e6c56-fa1d-477c-814e-83c717c23aad','und'),(377,378,'image','d66a89b6-b62f-4794-9eef-bd8b09201ead','und'),(380,381,'page','8ac866f7-55a9-4957-9251-b56a24da9079','und'),(382,639,'page','19de3020-5652-413a-b53d-9a026f380ae3','und'),(384,385,'what_is_special_about_yaffs','664b09ab-a5dc-4e2f-9889-9a8f61b0017c','und'),(385,386,'what_is_special_about_yaffs','dc36c8cd-8e9f-468a-91dd-af26f383fa03','und'),(388,389,'what_is_special_about_yaffs','44690426-a9a6-466e-adb5-e4e58521c2be','und'),(389,390,'what_is_special_about_yaffs','d884956b-47ae-45e1-bb19-25349e1f14db','und'),(390,391,'image','46ab1fa6-0fc5-4da5-8ea9-bcaca47dde18','und'),(391,392,'image','d2df8049-af19-4ced-80ce-04059782c082','und'),(397,398,'yaffs_user_logo','73d2bdce-bc12-4215-8b33-d7478f7248a5','und'),(398,399,'yaffs_user_logo','6444ad81-8e37-4969-8a5c-17807309c46b','und'),(399,400,'yaffs_user_logo','a5c10bec-5f10-4c54-9cd0-09ca8b4cc0af','und'),(400,401,'yaffs_user_logo','fe518988-cfd7-464f-bd0a-941c1ee56307','und'),(401,402,'yaffs_user_logo','82fb641c-f24f-4653-a58b-04377a5c1619','und'),(407,408,'what_is_special_about_yaffs','9b644329-6ec6-456a-a931-f6835022e8cd','und'),(408,409,'what_is_special_about_yaffs','75eeebed-ee75-4d5b-b444-1d10280549d1','und'),(409,627,'paper','7ded725e-366e-4ad5-a9c4-4d97e16adac0','und'),(411,412,'image','7d870ca4-57c2-4923-a821-472a92bd95e6','und'),(412,413,'image','341874f5-edfc-428c-90c6-03c5c0b6c79b','und'),(413,414,'image','b921fbe7-bc02-4e1f-9c68-4d7e7cb95ff2','und'),(414,415,'what_is_special_about_yaffs','796983fd-b8b0-48f9-9c95-377d7227350d','und'),(415,416,'what_is_special_about_yaffs','434a5659-0edd-45b9-a53f-d255b5a35cbe','und'),(416,417,'what_is_special_about_yaffs','1b9479c8-dfea-4726-aa1a-32e112b26879','und'),(417,418,'what_is_special_about_yaffs','c7610495-b4fb-4573-9fd2-db3c881fd503','und'),(418,419,'what_is_special_about_yaffs','2cdd1a43-8da4-4267-b769-46f663b3a333','und'),(420,605,'paper','c3d49866-ddb0-41b9-9505-630fed1d93f4','und'),(426,427,'what_is_special_about_yaffs','815de3d9-836e-47f9-b906-a5616f636a1c','und'),(427,428,'what_is_special_about_yaffs','36ba10da-e473-4dcb-9a8b-93bff1aa5352','und'),(428,429,'what_is_special_about_yaffs','3d33c389-b797-432c-851e-d4bfbfc90939','und'),(430,431,'image','410d7dba-1e22-41be-9ffc-7898fcf8533a','und'),(431,432,'image','dad86e98-8040-4d51-98ef-e3b0108ca566','und'),(432,433,'image','858a237f-a67c-40d1-9318-8fb18cc60782','und'),(433,434,'what_is_special_about_yaffs','c78280ea-162a-4912-ab61-f8e04c339100','und'),(434,435,'what_is_special_about_yaffs','84fbc590-6f47-4ffe-8974-3f83888b0bb2','und'),(435,436,'what_is_special_about_yaffs','c27bc1aa-c1b5-47a6-bad6-53fbab401cc4','und'),(436,437,'what_is_special_about_yaffs','e4ffc5ce-460f-498f-9f3b-86bdef504158','und'),(448,584,'paper','8ddb805d-cf10-4a08-9c47-6561a522a436','und'),(451,628,'paper','2c203694-6ed4-40e7-a800-21d2496f9392','und'),(452,468,'help_video','fcc51b78-40f6-4008-96f2-011028cf0ddd','und'),(453,606,'paper','4682c2f9-e73c-487f-9ed4-67796f6f0d82','und'),(454,607,'article','adc93566-7e69-422e-bbc6-a8e0157794d1','und'),(455,608,'paper','c6cde019-a48b-43e3-a51f-4e698c671336','und'),(456,474,'image','16dc44dc-cce7-42fd-a813-d5d4749bc016','und'),(457,475,'yaffs_user_logo','2ffb5739-49f5-4d7f-9fa6-67a49b203a97','und'),(458,476,'help_video','f11b579d-c18c-4d24-a3c8-0966540e167c','und'),(459,477,'help_video','142e8241-4353-4599-ae52-5a6be2bfeac9','und'),(460,478,'yaffs_user_logo','3d819054-b1c7-4aa6-9279-0ab0d6af19e3','und'),(461,589,'article','ba641871-d7ae-4d11-9935-c77482fd81af','und'),(462,590,'page','082d641d-2d02-45da-9553-a8bc4bf912cc','und'),(466,637,'paper','c75f1175-eb9e-4081-89ae-53bfad24a474','und'),(479,592,'paper','5e5d7db3-1074-48e1-922f-161a1228bbed','und'),(481,630,'restr','68a8f651-a4ef-45cd-8e4e-2141c290c190','en'),(487,636,'page','2b05bc65-3329-47e8-9fd0-39ae05a035ed','en'),(488,512,'page','c47338c9-e0a6-4d40-835e-146f6c2444d2','en'),(489,516,'page','807695fb-4c39-4c4f-b925-f945e51b2275','en'),(497,568,'article','4cbd1f90-ac05-419a-9640-e02fbc9261b2','en'),(498,615,'page','195e7e53-f027-4370-a470-79c2a579a0a0','en'),(499,616,'page','bf4b0a08-7ee4-44d1-ba5a-e3565ee8f04a','en'),(501,634,'book','2c36ff1f-4616-41af-8e34-8b663c469ef7','en'),(502,640,'case_study','5858a804-a30f-4fe4-9afa-7cab8db57830','en'),(503,643,'case_study','0c2547c9-76e6-49ce-a06f-db53f10b5155','en');
commit;

--
-- Table structure for table `node__body`
--

CREATE TABLE `node__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`,`deleted`,`delta`,`langcode`),
  KEY `bundle` (`bundle`),
  KEY `revision_id` (`revision_id`),
  KEY `body_format` (`body_format`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Data storage for node field body.';

--
-- Dumping data for table `node__body`
--

set autocommit=0;
INSERT INTO `node__body` VALUES ('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,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,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,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,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,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,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,573,'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>','full_html'),('page',0,43,553,'und',0,'<p>Yaffs came about because Toby Churchill Ltd (TCL) needed a flash filing system for their devices. They wanted something reliable and one of their fundamental requirements was fast boot time. We looked at adding NAND support to the existing flash filesystems, JFFS and particularly JFFS2, but it became clear that the boot time and ram consumption (a 128MB NAND would use about 4MB RAM in node tables) were a problem, and adding NAND support wasn\'t trivial either (but has since been done). In the end we decided a different filing system explicitly for NAND was the way to go. The design was greatly simplified by not including compression in the FS - which makes sense as nearly all the large data files TCL used were compressed anyway, and the larger size of NAND devices makes compression less important. A cramfs filesystem can be mounted within Yaffs if you need to compress some of your data.</p><p>The original work was paid for by <a href=\"http://www.toby-churchill.com/\">Toby Churchill Ltd</a>, the project instigators, and <a href=\"http://www.brightstareng.com/\">Brightstar Engineering</a>.</p><p>Here is a collection of notable events and milestones in the history of Yaffs.</p><ul><li>2006.10 Yaffs updated to work properly with Linux 2.6.17+ MTD on 512B and 2K page NAND</li><li>2006.05.08 Checkpointing added - so start-up scanning time enormously reduced</li><li>2004.08.02 Linux kernel 2.6 support checked in.</li><li>2004.02 Yaffs presentation given at FOSDEM on embedded track</li><li><i>2003.06.21</i> Yaffs runs with Linux kernel 2.5.70.</li><li><i>2003.05</i> First two Yaffs/direct licencees.</li><li><i>2003.04</i> Yaffs/direct non-GPL license option created for those who can\'t use the GPL.</li><li><i>2003.03.07</i> ViewCVS installed to make CVS browsing much easier and help those behind CVS-blocking firewalls get access to the code.</li><li><i>2003.01</i> Yaffs Direct ported to pSOS.</li><li><i>2003.01.21</i> \'Yaffs Direct Interface\' checked in - a version of Yaffs designed for integration into lightweight RTOSs and embedded systems.</li><li><i>2003.01.21</i> Yaffs Bootloader example code checked in, so your bootloader can read directly from Yaffs.</li><li><i>2002.11.04</i> <a href=\"/drupal/yaffs/yaffs2.html\">Yaffs2 spec</a> announced for discussion.</li><li><i>2002.11.08</i> WinCE port code checked-in to CVS.</li><li><i>2002.09.23</i> Announced to the world.</li><li><i>2002.09.17</i> Header files relicensed under LGPL to make it easier to add Yaffs support to bootloaders or other non-free software.</li><li><i>2002.09.13</i> Stand-alone system using Yaffs root partition booted.</li><li><i>2002.08</i> WinCE Yaffs port working.</li><li><i>2002.05.20</i> MTD interface tested on hardware emulation and some real hardware.</li><li><i>2002.05.14</i> v0.1 release. MTD interface done and incorporated. This is essentially untested. yaffs.o provides two file systems (one to support internal RAM emulation [called yaffsram] and the other mtd [called yaffs]). Docs improved/updated. mkyaffs filesystem creator written.</li><li><i>2002.04.24</i> Now includes device contexts, (but as there is only one emulation instance this isn\'t any practical use yet), some bugs fixed and disk full handling. Still some VFS problems apparent in sub-directories. Statfs, attributes still to do, symlinks and hardlinks not yet wired to VFS layer.</li><li><i>2002.04.15</i> kernel module that runs as an fs on 2MB internal emulation. The core filing-system seems to work pretty well. Some problems remain in the VFS layer producing various odd effects. Only one instance of the fs supported</li><li><i>2002.04.03</i> Core fs runs on emulation layer (instead of real NAND), create/read/write/delte/resize/reanem files, create directories, scans media on startup, garbage collection.</li></ul><p>&nbsp;</p>','<p>A chronology and list of milestones in Yaffs development.</p>','full_html'),('page',0,44,44,'und',0,'<h3>Paid support&nbsp;</h3>    <p>Support for YAFFS and ARM Linux is available from Aleph One</p> <p> </p> <p>YAFFS is available both as free software, under the GNU GPL, and under the Aleph One Licence. We provide different support and consulting services on its use with particular hardware and OSes as described below. <br /> <br /> We provide YAFFS support and documentation at a negotiable price; guide prices in GBP are:</p>     <table border=\"0\">      <tbody><tr>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; YAFFS Product type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GPL YAFFS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Licence YAFFS </tr>     <tr>     <td><u>BRONZE</u></td>    </tr>    <tr>    <td>One copy of USERS\' GUIDE TO YAFFS and one hour consultation by phone  or email but no Guarantee</td><td>&pound;100</td><td>&pound;1000</td>    </tr>    <tr>     <td><u>SILVER</u></td>    </tr>    <tr>     <td>USERS\' GUIDE TO YAFFS and 10 hours of support by phone and email within one month of purchase</td>     <td>&pound;500</td><td>[&pound;3000]</td>    </tr>   <tr>    <td><u>GOLD</u></td>   </tr>   <tr>    <td>Whatever Support is necessary to produce a satisfactory working integration of    YAFFS with your product.</td><td>Negotiable</td><td>Negotiable</td>   </tr>   </tbody></table>         <p>For the GOLD level please contact us with a description of the project. Our standard charge for short-period consulting time is GBP800 per day. If you would prefer to sign mutual Non-Disclosure Agreements before discussing your requirements with us, and do not have your own, we have a standard one which is usually suitable. You or we can sign and send by post.</p><p>Sustained serious work is the subject of negotiated contracts which describe exactly what are the tasks and&nbsp; the cost.&nbsp; Support for simpler matters can usually be obtained in exchange for a payment of GB&pound;50 to us through PayPal, for which sum we will spend time dealing with your questions by telephone or email.<br /> </p> <h3>Mailing list</h3>   <p>There is a <a href=\"http://aleph1.co.uk/mailman/listinfo/yaffs\">YAFFS mailing list</a> for the development and discussion of YAFFS. It\'s a fairly low-traffic list. You will be emailed and asked to confirm your subscription request. You can also browse and search the <a href=\"http://aleph1.co.uk/lurker/splash/index.en.html\">list archives</a>. </p>','Information on YAFFS support options.<br />','full_html'),('page',0,61,556,'und',0,'<p>Here is the text of a talk given by Wookey (Chief Nerd at Aleph One) to a meeting in Cambridge of Developers, Businesspeople and IP practioners, on June 5th 2003.</p>   <hr />  <h2>Introduction</h2>   <p>Hi, I\'m Wookey, Chief Nerd at Aleph One, a small software and hardware producer in Cambridge. We do both free and proprietary software, these days largely around embedded systems and ARM-linux.</p>    <p>I\'ve been mugged into speaking against software patents this evening. Now I don\'t claim to be an expert - A few months ago I know nothing about this subject but after hearing Richard Stallman speak at the Cambridge Computer Lab, my interest was piqued, and with some reading the web and going to a conference about it in Brussels (Brussel/Bruxelles) I think I\'ve now got a reasonable grasp of the arguments. It\'s a big subject but I\'ll try and sumarize the main points here.</p>   <p>I\'m nominally representing the <a href=\"http://swpat.ffii.org/\">FFII viewpoint</a> here. They are a European (German-based) organisation campaigning for a free information infrastructure. They have amassed an amazing amount of information on their website.</p>   <h2>The basics</h2>   <p>Patents are a bargain between state and public - a monopoly granted in exchange for publication of information. This is intended to preserve info so it doesn\'t get lost and to avoid the appropriation of inventions.</p>   <p>We\'ve got very used to them, But they are not a free market or a right or a natural state of things and need to be justified in a given sphere. Most people on the street will say \'yes patents are a good thing\' if asked, but at least in the sphere of software, that attitude needs to be challenged and some evidence produced for why.</p>   <p>First lets be clear about what is meant by being against \'software patents\'. This refers to things which are just software; it doesn\'t mean that you can\'t patent anything with some software in it. So computer-controlled industrial process is patentable, but JPEG compression is not.</p>   <h2>Copyright</h2>   <p>Copyright already exists for software and is well-suited. It stops wholesale copying of your implementation, but it doesn\'t stop someone making something that does the same job. To \'copy\' your program someone will have to re-implement it - that\'s about the same amount of work as it took you, which is fair enough, and you\'ll have a head start of however long it took. By the time they\'ve caught up you\'ll be on the next verion. Innovation, copyright and trade secrets (for propietary software) are all that are needed to protect software in the market.</p>   <p>Patent lawyers will say copyright is only for poetry and the like, but in fact it works quite well for music scores, music sound, pictures, films etc.</p>   <p>The biggest problem with patents is uncertainty: You can easily run your business so you don\'t trip over copyright - just don\'t plagiarise. But it\'s impossible to run it such that you are safe from unexpected attack by patent lawyers. Patents are written in a special language which even experts in a field find difficult to understand. In order to decide if you infringe a patent you have to ask a patent lawyer, and they generally charge several thousand pounds/dollars/euros per patent for an opinion. Examing thousands of patents every year to check whether you infringed is impossibly expensive and/or time-consuming for most SMEs, so they don\'t do it. In practice every day you write code you probably infringe a patent or two, so one day someone will turn up telling you you infringed. It literally makes software writing into a minefield - suddenly one day a patent mine will blow up under you or your company - and the costs could easily destroy it, whether or not you really did infringe - 2 or 3 such attacks will almost certainly be fatal.</p>   <p>In practice patent lawsuits generally cost about half a million dollars. Those involved in real cases said that even when the accusations were obviously frivolous, it was still cheaper to just pay up than go to court and try to prove them wrong or demonstrate prior art. And do you realise that if you had invented the relevant technique prior to the patent then that might get you off the hook, but if it wasn\'t published then the patent remains valid and others can be hassled with it. None of this helps companies write software and innovate. If they play the game they need to employ some lawyers and spend a lot of engineer time writing patent applications. If they don\'t they will one day find that they got big enough to sue.</p>   <p>&hellip;</p>   <p>The existing software market isn\'t broken - software and software companies developed just fine without patents (Microsoft never had any patents before it got be huge, for example), so the premise that they are necessary to encourage investment and innovation is clearly wrong. No-one had any before about 1982 and the floodgates didn\'t open until around 1994, and plenty of software got written. To change the software legal environment in this fundamental way needs some very good reasons and evidence. And that evidence simply doesn\'t exist. You can find lots of legal argument promoting the idea but almost no economic arguments or studies.</p>   <p>Patent lawyers always talk about this subject from legal perspective, not from social or economic - they believe all patents are are good thing per se and don\'t even consider the idea that they might not be. We, and MEPs, must consider the overall economic, social and innovation effects to see if they really are a good idea.</p>   <p>The classical idea of patents is that they protect individual inventors with great ideas from large corporations, and whilst they may work occaisionally, in practice they seem to do exactly the opposite. Only large corporations can absorb the costs and get lots of software patents and use them to stifle competition from innovative startups. It\'s largely big corporations, lawyers who make a living from them, and parasitic companies that use patents for extortion but never invent anything, that promote software patents. The vast majority of software developers and SMEs are not in favour of them. 140,000 signed the FFII petition for example.</p>   <p>The only evidence that does suggest SMEs benefit from patents in the US includes in its definition of SMEs companies which do no research or development of their own at all - so-called \'patent-trolls\'. They just buy up patents from defunct companies and then go round suing other companies which are making real products. Is this the sort of development we wish to encourage?</p>   <p>Patenting works reasonably well where one patent corresponds to one product, as in chemistry and pharmaceuticals. But every program of any significance has thousands of ideas in it, and thus can be affected by thousands of patents. Avoiding them all becomes increasingly difficult as more and more patents on fundamental building-blocks are issued.</p>    <p>The US is a handy test case, being some 4 or 5 years ahead of us in software patent terms, and the evidence clearly shows that patents cause plenty of problems. The longer the patent-grab game goes on the worse it gets. At the recent FTC hearings company after company said the situation was out of control and not helping at all. The FTC studies should be published in August and it would be a very good thing if the EU could be persuaded to wait till that evidence is in before completing the directive.</p>   <h2>Suggestions</h2>   <p>&quot;Trviality is the problem&quot;: just raise the non-obviousness requirement. The examination (of patent applications) problem is insoluble - There are so many areas of expertise needed that it is now impossible to have patent examiners proficient in every sphere of software, so trivial patents will always get through. The economics of patent offices also drives this process, because they want to give value for money to their customers.</p>   <p>Consider existing patents on software to see how trivial they are. Progress Bar, electronic shopping cart, Dynamically extensible webserver (CGI scripts), controlling one computer from another (RPC, telnet, client-server), displaying objects in overlapping windows.</p>   <p>&quot;America has patents - so we must too&quot;. This is a barmy argument. The EU currently has an advantage because European companies can write software without tripping over patents all the time. They can still get US patents if they want to use them in the US, but are safe at home. Americans have the opposite problem.... Most of the EU software patents are owned by US and japanese corporations - just look at the list of applications for recent EU software patents. Making them legal would simply hand a significant chunk of the EU software business to foreign companies.</p>   <p>Software patents are currently illegal in Europe according to the European patent convention, and have been since at least 1973. The legislation says quite clearly that ideas, art, algorithms and computer programs as such are not patentable. So how come we have 30,000 of them already? It\'s because patent lawyers at the European Patent Office (EPO) have twisted the words of the law out of all recognition, essentially saying a \'computer program as such\' is not the same as a \'computer program\' and that because software runs on hardware which has a \'physical effect\' (gets hot, uses electricity\') - it can be patented.</p>   <p>This \'physical effect\' logic is flawed because how the hardware behaves is irrelevant to software developers - it\'s like saying that music should be patentable because playing it in a stereo system produces physical effects in the loudspeaker. Developers don\'t need to understand the hardware to write software in the same way that you don\'t need to know how your engine works in order to drive your car.</p>   <p>This so of logic is why you have to be really paranoid when considering the wording of legislation. The MEPs say they don\'t want software patents, or business methods, but then write legislation that will allow unlimited patentability of ideas (business methods in computer program terms) either through ignorance or mendacity. The existing 1973 text is pretty clear - if that doesn\'t work we have to be astonishingly careful in the wording of new law.</p>    <h2>Drawing the line</h2>   <p>Allright, so how do we draw the line?<br /> This is quite a difficult thing to think about clearly.</p>   <p>A computer is a turing machine - programs are logically equivalent to maths, and that is why they should remain unpatentable. As soon as you allow algorithms to be patented, then ideas and everything in human endeavour follows, including voting systems and social organisation methods.</p>   <p>The question  boils down to the two sides of the argument:</p>   <ol> <li>If physical processes are patentable, why should it make any difference whether they run on special hardware or on general purpose hardware?</li><li>If rules of organisation and calculation are not patentable why should it make any difference whether I run them in my head, with pencil and paper or with today\'s normal tool - a universal computer?</li> </ol>   <p>The 2nd argument is right because the economic argument comes in here: abstract ideas, regardless of their applicability, are produced without experimentation cost, applicable to an infinite number of problems and are replicated at zero cost, with no overhead to which patent costs could be added. This is the right place to draw the line.</p>   <p>Ideas should not be patentable. The FFII proposals distinguish between mind and matter and invention and implementation. In the real world making complex systems that work is difficult - in software it is easy due to the absence of physical effects: your for loops will not overheat and melt a nearby function, neither will an array cause electrical interference in your hash function. So patents are applicable to the industrial world of \'controllable forces of nature\', not to the world of algorithms and data processing.</p>   <p>There will always be borderline cases and FFII have set up a benchmarking suite of example patents against which legislation can be tested. Software is large collection of obvious things. Like a Recipie, or symphony. A cook takes a number of (obvious) things and combines them in an intersting way, yet no-one thinks that patenting a new way of slicing tomatoes is a good idea, or that whoever thinks of a chord first should be able to prevent anyone else using it.</p>    <h2>Standards</h2>   <p>Patents are making it increasingly difficult to set standards. JPEG was specifically created as a patent-free standard, even forgoing a few percent of speed to ber sure of avoiding existing patents. But now, 15 years later, a patent-troll has bought a relevant patent and is enforcing it. They got 22 million dollars out of a couple of Japanese companies last year, and when the president of the JPEG committee said that there was prior art they accused him <u>personally</u> of \'patent libel\'.</p>   <p>The MPEG2000 standard is probably already dead in the water due to arguments about patents. Anything that does legalise them must have strong safegards to stop things like the JPEG hijacking. There can be agreements amoungst those involved in the discussions but it\'s very difficult to do anything about people who don\'t join in and wait untill afterwards to come and sue. \'Use it or lose it\', and interoperability defence.</p>   <h2>Free software</h2>   <p>Free software has both advantages and particular problems with respect to patents. The fact that it is all published is a useful \'prior art\' defence. It also makes it very easy to see if there has been an infringement so it\'s authors are particularly open to being sued. There is no mechanism to pay for licenses so it cannot use any patented algorithms or features. An interoperability clause is essential to allow free software to interoperate, and even \'royalty-free\' patent agreements in standards could cuase problems as they only allow using the code for the specified purpose, not anything else anyone might come up with later.</p>   <p>It seems to me that \'Independent invention\' should be a sufficient defence.</p>   <p>In principle, a much shorter period for patents (3-5 years?) would help reduce the bad effects, but this is legally extremely difficult to do. The various international agreements (TRIPS) say that patents must be 20 years for all fields of endeavour. This is clearly inapropriate for software - imagine having to write all your software using only ideas from when the ZX-spectrum was the state of the art. 20 years is an eternity when most software products have a life of around 18 months. This 20 yrs-or-nothing aspect is actually a good argument for nothing.</p>   <p>One argument of the pro-patent lobyists is that we can\'t cause trouble with the EPO or pass laws that would invalidate existing patents. This is simply caving in to the EPO who have pushed the current status quo miles beyond what the law states. It\'s not our fault that clarifying the situation to a sensible state will mean a lot of patents have been issued on very shaky ground. They are mostly worthless anyway and should be treated as such.</p>   <p>So far as I can see software patents are a bad thing and have almost no overall benefit to society or developers. In the long term I think they will have very bad effects. I don\'t want to sound too much like some kind of anti-globalisation eco-nutter, but they do seem to be little more than an effective tool to allow large businesses and lawyers to supress competition from small ones and individuals, and to move fundamental ideas and algorithms from the public domain to private ownership. However powerful forces - the ones who stand to benefit from this legislation, disagree with this and are largely getting their own way in legislation-land at the moment. So, if you don\'t want to see everything under the sun patented, then you need to say so very clearly to your representatives right now.</p>','Presentation at Software Patent Discussion Meeting, Cambridge July 6th 2003 - Wookey presented the case against software patents. Aleph One believes that legislation making them legal in Europe will severely damage innovative small software businesses, especially those using Free Software.','full_html'),('page',0,62,557,'und',0,'    <div>    <p>Hi, I\'m Wookey, Chief Nerd at Aleph One, a small software and hardware producer in Cambridge. We do both free and proprietary software, these days largely around embedded systems and GNU/linux on ARM processors, - those are the ones found in most mobile phones and PDAs.</p>        <p>I\'ve been asked to come and speak to you about software patents today. This is currently a hot topic because there is a directive going through the EU at the moment which could either make software patents illegal or legal, depending on its exact wording. This will set the programming legal environment for the next 10 or 20 years, so it\'s important that anyone working in the field of computing understands the issues and implications.</p>        <p>Now, I don\'t claim to be an expert in this area, but my interest was piqued some 18 months ago by hearing Richard Stallman of the Free Software Foundation speak on the subject, and since then I\'ve been to a conference in Brussels, and various discussions in and around Cambridge, talking to people on both sides of the debate, so I\'ve now got a reasonable grasp of the arguments, and I hope I can adequately explain them to you. It\'s a big subject, but I\'ll try and cover the main points here today, and leave time for some questions &amp; discussion. I\'ve recently been to a 1hr version of this talk and that\'s a bit much even for dedicated geeks, so this one will be more like half an hour.</p>        <p>This talk is not entirely neutral - after examining the arguments I\'ve come firmly to the conclusion that software patents &nbsp;are a very bad thing for society. The viewpoint I\'ll give today is essentially is that of the FFII - a European (German-based) organisation campaigning for a free information infrastructure, concentrating largely on software patents for the last 2 years. They have amassed an amazing amount of info on software patents on their website, and are an excellent resource should you wish to read further about this.</p>        <p>I\'ll be putting this talk on the web when I get back home in a week or so, so if you want to refer to it for URLs or references, just search for Wookey or Aleph One (and ignore Wookey Hole Caves, who beat me to the top Google spot).</p>        <p>The basics</p>        <p>Patents are a bargain between state and public - a monopoly granted in exchange for publication of information. This is intended to promote inventive activity and preserve information so it doesn\'t get lost.</p>        <p>They are granted for inventions in a technical field, which are new, suitable for industrial use, and unobvious to an expert in the field.</p>        <p>There is an assumption of balance: that the width of protection granted is justified by the significance of the achievement. When a patent is granted - there is one winner who can exploit the invention exclusively, and potentially many losers who must forgo the invention, or buy a licence (if the patent owner chooses to sell them one). Where this balance holds, then the system is effective: the resources put into researching the invention justify the negative effects of the patent monopoly, as is often the case in pharmaceutical research. But software patents are very close to patents on pure ideas. The achievement is minor, and the research usually negligible, but the protection can be very wide, as a patent can affect an enormous number of pieces of software.</p>        <p>A patent only gives exclusive rights in the country of issue (unlike copyright, which automatically applies everywhere that has signed up to the Berne Convention), so a US patent only applies in the US, a French patent in France. The European Patent Office (the EPO) exists to simplify the process of getting numerous national patents in European countries. It deals with the examination process, and translations and the issuing of British, French, Polish, etc patents in the countries you have chosen to pay for patents in.</p>        <p>We\'ve got very used to patents, but they are not a free market, or a right, or a natural state of things, and need to be justified in a given sphere of activity. Most people on the street will say \'yes, patents are a good thing\' if asked, but at least in the sphere of software, the assumption that patents are good needs to be questioned and some evidence produced for why. </p>            <p>Copyright.</p>        <p>Copyright already exists for software and is well-suited. It stops wholesale copying of your implementation, but it doesn\'t stop someone making something that does the same job. To copy your program legally someone will have to re-implement it - that\'s about the same amount of work as it took you, which is fair enough, and you have a head start of however long it took. By the time they\'ve caught up you\'ll be on the next version. Innovation, copyright and trade secrets (for proprietary software) are all that is needed to protect software in the market.</p>        <p>Patent lawyers will say copyright is only for poetry and the like, but in fact it works quite well for music scores, music sound, pictures, films etc. Copyright is also free and automatic to obtain, and automatically applies internationally.</p>        <p>The biggest problem with patents, for programmers and businesses, is uncertainty: You can easily run your business so you don\'t trip over copyright - just don\'t plagiarise. But it is impossible to run it such that you are safe from unexpected attack by patent lawyers. Patents are written in a special language which even experts in a field find difficult to understand. In order to decide if you infringe a patent you normally have to ask a patent lawyer, and they charge several thousand pounds per patent for an opinion. Examining thousands of patents every year to check if you infringed is impossibly expensive and/or time-consuming for most small to medium sized businesses (SMEs), so they don\'t do it. Thus, in practice, every day a programmer writes code she infringes a patent or two, and one day someone will turn up telling her she infringed. It makes software writing into a minefield - suddenly one day a patent mine will blow up under you or your company - and the costs could easily destroy it, whether or not you really did infringe - 2 or 3 such attacks will almost certainly be fatal.</p>        <p>In practice patent lawsuits generally cost about half a million dollars. Those involved in real cases said that even when the accusations were obviously frivolous, it was still cheaper to just pay up than go to court and try to prove them wrong or demonstrate prior art. And do you realise that if you had invented the relevant technique prior to the patent then that might get you off the hook, but if you didn\'t publish it then the patent remains valid and others can still be hassled with it?</p>        <p>None of this helps companies write software and innovate. If they play the game they need to employ some lawyers and spend a lot of engineer time writing patent applications. If they don\'t, they will one day find that they got big enough to sue.</p>        <p>...</p>        <p>The existing software market isn\'t broken - software and software companies developed just fine without patents, so the premise that they are necessary to encourage investment and innovation is clearly wrong. (For example Microsoft never had any patents before it got be huge, but now that it\'s a dominant incumbent it\'s buying hundreds of them). No-one had any before about 1982 and the floodgates didn\'t open (in the US) until around 1994, and plenty of software got written, some of it highly innovative. To change the software legal environment in this fundamental way needs some very good reasons and evidence. And that evidence simply doesn\'t exist. You can find lots of legal argument promoting the idea but almost no economic arguments or studies.</p>        <p>Patent lawyers always talk about this subject from a legal perspective, not from a social or economic one - they believe all patents are a good thing per se and don\'t even consider the idea that they might not be. We, and MPs and MEPs, must consider the overall economic, social and innovation effects to see if they really are a good idea.</p>        <p>The classical idea of patents is that they protect individual inventors with great ideas from large corporations, and whilst they may work like this occasionally for software, in practice they seem to do exactly the opposite.</p>        <p>Having one patent on something is very little defence against a large corporation that wants to use your idea. Because any useful piece of software uses many many ideas and algorithms the corporation will just say, &quot;ah, yes we may be infringing your patent, but you\'re infringing six of ours &nbsp;- do you really want to go to court about it?&quot; IBM are masters of this strategy and there are many stories of cohorts of stony-faced lawyers turning up to give anyone threatening them with patent infringement a hard time.</p>        <p>So in practice, allowing software patents simply leads to a numbers game, where all the players need lots of patents and it doesn\'t matter if most of them are rubbish - they just need to cover as much of the field of computer science as possible. Only large corporations can absorb the costs and get lots of software patents and use them to stifle competition from innovative startups. It\'s largely big corporations, lawyers who make a living from them, and parasitic companies that use patents for extortion but never invent anything, that promote software patents. The vast majority of software developers and SMEs are not in favour of them. 300,000 signatories, including 700 companies signed a FFII petition against them, for example.</p>        <p>The only evidence that does suggest SMEs benefit from patents in the US includes in its definition of SMEs companies which do no research or development of their own at all - so-called \'patent-trolls\'. These outfits buy up patents from defunct companies and then go round suing other companies which are making real products. Is this the sort of development and innovation we wish to encourage?</p>        <p>Patenting works reasonably well where one patent corresponds to one product, as in chemistry and pharmaceuticals. But every program of any significance has thousands of ideas in it, and thus can be affected by thousands of patents. Avoiding them all becomes increasingly difficult as more and more patents on fundamental building-blocks and useful ideas are issued.</p>            <p>The US is a handy test case, being some 4 or 5 years ahead of us in swpat terms, &nbsp;and the evidence clearly shows that patents cause plenty of problems. The longer the patent-grab game goes on the worse it gets. The Federal Trade Commission recently held hearings &nbsp;on the state of the patent system and company after company said the situation was out of control in the field of software and was not helping at all. That study was published in August 2003 and is a fine example of a very staid government body concluding that they are actively unhelpful.</p>        <p>Nevertheless, there is a lot of pressure from the US for the EU to legalise software patents. This comes primarily from large companies which stand to gain from them, but even companies that don\'t like software patents, realise that they will lose out unless we operate under the same restrictive regime, so they tend to support the idea of software patents in the EU too.</p>        <p>....</p>            <p>In principle the problems of software patents would be enormously reduced if they were only given for things that were genuinely complex or hard to invent, but the system itself encourages very low standards of examination. Patents are supposed to be \'not obvious to an expert in the field\'. But how many of you think that these typical European patents are not obvious: </p>        <p>Progress Bar, electronic shopping trolley, dynamically extensible webserver (CGI scripts), controlling one computer from another (RPC, telnet, client-server), displaying objects in overlapping windows, or transferring pupil data between computers over a wireless network. </p>        <p>These are all just the obvious way you would do something if asked to provide that functionality. And they are not particularly unrepresentative examples - if you look at the patent database and read through the legalese, nearly all software patents are this trivial. You can get a patent for almost any computing idea if it is dressed up in the right language. The FFII maintains a database of patents translated back into something software engineers can understand, to show the sort of ridiculous things that already get patents.</p>        <p>The problem is that there are so many areas of expertise needed that it is now impossible to have patent examiners proficient in every sphere of software, so trivial patents will always get through. And the economics of patent offices also drive this process, because they want to give value for money to their customers - people pay to be granted patents, not to be refused them, but the office has to do nearly the same amount of work in both cases. Th EPO charges more than any other patent office (several thousand pounds), but still grants all sorts of trivial patents. The US Patent office is much worse.</p>        <p>Another irony of the system is that in the days of the industrial revolution a patent included a technical drawing of the invention that could be used to build it - the \'publication\' side of the \'monopoly in exchange for knowledge\' balance I mentioned earlier. But software patents only include a description of the idea, not an actual implementation that could be used for someone to build on. There is no requirement to publish working source code, and indeed patent lawyers resist this idea, claiming that it is much clearer to have them re-write your program in patent-speak, which if you have ever tried to read a patent, clearly isn\'t true. This process just makes it easier for lawyers to keep the whole system under their control, as you need them to apply for patents and to interpret patents, and programmers find the published patents completely useless as a source of knowledge, even though that is supposed to be a major part of their purpose. </p>        <p>One of the main arguments given in favour of software patents is &quot;The Americans have them- so we must too, in order to compete&quot;. This is a barmy argument. The EU currently has an advantage because European companies can write software without tripping over patents all the time. They can still get US patents if they want to use them in the US, but are safe at home. Americans are finding it harder and harder (or at least increasingly expensive) to write software, and are liable to being sued at home.... There have already been a lot of software patents granted in the EU, despite their dubious legality, and most of them are owned by US and Japanese corporations. Making them legal would simply hand a significant chunk of the EU software business to foreign companies. </p>        <p>(Standards) </p>        <p>Patents are making it increasingly difficult to set standards. JPEG was specifically created as a patent-free standard, even forgoing a few percent of speed to ensure no patents were infringed. But now 15 years later a patent-troll has bought a relevant patent and is enforcing it. They got 22 Million dollars out of a couple of Japanese digital camera companies last year, and when the president of the JPEG committee said that there was prior art they accused him personally (not the JPEG committee, or his company) of \'patent libel\'. This claim has not put them off and they are still hassling businesses that write JPEGs. </p>        <p>The MPEG2000 standard is probably already dead in the water due to arguments about patents. Anything that does legalise them must have strong safeguards to stop things like the JPEG hijacking. There can be agreements amongst those involved in the discussions but it\'s very difficult to do anything about people who don\'t join in and wait till afterwards to come and sue. A \'Use it or lose it\' provision, and and interoperability defence would both help here.</p>        <p>(Free software)</p>        <p>Free software has both advantages and particular problems with respect to patents. The fact that it is all published is a useful \'prior art\'</p>    <p>defence. It also makes it very easy to see if there has been an infringement so its authors are particularly open to being sued. As nearly all Free Software is distributed at no cost, there is no mechanism to pay for licenses so it can\'t use any patented algorithms or features. A clause in the law is essential to allow free software to interoperate, and even \'royalty-free\' patent agreements in standards could cause problems as they only allow using the code for the specified purpose, not any other possible use someone might come up with later.</p>        <p>It seems to me that \'Independent invention\', which happens all the time in software development, should be a sufficient defence, but that is anathema to the patent system.</p>        <p>In principle a much shorter period for patents (3-5 years?) would help reduce the bad effects, but this is legally extremely difficult to do. The international agreement (TRIPS) says that patents must be 20 years for all fields of endeavour. This is clearly inappropriate for software - imagine having to write all your software using only ideas from when the ZX-spectrum was the state of the art. 20 years is an eternity when most software products have a life of around 18 months. &nbsp;This 20 yrs-or-nothing aspect is actually a good argument for nothing.</p>        <p>One argument of the pro-patent lobbyists is that we can\'t cause trouble with the EPO or pass laws that would invalidate existing patents. This is the line taken by the UK government. But this reasoning is simply caving in to the EPO who have pushed the current status quo miles beyond what the law states. It\'s not our fault that clarifying the situation to a sensible state will mean a lot of patents have been issued on very shaky ground. They are mostly worthless anyway and should be treated as such.</p>        <p>So where are we now?</p>        <p>Software patents are currently illegal in Europe according to the European patent convention, agreed in 1973. The legislation says quite clearly that a number of things are not patentable </p>    <p> * discoveries, scientific theories, mathematical methods,</p>    <p> * aesthetic creations, </p>    <p> * schemes rules and methods for performing mental acts, playing games or doing business</p>    <p> * presentations of information</p>    <p> * and computer programs</p>        <p>You can see from this list how software is filed alongside things which are essentially ideas, discoveries, and creative acts like writing a novel or a symphony.</p>        <p>We don\'t allow patents on the arrangement of words in a particular form of clause or story;</p>    <p>We don\'t allow the creation of a particular motif or structure in music to be patented, and;</p>    <p>We don\'t allow patentability of a new sort of provision in a legal contract.</p>        <p>We do allow the complete arrangement of notes or words in these things to be copyrighted. Software is like these - it is the bringing together of many small obvious components into a coherent whole, and this process is a creative act, not an invention in the sense of patent law.</p>    <p> </p>    <p>So how come we have 30,000 software patents in Europe already? It\'s because patent lawyers at the European Patent Office (EPO) have, over 20 years of case law, twisted the word and spirit of the law out of all recognition, essentially saying a \'computer program as such\' (the wording in the EPC) is not the same as a \'computer program\' and that because software runs on hardware which is inherently \'technical\' (gets hot, uses electricity\') - it can be patented.</p>        <p> This is why you have to be really paranoid when considering the wording of legislation. Nearly everyone involved says they don\'t want software patents, and they certainly don\'t want business method patents, but then write legislation that allows unlimited patentability of ideas (business methods in computer program terms) either through ignorance or mendacity. The existing 1973 text is pretty clear - if that doesn\'t work we have to be astonishingly careful in the wording of new law to ensure that there are meaningful limits on what is and isn\'t patentable.</p>        <p>The legislative process</p>        <p>I need to step back a moment here and explain the legislative process in the EU. There is a tripartite system involving the European Commission, the European Parliament (your MEPs) and the Council of Ministers, (which is composed of representatives of each of the EU member governments). </p>        <p>Law is proposed by the Commission, amendments are proposed by committees and parliament, then voted on by the parliament. Next it goes to the Council of Ministers for a vote. With this particular piece of legislation (the directive on computer-implemented inventions), this is where we have currently got to. Next it goes back to the parliament where further amendments are possible, and finally back to the Council again for ratification.</p>        <p>The commission originally proposed a terrible directive, which effectively allowed unlimited software patentability. However, a huge lobbying campaign led by the FFII (which apparently produced the biggest petition the Parliament has yet been presented with) persuaded the Parliament to add a large number of amendments which put real limits on patentability, and included an interoperability clause. But then when the directive went on to the Council of Ministers, they discarded all of the Parliament\'s significant amendments and produced a version which was even worse than the Commission\'s original, as it included program claims too. (I\'ll explain what that means in a mo).</p>        <p>This was bizarrely described as a \'compromise position\', given that it totally ignored the democratically-elected parliament\'s position. This version was narrowly agreed two weeks ago by the Council, so now we go back to the Parliament. Unfortunately, second time round amendments are significantly harder to get passed as they need a majority of all MEPs, not just the ones present at the vote, and whilst that\'s not impossible, it won\'t happen unless your MEP hears from you that this is an important issue. It is also important to work on National governments. The UK has been at the forefront of those pushing for unlimited patentability via this directive, apparently driven by the UK Patent Office, and changing goverment policy is going to be very difficult, but many other European governments are getting rather nervous about this issue, and it is definately an argument that can still be won.</p>        <p>Key Issues</p>        <p>There are three key issues in the legislation:</p>    <p> * Program Claims</p>    <p> * Interoperability, and</p>    <p> * the meaning of the word &quot;technical&quot; - i.e. what is patentable.</p>        <p> &quot;Program Claims&quot; means that software patents can cover the publication of programs in machine-readable form, not just the use of those programs. This means that sending someone a file containing patented software becomes illegal without a license, and even discussing the software would become difficult, as there is nothing to say that discussing algorithms using code fragments (the way programmers normally discuss code) is allowed.</p>        <p>This is the provision that was added in the Council of Ministers draft, showing how the national patent offices (who obviously like this sort of maximisation of the reach of patent law) are currently controlling the views of our governments.</p>        <p>A \'fair use\' provision would at least offer an olive branch, but really the scope of patent protection should be kept to use of the invention, not extended to include information about the invention itself. Software is different from normal manufactured goods because it is just information - it is both the invention, and the description of it, in one thing. This is why Program claims make sense to Patent Lawyers, and equally explains why programmers believe software simply shouldn\'t be patentable at all, because it is information, not an industrial process.</p>        <p>Interoperability:</p>    <p>There is nothing in the proposed draft, short of a full-scale EU Competition Investigation, to prevent dominant patent owners preventing competitors from interoperating by refusing them licenses. The most obvious example is the recent patent Microsoft has been given on the particular XML format used in its newest Word documents. It must be possible for others to write software that is compatible without having to buy patent licenses, and this is the position backed by the European Parliament, which allowed automatic unfettered use.</p>        <p>The Danish parliment suggested a compromise of a fast-track procedure for courts to require compulsory RAND licensing - i.e. a paid licence, but available to all, and at the same cost. This would work for proprietary software but is not much use for Free Software. Should it be illegal for Openoffice to read and write MS Word documents, or the Linux movie software Mplayer not to be able to play films you bought? </p>        <p>Your MP and MEP needs to hear that you consider interoperability essential.</p>        <p>Technical</p>        <p>As I said earlier - According to the European Patent Convention, computer programs are excluded from patentability, to the extent that the claimed invention relates to the computer program &quot;as such&quot;.</p>        <p>The new directive legislates for a framework in which the crucial test for patentability is whether the claimed &quot;computer-implemented invention&quot; has a &quot;technical effect&quot;.</p>        <p>This has given supporters of patentability a figleaf that &quot;pure software as such will not be patentable&quot;.</p>        <p>But what is &quot;software&quot;, and what is &quot;technical&quot;</p>        <p>There are essentially three views:</p>        <p>1) &nbsp;There is general agreement that newly invented physical processes should be patentable, regardless of whether software control is needed for the process to be achievable. &nbsp;The classic example is an anti-lock braking system, if a particular non-obvious process of applying the brakes has a particular physical benefit.</p>        <p>This was the view taken by the parliament, and is supported by the German government - the characteristic wording is that &quot;control of the forces of nature&quot; is technical, but that internal processing of data is not technical.</p>        <p>2) UK case law goes further than this. So whilst processing of generic data is not generally patentable, the invention becomes &quot;technical&quot; if the data has technological relevance, so things like image-enhancement software is patentable because the image data is \'technical\'.</p>        <p>Because the UK has been giving software patents like this for some years now the goverment is steadfastly refusing any stricter definition of technical because it will invalidate existing patents.</p>        <p>3) The EPO has gone further still and takes the position that all computing is inherently technical and so anything that has practical usefulness makes a &quot;technical contribution&quot;. Thus they say that a new algorithm &quot;as such&quot; is not patentable, but any algorithm with any identifiable practical usefulness (runs faster, uses less memory) is patentable.</p>        <p>This third option is what the Council of Ministers draft proposes, and is what UK ministers are backing despite saying &quot;nothing shall be patentable which is not patentable already&quot;.</p>        <p>Here\'s a few more examples of what the EPO has already decided is \'technical\' (and granted patents for):</p>        <p> - emailing the recipient of a gift, to ask where they would like their gift delivered (Amazon gift ordering)</p>    <p>- using the same data without retying to update both a sales ledger and stock control</p>    <p>- Tabbed windows (making more efficient use of screen space)</p>        <p>This laughable list is, unfortunately, almost endless.</p>        <p>This \'computing is technical, so software should be patentable\' argument is like saying that music should be patentable because playing it in a stereo system produces physical effects in the loudspeaker. Software ideas are independent from the hardware in the same way that music is independent of the reproduction equipment.</p>        <p>Here is another way to look at why the \'controllable forces of nature\' definition of \'technical\' makes sense:</p>    <p> </p>    <p>A computer is a Turing machine - programs are logically equivalent to maths, and that is why they should remain unpatentable. As soon as you allow algorithms to be patented, then ideas and everything in human endeavour follows, including voting systems and social organisation methods.</p>        <p>The question &nbsp;boils down to the two sides of the argument:</p>    <p>a) If physical processes are patentable, why should it make any difference whether they run on special hardware for that process or on general purpose hardware (i.e. a computer)?</p>        <p>b) If rules of organisation and calculation are not patentable why should it make any difference whether I run them in my head, with pencil and paper, or with today\'s normal tool - a universal computer?</p>        <p>Both these apparently-logical arguments cannot be right, and in fact the 2nd argument is right because the economic argument comes in here: abstract ideas, regardless of their applicability, are produced without experimentation cost, applicable to an infinite number of problems and are replicated at zero cost, with no overhead to which patent costs could be added. This is the right place to draw the line between what is and isn\'t patentable.</p>        <p>Ideas should not be patentable. The FFII proposals distinguish between mind and matter and invention and implementation. In the real world making complex systems that work is difficult - in software it is easy. Your for loops will not overheat and melt a nearby function, and neither will an array cause electrical interference in your hash function. So patents are applicable to the industrial world of \'controllable forces of nature\', not to the world of algorithms and rules of organisation and calculation.</p>        <p>There will always be borderline cases and FFII have set up a</p>    <p>benchmarking suite of example patents against which legislation can be tested.</p>        <p>Advances in software are like advances in science. Everyone is building on the work of those who went before by making small improvements - \'standing on the shoulders of giants\'. Free publication and re-use of ideas is an essential component of this development. Would having to pay a licensing fee for the use of every idea or reference in your PhD thesis increase your innovation? Where would we be if Newton or Einstein, or any others of a host of scientists in the last 200 years had patented their ideas? </p>        <p>The Free software movement has shown in the last 15 years that a co-operative model of software writing is more efficient than a closed, proprietary one, at least within the commodity zone of general-purpose software such as operating systems, data protocols and office software. The internet has become a remarkably pervasive thing over that same time period, precisely because it runs on open, patent-free standards. Everyone can use it on an equal footing and write interesting applications for it without payments or legal restrictions.</p>        <p>If Tim Berners-Lee had patented HTTP back in 1987 the whole world would be a great deal poorer. We wouldn\'t have the web in the ubiquitous form we have it today - perhaps we wouldn\'t have it at all. And he probably wouldn\'t even be better off as he\'s just won a prize of a million dollars for his contribution to mankind. He would have struggled to make that much money from a patented, and thus stangled-at-birth web. Just because something is a good idea, doesn\'t mean it must be patented, or even patentable.</p>        <p>So far as I can see software patents are a bad thing and have no overall benefit to society or developers. In the long term, all the evidence shows that they will constrain development, reduce innovation, and prevent Free Software and small businesses from competing on a level playing field. &nbsp;They seem to be little more than an effective tool to allow large businesses and lawyers to suppress competition from small ones and individuals, and to move fundamental ideas and algorithms from the public domain to private ownership.</p>        <p>However, powerful forces - the ones who stand to benefit from this legislation - disagree with this and are largely getting their own way in legislation-land at the moment. So, if you don\'t want to see everything under the sun patented, then you need to say so very clearly to your representatives right now.</p>   </div>','An updated, 30 minute, version of the shorter Cambridge talk, describing the problems with software patents and the current state of EU legislation covering this issue. This presentation was given to Lancaster University Phd Computer Science students, on the Isle of Man, on 2nd July 2004.','full_html'),('page',0,73,73,'und',0,'<p><img alt=\"The Old Courthouse\" class=\"image _original\" src=\"/sites/yaffs.net/files/images/OldCrt.jpg\" style=\"text-align: right; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; border-image: initial; float: right; width: 400px; height: 300px; \" title=\"The Old Courthouse\"></p><dl><dt><strong style=\"text-align: left; \">Telephone</strong></dt><dd style=\"text-align: left; \">+44 (0)1223 811679</dd><dt style=\"text-align: left; \">&nbsp;</dt><dt style=\"text-align: left; \"><strong>Email</strong> -<a href=\"mailto:info@aleph1.co.uk\"> info@aleph1.co.uk</a></dt><dt style=\"text-align: left; \"><strong>Post</strong></dt><dd style=\"text-align: left; \">The Old Courthouse<br>123 High Street<br>Bottisham<br>Cambridge<br>CB25 9BA<br>United Kingdom.</dd></dl><p style=\"text-align: -webkit-auto;\">&nbsp;</p><h2 style=\"text-align: left;\">Public Transport - Buses</h2><p style=\"text-align: left;\">You can reach us by bus from the bus station on Drummer Street in the centre of Cambridge, in 20 minutes. Buses run two or three times an hour much of the day. Click for <a href=\"http://www.stagecoachbus.com/cambridge\" target=\"_self\" title=\"Bus Times\"> timetables </a> and under Bus Timetable Lookup enter 10 or 11 in the Service No. box.<br>Look at the map below</p><p style=\"text-align: left;\">&nbsp;The Number 10 bus enters the village from the East end and passes Westwards along the High Street. Get off at the bus shelter on the South side of the High Street about 500 metres after leaving the main (A1303) road to enter the village. The Courthouse is a further 100 metres West and on the other (North) side of the road.</p><p style=\"text-align: left;\">The Number 10 buses leave Drummer Street at the hour and half hour and take 20 minutes.<br><br>The Number 11 bus leaves at 15 and 45 minutes past each hour and travels along the main A1303 road to Newmarket (and them Bury St Edmunds), passing the East end of Bottisham.&nbsp; Get off at the bus shelter on the main road, and walk back past First Copy, (the former White Swan pub) on the High Street; continue about 450 metres West along the High Street towards the centre of Bottisham. The Courthouse is on the North side of the High Street.</p><p style=\"text-align: left;\"><strong>If coming to visit please make an appointment before setting out.</strong></p><p style=\"text-align: left;\"><a href=\"?q=node/323\">Click here for a page with only these maps, for printing out</a>.</p><p style=\"text-align: left;\">This shows the location of Aleph One within Bottisham. Park in the layby on the South side of the road. We are opposite in a large building with three arched windows. There are doors on either side of the building, and you may need to try both to get a response.</p><center><img alt=\"Bottisham map\" src=\"/sites/yaffs.net/files/images/Bottisham.jpg\" style=\"border: 0;\" title=\"Bottisham map\" border=\"0\"></center><p>&nbsp;</p><p>Map below shows where we are in relation to Cambridge and the surrounding roads.</p><center><img alt=\"How to get to Aleph One\" src=\"/sites/yaffs.net/files/images/Cambridge.jpg\" style=\"border: 0;\" title=\"How to get to Aleph One\" border=\"0\"></center>','Everything needed to get in touch with us or visit.','full_html'),('book',0,77,473,'und',0,'<p>This info is significantly out of date, and we have removed it. You might be interested in one of these:</p><ul><li><a href=\"/documents/how-yaffs-works\">How Yaffs Works</a>&nbsp;</li><li><a style=\"border-style: initial; border-color: initial; border-image: initial; outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 12px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; font-family: Verdana, Helvetica, Arial, sans-serif; line-height: 18px; border-width: 0px; padding: 0px; margin: 0px;\" href=\"/documents/yaffs-nand-flash-failure-mitigation\">Yaffs&nbsp;<span class=\"caps\" style=\"border-style: initial; border-color: initial; border-image: initial; outline-width: 0px; outline-style: initial; outline-color: initial; font-size: 0.9em; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; background-position: initial initial; background-repeat: initial initial; border-width: 0px; padding: 0px; margin: 0px;\">NAND</span>&nbsp;Failure Mitigation</a></li><li><a href=\"yaffs-talk-pdf-slides-celf-2007\">Slides from CELF 2007</a></li></ul>','<p>This info has been removed. Formerly it contained:</p><p>Slides fom YAFFS - A NAND-flash filesystem. This was presented at FOSDEM on 23 February 2004, as part of the Embedded Track, and describes the YAFFS filesystem - it&#39;s origins, how it works, explains the differences between NAND and NOR flash and thus why a specialised NAND-flash filesystem is appropriate. It also covers embedded-system use with Yaffs Direct, presents some performance stats, and a comparison with JFFS2, and looks at supporting next-generation NAND with YAFFS2.</p>','full_html'),('book',0,79,79,'und',0,'<div class=\"image\"><a href=\"/drupal/?q=node/110\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_1.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_1.preview.jpg\" /></a><div class=\"caption\">&nbsp;</div> </div>\r\n','YAFFS\r\n','full_html'),('book',0,110,110,'und',0,'<div class=\"image\"><a href=\"/?q=node/111\"><img width=\"640\" height=\"480\" border=\"0\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_2.preview.jpg\" alt=\"yaffs_talk_2.jpg\" /></a><div class=\"caption\">&nbsp;</div> </div> <p>The areas covered by this talk: who\'s involved in the work on YAFFS, and how it got to the current stage, an explanation of the differences between NOR and NAND flash, then we\'ll look at the filesystem itself, covering the filesystem design,&nbsp; licencing, what you need to do to port it to a new OS.</p><p>We\'ll finish with some performance comparisons and the changes present in YAFFS2.&nbsp;</p>','<!-- none -->','full_html'),('book',0,111,111,'und',0,'<div class=\"image\"><a href=\"/drupal/?q=node/112\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_3.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_3.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->','full_html'),('book',0,112,112,'und',0,'<div class=\"image\"><a href=\"?q=node/113\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_4.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_4.preview.jpg\" /></a><div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->','full_html'),('book',0,113,113,'und',0,'<div class=\"image\"><a href=\"/drupal/?q=node/114\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_5.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_5.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->\r\n','full_html'),('book',0,114,114,'und',0,'<div class=\"image\">   <a href=\"?q=node/115\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_6.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_6.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->','full_html'),('book',0,115,115,'und',0,'<div class=\"image\">   <a href=\"?q=node/116\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_7.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_7.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->','full_html'),('book',0,116,116,'und',0,'<div class=\"image\">   <a href=\"?q=node/117\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_8.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_8.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->','full_html'),('book',0,117,117,'und',0,'<div class=\"image\">   <a href=\"?q=node/118\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_9.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_9.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->\r\n','full_html'),('book',0,118,118,'und',0,'<div class=\"image\">   <a href=\"?q=node/119\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_10.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_10.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>\r\n','<!-- none -->\r\n','full_html'),('book',0,119,119,'und',0,'<div class=\"image\">   <a href=\"?q=node/120\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_11.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_11.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,120,120,'und',0,'<div class=\"image\">   <a href=\"?q=node/121\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_12.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_12.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,121,121,'und',0,'<div class=\"image\">   <a href=\"?q=node/122\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_13.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_13.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,122,122,'und',0,'<div class=\"image\">   <a href=\"?q=node/123\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_14.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_14.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,123,123,'und',0,'<div class=\"image\">   <a href=\"?q=node/124\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_15.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_15.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->\r\n','full_html'),('book',0,124,124,'und',0,'<div class=\"image\">   <a href=\"?q=node/125\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_16.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_16.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,125,125,'und',0,'<div class=\"image\">   <a href=\"?q=node/126\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_17.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_17.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,126,126,'und',0,'<div class=\"image\">   <a href=\"?q=node/127\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_18.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_18.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,127,127,'und',0,'<div class=\"image\">   <a href=\"?q=node/128\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_19.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_19.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,128,128,'und',0,'<div class=\"image\">   <a href=\"?q=node/129\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_20.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_20.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,129,129,'und',0,'<div class=\"image\">   <a href=\"?q=node/130\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_21.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_21.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,130,130,'und',0,'<div class=\"image\">   <a href=\"?q=node/131\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_22.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_22.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,131,131,'und',0,'<div class=\"image\">   <a href=\"?q=node/132\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_23.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_23.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,132,132,'und',0,'<div class=\"image\">   <a href=\"?q=node/133\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_24.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_24.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,133,133,'und',0,'<div class=\"image\">   <a href=\"?q=node/134\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_25.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_25.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,134,134,'und',0,'<div class=\"image\">   <a href=\"?q=node/135\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_26.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_26.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,135,135,'und',0,'<div class=\"image\">   <a href=\"?q=node/136\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_27.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_27.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,136,136,'und',0,'<div class=\"image\">   <a href=\"?q=node/137\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_28.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_28.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,137,137,'und',0,'<div class=\"image\">   <a href=\"?q=node/77\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"yaffs_talk_29.jpg\" src=\"sites/yaffs.net/files/images/content/yaffs_talk_29.preview.jpg\" /></a>   <div class=\"caption\">&nbsp;</div> </div>','<!-- none -->','full_html'),('book',0,169,169,'und',0,'<div class=\"image\"><a href=\"?q=node/170\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"talk_emdebsys_1.jpg\" src=\"sites/yaffs.net/files/images/content/talk_emdebsys_1.jpg\" /></a><div class=\"caption\">&nbsp;</div></div>\r\n','<div class=\"image\"><a href=\"?q=node/170\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"talk_emdebsys_1.jpg\" src=\"/files/yaffs.net/images/content/talk_emdebsys_1.jpg\" /></a><div class=\"caption\">&nbsp;</div></div>\r\n','full_html'),('book',0,196,196,'und',0,'<div class=\"image\"><a href=\"?q=node/197\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"talk_arm_general_1.jpg\" src=\"sites/yaffs.net/files/images/content/talk_arm_general_1.jpg\" /></a><div class=\"caption\">&nbsp;</div></div>\r\n','<div class=\"image\"><a href=\"?q=node/170\"><img width=\"640\" height=\"480\" border=\"0\" alt=\"talk_arm_general_1.jpg\" src=\"/files/yaffs.net/images/content/talk_arm_general_1.jpg\" /></a><div class=\"caption\">&nbsp;</div></div>\r\n','full_html'),('book',0,265,265,'und',0,'<p>If you want to boot your system off a CF disk, you need to repartition it. You will need a reasonably sized CF though (over 16MB).</p> <p>First, you boot into <tt class=\"FILENAME\">initrds3.gz</tt> with a kernel that supports CF disks. When this has booted up, you need to execute <b class=\"COMMAND\">fdisk /dev/hda</b>. You can then repartition your    system. Ideally you should make a 4-6MB Fat16 partition as /dev/hda1,   and then assigning the rest for Linux (/dev/hda2). When you have done this,  boot into EPOC and format the CF. Install Arlo, a kernel and an initrd in the  root of this partition. Now you don\'t have to re-install Arlo every time you  reboot.</p> <p>To boot a CF based system, you need to pass the appropriate option into  the kernel (see <a href=\"http://www.aleph1.co.uk../../../armlinux/book/x977.html#PASSING\">the section called <i>Passing Additional Parameters into the Kernel</i></a>), alternatively, you will need to  use the <b class=\"COMMAND\">rdev</b> command to alter the flags in your homebrew  kernel before you glue it.</p> ','<p>If you want to boot your system off a CF disk, you need to repartition it. You will need a reasonably sized CF though (over 16MB).</p> <p>First, you boot into <tt class=\"FILENAME\">initrds3.gz</tt> with a kernel that supports CF disks. When this has booted up, you need to execute <b class=\"COMMAND\">fdisk /dev/hda</b>. You can then repartition your    system. Ideally you should make a 4-6MB Fat16 partition as /dev/hda1,   and then assigning the rest for Linux (/dev/hda2). When you have done this,  boot into EPOC and format the CF. Install Arlo, a kernel and an initrd in the  root of this partition. Now you don\'t have to re-install Arlo every time you  reboot.</p> <p>To boot a CF based system, you need to pass the appropriate option into  the kernel (see <a href=\"http://www.aleph1.co.uk../../../armlinux/book/x977.html#PASSING\">the section called <i>Passing Additional Parameters into the Kernel</i></a>), alternatively, you will need to  use the <b class=\"COMMAND\">rdev</b> command to alter the flags in your homebrew  kernel before you glue it.</p> ','full_html'),('book',0,271,271,'und',0,'<p>Uploading can be achieved via the JTAG port using software such a Jflash and Jflash-linux. Usage for Windows or GNU/Linux host is essentially identical. The examples given here use GNU/Linux syntax.</p> <div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN1447\">Using JTAG and Jflash-linux</a></h2><p>In order to use the JTAG programmer, you need to connect the parallel port of your computer to the JTAG port of the device you want to program. The details of this vary from device to device - see the relevant install chapter. Ensure the device is powered up. Jflash and Jflash-linux both autosense for available parallel ports so it shouldn\'t matter where you plug it in.</p><p>You can then issue the following command as root:</p><p class=\"LITERALLAYOUT\"><b class=\"COMMAND\">./Jflash-linux blob-1.0.7b</b></p><p>and you should see something like the following (this example is using the blob-1.08-pre2 binary on the CD on a LART). After uploading the device will reset itself before running Blob.</p><table width=\"100%\" border=\"0\" bgcolor=\"#e0e0e0\"><tbody><tr><td><pre class=\"SCREEN\">using printer port at 378<br />Seems to be a pair of 28F160F3, bottom boot. Good. <br /><br />Starting erase for    c8e bytes<br />Erasing block   0   <br />Erasing done                                           <br />Starting programming<br />Writing flash at hex address      1b0, 13.44% done    <br />Writing flash at hex address      3d0, 30.37% done    <br />Writing flash at hex address      5f0, 47.29% done    <br />Writing flash at hex address      810, 64.22% done    <br />Writing flash at hex address      a30, 81.14% done <br />Writing flash at hex address      c50, 98.07% done <br />Programming done                                            <br />Starting verify<br />Verifying flash at hex address      643, 49.88% done    <br />Verification successful!                           </pre></td></tr></tbody></table><div class=\"NOTE\"><blockquote class=\"NOTE\"><p><b>Note: </b>If something is wrong you will see error messages like the following:</p></blockquote></div><table width=\"100%\" border=\"0\" bgcolor=\"#e0e0e0\"><tbody><tr><td><pre class=\"SCREEN\">error, failed to read device ID<br />ACT: 0000 0000000000000000 00000000000 0<br />EXP: X001 0001000010000100 00000110101 1<br /><br />failed to read device ID for the SA-1100</pre></td></tr></tbody></table><p>or</p><table width=\"100%\" border=\"0\" bgcolor=\"#e0e0e0\"><tbody><tr><td><pre class=\"SCREEN\">error, failed to read device ID<br />ACT: 1111 1111111111111111 11111111111 1<br />EXP: X001 0001000010000100 00000110101 1<br /><br />failed to read device ID for the SA-1100</pre></td></tr></tbody></table><p>or</p><table width=\"100%\" border=\"0\" bgcolor=\"#e0e0e0\"><tbody><tr><td><pre class=\"SCREEN\">error, failed to read device ID<br />ACT: 1001 1010000111001011 01011000111 1<br />EXP: X001 0001000010000100 00000110101 1<br /><br />failed to read device ID for the SA-1100</pre></td></tr></tbody></table><p>There are a number of possible causes. If you get all 1\'s then you maybe using the wrong parallel port, or the cable or dongle is not plugged in, or the device is not powered up. If you get all zeros then you may be using the wrong version of JFlash-linux, or (on a LART) you may be suffering from the \'JTAG reset problem\', see <a href=\"http://www.aleph1.co.uk../../../armlinux/book/x350.html#LARTJTAGPROB\">the section called <i>LART JTAG reset problem</i> in Chapter 3</a>. If you get random numbers some of the time and zeros the rest of the time then you are almost certainly using the wrong version of JFlash-linux.</p></div> ','<p>Uploading can be achieved via the JTAG port using software such a Jflash and Jflash-linux. Usage for Windows or GNU/Linux host is essentially identical. The examples given here use GNU/Linux syntax.</p> <div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN1447\">Using JTAG and Jflash-linux</a></h2><p>In order to use the JTAG programmer, you need to connect the parallel port of your computer to the JTAG port of the device you want to program. The details of this vary from device to device - see the relevant install chapter. Ensure the device is powered up. Jflash and Jflash-linux both autosense for available parallel ports so it shouldn\'t matter where you plug it in.</p>','full_html'),('book',0,274,274,'und',0,'<div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN1555\">Obtaining the Kernel Source</a></h2><p>To compile your own kernel you need the source and the right set of patches. For all cases you need the base source tree and the ARM kernel patch. The SA1100 patches are usually a good idea too, and are necessary for SA1100 or later processors. For some devices, especially newly-supported ones, you may need a further patch for that device. </p><dl><p><b>Kernel Source</b></p><dt>Base source tree</dt><dd><p><tt class=\"FILENAME\">linux-2.4.1-tar.bz2</tt></p><p>or <tt class=\"FILENAME\">linux-2.4.1-tar.gz</tt></p></dd><dt>ARM kernel (Russell King) patch</dt><dd><p><tt class=\"FILENAME\">patch-2.4.1-rmk1.gz</tt></p></dd><dt>SA1100 (Nico Pitre) patch</dt><dd><p><tt class=\"FILENAME\">diff-2.4.0-rmk1-np2.gz</tt></p></dd></dl><p>Each applied patch adds a suffix to the kernel name, so a kernel made with the 2.4.1 source with the rmk1 ARM kernel patch and the np2 SA1100 patch would be called zImage-2.4.1-rmk1-np2. The letters indicate the patch source. In the above cases they are the names of the patch maintainers Russell King and Nico Pitre respectively. Note that although they use different naming conventions, both patch files are of the same type.</p><p>The kernel source is normally available in both gzipped and bzip2 form. The latter is significantly smaller so that is normally the better one to download. You will need the bzip2 utility to decompress bzip2 files.</p><p>All these are on the CD but you will need to copy them into your development directory. Alternatively, obtain the latest version of kernel base, ARM kernel and SA1100 patches from these ftp sites but remember to use your local mirror, e.g. ftp://ftp.uk.kernel.org/ for the UK mirror.</p><dl><p><b>Kernel Source - Current Version</b></p><dt>Kernel Base</dt><dd><p><a target=\"_top\" href=\"ftp://ftp.kernel.org/pub/linux/kernel/v2.4/\">ftp://ftp.kernel.org/pub/linux/kernel/v2.4/</a></p></dd><dt>ARM kernel Patch</dt><dd><p><a target=\"_top\" href=\"ftp://ftp.arm.linux.org.uk/pub/linux/arm/source/kernel-patches/v2.4/\">ftp://ftp.arm.linux.org.uk/pub/linux/arm/source/kernel-patches/v2.4/</a></p></dd><dt>SA1100 Patch</dt><dd><p><a target=\"_top\" href=\"ftp://ftp.arm.linux.org.uk/pub/linux/arm/people/nico/\">ftp://ftp.arm.linux.org.uk/pub/linux/arm/people/nico/</a></p></dd></dl><p>The source tree can then be unpacked into your development source directory. You can put this anywhere you like, but it must be kept separate from your native source tree in /usr/src/linux. This is because many systems expect the version of headers in /usr/src/linux to correspond to the version of the kernel and glibc being run on the host machine. This is usually different from the version you are using for ARMLinux development. We recommend putting your ARM kernel source tree in <tt class=\"FILENAME\">/usr/arm-linux/linux</tt> (this is alongside the toolchain in a cross-compilation environment). Note that you need a fair amount of disk space free. The unpacked 2.4.1 source is a little over 100MB, and you should have two copies of it, and configuring and compiling only makes it bigger.</p><p>In your development directory enter the following command to unpack the source:</p><p><b class=\"COMMAND\">tar -xzvf linux-2.4.1.tar.gz</b></p><p>Or if you have the bzipped version, use these options:</p><p><b class=\"COMMAND\">tar -xIvf linux-2.4.1.tar.bz2</b></p><p>Finally, unzip/untar the source before applying the ARM and SA1100 patches to give you a new kernel source tree. Using patch -p0 can confuse various versions of patch so its best to cd into the linux directory and use p1, thus:</p><p>  </p><p class=\"LITERALLAYOUT\"><b class=\"COMMAND\">cd linux</b><br /> <b class=\"COMMAND\">zcat ../patch-2.4.0-rmk1.gz | patch -p1</b>&nbsp;<br /> <b class=\"COMMAND\">zcat ../diff-2.4.0-rmk1-np2.gz | patch -p1</b>&nbsp;</p><div class=\"SECT3\"><h3 class=\"SECT3\"><a name=\"AEN1625\">Kernel source mangement</a></h3><p>If you are intending to work on the kernel, the first thing you should do is take a copy of the pristine tree. This is so that you can generate patches against it after you have made changes. The simplest way to do this is simply to do:</p><p class=\"LITERALLAYOUT\"><b class=\"COMMAND\">cp</b>&nbsp;<tt class=\"OPTION\">-a</tt>&nbsp;linux&nbsp;linux-2.4.1.orig</p><p>However, as in practice you will only ever change a few files and having two copies of the whole thing, 99% of which are going to remain untouched, means that you may prefer to use hard links to create the copy as then only the changed files take up space. This method relies on the editor creating a new file after every save so that the original is preserved. If you have need of such an editor, take a look at Micro<span class=\"ACRONYM\">Emac</span>s or <span class=\"ACRONYM\">GNU</span> <span class=\"ACRONYM\">Emac</span>\'s <i class=\"EMPHASIS\">back-up-when-copying-when-linked</i> facility. To create a hard-linked source copy do this:</p><p class=\"LITERALLAYOUT\"><b class=\"COMMAND\">cp</b>&nbsp;<tt class=\"OPTION\">-a</tt>&nbsp;<tt class=\"OPTION\">-l</tt>&nbsp;linux&nbsp;linux-2.4.1.orig</p><p>Alternatively, you can use CVS to control your source versions, but that is not covered here.</p></div></div> <div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN1641\">Making a Kernel</a></h2><p>First you should tidy up the source to get rid of old files and stale dependencies, especially if you have previously configured for a different device with <b class=\"COMMAND\">make mrproper</b>. You should then issue the appropriate <b class=\"COMMAND\">make <i class=\"EMPHASIS\">target-device</i>_config</b> command to set up a default configuration file for your target device. The list of possibilties for <i class=\"EMPHASIS\">target-device</i> is found in <tt class=\"FILENAME\">linux/arch/arm/def-configs/</tt>. You will then need to set up a kernel configurations file using the defaults which have just been created. This can be accomplished with the <b class=\"COMMAND\">make oldconfig</b> command. Finally, <b class=\"COMMAND\">make dep</b> sets up kernel dependencies and sub-configuration files on the basis of the specified config whilst <b class=\"COMMAND\">make zImage</b> builds the kernel image. The kernel should consequently appear in <tt class=\"FILENAME\">linux/arch/arm/boot/zImage</tt>. So, to summarise:</p><p class=\"LITERALLAYOUT\"><b class=\"COMMAND\">make mrproper</b><br /> <b class=\"COMMAND\">make <i class=\"EMPHASIS\">target-device</i>_config</b><br /> <b class=\"COMMAND\">make oldconfig</b><br /> <b class=\"COMMAND\">make dep</b><br /> <b class=\"COMMAND\">make zImage</b></p></div> ','<div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN1555\">Obtaining the Kernel Source</a></h2><p>To compile your own kernel you need the source and the right set of patches. For all cases you need the base source tree and the ARM kernel patch. The SA1100 patches are usually a good idea too, and are necessary for SA1100 or later processors. For some devices, especially newly-supported ones, you may need a further patch for that device. </p><dl><p><b>Kernel Source</b></p><dt>Base source tree</dt><dd><p><tt class=\"FILENAME\">linux-2.4.1-tar.bz2</tt></p><p>or <tt class=\"FILENAME\">linux-2.4.1-tar.gz</tt></p>','full_html'),('book',0,285,285,'und',0,'<p>In order to provide you with a working knowledge of the Linux filesystem, the following topics will be introduced in this section.</p><ol type=\"1\"><li><p>The Linux Root Filesystem</p></li><li><p>Permissions</p></li><li><p>Alternative Filesystems</p></li></ol><div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN2664\">Overview</a></h2><p>The filesystem is made up of <i class=\"EMPHASIS\">files</i> and <i class=\"EMPHASIS\">folders</i> or directories. The top level folder is called the <i class=\"EMPHASIS\">root</i> folder and contains all of the files that are pertinent to your system. Each file within this system is allotted a name and a path on the basis of where it lies in relation to the root folder. Thus a sample file -<tt class=\"FILENAME\">alephlinux.txt</tt>- may be found at <tt class=\"FILENAME\">/home/letters/alephlinux.txt</tt> where the forward slash <span class=\"QUOTE\">&quot;/&quot;</span> before <i class=\"EMPHASIS\">home</i> denotes root. </p><div class=\"IMPORTANT\"><blockquote class=\"IMPORTANT\"><p><b>Important: </b>The new user must also appreciate that the filesystem is case-sensitive and therefore distinguishes between <tt class=\"FILENAME\">ALEPHLINUX.txt</tt> and <tt class=\"FILENAME\">alephlinux.txt</tt>.</p></blockquote></div><p>Linux also provides support for long filenames although you should avoid the use of symbols like <span class=\"QUOTE\">&quot;@&quot;</span> within filenames, as they are used for other purposes.</p></div><div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN2685\">The Linux Root Filesystem</a></h2><p>The following schematic provides a simple representation of the most important directories and files which make up the root filesystem whilst the subsequent sub-section provides a brief description of the filesystem\'s structure. For more information about the root filesystem, enter <b class=\"COMMAND\">man hier</b> at the prompt for a full description.</p><div class=\"FIGURE\"><a name=\"LINUX-ROOT-FILESYSTEM\" /><p><b>Figure 9-1. Linux Root Filesystem</b></p><div class=\"MEDIAOBJECT\"><p><div class=\"photo\">\r\n<a href=\"?q=node/284\"><img src=\"?q=img_assist/gen/284\" width=\"545\" height=\"304\" alt=\"Linux - Root filesystem\" />\r\n<div class = \"caption\">Linux - Root filesystem\r\n</div></a>\r\n</div>\r\n</p></div></div></div><dl><p><b>Directories</b></p><dt><tt class=\"FILENAME\">/usr</tt></dt><dd><p>Contains files and sub-directories which may be shared between machines. Important sub-directories include:</p><ul><li><p><tt class=\"FILENAME\">/usr/lib</tt> which contains programming and language libraries</p></li><li><p><tt class=\"FILENAME\">/usr/local</tt> which provides the location for user-specific programs and files</p></li><li><p><tt class=\"FILENAME\">/usr/include</tt> for C #include files</p></li></ul></dd><dt><tt class=\"FILENAME\">/etc</tt></dt><dd><p>all configuration files should be in here (often in subdirectories)</p></dd><dt><tt class=\"FILENAME\">/home</tt></dt><dd><p>contains home directories for all users on the system. <tt class=\"FILENAME\">/home/paul</tt> would therefore be the home directory for user <i class=\"EMPHASIS\">paul</i>.</p></dd><dt><tt class=\"FILENAME\">/bin</tt></dt><dd><p>contains fundamental executable files (commands or programs) used by users. Only the basic ones are here, most are in /usr/local/bin, but usually a user doesn\'t care where the executable is actually stored. <b class=\"COMMAND\">which &lt;commandname&gt;</b> will tell you where an executable actually resides.</p></dd><dt><tt class=\"FILENAME\">/sbin</tt></dt><dd><p>includes executable files which are for system administration, as opposed to programs used by users. An example of this would be the <b class=\"COMMAND\">shutdown</b> command which closes the system down properly.</p></dd><dt><tt class=\"FILENAME\">/mnt</tt></dt><dd><p>location for <i class=\"EMPHASIS\">mounting</i> filesystems. For supplementary information, consult <a href=\"http://www.aleph1.co.uk../../../armlinux/book/x2654.html#ALTFILESYS\">the section called <i>Alternative Filesystems</i></a></p></dd><dt><tt class=\"FILENAME\">/tmp</tt></dt><dd><p>a directory which provides the temporary location for different programs. <tt class=\"FILENAME\">/tmp</tt> files tend to be deleted when the system is re-booted.</p></dd><dt><tt class=\"FILENAME\">/dev</tt></dt><dd><p>contains special <i class=\"EMPHASIS\">pseudo</i> files which give access to devices like the keyboard - /dev/kbd - and the virtual terminals - /dev/console, /dev/tty0 and /dev/tty1.     </p></dd><dt><tt class=\"FILENAME\">/var</tt></dt><dd><p>a directory which contains files which can grow through usage. Typical examples include email message files and system accounting files. </p><ul><li><p><tt class=\"FILENAME\">/var/adm</tt> for per-process accounting records</p></li><li><p><tt class=\"FILENAME\">/var/tmp</tt> for temporary files which are not deleted at re-boot time.</p></li><li><p><tt class=\"FILENAME\">/var/spool</tt> for running system processes. /var/spool/mail would be a typical file in this sub-directory </p></li></ul></dd></dl></div><div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN2820\">Permissions</a></h2><p>Although you should now have some appreciation of the Linux filesystem it is important to realise that Linux can be used in a multi-user or networked environment. It is therefore sensible to learn about the various types of <i class=\"EMPHASIS\">role</i> and <i class=\"EMPHASIS\">permission</i> which can be associated with a file so that the file <i class=\"EMPHASIS\">owner</i> can decide exactly who has access to files.</p><p>Any user may consequently fit into any one of three roles which include:</p><ol type=\"1\"><li><p>the <i class=\"EMPHASIS\">ownership</i> role</p></li><li><p>the <i class=\"EMPHASIS\">group</i> role</p></li><li><p>the <i class=\"EMPHASIS\">other</i> role</p></li></ol><p>The <i class=\"EMPHASIS\">owner</i> of a file can change file permissions at will. Moreover, a file may be associated with a <i class=\"EMPHASIS\">group</i> which is useful in a collaborative project context in which file access can be restricted to group members. Finally, the <i class=\"EMPHASIS\">other</i> role applies to a user who is neither the owner of the file nor the member of the group which is associated with the file.</p><p>In a similar vein, for every Linux file, three types of permission can be applied to each of the three roles. These permission <i class=\"EMPHASIS\">switches</i> are as follows</p><ol type=\"1\"><li><p><span class=\"ABBREV\">R</span> (Read): enables the user to read files, or (for a directory) to list files on the system</p></li><li><p><span class=\"ABBREV\">W</span> (Write): allows for the alteration or deletion of files, or (for a directory) deleting, adding and renameing of files</p></li><li><p><span class=\"ABBREV\">Execute</span> (Execute): allows for the execution of a file where it is an executable or for changing directories.</p></li></ol><p>In order to clarify matters, this information can be most effectively presented in tabular form. Note that a dash in the line of text denotes the absence of a permission whilst <span class=\"ABBREV\">r</span>, <span class=\"ABBREV\">w</span> or <span class=\"ABBREV\">e</span> indicates that one of the three types of switch is activated.</p><div class=\"TABLE\"><p><b>Table 9-3. Permissions by Role</b></p><table border=\"1\" class=\"CALSTABLE\"><tbody><tr><th valign=\"top\" align=\"left\">Owner</th><th valign=\"top\" align=\"left\">Group</th><th valign=\"top\" align=\"left\">Other</th></tr><tr><td valign=\"top\" align=\"left\">r w x</td><td valign=\"top\" align=\"left\">r w x</td><td valign=\"top\" align=\"left\">r - x</td></tr></tbody></table></div><p>To illustrate all of the above, consider a situation where we want to know the permissions which apply to a particular file. After invoking the <b class=\"COMMAND\">ls -l</b> &lt;filename&gt; command, our hypothetical output might look some thing like the following:</p><p class=\"LITERALLAYOUT\">&mdash;rw&mdash;r&mdash;&mdash;r&mdash;&mdash;&nbsp;1&nbsp;paul&nbsp;paul&nbsp;388&nbsp;June&nbsp;10&nbsp;09:30&nbsp;notes.txt</p><p>Reading across the listing from left to right, the first character position show the file\'s filetype which in this example is a normal file. Other possibilities include:</p><ol type=\"1\"><li><p>d for a directory</p></li><li><p>c for a device</p></li><li><p>b for a socket</p></li><li><p>s for a pipe</p></li></ol><p>The remaining nine bits apply to the user, group and other roles respectively with three bits being alotted to each of the roles. Thus our hypothetical output shows that the user has <i class=\"EMPHASIS\">read</i> and <i class=\"EMPHASIS\">write</i> permissions whilst the <i class=\"EMPHASIS\">group</i> and <i class=\"EMPHASIS\">other</i> roles have read permission only. Note also that a dash denotes the absence of a permission.</p><p>If however, it becomes necessary to change file permissions, this can be accomplished by:</p><ol type=\"1\"><li><p>setting file permissions with octal numbers</p></li><li><p>setting file permissions with a combination of symbols</p></li><li><p>setting the setuid, setgid and sticky bits</p></li></ol><p>To alter a file\'s permissions with numbers, Linux uses four numbers which determine permission types including:</p><ol type=\"1\"><li><p>4: read permissions</p></li><li><p>2: write permissions</p></li><li><p>1: execute permissions</p></li><li><p>0: no permissions</p></li></ol><p>Therefore, to alter the permissions status of our hypothetical file so that the <i class=\"EMPHASIS\">group</i> has <i class=\"EMPHASIS\">read</i> and <i class=\"EMPHASIS\">write</i> permissions, we would add 4 (read permission) and 2 (write permission) together before issuing the following command:</p><p><b class=\"COMMAND\">chmod 664 notes.txt</b> </p><p>The following table summarises the situation thus far:</p><div class=\"TABLE\"><p><b>Table 9-4. Permissions by Numbers</b></p><table border=\"1\" class=\"CALSTABLE\"><tbody><tr><th valign=\"top\" align=\"left\">Role</th><th valign=\"top\" align=\"left\">Permission</th><th valign=\"top\" align=\"left\">Calculation</th></tr><tr><td valign=\"top\" align=\"left\">Owner</td><td valign=\"top\" align=\"left\">6</td><td valign=\"top\" align=\"left\">4+2+0 (r+w+e)</td></tr><tr><td valign=\"top\" align=\"left\">Group</td><td valign=\"top\" align=\"left\">6</td><td valign=\"top\" align=\"left\">4+2+0 (r+w)</td></tr><tr><td valign=\"top\" align=\"left\">Other</td><td valign=\"top\" align=\"left\">4</td><td valign=\"top\" align=\"left\">4+0+0 (r)</td></tr></tbody></table></div><p>In a situation where it is necessary to set permissions one role and one permission at a time, the <i class=\"EMPHASIS\">symbolic permission</i> notation can be used. In order to make use of this facility, the user need only remember that permissions may be granted or denied by using the following three symbols in conjunction with the read, write and execute switches that we have already encountered:</p><ol type=\"1\"><li><p>u signifies the user/owner role</p></li><li><p>g represents the group role</p></li><li><p>o signifies the other role</p></li></ol><p>Therefore, in order to allocate a group read and write permissions for the file <tt class=\"FILENAME\">notes.txt</tt> using symbolic notation, the user could enter the following command:</p><p><b class=\"COMMAND\">chmod g+rw notes.txt</b> </p><p>Because many permutations are possible when using this method, the table below gives some indication of how permissions may be alterred. Note that <span class=\"QUOTE\">&quot;+&quot;</span> means that <i class=\"EMPHASIS\">permission is granted</i> whilst <span class=\"QUOTE\">&quot;-&quot;</span> shows that <i class=\"EMPHASIS\">permission is denied</i>.</p><div class=\"TABLE\"><p><b>Table 9-5. Permissions by Symbols</b></p><table border=\"1\" class=\"CALSTABLE\"><tbody><tr><th width=\"33%\" valign=\"top\" align=\"left\">Granted/Denied</th><th width=\"33%\" valign=\"top\" align=\"left\">Permissions</th><th width=\"33%\" valign=\"top\" align=\"left\">String</th></tr><tr><td width=\"33%\" valign=\"top\" align=\"left\">user, group, other</td><td width=\"33%\" valign=\"top\" align=\"left\">read, write, execute</td><td width=\"33%\" valign=\"top\" align=\"left\">ugo+rwx</td></tr><tr><td width=\"33%\" valign=\"top\" align=\"left\">user, group, other</td><td width=\"33%\" valign=\"top\" align=\"left\">read, write, execute</td><td width=\"33%\" valign=\"top\" align=\"left\">ugo-rwx</td></tr><tr><td width=\"33%\" valign=\"top\" align=\"left\">user, group</td><td width=\"33%\" valign=\"top\" align=\"left\">read, write</td><td width=\"33%\" valign=\"top\" align=\"left\">ug+rw</td></tr><tr><td width=\"33%\" valign=\"top\" align=\"left\">user, group</td><td width=\"33%\" valign=\"top\" align=\"left\">read, write</td><td width=\"33%\" valign=\"top\" align=\"left\">ug-rw</td></tr><tr><td width=\"33%\" valign=\"top\" align=\"left\">user</td><td width=\"33%\" valign=\"top\" align=\"left\">read</td><td width=\"33%\" valign=\"top\" align=\"left\">u+r</td></tr><tr><td width=\"33%\" valign=\"top\" align=\"left\">user</td><td width=\"33%\" valign=\"top\" align=\"left\">read</td><td width=\"33%\" valign=\"top\" align=\"left\">u-r</td></tr></tbody></table></div><p>Of course, there is much more that could be said about permissions but for further details on the specifics of topics like sticky bits, shadow passwords and filesystem maintenance, consult the relevant <b class=\"COMMAND\">man</b> page. Refer to <a href=\"http://www.aleph1.co.uk../../../armlinux/book/hlp.html\">the section called <i>Help!</i></a> for advice on using <b class=\"COMMAND\">man</b>.</p><p>The important thing to remember is that if you are having a problem with <i class=\"EMPHASIS\">missing files</i> or some other mysterious error, it is very often due to incorrect permissions somewhere in the system. Always remember to check.</p></div><div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"ALTFILESYS\">Alternative Filesystems</a></h2><p>ARMLinux can similarly make use of a range of filesystems in addition to its own Second Extended filesystem (ext2fs). </p><p>   Under Linux the user will however have to <i class=\"EMPHASIS\">mount a device</i> before it can be accessed and used. This is done with the <b class=\"COMMAND\">mount</b> command but you will initially have to edit the <tt class=\"FILENAME\">/etc/fstab</tt> file as the root user in order to avail of this facility. This file is also used to specify which filesystems should be mounted automatically at boot time. To edit this file - which is just a text file - use <span class=\"APPLICATION\">Vim</span> to open the file with the following command:</p><p><b class=\"COMMAND\">vim /etc/fstab</b></p><p> If your file doesn\'t include a line like the following: </p><p class=\"LITERALLAYOUT\">/dev/hda1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/adfs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;adfs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;noauto,user&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;0</p><p>then you should add one in order to be able to read your RISC OS drive from ARMLinux. Note that if your RISC OS drive is RISC OS 4 with long filenames then this is not supported at the time of writing so you can skip this section. The format of this file is explained in <b class=\"COMMAND\">man fstab</b>.Save and quit by depressing the <b class=\"KEYCAP\">ESC</b> key, waiting for a beep and then typing <b class=\"COMMAND\">:wq /etc/fstab</b>. Where this line is missing, type it in from scratch noting that there should be no spaces between <i class=\"EMPHASIS\">noauto</i> any punctuation and <i class=\"EMPHASIS\">user</i>. if you want this drive to be automatically mounted on boot then change the final 0 to a 1. You will then need to make a mount directory.</p><p><b class=\"COMMAND\">mkdir /adfs</b> </p><p>Congratulations, you are now in a position to mount your RISC OS filesystem with the following command:</p><p><b class=\"COMMAND\">mount /adfs</b> </p><p> You can now access your files from the <tt class=\"FILENAME\">/adfs</tt> directory.</p></div><div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"PACKAGES\">Debian Package Management</a></h2><p>In order to take full advantage of Debian, you need to learn a little about the package management system which underpins it. Debian packages everything in .DEB files. These packages are controlled by a program called <span class=\"ACRONYM\">dpkg</span>, or from a friendlier front-end such as <span class=\"APPLICATION\">dselect</span> or <span class=\"APPLICATION\">apt</span>. The system is extremely powerful; every file on your system is known about by the system and it takes care of a great deal of complexity when installing, removing or upgrading software. It knows about the interdependencies between pieces of software and if you ask to install something it will also get the other things it needs. It knows which files are configuration files and will not overwrite them when upgrading a package. It can also upgrade a running system without breaking things and lets you find out what is on your system. To a large extent the package management system is what makes Debian special and once you understand it you will find it a marvellous facility.</p><p><span class=\"APPLICATION\">dselect</span> is the interface that you will first use. It was designed when Debian had 500 rather than 5000 packages and suffers a bit because of this, but it is quite straightforward to use and a good introduction to the package system. Later you will just use <span class=\"APPLICATION\">apt</span> to install new software. Once <span class=\"APPLICATION\">apt</span> has been taught where to get software (usually off the CD and off the net) you can say things like <b class=\"COMMAND\">apt-get install &lt;software&gt;</b> and it will go away and get it for you, then install it, install anything else necessary and configure them all, often without asking you any further questions apart from telling you which CD to insert or if the download size is OK.</p><p>It is important to understand however that if you want to install software that is not in the Debian archive then everything is not taken care of for you and you will have to understand what is going on and do some work yourself. For example, if obtaining a package from a distribution which is meant for x86-based <span class=\"ACRONYM\">PC</span>s, you will have to compile it from source as the binary versions supplied will not work on an ARM-based machine. Such a procedure is outside this manual\'s scope but - assuming that you want to use a package which is on the ARMLinux <span class=\"ACRONYM\">CD</span> or in the huge Debian archive - read on!</p><p><span class=\"ACRONYM\">dpkg</span> can for example be used to install a package by using the <tt class=\"OPTION\">i</tt> (or --install) switch.</p><p><b class=\"COMMAND\">dpkg -i /cdrom/debian/dists/potato/main/binary-arm/utils/mc&lt;TAB&gt;</b> </p><p>Note that the &lt;TAB&gt; above means press the TAB key, not type in those letters. This uses the shell\'s <i class=\"EMPHASIS\">filename expansion</i> facility to fill in the end of the filename. It\'s a marvellous facility. If it beeps then there is more than one possible answer - press &lt;TAB&gt; again to see the list. It even works on commands.</p><p>However, it is standard practice to use <span class=\"APPLICATION\">apt</span> instead to save typing long pathnames, like this:</p><p><b class=\"COMMAND\">apt-get install mc</b> </p><p>Here <span class=\"APPLICATION\">apt</span> knows where to look for packages, finds <span class=\"APPLICATION\">mc</span> and then uses <span class=\"APPLICATION\">dpkg</span> to actually do the installation, but saves you worrying about the actual location of the package.</p><p> What you have just done is to use <span class=\"ACRONYM\">dpkg</span> to install <span class=\"APPLICATION\">Midnight Commander</span> (<span class=\"ACRONYM\">mc</span>) - a visual shell which does not need X Windows - on your system. Conversely, you may choose to delete or uninstall a package which can be accomplished by using the <tt class=\"OPTION\">-r</tt> (or --remove) switch. The following command consequently removes <span class=\"ACRONYM\">mc</span>.</p><p><b class=\"COMMAND\">dpkg -r mc</b> </p><p>Don\'t be too hasty however. <span class=\"ACRONYM\">MC</span> is an excellent way of navigating the filesystem when used in conjunction with the shell. So why not learn a bit about it before using <span class=\"ACRONYM\">dpkg</span>\'s <tt class=\"OPTION\">-r</tt> switch?</p><p>Congratulations, you\'ve managed to mount your filesystem and have a look at some files. Before removing your <span class=\"ACRONYM\">CD-ROM</span>, you will need to use the <b class=\"COMMAND\">umount</b> command which can either be used to unmount the current filesystem or a specific directory. But please be careful with your typing and key in <tt class=\"USERINPUT\"><b>umount</b></tt> rather than <tt class=\"USERINPUT\"><b>unmount</b></tt>. If it tells you that the <tt class=\"COMPUTEROUTPUT\">filesystem is busy</tt> then your current directory is probably in the mounted filesystem. You need to change directory elsewhere before you can <b class=\"COMMAND\">umount</b>.</p><p><b class=\"COMMAND\">umount /dev/cdrom</b> </p><p>or</p><p><b class=\"COMMAND\">umount /cdrom</b></p><p>In order to find out about other filesystem types and the specifics of the <b class=\"COMMAND\">mount</b> and <b class=\"COMMAND\">umount</b> commands, you can take advantage of the range of commands and applications which are briefly described in <a href=\"http://www.aleph1.co.uk../../../armlinux/book/hlp.html\">the section called <i>Help!</i></a>.</p></div>','<p>In order to provide you with a working knowledge of the Linux filesystem, the following topics will be introduced in this section.</p><ol type=\"1\"><li><p>The Linux Root Filesystem</p></li><li><p>Permissions</p></li><li><p>Alternative Filesystems</p></li></ol><div class=\"SECT2\"><h2 class=\"SECT2\"><a name=\"AEN2664\">Overview</a></h2><p>The filesystem is made up of <i class=\"EMPHASIS\">files</i> and <i class=\"EMPHASIS\">folders</i> or directories. The top level folder is called the <i class=\"EMPHASIS\">root</i> folder and contains all of the files that are pertinent to your system. Each file within this system is allotted a name and a path on the basis of where it lies in relation to the root folder. Thus a sample file -<tt class=\"FILENAME\">alephlinux.txt</tt>- may be found at <tt class=\"FILENAME\">/home/letters/alephlinux.txt</tt> where the forward slash <span class=\"QUOTE\">&quot;/&quot;</span> before <i class=\"EMPHASIS\">home</i> denotes root. </p>','full_html'),('page',0,323,323,'und',0,'<p>This shows the location of Aleph One within Bottisham. Park in the layby on the South side of the road. We are opposite in a large building with three arched windows. There are doors on either side of the building, and you may need to try both to get a response.<br /></p> <center><img alt=\"Bottisham map\" border=\"0\" src=\"/sites/yaffs.net/files/images/Bottisham.jpg\" style=\"border: 0;\" title=\"Bottisham map\"></center> <p>Map below shows where we are in relation to Cambridge and the surrounding roads.<br /></p> <center><img alt=\"How to get to Aleph One\" border=\"0\" src=\"/sites/yaffs.net/files/images/Cambridge.jpg\" style=\"border: 0;\" title=\"How to get to Aleph One\"></center>','<p>Maps of our location for printing.</p>','full_html'),('page',0,325,325,'und',0,'<p>Yaffs is a product from Aleph One Ltd.</p><p>The company was started in 1971.&nbsp; The name Aleph One was chosen to be non-specific.&nbsp; We started selling computer products in 1984, when we were using Biofeedback instruments to control video games on Acorn BBC Microcomputers&nbsp;&nbsp; This led to the development of processor cards for Acorn computers (which had their own unique operating system) which could run the DOS and Windows operating systems. Acorn users ran Windows applications in a window!</p><p>When Acorn left the computer market in 1998 we used our knowledge of other operating systems to move into Linux and then into embedded Linux.&nbsp; We have developed the Yaffs File System specifically to provide a robust journalling file system for NAND Flash chips, and it is now widely used in high-volume products around the world.</p><h2>Visitors</h2><p>We are happy to welcome visitors, though our premises are not a shop. Please contact us to make an appointment and let us know what you would like to talk about or look at.&nbsp;</p><h2>Staff</h2><h3>Core Staff</h3><ul><li>Managing Director: Mr Laurie van Someren</li><li>Charles Manning: Chief Yaffs Architect</li><li>Jenny Hopkins: Tech Support</li></ul><h2>Our name</h2><p>Aleph is the name of the first letter of the Hebrew alphabet.</p><p>A German mathematician active in the mid-19th century, Georg Cantor (1845-1918), realised that infinities came in different sizes; more precisely he showed that the infinite set of all integers was smaller than the infinite set of all real numbers, and gave the labels Aleph Null to the smaller, and Aleph One to the larger set.</p><p>J W Dauben, writing in <em>Scientific American</em>, June 1983, 112-121, said <em>The choice </em>of Aleph as a label for transfinite sets<em> was particularly clever, as Cantor was pleased to admit, because the Hebrew Aleph was also a symbol for the number 1. Since the transfinite cardinals were themselves infinite unities, the Aleph could be taken to represent a new beginning for mathematics.</em></p><p>The concept of Alephs is the subject of a successful book by Amir D Aczel called THE MYSTERY OF THE ALEPH. Paperback about £10 in the UK, ISBN 0-7434-2299-6 (We do not sell it)</p><h3><a name=\"VAT\"></a>VAT</h3><p>We are not registered for VAT and so our prices do not include it.</p><p>&nbsp;</p>','<p>The company was started in 1971.&nbsp; The name Aleph One was chosen to be non-specific.&nbsp; We started selling computer products in 1984.</p><p>In 1984, we were using Biofeedback instruments to control video games on Acorn BBC Microcomputers&nbsp;&nbsp; This led to the development of processor cards for Acorn computers (which had their own operating system) which could run the DOS and Windows operating systems. Acorn users ran Windows applications in a window!</p><p>When Acorn left the computer market we used our knowledge of other operating systems to move into Linux and then into embedded Linux.&nbsp; We have developed the yaffs File System specifically to provide a robust journalling file system for NAND Flash chips, and it is now widely used in high-volume products.</p>','full_html'),('page',0,342,574,'und',0,'<p>DB FUEL and YAFFS team up to offer new generation of database and flash memory solutions for developers of Mobile Handsets and Consumer Electronics.</p>\r\n\r\n<p>Revolutions in flash memory technology have greatly increased the practical uses of flash technology. Aleph One Ltd, a British company focusing on embedded device development, has released YAFFS, a superior file system for storing data on flash. ITTIA is partnering with Aleph One to provide the best data solution for embedded devices requiring persistent storage. The companies have confirmed compatibility between their product lines and will work together to promote the use of their technologies.</p>\r\n\r\n<p>Mobile devices and embedded systems that need to store persistent information have a limited number of choices. The shock resistance, power usage and smaller form factor makes flash memory a superior storage medium in most cases. However, developers using flash face some unique challenges. For example, too many writes to the same location on the flash disk can render that location inoperable. Developers must take these and other characteristics into consideration. In order to help developers overcome these challenges, YAFFS can either be used as a filesystem driver in the operating system, or be linked directly with FUEL to bypass the operating system – even if no operating system is available. This arrangement ensures that data is stored in an optimal format to take advantage of flash memory.</p>\r\n\r\n<p>“We developed YAFFS to provide a high reliability/high performance embedded file system on NAND flash and are delighted that YAFFS has been selected by ITTIA as a partner for their FUEL database,” said Laurie van Someren, Aleph One’s General Manager. “We believe the products combine to provide a highly effective embedded data storage solution and look forward to further cooperation and developments.”</p>\r\n\r\n<p>FUEL has been designed with enough flexibility to support the unique circumstances faced by embedded developers, such as persistent storage on a battery-powered (unreliably powered) device. Because FUEL is fast and small-footprint, it is a perfect match for mobile devices and embedded systems.</p>\r\n\r\n<p>ITTIA and Aleph One are a natural match for other reasons as well. Both companies have a commitment to provide top-notch support at whatever level the customer needs, and can provide development services and support to ensure an optimal solution. “We begin 2006 by emphasizing on meaningful business relationship and we are delighted to announce our solution offering with Aleph One,” said Sasan Montaseri, President of ITTIA, in Bellevue, WA. “Aleph One has served the embedded market for many years and our total solution add special value to our customers.”</p>\r\n\r\n<p>For more information about FUEL, visit www.ITTIA.com/fuel/fuel.html.</p>\r\n\r\n<p>For more information about YAFFS, visit www.yaffs.net</p>\r\n','<p>YAFFS and the new FUEL Database from ITTIA work together. ITTIA has released the first beta of an all-new database for mobile and embedded systems.&nbsp;</p>','full_html'),('page',0,344,576,'und',0,'<p>Yaffs is a filesystem designed specifically for the characteristics of NAND flash. Its well-proven primary features are:</p>\r\n\r\n<ul>\r\n	<li>Fast - typically much faster than alternatives</li>\r\n	<li>Easily ported (currently ported to GNU/Linux, WinCE, eCOS, pSOS, VxWorks, and various bare-metal systems)</li>\r\n	<li>Log structured, providing wear-levelling and making it very robust</li>\r\n	<li>Supports many flash geometries including 2K-Byte and 512-Byte page NAND flash chips</li>\r\n	<li>Supports MLC and SLC flash</li>\r\n	<li>Very fast mount - almost immediate startup</li>\r\n	<li>Typically uses less RAM than comparable File Systems</li>\r\n	<li>Flexible <a href=\"/yaffs-licensing-overview\">Licensing</a> suitable for most circumstances</li>\r\n</ul>\r\n\r\n<p>There is a great deal of information about Yaffs available on this site. This page indexes that information and provides an overview of the product.</p>\r\n\r\n<p>Yaffs is currently at version 2. Yaffs2 supports 2K-byte page flash as well as 512-byte page flash. (Yaffs1 only supports the original 512-byte page flash and is now in maintenance mode.) There is a minimal subset of the filesystem called Yaffs/Direct or the Yaffs Direct Interface which is intended to be used in embedded systems, and can be licensed for use in proprietary systems. Yaffs is available to all under the GPL for use or evaluation; full details of Git access are&nbsp;<a href=\"/download-yaffs-using-git\">available </a></p>\r\n\r\n<p>Yaffs 1 and 2 have both been deployed in numerous commercial applications, some in high volume. abd with large Flash arrays. It has been used in phones, most notably Android phones, GPS receivers, train controllers, speech synthesisers, VOIP chip development kits and other applications.</p>\r\n\r\n<p>We have a number of documents and papers describing how to use Yaffs, how to customise it for your particular hardware/system, and the original considerations and filesystem design of the two versions.</p>\r\n\r\n<h3>Backgrounder</h3>\r\n\r\n<p>The best overview information is currently this 28-slide presentation&nbsp; <a href=\"node/77\">What it Does and How it Does it</a></p>\r\n\r\n<p>A useful historical Timeline on development is<a href=\"node/43\"> here</a></p>\r\n\r\n<h3>Developer Documentation</h3>\r\n\r\n<p>Yaffs Direct Interface - <a href=\"node/349\">User Guide</a>, describing how to port Yaffs to an embedded environment or RTOS using the YDI \'personality\' module\'.</p>\r\n\r\n<p>Brief notes on <a href=\"node/40\">How to use it on GNU/Linux</a></p>\r\n\r\n<p>A <a href=\"node/348\">memory footprint analysis</a> putting some numbers on \'low memory footprint\'.</p>\r\n\r\n<p><a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS embedded structure: YAFFS embedded structure\" height=\"376\" src=\"/sites/yaffs.net/files/images/yaffs-diagram.gif\" width=\"358\" /></a><br />\r\n<strong>Yaffs embedded structure</strong></p>\r\n\r\n<h3>Papers</h3>\r\n\r\n<p></p>\r\n\r\n<p></p>\r\n\r\n<p></p>\r\n\r\n<ul>\r\n	<li><a>The </a><a href=\"node/42\">starting state of NAND MTD</a> which caused the Yaffs filesystem to be designed.</li>\r\n	<li><a href=\"node/37\">The Specifications</a> are available</li>\r\n	<li>Development Notes describing the <a href=\"node/39\">filesystem design decisions and data structures for Yaffs1</a></li>\r\n	<li><a href=\"node/38\">Yaffs2 Filesystem design</a>, covering changes from Yaffs1</li>\r\n	<li><a href=\"http://www.cis.nctu.edu.tw/~lpchang/papers/SAC_wu_sac06.pdf\">Efficient Initialization and Crash Recovery for Log-based File Systems over Flash Memory</a>, describing a mechanism for avoiding full flash scans, even when not properly shut down. This is a likely future development.</li>\r\n</ul>\r\n\r\n<h3>Mailing list</h3>\r\n\r\n<p>There is a <a href=\"http://aleph1.co.uk//mailman/listinfo/yaffs\">Yaffs mailing list</a> for the development and discussion of Yaffs. It\'s a fairly low-traffic list. You will be emailed and asked to confirm your subscription request. You can also browse and search the <a href=\"http://aleph1.co.uk/lurker/splash/index.en.html\">Yaffs mailing list archives</a>.</p>\r\n','YAFFS is a filesystem designed specifically for the characteristics of NAND flash. This page gives an overview of the project - what is available, how it works, how to use it, developer resources, and licensing options.','full_html'),('page',0,345,619,'und',0,'<p>Yaffs is the property of Aleph One Limited.</p>\r\n\r\n<ul>\r\n	<li>Yaffs is <a href=\"/get-yaffs\">available free of charge</a> under the <a href=\"http://www.gnu.org/copyleft/gpl.html\" target=\"_self\" title=\"Gnu Public Licence\">GNU General Public Licence,</a>&nbsp;version 2 (GPL).</li>\r\n	<li>Linking Yaffs to other software creates a derived work and our&nbsp;interpretation of linking includes dynamic and runtime linking;&nbsp;any use of Yaffs creates a derived work.&nbsp;</li>\r\n	<li>Under the GPL, you can test Yaffs with your product on your computers. Do not distribute this test version unless your product is normally licensed under the GPL. If you do not copy and distribute it, there are no requirement under the GPL regarding distribution of a derived work.&nbsp;&nbsp;</li>\r\n	<li>Under the terms of the GPL, derived works must be licensed using the GPL, unless&nbsp;you have a <a href=\"/commercial-licences\">Commercial Licence</a> for Yaffs.</li>\r\n	<li>When you distribute GPLed object code you must make the full source code available too, to anyone who uses your product.&nbsp;(Sections 3.a and 3.b of the GPL, and the sections that follow.)&nbsp;&nbsp;</li>\r\n</ul>\r\n\r\n<p>Circumstances where you need to licence Yaffs other than under the GPL include:-</p>\r\n\r\n<ul>\r\n	<li>If you want to use Yaffs, but want to distribute your code under your licence.</li>\r\n	<li>If you want to run a statically-linked commercial RTOS on top of a Yaffs filesystem.</li>\r\n	<li>if you want to sublicence Yaffs to your customers (under terms other than the GPL).</li>\r\n	<li>If you want to use Yaffs with WindowsCE version 4.&nbsp;WinCE version 3 can use GPL code but WinCE v.4 and later need an additional filesystem interface layer which is not part of Yaffs. This is available at extra cost; please contact us.</li>\r\n</ul>\r\n\r\n<p>In these cases, our <a href=\"/commercial-licences\">Commercial Licence</a> is appropriate.</p>\r\n\r\n<p>If you aren\'t sure whether your needs will be covered by the GPL version, <a href=\"/contact\">get in touch with us</a>.</p>\r\n\r\n<h2>Support</h2>\r\n\r\n<p>While Yaffs is released under GPL we can provide standard support options, consulting in its application to your particular product, or development of specific features to suit your needs or hardware.&nbsp;</p>\r\n\r\n<h2>Helping us to improve Yaffs</h2>\r\n\r\n<p>Although the code is downloadable at no charge, buying this product allows you to express your appreciation of Yaffs. Alternatively you can make a Donation to Aleph One Ltd via PayPal. You can do this at <a href=\"http://www.paypal.com\" target=\"_blank\" title=\"PayPal\">PayPal </a>by sending any sum to sales@aleph1.co.uk&nbsp; We shall appreciate it!</p>\r\n','<p>Yaffs is available free of charge under the <a href=\"http://www.gnu.org/copyleft/gpl.html\" target=\"_self\" title=\"Gnu Public Licence\">GNU General Public Licence,</a> GPL version 2.&nbsp; This free version is suitable for use in contexts where the associated software has a GPL-compatible licence.</p><p>Access to the free GPL code is through <a href=\"/using-git\" target=\"_blank\" title=\"CVS use\">our Git server</a></p>','full_html'),('book',0,347,347,'und',0,'Written by Charles Manning - Originally published at Linuxdevices.org Sept 20th 2002\r\n\r\n<h3>PHB Summary</h3>\r\nYAFFS stands for \"yet another flash file system\"(*). As far as I am aware, YAFFS is the only file system, under any operating system, that has been designed specifically for use with NAND flash. YAFFS is thus designed to work within the constraints of, and exploit the features of, NAND flash to maximise performance. YAFFS uses journaling, error correction and verification techniques tuned to the way NAND typically fails, to enhance robustness. The result is a file system that exploits low-cost NAND chips and is both fast and robust. YAFFS is highly portable and runs under Linux, ucLinux and Windows CE. YAFFS is an open source project.\r\n\r\n<h3>Why NAND flash?</h3>\r\n\r\nEmbedded and mobile systems are increasingly using NAND flash for storage because it has various advantages over other storage technologies. As always though, life is a compromise and those advantages come with some limitations that need to be addressed to provide a robust flash file system.\r\n\r\nHard disks are not a viable storage option for many embedded and handheld systems because they are too big, too fragile and use too much power. For some years now, people have been using common-old NOR flash for file system storage. JFFS and JFFS2 do an excellent job of this for Linux. For storage applications NOR flash is not that great because it is not very dense (ie. not much storage per chip), is costly and is slow to write. NAND flash, on the other hand, is low cost, dense and writes fast, but has other limitations. The most common consumer usage of NAND flash is on SmartMedia cards which are just NAND chips bonded to a carrier card. Consumer use of SmartMedia is driving down NAND prices while\r\ndriving up densities.\r\n\r\nThe standard SmartMedia file system is FAT based and is thus liable to corruptions due to power failures, crashes and other acts of demonic forces. This raises robustness concerns, particularly in embedded systems where a corrupted file system can kill the device. What\'s really needed is a journaling file system that is able to work around the limitations of NAND and exploit it for best performance.\r\n\r\n<h3>History</h3>\r\nThe lead-up to YAFFS started with an investigation into modifying the JFFS2 flash file system to work with NAND flash (**) for some Aleph One customers. It seemed reasonable that the best way to get a file system for NAND flash would be just \"tweaking\" an existing flash file system. On deeper investigation, it became apparent that designing a new file system specifically for NAND might have some benefits.\r\n<table width=\"568\" border=\"1\" bordercolor=\"#000000\" cellpadding=\"1\" cellspacing=\"0\"><col width=\"186\"><col width=\"187\"><col width=\"186\">\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p></p></td>\r\n <td width=\"187\"><p>NOR (typical, varies a lot)</p></td>\r\n <td width=\"186\"><p>NAND</p></td>\r\n</tr>\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p>Density</p></td>\r\n <td width=\"187\"><p>Up to 32MB chips</p></td>\r\n <td width=\"186\"><p>Currently 256MB and growing.</p></td>\r\n</tr>\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p>Cost per MB</p></td>\r\n <td width=\"187\"><p>$1-$2</p></td>\r\n <td width=\"186\"><p>25c</p></td>\r\n</tr>\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p>Access</p></td>\r\n <td width=\"187\"><p>Random</p></td>\r\n <td width=\"186\"><p>Page oriented with spare area on each page. Sequential access within a page.</p></td>\r\n</tr>\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p>Programmability</p></td>\r\n <td width=\"187\"><p>Can modify a single bit.</p></td>\r\n <td width=\"186\"><p>Very limited re-programming.</p></td>\r\n</tr>\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p>Read speed</p></td>\r\n <td width=\"187\"><p>50-100nS</p></td>\r\n <td width=\"186\"><p>10uS page \"seek\" + 50nS per byte</p></td>\r\n</tr>\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p>Program time</p></td>\r\n <td width=\"187\"><p>5uS per byte</p></td>\r\n <td width=\"186\"><p>200uS per page</p></td>\r\n</tr>\r\n<tr valign=\"top\">\r\n <td width=\"186\"><p>Erasure time</p></td>\r\n <td width=\"187\"><p>1s per 64kB block</p></td>\r\n <td width=\"186\"><p>2ms per 16kB block</p></td>\r\n</tr>\r\n<tr valign=\"top\"> \r\n <td width=\"186\"><p>Reliability</p></td> \r\n <td width=\"187\"><p>Relatively immune to corruption. No bad blocks.</p></td>\r\n <td width=\"186\"><p>Needs error correction. Bad blocks marked when shipped.</p></td>\r\n</tr>\r\n</table>\r\n\r\nDesigning an effective flash file system is a difficult task and you need to jump through many hoops of fire to get a useful system. Although both are called \"Flash\", NOR and NAND flash have very different properties. Thus, a flash file system that works with NOR incorporates various mechanisms that are not required for NAND, and NAND needs extra mechanisms not required for NOR.\r\n\r\nFor example, garbage collection performance is largely determined by the erasure time. NOR erases very slowly and thus an effective NOR garbage collection strategy is relatively complex and limits the design options. In comparison NAND erases very quickly; thus these limitations don\'t apply.\r\n\r\nAnother major difference is that NAND is shipped with marked bad blocks on the device, while NOR chips are shipped defect free. Thus, one expects to encounter some failures in NAND and should design accordingly.\r\n\r\nThis lead me to believe that it would be worth designing a file system specifically for NAND flash, exploiting the features of NAND to simplify the design and catering to NAND specific limitations directly, rather than trying to \"bend\" NAND to work with an existing file system architecture, or vice versa.\r\n\r\nThe first conceptual design for YAFFS was drawn up in late December 2001. Once the customers bought in to the idea, things progressed rapidly. The first line of code was cut in January 2002. By May 2002 we had the first publicly available CVS code. We now have at least six different companies using or experimenting with YAFFS in embedded or handheld systems. YAFFS is already very stable and is converging rapidly. We expect to see YAFFS-based products shipped before the end of the year.\r\n\r\n<h3>Design approach</h3>\r\nRather than develop and debug code inside the Linux kernel, I took the approach of developing the file system \"guts\" algorithms - the most complex part -- in a user space program. To achieve this, the code is split into four sections:\r\n<ul>\r\n<li>\r\n<p>yaffs_guts: The file system algorithms. This code is fully portable C.</p>\r\n</li>\r\n<li>\r\n<p>yaffs_fs.c: Interface layer to the Linux VFS. Can be replaced with a test harness for user space developing of yaffs_guts.c</p>\r\n</li>\r\n<li>\r\n<p>nand interface: wrapper layer between yaffs_guts and the NAND memory access functions. eg. calls Linux mtd layer or RAM emulation layer.</p>\r\n</li>\r\n<li>\r\n<p>Portability functions: wrapper functions for services such as memory allocation etc.</p>\r\n</li>\r\n</ul>\r\n\r\nThis modular design has provided a lot of flexibility for testing and development. A user space program and DDD is a far more rapid development environment than continually changing the Linux kernel. Also, a RAM-based NAND emulation layer provides an excellent way to debug the file system in-kernel without special hardware.\r\n\r\nA further spin-off has been that YAFFS is portable to other operating systems. For example, a port of YAFFS for Windows CE was readily achieved by writing a new wrapper layer to hook up to the WinCE file system manager and new NAND access layer. yaffs_guts.c remains 100% portable(***). YAFFS is thus likely to be easily portable to other OSs too.\r\n\r\n<h3>Results</h3>\r\n\r\nRemoving surplus constraints has lead to a simpler design that has improved performance and robustness as well and reduced development time.\r\n\r\nYAFFS reads and writes pretty fast. There is no significant hit due to garbage collection (ie. in most situations garbage collection overheads would not impact usage).</p>\r\n\r\nIt is difficult to give meaningful benchmarks given non-standard hardware. However herewith some results achieved on a StrongARM-based board with 128MB of NAND flash. Write speed is approx 800kB per second and read speed is approx 1.5MB per second. In a weekend stress test I wrote, triple-verified then deleted\r\n25gigabytes of file data without a single bit of file data being corrupted. 25GB exceeds the design lifetime of most embedded or handheld devices.\r\n\r\n<h3>Future</h3>\r\n\r\nAlthough YAFFS already performs well, there is still a lot of room for improvement. Development is continuing to enhance performance and robustness as well as add support software such as utilities, bootloader support and analysis tools.\r\n\r\nI expect to see ports to other OSs too. Increasing the user base of YAFFS is an important way to get more eyes over the code and test it under a wider set of scenarios.\r\n\r\nThe YAFFS development community is growing well with good involvement from people all over the world. YAFFS is realising all the benefits open source projects hope for and will, we expect, continue to grow.\r\n\r\n<h3>Resources</h3>\r\n\r\nThe YAFFS project home page is http://www.aleph1.co.uk/yaffs/\r\nThis provides further YAFFS documentation and instructions for GIT access and the YAFFS mailing list.</p>\r\n\r\n<h3>Footnotes:</h3>\r\n\r\n(*)The YAFFS name came from the first concept document proposing yet another flash file system. Some how that name just stuck.\r\n\r\n(**) NAND support has since been added to JFFS2 by others. The YAFFS, JFFS2 and mtd communities cooperate to provide a rich flexible set of solutions to draw from. As is the nature of open source projects, JFFS2 code was used as a reference for some parts of the YAFFS development, particularly for figuring out the VFS interface. Google for further info on JFFS2 and mtd.\r\n\r\n(***) Some features were added to the guts to enhance WinCE usage. For example, the string comparison function was made configurable to be either strcmp or scricmp because Windows file names are case insensitive.\r\n\r\n<h3>Bio</h3>\r\n\r\nCharles Manning (aka The Embedded Janitor) lives near Christchurch, New Zealand, and has been developing and mopping up embedded systems for twenty years. His hobbies include fly tying and spinning wool. Charles can be reached at <a href=\"mailto:charles@aleph1.co.uk\">charles@aleph1.co.uk</a>.\r\n','YAFFS stands for \"yet another flash file system\"(*). As far as I am aware, YAFFS is the only file system, under any operating system, that has been designed specifically for use with NAND flash. YAFFS is thus designed to work within the constraints of, and exploit the features of, NAND flash to maximise performance. YAFFS uses journaling, error correction and verification techniques tuned to the way NAND typically fails, to enhance robustness. The result is a file system that exploits low-cost NAND chips and is both fast and robust. YAFFS is highly portable and runs under Linux, ucLinux and Windows CE. YAFFS is an open source project.\r\n','full_html'),('book',0,348,348,'und',0,'<p>Yaffs claims a \'low memory footprint\', but what exactly does that mean? How low is low?</p>\r\n\r\n<p>Calculating an exact footprint is no easy task. There are many dependencies. Here is an approximation for Yaffs1 on Linux, assuming the standard block size of 512bytes per page and 16kB per block.</p>\r\n<ol>\r\n<li>Code size. This is dependent on various factors including CPU choice, optiomisation options etc. As a rough guide, the yaffs.o Linux module for x86 is around 55kBytes. This could be made smaller by stripping the debug text and ECC code if you don\'t need that.\r\n\r\n<li>Run-time data structures. Some of these are fixed size and others are generated in runtime and change as your file structures change. As a rough guide though I will give the following:\r\n<ol type=\"a\">\r\n <li>Each yaffs partition needs a device structure of less than 1kB + approx  2-4kB stack with the current implementation.\r\n <li>If shortOpCaches are enabled, then 524 bytes per cache entry (5 to 10 is a \r\ngood number).\r\n <li>About 120 bytes per file. (With short name caching enabled)\r\n <li>About 4 bytes per block of NAND (ie. about 128 bytes per MB of NAND).\r\n <li>About 4kBytes of RAM per MB of NAND for building the file TNode trees that \r\nare used to locate the data chunks.\r\n</ol>\r\n</ol>\r\n\r\n<p>Thus for a system using a 64MByte NAND and say 500 files you can budget on \r\napprox:</p>\r\n\r\n<ul>\r\n<li>1)    55kBytes\r\n<li>2a)    5kB\r\n<li>2b)   3kB (5 cache entries)\r\n<li>2c)   60kB\r\n<li>2d)  16kB\r\n<li>2e)   256kB\r\n</ul>\r\n<b>Total 410kBytes</b>\r\n\r\n<p>The last item, the tnodes, is the biggest expense in Yaffs. This can be \r\nreduced significantly by using a larger page size.</p>\r\n\r\n<p>There are some opportunities to tune some of these numbers so please feel \r\nfree to discusss further if required.</p>\r\n\r\n','Yaffs claims a \'low memory footprint\', but what exactly does that mean? How low is low? \r\n\r\n<p>Calculating an exact footprint is no easy task. There are many dependencies. Here is an approximation for Yaffs1 on Linux, assuming the standard block size of 512bytes per page and 16kB per block.','full_html'),('page',0,351,351,'und',0,'<h1>How to control debugging in yaffs</h1>\r\n\r\n<p>YAFFS provides a debugging mechanism which can be controlled at runtime if you have access to /proc, normally via a shell. If you need to trace things before you get to a shell, then you can set default trace options at compile time.</p>\r\n\r\n<h2>Available Trace Flags</h2>\r\n<table>\r\n <tr>\r\n  <th>name</th><th>C #define</th><th>bitmask value</th>\r\n </tr>\r\n <tr>\r\n  <td>error </td>       <td>YAFFS_TRACE_ERROR </td>           <td>0x00000001</td>\r\n </tr>\r\n <tr>\r\n  <td>os </td>          <td>YAFFS_TRACE_OS </td>              <td>0x00000002</td>\r\n </tr>\r\n <tr>\r\n  <td>allocate </td>    <td>YAFFS_TRACE_ALLOCATE </td>        <td>0x00000004</td>\r\n </tr>\r\n <tr>\r\n  <td>scan </td>        <td>YAFFS_TRACE_SCAN </td>            <td>0x00000008</td>\r\n </tr>\r\n <tr>\r\n  <td>bad_blocks </td>  <td>YAFFS_TRACE_BAD_BLOCKS </td>      <td>0x00000010</td>                                                     \r\n </tr>\r\n <tr>\r\n  <td>erase </td>       <td>YAFFS_TRACE_ERASE </td>           <td>0x00000020</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>gc </td>          <td>YAFFS_TRACE_GC </td>              <td>0x00000040</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>write </td>       <td>YAFFS_TRACE_WRITE </td>           <td>0x00000080</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>tracing </td>     <td>YAFFS_TRACE_TRACING </td>         <td>0x00000100</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>deletion </td>    <td>YAFFS_TRACE_DELETION </td>        <td>0x00000200</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>buffers </td>     <td>YAFFS_TRACE_BUFFERS </td>         <td>0x00000400</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>nandaccess </td>  <td>YAFFS_TRACE_NANDACCESS </td>      <td>0x00000800</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>gc_detail </td>   <td>YAFFS_TRACE_GC_DETAIL </td>       <td>0x00001000</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>scan_debug </td>  <td>YAFFS_TRACE_SCAN_DEBUG </td>      <td>0x00002000</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>mtd </td>         <td>YAFFS_TRACE_MTD </td>             <td>0x00004000</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>always </td>      <td>YAFFS_TRACE_ALWAYS </td>          <td>0x40000000</td>                                                      \r\n </tr>\r\n <tr>\r\n  <td>bug </td>         <td>YAFFS_TRACE_BUG </td>             <td>0x80000000</td>\r\n </tr>\r\n</table>\r\n\r\n<h2>Flag meanings</h2>\r\n<p>The flags cover possible debugging messages from various aspects of the filesystem - initial scanning, mtd interface, writing, nand access, garbage collection, OS interaction etc. Turning on everything results an awful lot of trace info, so it is usually best to just enable a few relevant flags.</p>\r\n\r\n<h2>Setting flags at runtime</h2>\r\n<p>The flags can be set or cleared by echoing the name of the flag into /proc/yaffs with a \'+\' or \'-\':<br />                                                                                                                                                                         \r\n  <tt>echo +os-write &gt; /proc/yaffs</tt></p>\r\n                                                                                                                                             <p>It can be set to to all or none using \'=\', and then flags can be added or removed:<br />\r\n  <tt>echo =none+os+write &gt; /proc/yaffs</tt></p>\r\n\r\n<p>And you can use numerical values, if you are so inclined (using standard C format):<br />\r\n  <tt>echo 0xf00001 &gt; /proc/yaffs</tt></p>\r\n                                                                                                                                          <p>So<br />\r\n  <tt>echo all &gt; /proc/yaffs</tt><br />\r\nwill turn all tracing on</p>\r\n\r\n<p><b>Note</b> that you only see the output showing you the current trace state if the \'always\' (YAFFS_TRACE_ALWAYS) flag is set, so to see what you are doing do this:<br />\r\n  <tt>echo +always &gt; /proc/yaffs</tt></p>                                                                                                                                                                                   \r\n\r\n<h2>Setting flags at compile time</h2>\r\n\r\n<p>Flags can be set in the code at compile-time by setting <tt>yaffs_traceMask</tt> in <tt>yaffs_fs.c</tt> (add new flags to <tt>always</tt> and <tt>bad_blocks</tt> which are set by default)</p>','<p>YAFFS provides a debugging mechanism which can be controlled at runtime, or set at build time. This page descirbes the options available and how to use them, for when you need to do some troubleshooting.</p>\r\n\r\n','full_html'),('page',0,353,577,'und',0,'<h3>Do we need a Licence for Yaffs ?</h3>\r\n\r\n<p>Yaffs is and will remain free of charge from <a href=\"/node/346\">our web site</a>.&nbsp; You can grab the latest version and work and test and play with it without charge.<br />\r\n<br />\r\nIt comes with a GNU General Public Public Licence, version 2,&nbsp; :&nbsp;<a href=\"http://www.gnu.org/licenses/gpl-2.0.html\">http://www.gnu.org/licenses/gpl-2.0.html</a>&nbsp;&nbsp; As usual with GPL work, if you sell or distribute work embodying Yaffs you also have an obligation to disclose your associated Source Code to anyone who asks.</p>\r\n\r\n<h3>What if we link other code to Yaffs ?</h3>\r\n\r\n<p>The GPL obligation is not affected by the kind of linking between Yaffs and any associated code, nor is it affected by your disclosure of modifications you make to the code and release back into the main line.&nbsp; For example if you use Yaffs under GPL with Linux you should treat it just the same as Linux code; if you want to publish a patched kernel please do.</p>\r\n\r\n<h3>We do not want to disclose Source Code</h3>\r\n\r\n<p>Because Aleph One Limited created and owns Yaffs we can sell you a Licence to use Yaffs which does not have the GNU GPLV2 obligations.&nbsp; Such a licence is always perpetual, world-wide, non-exclusive. and free of any continuing royalty obligations.&nbsp; It is paid for by a single fee at the time of signing a Licence Agreement between you and Aleph One.</p>\r\n\r\n<p>The fee depends on the number of distinct Products in which Yaffs will be used, and there is a base price of GBP £10,000.&nbsp; If more than one Product is included in the same Licence there is usually a reduction in the second fee.</p>\r\n\r\n<h3>What do we do next ?</h3>\r\n\r\n<p>Tell us some more about the product you will use Yaffs in.&nbsp; We like the Agreement to contain a brief description of the hardware involved and the part number or product name and any internal code name.&nbsp; If you want us to sign a Non-Disclosure Agreement before you give us these details, send it to us; we are used to signing them.&nbsp; We can send you a standard form if you do not have one.</p>\r\n\r\n<p>Then we will send a draft Agreement and price to you, and negotiate until we are both satisfied.&nbsp; Next we each sign and exchange copies of the Agreement and you pay us.</p>\r\n\r\n<h3>What happens when we sign a Licence ?</h3>\r\n\r\n<p>When we have both signed a Licence Agreement and you have paid us we provide you with a tarball of files whose headers show that this code is under a proprietary Licence which you have bought from us.&nbsp; You use these files to create the FS code you embed in your Products.</p>\r\n\r\n<h3>Is there more information about licensing?</h3>\r\n\r\n<p>Yes there is!</p>\r\n\r\n<ul>\r\n	<li>More detail about the <a href=\"/yaffs-licence-sample\">definition of a Product is given </a><a href=\"/node/32\">i</a><a href=\"/yaffs-licence-sample\">n our sample commercial licence</a>.&nbsp;</li>\r\n	<li>Notes which give&nbsp;<a href=\"/licences-more-background-and-detail\">further background and detail about our licensing</a>.</li>\r\n</ul>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>&nbsp;</p>\r\n','<p>Some questions about the commercial licence for Yaffs and how we arrive at one.</p>','basic_html'),('article',0,357,578,'und',0,'<p>Yaffs (Yet Another Flash File System) is an open-source file system specifically designed to be fast, robust and suitable for embedded use with NAND and NOR Flash.&nbsp; It is widely used with Linux, RTOSs, or no OS at all, in consumer devices. It is available under GNU Public License, GPL, or on commercial terms from Aleph One.</p>\r\n','','basic_html'),('article',0,358,544,'und',0,'The following archive documents will give you some insight into the internal history of YAFFS\r\n\r\n<ul>\r\n<li><a href=\"/node/39\">YAFFS Development notes</a>.</li>\r\n<li><a href=\"/node/42\">State of NAND MTD driver at start of project</a></li>\r\n<li><a href=\"/node/42\">YAFFS History</a></li>\r\n</ul>','A brief look into the history of YAFFS through a look at the the internals.','full_html'),('article',0,359,579,'und',0,'<p>On Friday 02 March 2007 10:59, Charles F Johnson wrote:</p>\r\n\r\n<p>\"I\'m trying to understand the relative merits of JFFS2 vs YAFFS2. The response on the YAFFS mailing list is quite positive as far as leading me to believe that there are actual products shipping.\"</p>\r\n\r\n<p><br />\r\nCharles Manning replied:<br />\r\nAt a technical level, it is very difficult to make X vs Y comparisons because there are many factors involved which manifest differently on different systems therefore \'your mileage will vary\'. But, as a general rule of thumb, the following might help:</p>\r\n\r\n<p>1) YAFFS uses less run-time RAM to hold its state, so YAFFS scales better than JFFS2. There are quite a few systems using large NAND arrays (the largest partitions I know of are around the 6Gbyte mark).<br />\r\n<br />\r\n2) YAFFS garbage collection is simpler and faster, typically making for better performance under hard writing.<br />\r\n<br />\r\n3) YAFFS uses a whole page per file for headers, and does not provide compression. This means that JFFS2 is probably a better fit to small partitions. The flip side is that a lot of data (eg. MP3) does not compress very well, and enabling compression really hurts performance.<br />\r\n<br />\r\n4) While YAFFS has been used on NOR, it does not fit very well (because YAFFS does not use erase suspend). Thus if you\'re using smaller NAND partitions and using JFFS2 on NOR, then a JFFS2-only solution is very appealing.<br />\r\n<br />\r\nAll the above can generally boil down to: If you\'re using less than about 64MB the pain vs gain might play in favour of JFFS2. As you increase partition size, YAFFS makes more and more sense.</p>\r\n','If you are trying to decide between Yaffs and JFFS2 then this note will give you an idea of the relative advantages of each.','basic_html'),('article',0,360,580,'und',0,'<p><a href=\"http://www.cis.nctu.edu.tw/~lpchang/papers/SAC_wu_sac06.pdf\">This paper</a> proposes a method for efficient initialization and crash recovery for Flash-memory file systems. A log management scheme for the Flash-memory file systems is presented. The proposed log management method is implemented in a log-record manager and a logger. It was written by Chin-Hsein Wu, Tei-Wei Kuo and Li-Pen Change of the Department of Computer Science of National Taiwan University, Taipei, TAIWAN, and presented at an international SAC Conference in 2006. Copyright 2006 ACM 1-59593-108-2/06/0004</p>\r\n','<p>This provides a link to a PDF of a paper by Taiwanese scholars.</p>','basic_html'),('page',0,365,366,'und',0,'You can pay us, as Aleph One Ltd, for an agreed product or service by clicking  <a href=\"http://www.aleph1.co.uk/other\"> HERE </a>\r\n','','full_html'),('image',0,366,367,'und',0,'YAFFS embedded structure','','full_html'),('page',0,367,610,'und',0,'<p>Attached is a PDF with slides from the Yaffs talk at CELF\'s Embedded Linux Conference Europe 2007. If you are able to view Ogg Theora video files, the talk is also <a href=\"http://free-electrons.com/pub/video/2007/elce/elce-2007-wookey-yaffs.ogg\">online</a>. Ogg Theora is a Free video format. Free players are available for all platforms. See the list <a href=\"http://wiki.xiph.org/index.php/TheoraSoftwarePlayers\">here</a>. If in doubt, VLC is probably available for your operating system.</p>\r\n\r\n<p>If you prefer to go straight to the .pdf if clides&nbsp; click <a href=\"http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf\">http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf</a></p>\r\n','<p>Attached is a PDF with slides from the Yaffs talk at CELF\'s Embedded Linux Conference Europe 2007. If you are able to view Ogg Theora video files, the talk is also <a href=\"http://free-electrons.com/pub/video/2007/elce/elce-2007-wookey-yaffs.ogg\">online</a>. Ogg Theora is a Free video format. Free players are available for all platforms. See the list <a href=\"http://wiki.xiph.org/index.php/TheoraSoftwarePlayers\">here</a>. If in doubt, VLC is probably available for your operating system.</p><p>If you prefer to go straight to the .pdf if clides&nbsp; click <a href=\"http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf\">http://www.yaffs.net/sites/yaffs.net/files/yaffs.pdf</a></p>','basic_html'),('book',0,368,369,'und',0,'<b>Overview</b>\r\n<br />\r\n<br />\r\n<div align=\"left\">\r\nYAFFS is an Open Source flash file system used in many embedded applications \r\nsuch as mobile phones, PDAs, aerospace and point of sale. YAFFS is mainly used in Linux systems but is also used with other OSs.\r\nYAFFS is even used in the Google Android platform!\r\n<br />\r\n<br />\r\n<div align=\"left\">\r\nWe\'re looking for some bright minds interested in the GSoC concept - \r\n<a href=\"http://code.google.com/soc/2008\">Google 2008 Summer of Code</a>\r\n- to help make YAFFS even better.  The particular area of interst here is performance improvement, and enriching the YAFFS development environment with support tools.\r\n<p>\r\nWe strongly encourage student generated ideas, as well as further ideas from the YAFFS community.\r\n<br />\r\n<br />\r\n<b>Performance analysis</b>\r\n<br />\r\n</p>\r\n<div align=\"left\">\r\nPerformance is increasingly important in delivering high quality user experience on media-rich devices such as Google Android-based devices. High file system performance leads to slicker UI and faster data transfers. High performance also reduces flash memory read/writes which  reduces power consumption, meaning better battery life.\r\n<br />\r\n<br />\r\n<div align=\"left\">\r\nOur major focus for GSoC is to develop a  performance analysis framework and tools that will help to identify opportunities for improvement as well as evaluate the performance impact of code changes. It would be great if this performance toolkit could be generalised for other applications, but that\'s beyond the focus of what we want to achieve here. \r\n<br />\r\n<br />\r\n<div align=\"left\">\r\nWe have some ideas to seed this, but encourage students to think of their own \r\nideas too. \r\n</div>\r\n<div align=\"left\">\r\n* Develop an environment-neutral data gathering framework.\r\n</div>\r\n<div align=\"left\">\r\n* Write a FUSE wrapper for YAFFS to improve test scripting. Include the data gathering framework in the FUSE wrapper.\r\n</div>\r\n<div align=\"left\">\r\n* Extend the Android simulator with these tools, thus allowing performance analysis of Linux-based mobile devices.\r\n</div>\r\n<div align=\"left\">\r\n* Develop performance-analysis display tools to allow clear observation of gathered data.\r\n</div>\r\n<div align=\"left\">\r\n* Help in performance analysis.\r\n<br />\r\n<br />\r\n<b>Other ideas</b>\r\n<br />\r\n</div>\r\n<div align=\"left\">\r\nWe have some ideas of things we\'d like to see done, but are not sufficient for a GSoC project on their own. These could be included with other ideas to make sufficient scope for a GSoc project. These tasks  include:\r\n<br />\r\n<br />\r\n</div>\r\n<div align=\"left\">\r\n* If documentation is your delight we would love to have someone build on the \r\nexisting material and generate lucid new docs on How to integrate YAFFS, How it \r\nworks, YDI Interface details, and anything else your training or experience \r\nmakes clear our users would benefit from.\r\n</div>\r\n<div align=\"left\">\r\n* Develop developer-support tools such as unyaffs: a tool to take a yaffs image and unpack the files on the host device. <br>\r\n*Improve/rewrite mkyaffsimage and related mtdutils to make image  generation and extraction easier to do.\r\n<p>\r\n&nbsp;\r\n</p>\r\n</div>\r\n<div align=\"left\">\r\nGot some ideas of you own? Give us a yell!\r\n</div>\r\n</div>\r\n</div>\r\n</div>\r\n</div>\r\n','This describes YAFFS subject areas that need work done, in order to get the attention of those involved in Google\'s Summer of Code','full_html'),('page',0,369,582,'und',0,'<p>version 2.0</p>\r\n\r\n<p>Last changed: rrw@kynesim.co.uk, 2009-03-20<br />\r\n&nbsp;</p>\r\n\r\n<h3>Purpose</h3>\r\n\r\n<p>The purpose of this document is to describe how to bring up Yaffs2 on a board previously unsupported using the Yaffs Direct Interface, with an example using eCos on a Balloon board.</p>\r\n\r\n<p>Before we start you probably want to have the data sheet for the NAND chips you are using in front you so that you can refer to it as we go along.</p>\r\n\r\n<h3>Background and NAND Flash Properties</h3>\r\n\r\n<p>NAND flash is generally arranged in <em>pages</em> and <em>blocks</em>. A page contains a section of data bytes and then a section of out-of-band (<em>OOB</em>) data bytes. Blocks contain a number of pages .<br />\r\n<a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram\" height=\"335\" src=\"/sites/yaffs.net/files/images/yaffs_porting_guide_html_2de490f8.png\" width=\"783\" /></a></p>\r\n\r\n<p>The OOB section of each page is used keep track of various things like file system state, error correction data and bad block marking.</p>\r\n\r\n<p>NAND flash is programmed (written to) and read on a largely page basis (though with some level of random access) and is erased on a block basis. That is, to erase a page, you must erase the rest of the containing block along with it.</p>\r\n\r\n<p>When programming NAND flash only 1\'s can be programmed to 0\'s, so to change a byte containing 0x00 to 0xFF it must be erased, along with the rest of the block. However subsequent programs may still be made without an erase if no 0s are to be changed to 1s, this might be useful in a scenario where subsequent data might regularly have this property.</p>\r\n\r\n<p>When manufactured NAND flash contains bad blocks, these are blocks that are not reliable and any data in them will commonly corrupt easily. These must be kept track of and the OOB data section is used to mark a bad block.</p>\r\n\r\n<p>NAND in general is prone to bit errors and for that reason the OOB data is also used to write error correction codes (ECC) so that some errors can be corrected.</p>\r\n\r\n<h3>Yaffs NAND Model</h3>\r\n\r\n<p>It is probably a good thing to detail at this point how Yaffs2 expects the NAND to behave so that you are aware of what you have to provide in the NAND driver to get YAFF running. Yaffs uses some different terminology in that it refers to a page as a <em>chunk</em>.</p>\r\n\r\n<p>Yaffs2 uses a fairly abstract model for NAND flash, this allows a lot of flexibility in the way Yaffs can be used. Yaffs is designed for NAND flash and makes the following assumptions and definitions:</p>\r\n\r\n<ul>\r\n	<li>NAND flash is arranged in blocks. Each block is the same size and comprises an integer number of chunks. Each block is treated as a single erasable item.</li>\r\n	<li>A page (chunk) equates to the allocation units of flash.</li>\r\n	<li>All accesses (reads and writes) are page (chunk) aligned.</li>\r\n	<li>When programming a NAND flash, only the zero bits in the pattern being programmed are relevant, and one bits are \"don\'t care\". For example, if a byte already contains the binary pattern 1010, then programming 1001 will result in the pattern which is the logical AND of these two patterns i.e. 1000. This is different to NOR flash.</li>\r\n</ul>\r\n\r\n<p>Yaffs identifies blocks by their block number and chunks by their chunk Id. Yaffs treats a blank (0xFF filled) block as being free or erased. Thus, the equivalent of formatting for a Yaffs partition is to erase all the blocks that are not bad.</p>\r\n\r\n<p>Therefore Yaffs minimally needs access to functions that enable it to erase blocks and to read and write on a page basis. It is also helpful to be able to read only OOB data as reading/writing a full page to only view/update OOB data will cost many serial read cycles over the bus. This is an overhead that can be avoided using the random access read and write features of some nand chips.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h2>Writing a Driver for NAND flash Chips</h2>\r\n\r\n<h3>Writing a Driver for the Samsung 628 K9F2G08U0M PCB0 on the Balloon Board (v3.01)</h3>\r\n\r\n<p>For the Balloon board the NAND chips hang off the CPLD which is in turn hooked up to the system bus. This is quite board specific and in this case reading the VHDL code reveals how to change the values on the pins of the NAND chips. You may look at the code by downloading the balloon source code (Appendix A) and looking at balloon3.vhd and Balloon_nand.vhd in balloon/vhdl/fpga/.</p>\r\n\r\n<p>It will be likely that this is significantly different on your platform and you should consult the relevant data sheets and documentation to determine how to access the NAND hardware on your board. I will present an example of the balloon board in order to give an overview of the kind of thing that is required.</p>\r\n\r\n<p>On the Balloon the CPLD routes data on the bus with certain address to the logic on the CPLD that actually controls the flash chips. They are as follows:</p>\r\n\r\n<p><code>NAND Data Bus : 0x10e00000</code> <code>NAND Control 2: 0x10e00010</code> <code>NAND Control : 0x10e00014</code></p>\r\n\r\n<p>Sending data to the \'NAND Data Bus\' address will put that data onto the I/O pins of the NAND chips. All of the nand chips are hooked up to the same pins on the CPLD so writing to the \'NAND Data Bus\' address will put the value written on the I/O pins for <em>all</em> of the available flash chips. To isolate the chip you want to work with using the chip enable pin on each flash chip.</p>\r\n\r\n<p>This is done by writing to the \'NAND Control\' (0x10e00014) address. When writing to \'NAND control\', the CPLD takes the data value on the bus and routes each bit to a different wire. This bit field is structured as follows:</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<table>\r\n	<colgroup>\r\n		<col />\r\n		<col />\r\n	</colgroup>\r\n	<tbody>\r\n		<tr>\r\n			<td><em>Pin Attached To</em></td>\r\n			<td><em>Bit in NAND Control value</em></td>\r\n		</tr>\r\n		<tr>\r\n			<td>CLE (Control Latch Enable)</td>\r\n			<td>0</td>\r\n		</tr>\r\n		<tr>\r\n			<td>ALE (Address Latch Enable)</td>\r\n			<td>1</td>\r\n		</tr>\r\n		<tr>\r\n			<td>nCE0 (not Chip Enable for chip 0)</td>\r\n			<td>2</td>\r\n		</tr>\r\n		<tr>\r\n			<td>nCE1 (for chip 1)</td>\r\n			<td>3</td>\r\n		</tr>\r\n		<tr>\r\n			<td>nCE2 (for chip 2)</td>\r\n			<td>4</td>\r\n		</tr>\r\n		<tr>\r\n			<td>nCE3 (for chip 3)</td>\r\n			<td>5</td>\r\n		</tr>\r\n		<tr>\r\n			<td>nSE (not Chip Enable for chip 0)</td>\r\n			<td>6</td>\r\n		</tr>\r\n		<tr>\r\n			<td>nWP (not Write Protect)</td>\r\n			<td>7</td>\r\n		</tr>\r\n	</tbody>\r\n</table>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>So for example bit 1 on the data lines is put onto the ALE pin on the physical chip. Bits prefixed with \'n\' are active low, for example chip 0 is selected when nCE0 is low and nCE1-3 are high.</p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>So writing to \'NAND Control\' we can change the values of the pins on the flash. Again, CLE, ALE, nSE and nWP change the value of the corresponding pin on all the flash chips available, nCE[0-3] will select the chip you are using.</p>\r\n\r\n<p>Finally, NAND flash typically comes in couple of flavours, 8 bit wide (x8) and 16 bit wide (x16). This means that x8 chips have 8 I/O pins and x16 have 16. The logic on the CPLD on the Balloon can handle both if you tell it which you are currently dealing with. Writing to \'NAND Control 2\' a value of 1 puts the CPLD logic for the NAND chips into x8 mode and 0 into x16 mode. I will assume for the rest of this document that there are only x8 chips connected to the balloon but it should be fairly trivial to extend it to support both.</p>\r\n\r\n<h3>Using the Flash Chips</h3>\r\n\r\n<p>The flash chips we\'re using have a number of commands, each triggered by a sequence of one or two command codes. You will want to refer to the data sheets for precise details of these functions, but I will briefly describe some of them in this document. The command set that we have for the particular chip we\'re using is table 1 on page 7 of the data sheet.</p>\r\n\r\n<p>To input a command there is generally one or two command input cycles. For two cycle commands there is generally an initial command followed by some data needed to complete the command then another command cycle to notify that the relevant data has been input and to start execution. For example for read operations the command 0x00 is latched in followed by some address input cycles followed by the command 0x30 to start the operation. With this in mind I will now describe how to input commands, the \'Command Latch Cycle\'.</p>\r\n\r\n<p>Note that for this section I have assumed that the bus is sufficiently slow that the set-up and hold times are not an issue, if you have a fast bus then you may have to wait for a small amount of time (refer to the data sheet) after changing values on the pins (by writing to the correct address) so that set-up and hold times are not violated.</p>\r\n\r\n<h3>Command Latch Cycle</h3>\r\n\r\n<p>For the command latch cycle you need to first select a chip by setting the relevant nCE low and then you need to set the CLE bit high, that means writing to the \'NAND Control\' address. ALE must also be low and should be set at the same time as CLE. It is then a case of putting the command value onto the I/O pins by writing to the \'NAND Data Bus\' address the value of the command you want. This will then latch in the command, afterwards you will need to clear the CLE bit again.</p>\r\n\r\n<p>You will also notice from looking at the data sheet that something needs to be done with the nWE (not <strong>w</strong>rite <strong>e</strong>nable) pin (specifically it should be low while latching in the command), but that I have yet to describe a mechanism for changing its value. This is because it is dealt with by the logic in the CPLD and whenever data is sent to the data address the CPLD will toggle nWE appropriately. (This is also true of nRE (not <strong>r</strong>ead <strong>e</strong>nable) when reading). This process is implemented in the nand_chip_select and the send_command functions (flash.c).</p>\r\n\r\n<h3>Address Latch Cycle and Addressing</h3>\r\n\r\n<p>The process for the Address Latch Cycle is similar to that for command latching (with the sense of ALE and CLE reversed) and can be looked at in the data sheet and is implemented in send_address in flash.c. The addressing is done by row and column. There are 5 address cycles on the flash chips we\'re looking at. The first cycle contains bits 0-7 of the column address, the second bits 8-11 with the remaining bits of the byte to be sent low. The row address is over 3 more cycles in a similar fashion.</p>\r\n\r\n<p>You may wish to chose to address the individual bytes of the chip with the OOB data not directly addressable. This has enabled me to lump several chips into the same address space and select the correct chip based on the address. Addresses then need to be converted to row and column. You should also check that they are page/block aligned in the relevant places if that\'s what your functions expect. It needn\'t be done this way any you could use page numbers instead of bytes just as easily.</p>\r\n\r\n<p><br />\r\n<a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram 2\" height=\"209\" src=\"sites/yaffs.net/files/images/yaffs_porting_guide_html_m11b1f893.png\" width=\"654\" /></a></p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<p>The \'row\' is essentially the page index and the \'column\' is the index into to that page, so if you wanted to read from the start of page 213 you would send 0 for the column and 213 for the row. Conversely if you wanted just the OOB bytes from the same page you would send a column value of 2048 (given a page size of 2048+64 bytes).</p>\r\n\r\n<p><br />\r\n<a href=\"/yaffs-embedded-structure\"><img alt=\"YAFFS porting guide diagram 3\" height=\"271\" src=\"sites/yaffs.net/files/images/yaffs_porting_guide_html_m4650262f.png\" width=\"347\" /></a></p>\r\n\r\n<p>&nbsp;</p>\r\n\r\n<h3>Finding Chip information</h3>\r\n\r\n<p>You will then need to find out which chips are active (e.g. on the balloon there are 4 possible chips, not all of which will exist) and what type of chips they are. For this there is the \'Read ID\' operation. This operation is implemented in the read_ids function in flash.c. The result of the operation gives the manufacturer and device code of the chip and information about the chip (page size, block size, oob size etc). To find which chips are available, loop through the possible chips and start a Read ID command on each of them, if the expected data is returned then there is a chip at that location.</p>\r\n\r\n<p>The operation is started by sending the command 0x90 and then one address cycle of 0x00. There are then 5 read cycles which give you data about the device. A description of how to unpack this information from the returned bytes is located on page 32 of the data sheet for the chip described here.</p>\r\n\r\n<p>This then gives you how many chips you have and what layout the data in them has.</p>\r\n\r\n<h3>Bad Block Checking</h3>\r\n\r\n<p>Contained within a nand chip are blocks that the manufacturer will not guarantee the reliability of (this is to increase yield in manufacturing) and so bad blocks must be kept track of. The Samsung chips come with the first byte (or word for x16) of the first and second page of each bad block not programmed as 0xFF.</p>\r\n\r\n<p>This bad block marking should be maintained and should be added to in the same way when a bad block is is discovered. Yaffs will expect you to provide a function it can call to mark a particular block as bad when yaffs decides it is necessary.</p>\r\n\r\n<p>Yaffs keeps track of bad blocks itself so that the driver doesn\'t need to worry about masking out bad blocks.</p>\r\n\r\n<h3>Erasing a Block</h3>\r\n\r\n<p>An example of this operation is given in nand_erase_block in flash.c. If you are addressing the nand by bytes then you must first check that the address is aligned to the start of a block and then convert the address into a block number. If there is more than one chip this will involve working out which chip the address refers to and then selecting the correct chip. This can be seen in the select_chip function in flash.c. You must then send the first command cycle for the erase operation before sending 3 cycles of address and then finally the last command cycle.</p>\r\n\r\n<p>For the erase operation the 3 address cycles are different than for the read/write operations. Only address bits A18 to A29 is valid (for x8) while A12 to A17 is ignored. In terms of the ordinary 5 cycles address input you only need to deal with the last 3 cycles and of those only the highest 2 bits of the 3rd cycle are used and the full 4th and 5th cycle are used.</p>\r\n\r\n<p>Once the operation has been started the program can check the progress of the operation by sending a command of 70h. Each subsequent read will contain the read status. The driver should wait until the read is complete (by the read status operation), the read status operation also contains information about whether the erase failed and this information should be returned from the function doing the erase.</p>\r\n\r\n<h3>Reading a Page</h3>\r\n\r\n<p>Reading a page is performed by first selecting the correct chip and then converting the address to a row and column number. You can then sending the first command cycle for the read operation followed by 5 address cycles as described in the previous sections. The second command cycle then starts the read operation. The driver must then wait for the data to be retrieved into the data registers on the NAND before they can be read out over the bus. For the example chip this is 25us, consult the data sheet as this may differ. The data can then be read out sequentially byte by byte until all the data needed is obtained.</p>\r\n\r\n<h3>Writing a Page</h3>\r\n\r\n<p>Page program operations are performed by first selecting the correct chip converting the address to row and column numbers. The page program operation is initiated by the relevant fist command latch cycle (command 0x80) followed by an address latch cycle (as for read), serial data loading and then the second command latch cycle (command 0x10).</p>\r\n\r\n<p>The serial data loading is done by serially writing data to the I/O pins. Up to 2112 bytes (x8) can be loaded into the data registers. Once the second command cycle is sent the program is initiated and there is then a programming period where the loaded data is programmed into the appropriate cell. The driver should wait for this to complete by issuing a read status command (0x70) and monitoring the R/nB (ready / not busy) bit. The R/nB flag is on I/O pin 6 and can be checked by repeatedly reading from the \'NAND Data Bus\' address. Once the operation is complete the Write Status Bit (I/O 0 ) may be checked to confirm that the operation was successful.</p>\r\n\r\n<h2>Yaffs</h2>\r\n\r\n<h3>How To Use Yaffs</h3>\r\n\r\n<h3>Checking Out From Git</h3>\r\n\r\n<p>The first thing to do is to obtain the source code for Yaffs. This can be done from CVS, details of the process can be found at <a href=\"http://www.yaffs.net/download-yaffs-using-git\">http://www.yaffs.net/download-yaffs-using-git</a>.</p>\r\n\r\n<p>The following command will checkout the latest Git version using public read-only access, if you are using bash.</p>\r\n\r\n<p><code>$&nbsp;</code>git clone git://www.aleph1.co.uk/yaffs2&nbsp;</p>\r\n\r\n<h3>Making Some Tweaks to the Source Code</h3>\r\n\r\n<p>As of the latest version from CVS in January 2009, you will need to make a small number of changes before you can compile the source code without errors and warnings. There is a patch file included with this document.</p>\r\n\r\n<p>You will need to provide a definition of loff_t (in yaffs2/direct/ydirectenv.h) this is for holding the file size in bytes, you should make it big enough to hold the largest file size you wish to support. Unsigned long is probably a good place to start. You will need to edit yaffsfs.c to change a #if to a #ifdef. Then if you have the relevant warnings and -Werror switched on you will need to correct a couple of printf format strings to get the type right (changing a few \'%d\' to \'%ld\').</p>\r\n\r\n<p><code>change yaffs/ydirectenv.h </code></p>\r\n\r\n<p><code>+ typedef unsigned long loff_t; </code></p>\r\n\r\n<p><code>change yaffs2/direct/yaffsfs.c ~line 1117 </code></p>\r\n\r\n<p><code>- #if CONFIG_YAFFS_WINCE </code></p>\r\n\r\n<p><code>+ #ifdef CONFIG_YAFFS_WINCE</code></p>\r\n\r\n<h3>Relevant Files to the Direct Interface</h3>\r\n\r\n<p>There are quite a few files that get checked out, not all of which you will need to get going with the yaffs direct interface. The ones you will actually need are listed bellow, you do not need to compile the rest in.</p>\r\n\r\n<p><code><code>direct/yaffsfs.c </code></code></p>\r\n\r\n<p><code><code>yaffs_guts.c </code></code></p>\r\n\r\n<p><code><code>direct/yaffscfg.c </code></code></p>\r\n\r\n<p><code><code>yaffs_nand.c </code></code></p>\r\n\r\n<p><code><code>yaffs_tagsvalidity.c </code></code></p>\r\n\r\n<p><code><code>yaffs_checkptrw.c </code></code></p>\r\n\r\n<p><code><code>yaffs_qsort.c </code></code></p>\r\n\r\n<p><code><code>yaffs_tagscompat.c </code></code></p>\r\n\r\n<p><code><code>yaffs_ecc.c </code></code></p>\r\n\r\n<p><code><code>yaffs_packedtags2.c</code></code></p>\r\n\r\n<h3>Some Relevant Preprocessor Flags</h3>\r\n\r\n<p>There are many different configuration options for yaffs, here are a few that you should be aware of for using the yaffs direct interface.</p>\r\n\r\n<ul>\r\n	<li>CONFIG_YAFFS_DIRECT - Tell yaffs to use the direct interface.</li>\r\n	<li>CONFIG_YAFFS_YAFFS2 - Tell yaffs we want to use yaffs2</li>\r\n	<li>CONFIG_YAFFS_PROVIDE_DEFS - provides some definitions for file types and #includes linux/types.h, linux/fs.h, linux/stat.h (see yaffs2/devextras.h).</li>\r\n	<li>CONFIG_YAFFSFS_PROVIDE_VALUES - This may be used so that you can customise error values and constants like O_RDONLY to match the underlying system values, if itis not defined then it includes errno.h,sys/stat.h and fcntl.h (see yaffs2/direct/yaffsfs.h).</li>\r\n</ul>\r\n\r\n<p>Specify these options when compiling yaffs, i.e. -DCONFIG_YAFFS_DIRECT etc.</p>\r\n\r\n<h3>Configuring</h3>\r\n\r\n<p>You will then need to provide yaffs with configuration information. This includes details about the nand flash you are using and also tells yaffs which functions to call when when it wants to read/write/erase parts of the flash, these functions will form the bridge between yaffs and the underlying hardware driver. This customisation is done in yaffscfg.h. Within yaffscfg.h you will need to provide a number of operating-system-like functions and a function to initialise yaffs. For example providing functions for malloc and free. Here is a breakdown of those functions that need to be implemented.</p>\r\n\r\n<h3>Operating System Functions</h3>\r\n\r\n<p><code><code>void yaffsfs_SetError(int err); </code> </code></p>\r\n\r\n<p>Report system errors, for example using errno if it exists.</p>\r\n\r\n<p><code><code>void *yaffs_malloc(size_t size);</code> <code>void yaffs_free(void *ptr);</code> </code></p>\r\n\r\n<p>As for the standard malloc and free functions, if they already exist on your system then you can just shim them.</p>\r\n\r\n<p><code><code>void yaffsfs_LocalInitialisation(void);</code> <code>void yaffsfs_Lock(void);</code> <code>void yaffsfs_Unlock(void);</code> </code></p>\r\n\r\n<p>Use yaffsfs_LocalInitalisation to initialise \"Real Time Operating System\" state, if the system is multi-threaded then it should initialise a semaphore/mutex for use by lock and unlock. Lock/unlock should use the semaphore set up in LocalInitialisation to lock yaffs from multi-threaded access.</p>\r\n\r\n<p><code><code>__u32 yaffsfs_CurrentTime(void);</code> </code></p>\r\n\r\n<p>This can be any time increment of use to the system. If this is not required, then it is fine to just use a function that returns zero.</p>\r\n\r\n<h3>Yaffs Startup Function</h3>\r\n\r\n<p><code><code>int yaffs_StartUp(void); </code> </code></p>\r\n\r\n<p><code><code>Return value: YAFFS_OK or YAFFS_FAIL</code> </code></p>\r\n\r\n<p>This functions should be used to provide yaffs with many details about the properties of the underlying nand device. Within this function you will need to set up a \'yaffs_Device\' (yaffs_guts.h) and a \'yaffsfs_DeviceConfiguration\' (direct/yaffscfg.h). How to set up a yaffs device will follow in the next section. Once you have set up the required yaffs_Device structures you should call yaffs_initialise (yaffs_guts.h) with a pointer to a null terminated array of yaffs_DeviceConfiguration structures. A yaffs_DeviceConfiguration structure contains a pointer to a yaffs_Device and the \'mount point\' string (prefix) that that device corresponds to.</p>\r\n\r\n<h3>Yaffs Devices</h3>\r\n\r\n<p>A yaffs device is a logical device that represents part of or a whole physical device. You might think of it as a \'partition\' on the nand. For example, it might cover the whole of the nand device or perhaps only claim half, with another yaffs_Device claiming the other half. It may also be used so that you can use a device other than a flash device (e.g. RAM) for testing purposes.</p>\r\n\r\n<p>A yaffs_Device keeps track of the start and end block, so you may have more than one yaffs_Device corresponding to the same physical device by altering the start and end block of the yaffs device.</p>\r\n\r\n<p>The fields on the yaffs_Device struct that you need to set up yourself are listed below, all other fields are setup automatically by yaffs.</p>\r\n\r\n<p><code><code>int nDataBytesPerChunk</code> </code></p>\r\n\r\n<p>As the name suggests this is the number of bytes per chunk, remembering that in yaffs terminology a page is referred to as a chunk, this is then the number of bytes per page. This is the number of data bytes, that is the number of bytes excluding the OOB byte data. E.g. if a page is 2048byte + 64bytes of OOB then set nDataBytesPerChunk to 2048.</p>\r\n\r\n<p><code><code>int nChunksPerBlock </code> </code></p>\r\n\r\n<p>Straightforwardly the number of chunks (pages on the nand) in each block on the physical nand device. Must be at least 2.</p>\r\n\r\n<p><code><code>int spareBytesPerChunk</code></code><br />\r\nThis is the size of the spare area, i.e. the number of OOB bytes per chunk (page)<code>. </code></p>\r\n\r\n<p><code><code>int startBlock</code> </code></p>\r\n\r\n<p>The block number (not the address in bytes) on the chip of the first block of this logical yaffs_Device. Beware, yaffs needs the first block to be free so you should not set this to 0, if it is then yaffs will add on one to it itself and also add on one to the end block which could be an issue if you wanted your device to start at block 0 and finish at the last block which might mean yaffs trying to write to a non-existent block.</p>\r\n\r\n<p><code><code>int endBlock</code> </code></p>\r\n\r\n<p>The block number on the chip of the last block for this logical yaffs_Device. If startBlock == 0 then yaffs will use endBlock+1. Must be at least startBlock + nReservedBlocks + 2.</p>\r\n\r\n<p><code><code>int nReservedBlocks</code> </code></p>\r\n\r\n<p>This is then number of erasable blocks that Yaffs must keep in reserve for garbage collection and to cover for block failures. This must be a minimum of 2, but 5 or so is better. If you are using a medium that is not expected to fail (eg. RAM for a RAM disk, or a host file system emulation then 2 is OK).</p>\r\n\r\n<p><code><code>int nShortOpCaches</code> </code></p>\r\n\r\n<p>This configures the number of entries in the Yaffs cache for this device. A value of zero defeats the cache. A value of 10 to 20 is recommended for most systems. Cannon be any bigger than YAFFS_MAX_SHORT_OP_CACHES.</p>\r\n\r\n<p><code><code>int useNANDECC</code> </code></p>\r\n\r\n<p>This is a flag that tells yaffs whether it should be doing ECC calculations or if it should be left to the driver.</p>\r\n\r\n<p><code><code>void *genericDevice</code> </code></p>\r\n\r\n<p>This is a pointer which should point to any data that the underlying nand driver will need to know to write and read from the physical device.</p>\r\n\r\n<p><code><code>int isYaffs2</code> </code></p>\r\n\r\n<p>Are we using Yaffs2? We only deal with Yaffs2 in this document.</p>\r\n\r\n<p><code><code>int inbandTags</code> </code></p>\r\n\r\n<p>Is there an OOB section? If not then this should be true. Only relevant to Yaffs2.</p>\r\n\r\n<p><code><code>_u32 totalBytesPerChunk</code> </code></p>\r\n\r\n<p>Possibly a misleading name, it should be equal to nDataBytesPerChunk not nDataBytesPerChunk + spareBytesPerChunk as the name might suggest. If inbandTags is true then yaffs sets nDataBytesPerChunk such that there is enough space for the data yaffs would normally store in the spare area.</p>\r\n\r\n<p><code><code>write/readChunkWithTagsFromNAND, markNANDBlockBad, queryNANDBlock</code> </code></p>\r\n\r\n<p>These are all pointers to functions that you shall provide to provide Yaffs with a method of writing/reading etc from the NAND.</p>\r\n\r\n<h3>NAND access functions</h3>\r\n\r\n<p>If you are using Yaffs2 you need to provide pointers to functions that Yaffs can call to write and read from the nand. Example implementations of these function can be seen in yaffs_mtdif.c, these are the functions written to do the same job for the linux mtd layer and provides the write and read functions. The following functions return YAFFS_OK on success and YAFFS_FAIL on failure.</p>\r\n\r\n<p><code><code>int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,</code> <code>int chunkInNAND, const __u8 * data,</code> <code>const yaffs_ExtendedTags * tags);</code> <code>dev: yaffs_Device to write to.</code> <code>chunkInNAND: Which page to write the chunk to.</code> <code>Data: Pointer to the data to write</code> <code>tags: Unpacked OOB data.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\r\n\r\n<p>This function is to write pages (chunks) to the nand. In this function you will probably want to first retrive any useful data that you put in dev-&gt;genericDevice (in the yaffs_StartUp function) and use it to call the function you wrote previously to write data to the nand. For yaffs2 data and tags should never be NULL. chunkInNand is the page number of the page to write to, not an address so it will need converting if that\'s what your underling functions to write to the nand expect.</p>\r\n\r\n<p>You will then need to pack the tags into a yaffs_PackedTags2 structure, this takes out the all relevant details from the yaffs_ExtendedTags tags structure and calculates ECC data on it before placing them in the packedtags2 structure. This structure is the OOB data you will want to write out to the nands spare area.</p>\r\n\r\n<p>How you write these out to the OOB data depends on your architecture, nand chips and therefore how bad block marking is done. If for example the first byte is used for bad block marking then simply writing the tags out after the first byte is acceptable. The ECC data in packed tags only covers error correction and detection for the tags in the OOB data, if you want ECC on the data then you must do that yourself.</p>\r\n\r\n<p>To perform ECC checks to the data bytes you may use the yaffs_ECCCalculate function which calculates ECC data for 256 byte sections of data. This function produces 3 bytes of ECC data per 256 bytes. Therefore for 2048 bytes of data in each page you would need (2048/256) * 3 = 8 * 3 = 24 extra bytes of ECC data. This can be written out after the bad block byte and packed tags data.<br />\r\n&nbsp;</p>\r\n\r\n<p><code><code>int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,</code> <code>int chunkInNAND, __u8 * data,</code> <code>yaffs_ExtendedTags * tags);</code> <code>dev: The yaffs_Device to read from.</code> <code>chunkInNAND: Which page to read from.</code> <code>Data: Pointer to a buffer to read data to.</code> <code>tags: Pointer to a buffer to unpacked OOB data into.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\r\n\r\n<p>This function should do the opposite to the previous function. Firstly, read in the data and OOB bytes. Secondly place the data bytes in the area pointed to by data, then unpack the OOB bytes into into the pointer to tags using yaffs_UnpackTags2.</p>\r\n\r\n<p>Once the tags have been unpacked you should then recalculate the ECC data on the data bytes you just read back, just as you did for the write operation. Then use the recalculated ECC and the ECC data read out of the OOB bytes with yaffs_ECCCorrect to correct the data.</p>\r\n\r\n<p>Depending on the return value from yaffs_ECCCorrect you should set tags-&gt;eccResult to reflect whether anything was corrected or the correction failed. yaffs_UnpackTags2 also sets tags-&gt;eccResult so you should only update it if the result of the data correction is worse than is already there. i.e. if after the tags are unpacked and eccResult is YAFFS_ECC_RESULT_FIXED and ECC correction on the data read back resulted in no errors then you should leave unpackedtags2 and YAFFS_ECC_RESULT_FIXED and not set it to YAFFS_ECC_RESULT_NO_ERROR.</p>\r\n\r\n<p><code><code>int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);</code> <code>dev: yaffs_Device to write to.</code> <code>blockNo: Which block to mark.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code></code></p>\r\n\r\n<p>This should mark the block bad. This probably means reading the OOB data and changing the relevant byte that marks the bad block, and writing the OOB data back.</p>\r\n\r\n<p><code><code>int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,</code> <code>yaffs_BlockState * state, __u32 *sequenceNumber);</code> <code>dev: The yaffs_Device to write to.</code> <code>blockNo: Which block to mark.</code> <code>state: Upon returning this should be set to the relevant state of this particular block.</code> <code>Sequence number: The Sequence number of this block. 0 if the block is unused.</code> <code>Return: YAFFS_OK / YAFFS_FAIL</code> </code></p>\r\n\r\n<p>This should check whether or not the block is valid.</p>\r\n\r\n<p>If the bad block marker is set in the OOB then *state should be set to YAFFS_BLOCK_STATE_DEAD *sequenceNumber set to 0, and return YAFFS_FAIL.</p>\r\n\r\n<p>If the block is not bad then the tags should be unpacked. After the tags are unpacked, and it is found that chunk is used (see tags.chunkUsed) *sequenceNumber should be set to tags.sequenceNumber and *state to YAFFS_BLOCK_STATE_NEEDS_SCANNING, otherwise if the block is not used then *sequenceNumber should be 0 and *state should be set to YAFFS_BLOCK_STATE_EMPTY.</p>\r\n\r\n<h3>Application Interface</h3>\r\n\r\n<p>The yaffs provides a number of functions for applications to interface with it. These are mostly the same as the standard clib open/close etc prefixed with yaffs_ eg yaffs_open. These functions are defined in direct/yaffsfs.h.</p>\r\n\r\n<p>To initialise yaffs so that reading and writing can be done, you must call yaffs mount for each yaffs device you would like to use, e.g. yaffs_mount(\"/boot\"). This could be done at system boot if there is an operating system present so that the application need to worry about this. You will also need to call yaffs_unmount when you have finished so that yaffs may write any state it needs to to disk.</p>\r\n\r\n<p>If there is already an application interface for reading and writing files you may shim the relevant function calls with the related operating system calls.</p>\r\n\r\n<p>E.g. simply doing #define open(path, oflag, mode) yaffs_open(path, oflag, mode)</p>\r\n\r\n<p>Or having something more complex to provide redirection functions if there is more than one file system present.</p>\r\n\r\n<p><code><code>For example: int open(const char *path,...)<br />\r\n{<br />\r\n//Determine which file system is being used </code> <code>if(it_is_a_yaffs_path(path)) {</code> <code> return yaffs_open(...);<br />\r\n} else {<br />\r\n// Do something else<br />\r\n}<br />\r\n}</code></code></p>\r\n\r\n<h2>Appendices</h2>\r\n\r\n<h3>Appendix A - Accessing the Balloon Source Code</h3>\r\n\r\n<p>The latest source code for the balloon board can be checked out from SVN. There is different code for different balloon versions. Details of getting the source and setting up tool chains is decribed in the following page <a href=\"http://www.balloonboard.org/software.html\">http://www.balloonboard.org/software.html</a>. If you just want to take a look at the latest mainline code then the following will give you what you want.</p>\r\n\r\n<p>svn checkout svn://balloonboard.org/balloon/trunk/</p>\r\n\r\n<p>&nbsp;</p>\r\n','The purpose of this document is to describe how to bring up Yaffs2 on a board previously unsupported using the Yaffs Direct Interface, with an example using eCos on a Balloon board.','basic_html'),('page',0,380,381,'und',0,'<p>We offer support for Yaffs through the <a href=\"http://stoneboat.aleph1.co.uk/mailman/listinfo/yaffs\">Yaffs mailing list</a>. It\'s best to start by searching the <a href=\"http://www.aleph1.co.uk/lurker/list/yaffs.html\">list archive</a> to see if someone has already asked the same question.</p><p>If you feel uncomfortable asking your question on an open mailing list you can try mailing us, but we (or you) may say \'You should be paying for this\', and if that is agreed, then we can accept payments via PayPal or other means.</p><p>Serious long-term work is best done as a negotiated contract; for instance we have built special features for clients with very particular needs. If you think you may want this sort of help then <a href=\"/contact\">contact us</a>, telling us a bit about your problem.</p>','<p>We offer support for Yaffs through the&nbsp;<a href=\"http://stoneboat.aleph1.co.uk/mailman/listinfo/yaffs\">Yaffs mailing list</a>. We also offer paid contracts for longer term needs.</p>','full_html'),('page',0,382,639,'und',0,'<h2>Licences</h2>\r\n\r\n<p>Yaffs belongs to Aleph One Limited. It&nbsp;is available under two licences:</p>\r\n\r\n<ul>\r\n	<li>The <a href=\"https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html\">GPL Version 2</a> (GNU Public Licence, Version 2). You can try it for free under this licence, and you can use Yaffs&nbsp;in GPL licensed software.&nbsp;</li>\r\n	<li>A proprietary, <a href=\"commercial-licences\">commercial licence</a> from Aleph One Limited, for use with proprietary, or closed-source software.&nbsp;These licences are non-exclusive, perpetual, world-wide, royalty-free and paid for with a single fee for one product.</li>\r\n</ul>\r\n\r\n<p>Yaffs functionality is the same under both licences, and both licences are royalty-free, but the terms of the GPL place significant obligations on<strong>&nbsp;all who&nbsp;use Yaffs under GPL</strong>. Please be certain to <a href=\"/yaffs-gpl\">understand these legal obligations</a> before distributing any software together with Yaffs.</p>\r\n\r\n<h2>Download options</h2>\r\n\r\n<p>We use <a href=\"https://git-scm.com/\">Git</a> to manage our software development.</p>\r\n\r\n<ul>\r\n	<li>To browse or download code,&nbsp;<strong><a href=\"http://www.aleph1.co.uk/gitweb?p=yaffs2.git;a=summary\" target=\"_self\">access our Git repository over the web</a></strong>. This is also the best option if you are behind a firewall that does not allow direct Git&nbsp;access.</li>\r\n	<li>To get a tarball of the top of the tree, just click \'snapshot\' for the release that you want, or to quickly obtain a snapshot of the top of the tree you can <a href=\"http://aleph1.co.uk/gitweb?p=yaffs2.git;a=snapshot;h=HEAD;\" target=\"_self\">use this URL</a>.</li>\r\n	<li>Clone Yaffs using:</li>\r\n</ul>\r\n\r\n<pre>\r\ngit clone git://www.aleph1.co.uk/yaffs2\r\n</pre>\r\n\r\n<ul>\r\n	<li>If you are a registered developer with a server account you can get read/write access using:</li>\r\n</ul>\r\n\r\n<pre>\r\ngit clone ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2</pre>\r\n\r\n<p>&nbsp;&nbsp;</p>\r\n\r\n<p wrap=\"\">If you have any questions, or would like to buy a commercial licence, please contact us either at&nbsp;+44 (0)1223 811679 or email&nbsp; sales@aleph1.co.uk&nbsp; or see our Contacts page:-&nbsp; <a href=\"http://www.aleph1.co.uk/contact\">http://www.aleph1.co.uk/contact</a></p>\r\n','<p>For experimental purposes you can grab Yaffs free of charge right now&nbsp;<a href=\"/download-yaffs-using-git\">from our GIT repository</a>.</p><p>If you distribute a product using Yaffs you must release all your linked source code in accordance with the <a href=\"http://www.gnu.org/licenses/gpl-2.0.html\">GNU General Public Licence</a>. Alternatively if you do not wish to disclose your Source Code, commercial licences are available.</p>','full_html'),('what_is_special_about_yaffs',0,384,385,'und',0,'<p><strong>100% ROYALTY FREE</strong></p>\r\n\r\n<p>Of course there\'s no royalty when you use Yaffs under the GPL; it\'s the GPL!</p>\r\n\r\n<p>Our commercial licences are paid for once at the time of buying the Licence, and so they are also royalty free. No accounting and no need to worry about increasing costs as you make or sell more units.</p>\r\n','Whether you use Yaffs under the GNU General Public Licence or under a commercial licence, Yaffs is free of any royalty. No need to worry about rising costs for your hit product!','basic_html'),('what_is_special_about_yaffs',0,385,386,'und',0,'<p>As part of our regular testing, we run power-fail tests. Whether it\'s during a read or a write, Yaffs is designed to preserve your existing data during a device power failure. And because Yaffs is open source, you can download the tests and run them yourself in the most severe conditions you expect the product to encounter. See:- http://www.yaffs.net/documents/yaffs-robustness-and-testing</p>\r\n','After more than 100,000 <strong>random</strong> power-failures during reading or writing, a test file showed NO data corruption at all!','basic_html'),('what_is_special_about_yaffs',0,388,389,'und',0,'<p>Yaffs is downloadable with a GNU General Public Licence v.2, as at&nbsp; http://www.gnu.org/licenses/gpl-2.0.html&nbsp;&nbsp; You get the source code, with all the benefits that brings. And of course, if you buy a commercial licence, you get the source code too, but without the encumberance of your responsibilities under the GNU GPL</p>\r\n\r\n<p>Because it\'s Open Source, you can always see what the code is doing and trace through; and having the code means you\'ll never be in a situation where you are critically dependent on us, either from a technical or a business perspective.</p>\r\n','You can have a look at the code at any time. <a title=\"Get it now!\" href=\"/downloads\">Download it now</a>! And it\'s suitable for GPL and commercially licensed projects.','basic_html'),('what_is_special_about_yaffs',0,389,390,'und',0,'<p>Yaffs is the leading Flash file system, running in millions of devices. It\'s been used on Linux computers, in cameras, mobile phones, hard drives, and on many custom boards. People and companies trust it to keep their data safe. Read more about <a href=\"/documents/yaffs-robustness-and-testing\">how we test Yaffs in our Robustness and Testing white paper</a>.</p>\r\n','Yaffs is widely used in Linux and proprietary commercial RTOSs. It\'s been included in hundreds of devices, and shipped as part of Google\'s Android, with millions of units sold. ','basic_html'),('yaffs_user_logo',0,397,398,'und',0,'<p>Design Electronics use Yaffs</p>\r\n','Design Electronics use Yaffs','basic_html'),('yaffs_user_logo',0,398,399,'und',0,'<p>Eaton use Yaffs</p>\r\n','Eaton use Yaffs','basic_html'),('yaffs_user_logo',0,399,400,'und',0,'<p>Lancom Systems use Yaffs.</p>\r\n','','basic_html'),('yaffs_user_logo',0,400,401,'und',0,'<p>Bernina use Yaffs.</p>\r\n','','basic_html'),('yaffs_user_logo',0,401,402,'und',0,'<p>Used by Gallagher</p>\r\n','Used by Gallagher','basic_html'),('what_is_special_about_yaffs',0,407,408,'und',0,'<p>Being quick to boot was one of the fundamental requirements in Yaffs\' design. Boot-time scanning to build the file structure lists should require just one pass reading NAND memory.</p>\r\n','It is important for a Flash filesystem to boot fast, so boot speed was a fundamental consideration in the design of Yaffs.','basic_html'),('what_is_special_about_yaffs',0,408,409,'und',0,'<p>You can learn from the experience of people and companies who are working with Yaffs. Thousands of developers have used Yaffs successfully, and commercially-licensed Yaffs has many customers that use it repeatedly. Have a look at the mailing list - it\'s a great place to start if you have some questions.<br />\r\n<a href=\"http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs\">http://stoneboat.aleph1.co.uk/cgi-bin/mailman/listinfo/yaffs</a></p>\r\n\r\n<p>The searchable archive of postings is at <a href=\"http://lists.aleph1.co.uk/lurker/list/yaffs.html\">http://lists.aleph1.co.uk/lurker/list/yaffs.html&nbsp;&nbsp; </a>Or search online to see the variety of work done with Yaffs as its basis - from research papers through to skunkworks projects for testing particular concepts.</p>\r\n','There\'s an active community of people who use Yaffs and who have developed with Yaffs, just a click or two away.','basic_html'),('paper',0,409,627,'und',0,'<p align=\"center\" style=\"margin-top: 0.42cm; orphans: 0; widows: 0; page-break-after: avoid\">\r\n<br/>\r\n<br/>\r\n\r\n</p>\r\n\r\n	<p class=\"western\" align=\"justify\">This document aims to give an explanation of most of the core mechanisms that make\r\n	Yaffs work. \r\n	</p>This document is the starting point for understanding Yaffs.</p>\r\n\r\n<h1 class=\"western\">1 Purpose</h1>\r\n<p class=\"western\">The purpose of this document is to give a\r\nreasonable explanation of most of the core mechanisms that make Yaffs\r\nwork. As of the time of writing this, the Yaffs2 code base includes\r\napproximately 19,000 lines of code making a very detailed discussion\r\nimpractical.</p>\r\n<p class=\"western\">This document should serve as a first port of call\r\nfor understanding Yaffs. Further detailed questions and discussions\r\nare welcomed on the Yaffs discussion list.</p>\r\n<p class=\"western\">This document is updated periodically. Yaffs\r\nmechanism design changes from time to time and this document will not\r\nalways reflect the most up to date code. \r\n</p>\r\n<h1 class=\"western\">2 What is Yaffs?</h1>\r\n<p class=\"western\">Yaffs stands for <i>Yet Another Flash File System</i>,\r\na term coined by Charles Manning in 2001 when suggesting that the\r\nalready cluttered flash file system space could do with yet another\r\noffering – this time a flash file system designed from the ground\r\nup to work with NAND flash.</p>\r\n<p class=\"western\">The first release of Yaffs was developed during\r\nthe end of 2001 and the beginning of 2002. By mid-2002, Yaffs was\r\nbeing trialled in various products.  In May 2002,  Yaffs was\r\nannounced and a few more projects started playing with it. In June,\r\nporting to other OSs started. In September 2002, Yaffs was announced\r\non linuxdevices.com which started a far wider uptake of Yaffs.</p>\r\n<p class=\"western\">Yaffs1, the original version of Yaffs, supported\r\n512-byte page NAND devices with a SmartMedia-like memory layout.</p>\r\n<p class=\"western\">Yaffs2 is a follow-up to Yaffs1 extending Yaffs1\r\nto support larger and different devices with different constraints.</p>\r\n<p class=\"western\">Yaffsis highly portable and has been used in many\r\ndifferent products and applications as varied as sewing machines,\r\npoint of sale, phones and aerospace. Yaffs has been used with\r\nmultiple different operating systems. Native support is available for\r\nLinux, WindowsCE and eCOS while Yaffs Direct Interface provides a\r\nlayer that can be used in other applications such as RTOSs. Yaffs has\r\nbeen used with multiple different CPUs and compilers.</p>\r\n<p class=\"western\">Yaffs has also been used as a NOR file system and\r\neven as a RAM file system.</p>\r\n<h1 class=\"western\">3 Design and coding strategies</h1>\r\n<p class=\"western\">Yaffs is designed to work in multiple environments\r\nwhich drives the need for portability. Portability also improves the\r\ndebugging and testing since it is easier to develop and debug code in\r\nan application environment than within an OS kernel. This generally\r\nallows Yaffs to progress faster with less programming resources and\r\nprovides more varied testing. Primary strategies that improve\r\nportability include:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">No OS-specific features used in main code\r\n	body.</p>\r\n	<li/>\r\n<p class=\"western\">No compiler-specific features used in the\r\n	main code body.</p>\r\n	<li/>\r\n<p class=\"western\">Abstract types and functions used to allow\r\n	Unicode or ASCII operation.</p>\r\n</ul>\r\n\r\n<p class=\"western\" style=\"page-break-before: auto; page-break-after: avoid\">\r\nSimplicity is another key goal. Complexity is limited to those\r\nsituations that provide significant improvements to performance or\r\nutility. Simplicity improves robustness and the ease of integration\r\nand development. Primary strategies that improve simplicity are:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Single threaded model. Yaffs is locked on a\r\n	per-partition basis at a high level. This is simpler than tracking\r\n	lower-level locking. Yaffs Direct Interface uses a single lock for\r\n	all partitions.</p>\r\n</ul>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Log structure makes for a simpler garbage\r\n	collector and allocation methodology.</p>\r\n	<li/>\r\n<p class=\"western\">Abstractions that build layered code which\r\n	is easier to understand, port and debug.</p>\r\n</ul>\r\n<h1 class=\"western\">4 Terminology: Yaffs vs Yaffs1 vs Yaffs2</h1>\r\n<p class=\"western\">Before we embark on our quest to understand what\r\nYaffs is, a terminology explanation is in order.</p>\r\n<p class=\"western\">There are two versions of Yaffs code: the original\r\nYaffs code-base and the current Yaffs2 code-base. The Yaffs2\r\ncode-base supports functionality provided by the Yaffs code-base as\r\nwell as being extended with new functionality to provide extra modes\r\nof operation, most importantly those required to work with larger and\r\nmore modern NAND parts. The Yaffs2 code-base supports the Yaffs1 mode\r\nof operation through a backward compatibility mode.</p>\r\n<p class=\"western\">Unless explicitly mentioned, this text refers to\r\nthe Yaffs2 code-base.</p>\r\n<p class=\"western\">This text uses three terms Yaffs, Yaffs1 and\r\nYaffs2 depending on various modes of operation.</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Yaffs1\r\n	is a simpler mode of operation that uses deletion markers to track\r\n	state. </font>\r\n	</p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Yaffs2\r\n	is a more complex mode of operating that was developed to support\r\n	larger modern flash types, in particular MLC NAND, that cannot used\r\n	deletion markers.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Yaffs\r\n	means operations common to both.</font></p>\r\n</ul>\r\n<p class=\"western\">Yaffs1 originally only worked with 512-byte page\r\ndevices but has been extended to support larger flash pages such as\r\nIntel M18 flash with 1k pages.</p>\r\n<p class=\"western\">Yaffs2 was originally designed for 1k or larger\r\npage sizes but can be used with smaller pages by using in-band tags.</p>\r\n<p class=\"western\">Since the Yaffs1 mode of operation is simpler to\r\nunderstand than the Yaffs2 mode of operation,  Yaffs1 will be\r\ndescribed first and readers interested in Yaffs2 operation should\r\nfirst fully acquaint themselves with the Yaffs1 mode of operation. It\r\nis suggested that this document be read sequentially rather than\r\nbrowsing it.</p>\r\n<h1 class=\"western\">5 Objects</h1>\r\n<p class=\"western\">In Yaffs-speak, an Object is anything that is\r\nstored in the file system. These are:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Regular data files</p>\r\n	<li/>\r\n<p class=\"western\">Directories</p>\r\n	<li/>\r\n<p class=\"western\">Hard-links</p>\r\n	<li/>\r\n<p class=\"western\">Symbolic links</p>\r\n	<li/>\r\n<p class=\"western\">Special objects (pipes, devices etc).</p>\r\n</ul>\r\n<p class=\"western\">All objects are identified by a unique integer\r\nobject id (<i><b>obj_id</b></i><i><b>)</b></i>.</p>\r\n<p class=\"western\">In the standard POSIX model, as used by Linux,\r\nthere are inodes and directory entries (dentries). \r\n</p>\r\n<p class=\"western\">An inode may be a regular file, directory, or\r\nspecial file.</p>\r\n<p class=\"western\">Directory entries provide the naming mechanism\r\nthat is used to locate inodes.</p>\r\n<p class=\"western\">Under POSIX, each inode may have zero, one or many\r\ndentries:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">One dentry per inode is commonly\r\n	understood.</p>\r\n	<li/>\r\n<p class=\"western\">Multiple dentries per inode allow the same\r\n	inode to be accessed via multiple names. This is achieved through\r\n	hard links.</p>\r\n	<li/>\r\n<p class=\"western\">Zero dentries per inode is less often\r\n	understood. This happens when an inode is unlinked while there is\r\n	still a handle open to the inode. The unlinking deletes the dentry\r\n	but the inode still exists. As soon as the handle is closed the\r\n	inode is deleted too.</p>\r\n</ul>\r\n<h1 class=\"western\">6 The Yaffs NAND model</h1>\r\n<p class=\"western\">The memory in NAND flash is arranged in <i><b>pages.</b></i>\r\nA page is the unit of allocation and programming.  In Yaffs, the unit\r\nof allocation is the<i> </i><i><b>chunk</b></i>. Typically a chunk\r\nwill be the same as a NAND page, but there is flexibility to use\r\nchunks which map to multiple pages (eg. A system may have two NAND\r\nchips in parallel requiring 2x2048 = 4096 byte chunks) . This\r\ndistinction gives a lot of flexibility in how the system can be\r\nconfigured.  In this text the term page and chunk are synonymous\r\nunless stated otherwise.</p>\r\n<p class=\"western\">Many, typically 32 to 128 but as many as a few\r\nhundred, chunks form a <i><b>block</b></i>. A block is the unit of\r\nerasure. \r\n</p>\r\n<p class=\"western\">NAND flash may be shipped with bad blocks and\r\nfurther blocks may go bad during the operation of the device. Thus,\r\nYaffs is aware of bad blocks and needs to be able to detect and mark\r\nbad blocks.</p>\r\n<p class=\"western\">NAND flash also typically requires the use of some\r\nsort of error detection and correction code (ECC). Yaffs can either\r\nuse existing ECC logic or provide its own.</p>\r\n<h1 class=\"western\">7 How Yaffs1 stores files</h1>\r\n<p class=\"western\">Yaffs1 has a modified log structure, while Yaffs2\r\n(see below) has a true log structure. A true log structured file\r\nsystem only ever writes sequentially. Yaffs1 uses deletion markers,\r\nwhich breaks the sequential write rule. Yaffs2 does not use deletion\r\nmarkers and is thus a true log structured file system.</p>\r\n<p class=\"western\">Instead of writing data in locations specific to\r\nthe files, the file system data is written in the form of a\r\nsequential log, The entries in the log are all one chunk in size and\r\ncan hold one of two types of chunk:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><i><b>Data chunk</b></i>: A chunk holding\r\n	regular data file contents.</p>\r\n	<li/>\r\n<p class=\"western\"><i><b>Object Header</b></i>: A descriptor\r\n	for an object (directory, regular data file, hard link, soft link,\r\n	special descriptor,...). This holds details such as the identifier\r\n	for the parent directory, object name, etc.</p>\r\n</ul>\r\n<p class=\"western\">Each chunk has <i><b>tags</b></i> associated with\r\nit. The tags comprise the following important fields (others being\r\nignored for now):</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><i><b>Object Id (</b></i><i><b>obj_id</b></i><i><b>)</b></i>:\r\n	Identifies which object the chunk belongs to.</p>\r\n	<li/>\r\n<p class=\"western\"><i><b>Chunk Id (</b></i><i><b>chunk_id</b></i><i><b>)</b></i>:\r\n	Identifies where in the file this chunk belongs. A chunk_id of zero\r\n	signifies that this chunk contains an objectHeader. chunk_id==1\r\n	signifies the first chunk in the file (ie. At file offset 0),\r\n	chunk_id==2  is the next chunk and so on.</p>\r\n	<li/>\r\n<p class=\"western\"><i><b>Deletion Marker (</b></i><i><b>is_deleted</b></i><i><b>)</b></i><i><b>:</b></i>\r\n	(Yaffs1 only)  Shows that this chunk is no longer in use.</p>\r\n	<li/>\r\n<p class=\"western\"><i><b>Byte Count</b></i><b>: </b><b>(n_bytes)</b>:\r\n	Number of bytes of data if this is a data chunk.</p>\r\n	<li/>\r\n<p class=\"western\"><i><b>Serial Number </b></i><i><b>(ser</b></i><i><b>ia</b></i><i><b>l_number)</b></i>:\r\n	 (Yaffs1 only) Serial number used to differentiate chunks with the\r\n	same obj_id and chunk_id.</p>\r\n</ul>\r\n\r\n<p class=\"western\" style=\"page-break-before: always\">Now let\'s bring\r\nthat all together in an explanation. This is a simplified explanation\r\nand skips over issues such as Soft Deletion (mentioned later in the\r\ndocument). For explanation purposes, we shall consider usage of\r\nfictitious NAND type that has 4 chunks per block, starting with an\r\nempty (erased) flash.</p>\r\n\r\n<p class=\"western\">First we\'ll create a file.</p>\r\n\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\">\r\n	<col width=\"37\">\r\n	<col width=\"56\">\r\n	<col width=\"67\">\r\n	<col width=\"60\">\r\n	<col width=\"64\">\r\n	<col width=\"271\">\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" style=\"font-weight: normal\">Block</p>\r\n		</td>\r\n		<td width=\"56\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" style=\"font-weight: normal\">Chunk</p>\r\n		</td>\r\n		<td width=\"67\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" style=\"font-weight: normal\">obj_id</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" style=\"font-weight: normal\">chunk_id</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" style=\"font-weight: normal\">Deletion</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\" style=\"font-weight: normal\">Comment</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" height=\"26\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"56\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"67\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Object Header for this file (length 0)</p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n\r\n<p class=\"western\">Next we write a few chunks of data to the file.</p>\r\n\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\">\r\n	<col width=\"37\">\r\n	<col width=\"48\">\r\n	<col width=\"60\">\r\n	<col width=\"64\">\r\n	<col width=\"56\">\r\n	<col width=\"290\">\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Block</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Chunk</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">obj_id</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">chunk_id</p>\r\n		</td>\r\n		<td width=\"56\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deletion</p>\r\n		</td>\r\n		<td width=\"290\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\">Comment</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"56\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"290\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Object Header for t<font size=\"3\" style=\"font-size: 12pt\">his\r\n			file (length 0)</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"56\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"290\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">First chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"56\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"290\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Second chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"56\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"290\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Third chunk of data</p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n\r\n<p class=\"western\">Next we close the file. This writers a new object\r\nheader for the file. Notice how the previous object header is\r\ndeleted.</p>\r\n\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\">\r\n	<col width=\"37\">\r\n	<col width=\"48\">\r\n	<col width=\"60\">\r\n	<col width=\"68\">\r\n	<col width=\"60\">\r\n	<col width=\"282\">\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Block</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Chunk</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">obj_id</p>\r\n		</td>\r\n		<td width=\"68\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">chunk_id</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deletion</p>\r\n		</td>\r\n		<td width=\"282\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\">Comment</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"68\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"282\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsoleted object header <font size=\"2\" style=\"font-size: 10pt\">(length\r\n			0)</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"68\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"282\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">First chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"68\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"282\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Second chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"68\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"282\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Third chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"68\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"282\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">New object header <font size=\"2\" style=\"font-size: 10pt\">(length\r\n			n)</font></p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n\r\n<p class=\"western\" style=\"page-break-before: always\">Let\'s now open\r\nthe file for read/write, overwrite part of the first chunk in the\r\nfile and close the file. The replaced data and object header chunks\r\nbecome deleted.</p>\r\n\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\" style=\"page-break-inside: avoid\">\r\n	<col width=\"37\">\r\n	<col width=\"48\">\r\n	<col width=\"64\">\r\n	<col width=\"64\">\r\n	<col width=\"71\">\r\n	<col width=\"271\">\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Block</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Chunk</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">obj_id</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">chunk_id</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deletion</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\">Comment</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete object header.</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete first chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Second chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Third chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete object header</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">New first chunk of file</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">New object header</p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n\r\n<p class=\"western\">Now let\'s resize the file to zero by opening the\r\nfile with O_TRUNC and closing the file. This writes a new object\r\nheader with length 0 and the contents are pruned making the data\r\nchunks deleted.</p>\r\n\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\">\r\n	<col width=\"37\">\r\n	<col width=\"48\">\r\n	<col width=\"64\">\r\n	<col width=\"64\">\r\n	<col width=\"71\">\r\n	<col width=\"271\">\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Block</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Chunk</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">obj_id</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">chunk_id</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deletion</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\">Comment</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete object header.</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete first chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Second chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Third chunk of data</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete object header</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Deleted first chunk of file</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Delted</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsoleted object header</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"37\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"48\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"64\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"71\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"271\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">New object header <font size=\"2\" style=\"font-size: 10pt\">(length\r\n			0).</font></p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n\r\n<p class=\"western\">Note how all the pages in block 1 are now marked\r\nas deleted. This means that block 1 no longer contains useful\r\ninformation so we can now erase block 1 and reuse the space.</p>\r\n<p class=\"western\">We will now rename the file. To do this we write a\r\nnew object header for the file</p>\r\n\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\" style=\"page-break-inside: avoid\">\r\n	<col width=\"38\">\r\n	<col width=\"42\">\r\n	<col width=\"58\">\r\n	<col width=\"60\">\r\n	<col width=\"60\">\r\n	<col width=\"297\">\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Block</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Chunk</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">obj_id</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">chunk_id</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\">Comment</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Erased</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Erased</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Erased</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"1\" sdnum=\"2057;\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\"><br/>\r\n\r\n			</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Erased</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete object header</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">1</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Deleted first chunk of file</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsoleted object header</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"2\" sdnum=\"2057;\">\r\n			<p class=\"western\">2</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Deleted</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">Obsolete object header</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"38\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\" sdval=\"3\" sdnum=\"2057;\">\r\n			<p class=\"western\">3</p>\r\n		</td>\r\n		<td width=\"42\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"58\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">500</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">0</p>\r\n		</td>\r\n		<td width=\"60\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Live</p>\r\n		</td>\r\n		<td width=\"297\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">New object header showing new name</p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n\r\n<p class=\"western\">Block 2 now contains only deleted chunks and can\r\nbe erased and reused.</p>\r\n<p class=\"western\">Note how the tags tell us:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Which\r\n	chunks belong to which object</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">The\r\n	position of the chunks within a file,</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Which\r\n	chunks are current</font></p>\r\n</ul>\r\n<ul>\r\n	<p class=\"western\"><font size=\"3\" style=\"font-size: 12pt\">With that\r\n	information we can recreate the state of the files regardless of the\r\n	placement of the chunks in NAND. This means that should the system\r\n	fail (crash, power fail,...) at any point during the sequences\r\n	above, we are still able to recover the file system state up to that\r\n	point.</font></p>\r\n</ul>\r\n<p class=\"western\"><font size=\"3\" style=\"font-size: 12pt\">Note that\r\nthere are no file allocation tables or similar structures stored in\r\nthe flash. This reduces the amount of writing and erasing (improving\r\nwrite performance) while also improving robustness. Corruption of\r\nfile allocation tables and similar structures is a common failure\r\nmechanism for embedded file systems. The lack of such structures\r\nmakes Yaffs more robust. Or, to put it another way, you can\'t corrupt\r\nwhat you don\'t store.</font></p>\r\n<h1 class=\"western\">8 Garbage collection</h1>\r\n<p class=\"western\">As we have shown so far, when a block is made up\r\nonly of deleted chunks, that block can be erased and reused. However,\r\nconsider what will happen if we have many blocks which each have a\r\nfew current chunks in them. Clearly we cannot erase any of the\r\ncurrent blocks or we will destroy data. What we need to do is copy\r\nthe useful data chunks off a block, deleting the originals and\r\nallowing the block to be erased and reused. This process is referred\r\nto as <i><b>garbage collection</b></i>.</p>\r\n<p class=\"western\">The Yaffs garbage collection process works as\r\nfollows:</p>\r\n<ol>\r\n	<li/>\r\n<p class=\"western\">Find a block worth collecting (according\r\n	the the heuristics below). If none found, then exit.</p>\r\n	<li/>\r\n<p class=\"western\">Iterate through the chunks in the block. If\r\n	the chunk is in use then create a new copy and delete the original.\r\n	Fix up the RAM data structures to reflect the change.</p>\r\n</ol>\r\n<p class=\"western\">Once all chunks in this block have been deleted,\r\nthe block can be erased ready for reuse.</p>\r\n<p class=\"western\">Note that although step 2 deletes the original\r\nchunk when it gets copied there is not much point in actually\r\nprogramming the deletion marker (is_deleted flag) in flash since\r\nwe\'re about to erase the block anyway. Thus Yaffs does not program\r\nthe deletion marker in these cases. If power is lost part way through\r\nthe operation we can still tell the difference between the original\r\nand the copy by looking at the serial number (not that it really\r\nmatters anyway since the two have the same contents so either can be\r\nused).</p>\r\n<p class=\"western\">The heuristics to determine whether a block is\r\nworth collecting are as follows:</p>\r\n<ol>\r\n	<li/>\r\n<p class=\"western\">If there are many erased blocks available,\r\n	then Yaffs does not need to work hard, but will instead only attempt\r\n	to perform garbage collection of blocks with very few chunks in use.\r\n	This is termed <i><b>passive</b></i> garbage collection.</p>\r\n	<li/>\r\n<p class=\"western\">If, however, there are very few erased\r\n	blocks, Yaffs will work much harder to recover more space and will\r\n	garbage collect blocks with more chunks in use. This is termed\r\n	<i><b>aggressive</b></i> garbage collection.</p>\r\n</ol>\r\n<p class=\"western\">OK, the passive/aggressive names are a bit silly,\r\nbut they were contrived around midnight... give me a break!</p>\r\n<p class=\"western\">If garbage collection is aggressive, we need\r\nerased space urgency and the whole block is collected in a single\r\ngarbage collection cycle. If the collection is passive then only a\r\nfew chunks are collected at a time thus spreading the effort over\r\nmany garbage collection cycles. This is done to reduce garbage\r\ncollection load and improve responsiveness.</p>\r\n<p class=\"western\">The rationale behind the above heuristics is to\r\ndelay garbage collection when possible to reduce the amount of\r\ncollection that needs to be performed, thus increasing average system\r\nperformance. Yet there is a conflicting goal of trying to spread the\r\ngarbage collection so that it does not all happen at the same causing\r\nfluctuations in file system throughput. These conflicting goals make\r\ngarbage tuning quite challenging.</p>\r\n<p class=\"western\">All flash file systems need some sort of garbage\r\ncollector to reclaim space. The garbage collector is often a\r\ndetermining factor in the performance of the flash file system. Many\r\nfile systems have to do a significant amount of effort in a single\r\ncollection sweep.</p>\r\n<p class=\"western\">Yaffs only deals with one block at a time which\r\nconstrains the amount of effort in a garbage collection cycle, thus\r\nreducing the “stall time”.  Under normal conditions that garbage\r\ncollection is performed a few chunks at a time, further reducing\r\n“stall time”.</p>\r\n<h1 class=\"western\">9 Yaffs1 serial numbers</h1>\r\n<p class=\"western\">In Yaffs1, each chunk is marked with a 2-bit\r\nserial number that is incremented every time a chunk with the same\r\ntags value is replaced (eg. When a chunk is overwritten or when\r\ncopied by garbage collection).</p>\r\n<p class=\"western\">Now let\'s suppose first that we did not have a\r\nserial number. \r\n</p>\r\n<p class=\"western\">Let\'s consider a rename where an object header\r\nchunk must be replaced with a new one with the new name. Yaffs could\r\ndo the following:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Delete\r\n	the old chunk.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Write\r\n	the new chunk. </font>\r\n	</p>\r\n</ul>\r\n<p class=\"western\">If the system fails after the delete, the system\r\ncould end up with no chunks matching the relevant tags values. This\r\ncould cause files to be lost (end up in the lost+found directory).\r\nThus, we have to write the new chunk before deleting the old chunk.</p>\r\n<p class=\"western\">But now consider what might happen if we did this:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">W<font face=\"Liberation Serif, serif\">rite\r\n	new chunk.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Delete\r\n	old chunk.</font></p>\r\n</ul>\r\n<p class=\"western\">If the system failed after the write we now have\r\ntwo chunks that match the tags. How can we tell which one is current?</p>\r\n<p class=\"western\">The current chunk is determined by inspecting the\r\nserial number.  Since the serial number is only incremented by one\r\nbefore the old chunk is deleted, a 2-bit serial number is sufficient.\r\nValid pairs are:</p>\r\n<table width=\"86\" cellpadding=\"4\" cellspacing=\"0\">\r\n	<col width=\"35\">\r\n	<col width=\"33\">\r\n	<tr valign=\"top\">\r\n		<td width=\"35\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">Old</p>\r\n		</td>\r\n		<td width=\"33\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\">New</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"35\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">00</p>\r\n		</td>\r\n		<td width=\"33\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">01</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"35\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">01</p>\r\n		</td>\r\n		<td width=\"33\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">10</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"35\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">10</p>\r\n		</td>\r\n		<td width=\"33\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">11</p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"35\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\">11</p>\r\n		</td>\r\n		<td width=\"33\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\">00</p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n\r\n<p class=\"western\">Thus, by inspecting the serial number attached to\r\nthe old and new tags the current chunk can be determined and the old\r\nchunk can be deleted.</p>\r\n<h1 class=\"western\">10 Yaffs2 NAND model</h1>\r\n<p class=\"western\">Yaffs2 is an extension of Yaffs designed to\r\nfulfill a new set of objectives to work with newer NAND types\r\nincluding:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Zero overwrites. Yaffs1 only ever\r\n	overwrites a single byte in the spare area of the chunks to set the\r\n	deletion marker. More modern NAND devices are less tolerant of\r\n	overwrites and Yaffs2 performs no overwrites at all.</p>\r\n	<li/>\r\n<p class=\"western\">Sequential chunk writing within a block.\r\n	More modern NAND reliability specifications tend to assume\r\n	sequential writing. Since Yaffs2 does not write deletion markers,\r\n	the writing of chunks within a block is strictly sequential.</p>\r\n	<li/>\r\n<p class=\"western\">Some flash technologies – such as MLC –\r\n	only work properly if pages are written sequentially. This is a\r\n	fundamental requirement of how many MLC types perform the bit\r\n	overlaying.</p>\r\n</ul>\r\n<p class=\"western\">Since Yaffs2 performs less writes, there is\r\npotential for Yaffs2 to have improved write performance.</p>\r\n<p class=\"western\">Yaffs2 cannot use a deletion marker because that\r\nwould violate the zero overwrites mandate and alternate mechanisms\r\nare provided to determine which chunks are current and which are\r\ndeleted. These mechanisms are:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><i><b>Sequence Number </b></i><i><b>(seq_number)</b></i>:\r\n	As each block is allocated, the file system\'s sequence number is\r\n	incremented and each chunk in the block is marked with that sequence\r\n	number. The sequence number thus provides a way of organising the\r\n	log in chronological order.</p>\r\n	<li/>\r\n<p class=\"western\"><i><b>Shrink Header Marker </b></i><i><b>(shrink_header)</b></i>:\r\n	The shrink header marker is used to mark object headers that are\r\n	written to shrink the size of a data file. This is explained more in\r\n	the accompanying text.</p>\r\n</ul>\r\n\r\n<p class=\"western\" align=\"center\"><i><b>Note: The Yaffs2 sequence\r\nnumber is not the same as the Yaffs1 serial number!</b></i></p>\r\n\r\n<p class=\"western\">Note: We still refer to chunk deletion in Yaffs2.\r\nThe chunks are marked as deleted in the RAM data structures used by\r\ngarbage collection etc, but there is no deletion marker written to\r\nflash.</p>\r\n<h2 class=\"western\">10.1 Sequence Number</h2>\r\n<ul>\r\n	<p class=\"western\">The sequence number allows the chronological\r\n	order to be determined which allows Yaffs to determine the sequence\r\n	of events and restore the file system state. This is achieved by\r\n	scanning <i><b>backwards</b></i> chronologically (ie. From the\r\n	highest sequence number backwards to the lowest sequence number).\r\n	Thus:</p>\r\n	<li/>\r\n<p class=\"western\">Since we\'re scanning backwards, the most\r\n	recently written – and thus current – chunk matching an\r\n	obj_id:chunk_id pair will be encountered first and all subsequent\r\n	matching chunks must be obsolete and treated as deleted.</p>\r\n	<li/>\r\n<p class=\"western\">The file length in object headers are used\r\n	to trim back resized files. If an object header is encountered, then\r\n	subsequent data chunks that lie beyond that file length are clearly\r\n	obsolete and treated as deleted. Note that both current and obsolete\r\n	object header sizes must be used to obtain an accurate\r\n	reconstruction.</p>\r\n</ul>\r\n<h2 class=\"western\">10.2 Shrink Header</h2>\r\n<p class=\"western\">Explaining the purpose of the shrink header marker\r\nis a bit convoluted. The purpose of a shrink header marker is to show\r\nthat this object header indicates that a file has shrunken in size,\r\nand to prevent those object headers from being deleted by garbage\r\ncollection.  To understand this, it is easiest to consider what would\r\nhappen if the shrink header markers did not exist.</p>\r\n<p class=\"western\">For simplification we\'ll assume no garbage\r\ncollection happens during this part of the exercise. It is safe to\r\nmake that assumption since it does not alter the reasoning.</p>\r\n<p class=\"western\">Consider a file that has been through the\r\nfollowing:</p>\r\n<p class=\"code-western\"><font face=\"Liberation Mono, monospace\"><font size=\"2\" style=\"font-size: 10pt\"><b>#define\r\nMB (1024 * 1024)<br/>\r\n</b></font></font><br/>\r\n\r\n</p>\r\n<p class=\"code-western\"><code class=\"western\"><font face=\"Liberation Mono, monospace\"><font size=\"2\" style=\"font-size: 9pt\">h\r\n= open(“foo”,O_CREAT| O_RDWR, S_IREAD|S_IWRITE); /* create file\r\n*/</font></font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\"><br/>\r\nwrite(h,data,5*</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">MB</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">);\r\n/* write 5 MB of data /<br/>\r\ntruncate(h,1*</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">MB</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">);\r\n /* truncate to 1MB */<br/>\r\nlseek(h,2*</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">MB</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">,\r\nSEEK_SET); /* set the file access position to 2MB\r\n*/<br/>\r\nwrite(h,data,1*</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">MB</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 9pt\">);\r\n/* write 1MB of data */<br/>\r\nclose(h);</font></code><br/>\r\n<br/>\r\n\r\n</p>\r\n<p class=\"western\">The file will now be 3MB in length, but there will\r\nbe a “hole” between 1MB and 2MB. According to POSIX (and to aid\r\nsecurity etc) that “hole” should always read back as zeros.</p>\r\n<p class=\"western\">Yaffs2 would represent that in NAND with the\r\nfollowing sequence of chunks:</p>\r\n<ol>\r\n	<li/>\r\n<p class=\"western\">Object header for file creation (file\r\n	length = 0)</p>\r\n	<li/>\r\n<p class=\"western\">5MB worth of data chunks (0 to 5MB)</p>\r\n	<li/>\r\n<p class=\"western\">Object header for truncation (file length =\r\n	1MB)</p>\r\n	<li/>\r\n<p class=\"western\">1MB worth of data chunks (2MB to 3MB)</p>\r\n	<li/>\r\n<p class=\"western\">Object header for close (file length = 3MB)</p>\r\n	<p class=\"western\">At this stage, only the the following data chunks\r\n	are current:</p>\r\n</ol>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">The first 1MB of data created in step 2\r\n	above.</p>\r\n	<li/>\r\n<p class=\"western\">The 1MB of data created in step 4 above.</p>\r\n	<li/>\r\n<p class=\"western\">The object header created in step 5 above.</p>\r\n</ul>\r\n<p class=\"western\">But Yaffs must remember the truncation that\r\nhappened in step 3, otherwise Yaffs will “forget”  that there is\r\na hole, which would cause the old data to be visible again. Thus, if\r\nYaffs creates a hole it first writes a shrink header to indicate the\r\nstart of the hole and a regular object header to mark the end of the\r\nhole. \r\n</p>\r\n<p class=\"western\">The shrink header modifies the behavior of the\r\ngarbage collector to ensure that  these shrink headers are not erased\r\nuntil it is safe to do so. This unfortunately has a negative impact\r\non garbage collection in systems which make extensive use of files\r\nwith holes.</p>\r\n<p class=\"western\">Shrink headers are also used to indicate that a\r\nfile has been deleted and that the record of the file deletion is not\r\nlost.</p>\r\n<h2 class=\"western\">10.3 Yaffs2 extended tags</h2>\r\n<p class=\"western\">Yaffs2 extends the tags in object headers with\r\nextra fields to improve mount scanning performance. The operation of\r\nextended tags is described later in this document.</p>\r\n<h1 class=\"western\">11 Bad block handling NAND error handling</h1>\r\n<p class=\"western\">NAND flash is designed to be very low cost and\r\nvery high density. In order to get high yields, and thus keep costs\r\ndown, NAND flash is typically shipped with a few bad blocks and some\r\nfurther blocks are expected to go bad during the use of the device.\r\nThus, any flash file system without an effective bad block handling\r\npolicy is unsuitable for NAND flash.</p>\r\n<p class=\"western\">Yaffs1 uses the Smart-Media style of bad block\r\nmarking. This checks the sixth byte (byte 5) of the spare area. In a\r\ngood block this should be 0xFF. A factory-marked bad block should be\r\n0x00. If Yaffs1 determines that a block has gone bad it is marked bad\r\nwith 0x59 (\'Y\'). Using a distinctive marker allows Yaffs-marked bad\r\nblocks to be differentiated from factory-marked bad blocks.</p>\r\n<p class=\"western\">Yaffs2 mode is designed to support a wider range\r\nof devices and spare-area layouts. Thus, Yaffs2 does not decide which\r\nbytes to mark but instead calls driver functions to determine whether\r\nthe block is bad, or to mark it bad.</p>\r\n<p class=\"western\">So, when does Yaffs mark a block bad? Yaffs will\r\nmark a block bad if a read or write operation fails or if three ECC\r\nerrors are detected. A block that is marked bad is retired from use,\r\nthus improving the robustness of the file system. This policy is\r\nsuitable for SLC flash. MLC policies are under development.</p>\r\n<p class=\"western\">Further, NAND flash cells can sometimes be\r\ndisturbed (corrupted) by NAND activity and charge loss.  These errors\r\nare corrected by error correction codes (ECC) which may be\r\nimplemented in hardware, software drivers, or within Yaffs itself.\r\nAgain, any flash file system lacking effective ECC handling is\r\nunsuitable for NAND flash.</p>\r\n<p class=\"western\">Yaffs1 mode can use either the built in ECC or use\r\nECC provided by the driver or hardware.</p>\r\n<p class=\"western\">Since Yaffs2 mode is designed for a wider range of\r\ndevices, it does not provide ECC internally but requires that the\r\ndriver provide the ECC.</p>\r\n<p class=\"western\">The ECC code supplied with Yaffs (yaffs_ecc.c) is\r\nthe fastest C code implementation of a Smart Media compatible ECC\r\nalgorithm that we are aware of. This code will correct any single bit\r\nerror within a 256-byte data block and detect 2 errors per 256-byte\r\ndata block. This is sufficient error correction to provide very high\r\nreliability on most SLC-type NAND flash.</p>\r\n<p class=\"western\">For a more complete description of failure\r\nhandling, please refer to the Yaffs error mitigation document.</p>\r\n<h1 class=\"western\">12 RAM structures</h1>\r\n<p class=\"western\">While it is theoretically possible to use a log\r\nstructured file system with very few RAM structures, this would\r\nprovide reduce performance. Thus, significant RAM data structures are\r\nrequired to store enough information to provide sufficiently high\r\nperformance. \r\n</p>\r\n<p class=\"western\">Before we jump in, it is a good idea to first\r\nfigure out what purpose the RAM structures serve. The main structures\r\nare defined in yaffs_guts.h and their main purposes, are :</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Device/partition: This is named <i><b>yaffs_dev</b></i><span style=\"font-style: normal\"><span style=\"font-weight: normal\">.\r\n	</span></span>This is required to hold information relating to a\r\n	Yaffs “partition” or “mount point”. Using these, rather than\r\n	globals, allows Yaffs to simultaneously support multiple partitions\r\n	and partitions of different types. In fact, almost other data\r\n	structures mentioned here are part of, or accessed via, the\r\n	structure.</p>\r\n	<li/>\r\n<p class=\"western\">NAND Block Information: This is named\r\n	<i><b>yaffs_block_info </b></i>and holds the current state of the\r\n	NAND blocks. Each yaffs_dev has an array of these.</p>\r\n	<li/>\r\n<p class=\"western\">NAND Chunk Information: This is a bitfield\r\n	attached to the yaffs_dev that holds the current in-use state of\r\n	each chunk in the system. There is one bit per chunk in the\r\n	partition.</p>\r\n	<li/>\r\n<p class=\"western\">Object: This is named <i><b>yaffs_obj</b></i>\r\n	and holds the state of an object (see section 3). There is one of\r\n	these for each object in the file system, where an object is one of\r\n	a regular file, directory, hard link, symbolic link or special link.\r\n	There are different variants of yaffs_Objects to reflect the\r\n	different data required for these different object types. Each\r\n	object is uniquely identified by an obj_id.</p>\r\n	<li/>\r\n<p class=\"western\">File structure: For each file object, Yaffs\r\n	holds a tree which provides the mechanism to find the data chunks in\r\n	a file. The tree consists of nodes called <i><b>yaffs_tnode</b></i>\r\n	(tree nodes).</p>\r\n	<li/>\r\n<p class=\"western\">Directory structure: The directory\r\n	structure allows objects to be found by name. The directory\r\n	structure is built from a doubly-linked list that is rooted in the\r\n	directory and binds together the sibling objects within a directory.</p>\r\n	<li/>\r\n<p class=\"western\">Object number hash table: The object number\r\n	hash table provides a mechanism to find an object from its obj_id.\r\n	The obj_id is hashed to select a hash bucket. Each hash bucket has a\r\n	doubly-linked list of objects that belong in this hash bucket, as\r\n	well as a count of the objects in the bucket.</p>\r\n	<li/>\r\n<p class=\"western\">Cache: Yaffs provides a read/write cache\r\n	that significantly improves performance for short operations. The\r\n	size of the cache can be set at run-time.</p>\r\n</ul>\r\n<p class=\"western\">The usage of these structures is described in more\r\ndetail below.</p>\r\n<p class=\"western\">Yaffs makes significant use of doubly-linked\r\nlists. These data structures are very useful because they provide\r\nrapid insertion, removal and traversal. They do however come at the\r\nexpense of requiring two pointers rather than just one that would be\r\nrequired by a singly-linked list.</p>\r\n<h2 class=\"western\">12.1 Yaffs objects (struct yaffs_obj)</h2>\r\n<p class=\"western\">Each object (file, directory,...) in the system is\r\nrepresented by a yaffs_obj structure \r\n</p>\r\n<p class=\"western\">The yaffs_obj\'s main function is to store most of\r\nthe object metadata and type-specific information. This means that\r\nalmost all the information about an object can be accessed\r\nimmediately without reading flash.</p>\r\n<p class=\"western\">The metadata includes, amongst others:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">obj_id:\r\n	The number used to identify the object.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">parent:\r\n	A pointer to the parent directory. Not all objects have a parent.\r\n	The root director and special directories for unlinked and deleted\r\n	files do not have parents so this is NULL.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">short_name:\r\n	If the name is short enough to fit in a small fixed-sized array\r\n	(default 16 characters) then it is stored here otherwise it must be\r\n	fetched from flash each time it is requested.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">type:\r\n	Type of object.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Permissions,\r\n	time, ownership and other attributes</font></p>\r\n</ul>\r\n<p class=\"western\"><font size=\"3\" style=\"font-size: 12pt\">Depending\r\non the object type, yaffs_obj also stores:</font></p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">A\r\n	tnode tree, file extents etc for data files</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">A\r\n	directory chain for directories</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">An\r\n	equivalent object for hard links</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">A\r\n	string for symbolic links</font></p>\r\n</ul>\r\n<h2 class=\"western\">12.2 Look-up by obj_id</h2>\r\n<p class=\"western\">The purpose of this mechanism is to rapidly access\r\nan object by its device and obj_id. This is required during garbage\r\ncollection, scanning and similar operations.</p>\r\n<p class=\"western\">Each yaffs_dev uses a hash table for this purpose.\r\nThe hash table has 256 “buckets” (tunable), each holding a\r\ndoubly-linked list of the yaffs_objs in that bucket.</p>\r\n<p class=\"western\">The hash table\'s hash function is just masking the\r\nleast significant bits of the obj_id. This is a very cheap function\r\nthat provides reasonable “spread”.</p>\r\n<p class=\"western\">Yaffs makes an attempt to assign obj_ids in a way\r\nthat keeps the number of objects in each hash bucket quite low, thus\r\npreventing any one hash entry getting too long.</p>\r\n<p class=\"western\">This mechanism is also charged with assigning new\r\n(unique) obj_id values.</p>\r\n<h2 class=\"western\">12.3 Directory structure</h2>\r\n<p class=\"western\">The purpose of the directory structure is to\r\nrapidly access an object by name. This is required to perform file\r\noperations such as opening, renaming etc.</p>\r\n<p class=\"western\"><font size=\"3\" style=\"font-size: 12pt\">The Yaffs\r\ndirectory structure is formed by a tree of objects of type\r\nYAFFS_OBJECT_TYPE_DIRECTORY. These objects have a doubly linked node\r\nof children.</font></p>\r\n<p class=\"western\">Each yaffs_obj also has a doubly linked list node\r\ncalled sibling which chain together the siblings in a directory.</p>\r\n<p class=\"western\">Each Yaffs partition has a root directory.</p>\r\n<p class=\"western\">Each yaffs partition also has some special purpose\r\n“fake” directories which are not stored in NAND but are instead\r\ncreated on mounting:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">lost+found: This directory is used as a\r\n	place to store any lost file parts that cannot be placed in the\r\n	normal directory tree.</p>\r\n	<li/>\r\n<p class=\"western\">Unlinked and deleted: These are\r\n	pseudo-directories that are not in the directory tree. Placing\r\n	objects in these directories gives them a status of being unlinked\r\n	or deleted.</p>\r\n</ul>\r\n<p class=\"western\" align=\"left\">Each object has a name that is used\r\nto look up the object within the directory, Thus, each name within a\r\ndirectory must be unique. This rule does not apply to objects in the\r\nunlinked and deleted pseudo-directories since we never use names to\r\nlook up unlinked/deleted files and there may be many files of the\r\nsame name that have been deleted.</p>\r\n<p class=\"western\">Name resolution is sped up by two mechanisms:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">short_names\r\n	are stored directly in the yaffs_obj so that they don\'t have to be\r\n	loaded from flash.</font></p>\r\n	<li/>\r\n<p class=\"western\"><font face=\"Liberation Serif, serif\">Each\r\n	object has a “name sum”. This is a simple hashing of the name\r\n	which speeds up the matching process because it is cheaper to\r\n	compare the hash than compare the whole name string.</font></p>\r\n</ul>\r\n<p class=\"western\"><img src=\"data:image/png;base64,[encoded data, 22776 characters]\" name=\"Object2\" align=\"left\" width=\"412\" height=\"355\">\r\n  <br clear=\"left\"/>\r\n</img>\r\n<br/>\r\n<br/>\r\n\r\n</p>\r\n\r\n<p class=\"western\">The above directory structure represents the\r\nfollowing directory tree</p>\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\">\r\n	<col width=\"119\">\r\n	<col width=\"468\">\r\n	<tr valign=\"top\">\r\n		<td width=\"119\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font face=\"Courier, monospace\"><font size=\"3\" style=\"font-size: 12pt\">/</font></font></p>\r\n		</td>\r\n		<td width=\"468\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Root directory</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"119\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font face=\"Courier, monospace\"><font size=\"3\" style=\"font-size: 12pt\">/a</font></font></p>\r\n		</td>\r\n		<td width=\"468\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Directory containing c,d,e</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"119\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font face=\"Courier, monospace\"><font size=\"3\" style=\"font-size: 12pt\">/b</font></font></p>\r\n		</td>\r\n		<td width=\"468\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Empty directory</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"119\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font face=\"Courier, monospace\"><font size=\"3\" style=\"font-size: 12pt\">/lost+found</font></font></p>\r\n		</td>\r\n		<td width=\"468\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Empty directory</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"119\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font face=\"Courier, monospace\"><font size=\"3\" style=\"font-size: 12pt\">/a/c</font></font></p>\r\n		</td>\r\n		<td width=\"468\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Directory</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"119\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font face=\"Courier, monospace\"><font size=\"3\" style=\"font-size: 12pt\">/a/d</font></font></p>\r\n		</td>\r\n		<td width=\"468\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Data file</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"119\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font face=\"Courier, monospace\"><font size=\"3\" style=\"font-size: 12pt\">/a/e</font></font></p>\r\n		</td>\r\n		<td width=\"468\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Data file</font></p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n<p class=\"western\" align=\"left\" style=\"margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<br/>\r\n\r\n</p>\r\n<p class=\"western\">If a Yaffs partition has been somehow corrupted\r\nthen it is possible for an object to be created during scanning but\r\nwith no object header (which contains the object name) being found.\r\nThe object would then not have a name. In these cases, Yaffs creates\r\na pseudonym from the object number of the form objnnnn so that the\r\nobject can be placed in the directory structure. \r\n</p>\r\n\r\n<h2 class=\"western\" style=\"page-break-before: always\">12.4 Hard links</h2>\r\n<p class=\"western\">In POSIX file systems, the objects (inodes in\r\nLinux terminology, vnode in BSD-speak) and the object names (dentry\r\nin Linux terminology)  are independent in that an object can have\r\nzero, one or more names.</p>\r\n<p class=\"western\">Having files with zero links is caused by\r\nconstructs such as:</p>\r\n<p class=\"western\" align=\"left\" style=\"margin-left: 1.25cm; margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<font face=\"Courier 10 Pitch\"><font size=\"1\" style=\"font-size: 8pt\"><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">h\r\n= open(“foo”,O_CREAT | O_RDWR, S_IREAD | S_IWRITE); /* create\r\nfile “foo” */</font></code></font></font></p>\r\n<p class=\"western\" align=\"left\" style=\"margin-left: 1.25cm; margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<font face=\"Courier 10 Pitch\"><font size=\"1\" style=\"font-size: 8pt\"><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">unlink(“foo”);	/*\r\nunlink it </font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">to\r\nremove</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">\r\ndirectory </font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">entry\r\n</font></code><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">*/</font></code></font></font></p>\r\n<p class=\"western\" align=\"left\" style=\"margin-left: 1.25cm; margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<font face=\"Courier 10 Pitch\"><font size=\"1\" style=\"font-size: 8pt\"><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">/*\r\nwe still have a handle to the file so can still access it via the\r\nhandle */</font></code></font></font></p>\r\n<p class=\"western\" align=\"left\" style=\"margin-left: 1.25cm; margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<font face=\"Courier 10 Pitch\"><font size=\"1\" style=\"font-size: 8pt\"><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">read(h,buffer,100);	</font></code></font></font></p>\r\n<p class=\"western\" align=\"left\" style=\"margin-left: 1.25cm; margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<font face=\"Courier 10 Pitch\"><font size=\"1\" style=\"font-size: 8pt\"><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">write(h,buffer,100);</font></code></font></font></p>\r\n<p class=\"western\" align=\"left\" style=\"margin-left: 1.25cm; margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<font face=\"Courier 10 Pitch\"><font size=\"1\" style=\"font-size: 8pt\"><code class=\"western\"><font size=\"2\" style=\"font-size: 10pt\">close(h);\r\n/* as soon as the handle is closed the file is deleted */</font></code></font></font></p>\r\n<p class=\"western\" align=\"left\" style=\"margin-left: 1.25cm; margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<br/>\r\n\r\n</p>\r\n<p class=\"western\">Yaffs does not store separate object and name\r\nrecords because that would waste space and incur extra\r\nreading/writing. Instead, Yaffs is optimised for the most typical\r\ncase of one name per object. That is, Yaffs stores one name per\r\nyaffs_obj and uses “cheats” to achieve other behavior:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Objects that have zero names (ie unlinked\r\n	objects) are handled by renaming the object into a fake directory\r\n	that is used to designate unlinked objects.</p>\r\n	<li/>\r\n<p class=\"western\">Multiple names object are handled by\r\n	designating one of the objects the main object and having multiple\r\n	hard link pseudo-objects that refer to it.</p>\r\n	<li/>\r\n<p class=\"western\">The inode number (vnid in BSD-speak) is a\r\n	per-file system unique number that identifies the object. The Yaffs\r\n	obj_id of the main object is presented to the user. That is, if the\r\n	inode number is queried from a hardlink object then the obj_id of\r\n	the equivalent object is returned.</p>\r\n</ul>\r\n<p class=\"western\">The linkage between hard link pseudo-objects and\r\ntheir equivalent object is through two fields:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Each object has a hard_links doubly linked\r\n	list node that links the list of hard links to that object.</p>\r\n	<li/>\r\n<p class=\"western\">Each hard link has a equiv_obj pointer to\r\n	the “equivalent object”.</p>\r\n</ul>\r\n\r\n<p class=\"western\" style=\"page-break-before: always\">The usage of\r\nthis structure is straight forward except for one interesting case\r\nwhen hard links are being deleted. Consider the following sequence of\r\nevents:</p>\r\n<table width=\"605\" cellpadding=\"4\" cellspacing=\"0\">\r\n	<col width=\"50\">\r\n	<col width=\"80\">\r\n	<col width=\"449\">\r\n	<tr valign=\"top\">\r\n		<td width=\"50\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">1</font></p>\r\n		</td>\r\n		<td width=\"80\" style=\"border-top: 1px solid #000000; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0.1cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\"># touch a</font></p>\r\n		</td>\r\n		<td width=\"449\" style=\"border: 1px solid #000000; padding: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Create file a</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"50\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">2</font></p>\r\n		</td>\r\n		<td width=\"80\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\"># ln a b</font></p>\r\n		</td>\r\n		<td width=\"449\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Create a hard link b with\r\n			equivalent object a.</font></p>\r\n		</td>\r\n	</tr>\r\n	<tr valign=\"top\">\r\n		<td width=\"50\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">3</font></p>\r\n		</td>\r\n		<td width=\"80\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: none; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\"># rm a</font></p>\r\n		</td>\r\n		<td width=\"449\" style=\"border-top: none; border-bottom: 1px solid #000000; border-left: 1px solid #000000; border-right: 1px solid #000000; padding-top: 0cm; padding-bottom: 0.1cm; padding-left: 0.1cm; padding-right: 0.1cm\">\r\n			<p class=\"western\" align=\"left\" style=\"orphans: 0; widows: 0; page-break-before: auto\">\r\n			<font size=\"3\" style=\"font-size: 12pt\">Remove a. The object must\r\n			still exist under the name b</font></p>\r\n		</td>\r\n	</tr>\r\n</table>\r\n<p class=\"western\" align=\"left\" style=\"margin-bottom: 0cm; orphans: 0; widows: 0; page-break-before: auto\">\r\n<br/>\r\n\r\n</p>\r\n<p class=\"western\">In step 3, Yaffs cannot just delete the equivalent\r\nobject since that would leave a “hanging” hard link with no\r\nequivalent object. \r\n</p>\r\n<p class=\"western\">We also cannot just change the type of one of the\r\nhardlink objects because that would cause the object\'s obj_id to\r\nchange. This would be unacceptable since it would break any mechanism\r\nthat use the obj_id (of which there are many within and outside of\r\nYaffs).</p>\r\n<p class=\"western\">Thus, if an object is deleted and it has hard\r\nlinks to it then we do the following:</p>\r\n<ul>\r\n	<li/>\r\n<p class=\"western\">Select one of the object\'s hard links.</p>\r\n	<li/>\r\n<p class=\"western\">Rename the object to the name in the hard\r\n	link.</p>\r\n	<li/>\r\n<p class=\"western\">Delete the hard link pseudo-object.</p>\r\n</ul>\r\n<h2 class=\"western\">12.5 Symbolic links and special objects</h2>\r\n<p class=\"western\">These object types just store values that are\r\nneeded to provide a full POSIX file system.</p>\r\n<p class=\"wester