+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion));
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_super: block size %d\n"),
+ (int)(sb->s_blocksize)));
+
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
+ MAJOR(sb->s_dev), MINOR(sb->s_dev),
+ yaffs_devname(sb, devname_buf)));
+
+ /* Check it's an mtd device..... */
+ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
+ return NULL; /* This isn't an mtd device */
+
+ /* Get the device */
+ mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+ if (!mtd) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
+ MINOR(sb->s_dev)));
+ return NULL;
+ }
+ /* Check it's NAND */
+ if (mtd->type != MTD_NANDFLASH) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
+ mtd->type));
+ return NULL;
+ }
+
+ T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
+ T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
+ T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
+ T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
+ T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
+ T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
+ T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
+ T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
+ T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+ T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
+#else
+ T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
+#endif
+
+#ifdef CONFIG_YAFFS_AUTO_YAFFS2
+
+ if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: auto selecting yaffs2\n")));
+ yaffsVersion = 2;
+ }
+
+ /* Added NCB 26/5/2006 for completeness */
+ if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: auto selecting yaffs1\n")));
+ yaffsVersion = 1;
+ }
+
+#endif
+
+ if (yaffsVersion == 2) {
+ /* Check for version 2 style functions */
+ if (!mtd->erase ||
+ !mtd->block_isbad ||
+ !mtd->block_markbad ||
+ !mtd->read ||
+ !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ !mtd->read_oob || !mtd->write_oob) {
+#else
+ !mtd->write_ecc ||
+ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not support required "
+ "functions\n")));
+ return NULL;
+ }
+
+ if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+ mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
+ !options.inband_tags) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not have the "
+ "right page sizes\n")));
+ return NULL;
+ }
+ } else {
+ /* Check for V1 style functions */
+ if (!mtd->erase ||
+ !mtd->read ||
+ !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ !mtd->read_oob || !mtd->write_oob) {
+#else
+ !mtd->write_ecc ||
+ !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not support required "
+ "functions\n")));
+ return NULL;
+ }
+
+ if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
+ mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs: MTD device does not support have the "
+ "right page sizes\n")));
+ return NULL;
+ }
+ }
+
+ /* OK, so if we got here, we have an MTD that's NAND and looks
+ * like it has the right capabilities
+ * Set the yaffs_Device up for mtd
+ */
+
+ if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
+ readOnly = 1;
+ printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
+ sb->s_flags |= MS_RDONLY;
+ }
+
+ dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+ context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
+
+ if(!dev || !context ){
+ if(dev)
+ kfree(dev);
+ if(context)
+ kfree(context);
+ dev = NULL;
+ context = NULL;
+ }
+
+ if (!dev) {
+ /* Deep shit could not allocate device structure */
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs_read_super: Failed trying to allocate "
+ "yaffs_Device. \n")));
+ return NULL;
+ }
+ memset(dev, 0, sizeof(yaffs_Device));
+ param = &(dev->param);
+
+ memset(context,0,sizeof(struct yaffs_LinuxContext));
+ dev->osContext = context;
+ YINIT_LIST_HEAD(&(context->contextList));
+ context->dev = dev;
+ context->superBlock = sb;
+
+ dev->readOnly = readOnly;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+ sb->s_fs_info = dev;
+#else
+ sb->u.generic_sbp = dev;
+#endif
+
+ dev->driverContext = mtd;
+ param->name = mtd->name;
+
+ /* Set up the memory size parameters.... */
+
+ nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
+
+ param->startBlock = 0;
+ param->endBlock = nBlocks - 1;
+ param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
+ param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
+ param->nReservedBlocks = 5;
+ param->nShortOpCaches = (options.no_cache) ? 0 : 10;
+ param->inbandTags = options.inband_tags;
+
+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
+ param->disableLazyLoad = 1;
+#endif
+#ifdef CONFIG_YAFFS_XATTR
+ param->enableXattr = 1;
+#endif
+ if(options.lazy_loading_overridden)
+ param->disableLazyLoad = !options.lazy_loading_enabled;
+
+#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
+ param->noTagsECC = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
+#else
+ param->deferDirectoryUpdate = 1;
+#endif
+
+ if(options.tags_ecc_overridden)
+ param->noTagsECC = !options.tags_ecc_on;
+
+#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
+ param->emptyLostAndFound = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
+ param->refreshPeriod = 0;
+#else
+ param->refreshPeriod = 500;
+#endif
+
+ if(options.empty_lost_and_found_overridden)
+ param->emptyLostAndFound = options.empty_lost_and_found;
+
+ /* ... and the functions. */
+ if (yaffsVersion == 2) {
+ param->writeChunkWithTagsToNAND =
+ nandmtd2_WriteChunkWithTagsToNAND;
+ param->readChunkWithTagsFromNAND =
+ nandmtd2_ReadChunkWithTagsFromNAND;
+ param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
+ param->queryNANDBlock = nandmtd2_QueryNANDBlock;
+ yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
+ param->isYaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ param->totalBytesPerChunk = mtd->writesize;
+ param->nChunksPerBlock = mtd->erasesize / mtd->writesize;
+#else
+ param->totalBytesPerChunk = mtd->oobblock;
+ param->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
+#endif
+ nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
+
+ param->startBlock = 0;
+ param->endBlock = nBlocks - 1;
+ } else {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+ /* use the MTD interface in yaffs_mtdif1.c */
+ param->writeChunkWithTagsToNAND =
+ nandmtd1_WriteChunkWithTagsToNAND;
+ param->readChunkWithTagsFromNAND =
+ nandmtd1_ReadChunkWithTagsFromNAND;
+ param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
+ param->queryNANDBlock = nandmtd1_QueryNANDBlock;
+#else
+ param->writeChunkToNAND = nandmtd_WriteChunkToNAND;
+ param->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
+#endif
+ param->isYaffs2 = 0;
+ }
+ /* ... and common functions */
+ param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
+ param->initialiseNAND = nandmtd_InitialiseNAND;
+
+ yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
+
+ param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
+ param->gcControl = yaffs_gc_control_callback;
+
+ yaffs_DeviceToLC(dev)->superBlock= sb;
+
+
+#ifndef CONFIG_YAFFS_DOES_ECC
+ param->useNANDECC = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
+ param->wideTnodesDisabled = 1;
+#endif
+
+ param->skipCheckpointRead = options.skip_checkpoint_read;
+ param->skipCheckpointWrite = options.skip_checkpoint_write;
+
+ down(&yaffs_context_lock);
+ /* Get a mount id */
+ found = 0;
+ for(mount_id=0; ! found; mount_id++){
+ found = 1;
+ ylist_for_each(l,&yaffs_context_list){
+ context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
+ if(context_iterator->mount_id == mount_id)
+ found = 0;
+ }
+ }
+ context->mount_id = mount_id;
+
+ ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
+ up(&yaffs_context_lock);
+
+ /* Directory search handling...*/
+ YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
+ param->removeObjectCallback = yaffs_RemoveObjectCallback;
+
+ init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
+
+ yaffs_GrossLock(dev);
+
+ err = yaffs_GutsInitialise(dev);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_super: guts initialised %s\n"),
+ (err == YAFFS_OK) ? "OK" : "FAILED"));
+
+ if(err == YAFFS_OK)
+ yaffs_BackgroundStart(dev);
+
+ if(!context->bgThread)
+ param->deferDirectoryUpdate = 0;
+
+
+ /* Release lock before yaffs_get_inode() */
+ yaffs_GrossUnlock(dev);
+
+ /* Create root inode */
+ if (err == YAFFS_OK)
+ inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
+ yaffs_Root(dev));
+
+ if (!inode)
+ return NULL;
+
+ inode->i_op = &yaffs_dir_inode_operations;
+ inode->i_fop = &yaffs_dir_operations;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
+
+ root = d_alloc_root(inode);
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
+
+ if (!root) {
+ iput(inode);
+ return NULL;
+ }
+ sb->s_root = root;
+ sb->s_dirt = !dev->isCheckpointed;
+ T(YAFFS_TRACE_ALWAYS,
+ (TSTR("yaffs_read_super: isCheckpointed %d\n"),
+ dev->isCheckpointed));
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
+ return sb;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
+ int silent)