- T(YAFFS_TRACE_OS,(" erase %p\n",mtd->erase));
- T(YAFFS_TRACE_OS,(" read %p\n",mtd->read));
- T(YAFFS_TRACE_OS,(" write %p\n",mtd->write));
- T(YAFFS_TRACE_OS,(" readoob %p\n",mtd->read_oob));
- T(YAFFS_TRACE_OS,(" writeoob %p\n",mtd->write_oob));
- T(YAFFS_TRACE_OS,(" block_isbad %p\n",mtd->block_isbad));
- T(YAFFS_TRACE_OS,(" block_markbad %p\n",mtd->block_markbad));
- T(YAFFS_TRACE_OS,(" oobblock %d\n",mtd->oobblock));
- T(YAFFS_TRACE_OS,(" oobsize %d\n",mtd->oobsize));
- T(YAFFS_TRACE_OS,(" erasesize %d\n",mtd->erasesize));
- T(YAFFS_TRACE_OS,(" size %d\n",mtd->size));
-
- if(yaffsVersion == 2)
- {
- // Check for version 2 style functions
- if(!mtd->erase ||
- !mtd->block_isbad ||
- !mtd->block_markbad ||
- !mtd->read ||
- !mtd->write ||
- !mtd->write_ecc ||
- !mtd->read_ecc ||
- !mtd->read_oob ||
- !mtd->write_oob )
- {
- T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support required functions\n"));;
- return NULL;
- }
-
- if(mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
- mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE)
- {
- T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support have the right page sizes\n"));
- return NULL;
- } }
- else
- {
- // Check for V1 style functions
- if(!mtd->erase ||
- !mtd->read ||
- !mtd->write ||
- !mtd->write_ecc ||
- !mtd->read_ecc ||
- !mtd->read_oob ||
- !mtd->write_oob )
- {
- T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support required functions\n"));;
- return NULL;
- }
-
- if(mtd->oobblock != YAFFS_BYTES_PER_CHUNK ||
- mtd->oobsize != YAFFS_BYTES_PER_SPARE)
- {
- T(YAFFS_TRACE_ALWAYS,("yaffs: MTD device does not support have the right page sizes\n"));
- return NULL;
+ return 0;
+}
+
+static int yaffs_BackgroundStart(yaffs_Device *dev)
+{
+ int retval = 0;
+ struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
+
+ if(dev->readOnly)
+ return -1;
+
+ context->bgRunning = 1;
+
+ context->bgThread = kthread_run(yaffs_BackgroundThread,
+ (void *)dev,"yaffs-bg-%d",context->mount_id);
+
+ if(IS_ERR(context->bgThread)){
+ retval = PTR_ERR(context->bgThread);
+ context->bgThread = NULL;
+ context->bgRunning = 0;
+ }
+ return retval;
+}
+
+static void yaffs_BackgroundStop(yaffs_Device *dev)
+{
+ struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
+
+ ctxt->bgRunning = 0;
+
+ if( ctxt->bgThread){
+ kthread_stop(ctxt->bgThread);
+ ctxt->bgThread = NULL;
+ }
+}
+#else
+static int yaffs_BackgroundThread(void *data)
+{
+ return 0;
+}
+
+static int yaffs_BackgroundStart(yaffs_Device *dev)
+{
+ return 0;
+}
+
+static void yaffs_BackgroundStop(yaffs_Device *dev)
+{
+}
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static void yaffs_write_super(struct super_block *sb)
+#else
+static int yaffs_write_super(struct super_block *sb)
+#endif
+{
+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
+ (TSTR("yaffs_write_super%s\n"),
+ request_checkpoint ? " checkpt" : ""));
+
+ yaffs_do_sync_fs(sb, request_checkpoint);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+ return 0;
+#endif
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
+static int yaffs_sync_fs(struct super_block *sb)
+#endif
+{
+ unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
+ (TSTR("yaffs_sync_fs%s\n"),
+ request_checkpoint ? " checkpt" : ""));
+
+ yaffs_do_sync_fs(sb, request_checkpoint);
+
+ return 0;
+}
+
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+ yaffs_Object *obj;
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_iget for %lu\n"), ino));
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_GrossLock(dev);
+
+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+ yaffs_FillInodeFromObject(inode, obj);
+
+ yaffs_GrossUnlock(dev);
+
+ unlock_new_inode(inode);
+ return inode;
+}
+
+#else
+
+static void yaffs_read_inode(struct inode *inode)
+{
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_Object *obj;
+ yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
+
+ T(YAFFS_TRACE_OS,
+ (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
+
+ if(current != yaffs_DeviceToLC(dev)->readdirProcess)
+ yaffs_GrossLock(dev);
+
+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+ yaffs_FillInodeFromObject(inode, obj);
+
+ if(current != yaffs_DeviceToLC(dev)->readdirProcess)
+ yaffs_GrossUnlock(dev);
+}
+
+#endif
+
+static YLIST_HEAD(yaffs_context_list);
+struct semaphore yaffs_context_lock;
+
+static void yaffs_put_super(struct super_block *sb)
+{
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
+
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+ (TSTR("Shutting down yaffs background thread\n")));
+ yaffs_BackgroundStop(dev);
+ T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
+ (TSTR("yaffs background thread shut down\n")));
+
+ yaffs_GrossLock(dev);
+
+ yaffs_FlushSuperBlock(sb,1);
+
+ if (yaffs_DeviceToLC(dev)->putSuperFunc)
+ yaffs_DeviceToLC(dev)->putSuperFunc(sb);
+
+
+ yaffs_Deinitialise(dev);
+
+ yaffs_GrossUnlock(dev);
+
+ down(&yaffs_context_lock);
+ ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
+ up(&yaffs_context_lock);
+
+ if (yaffs_DeviceToLC(dev)->spareBuffer) {
+ YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
+ yaffs_DeviceToLC(dev)->spareBuffer = NULL;
+ }
+
+ kfree(dev);
+}
+
+
+static void yaffs_MTDPutSuper(struct super_block *sb)
+{
+ struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
+
+ if (mtd->sync)
+ mtd->sync(mtd);
+
+ put_mtd_device(mtd);
+}
+
+
+static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
+{
+ struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
+
+ T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
+ if (sb)
+ sb->s_dirt = 1;
+}
+
+typedef struct {
+ int inband_tags;
+ int skip_checkpoint_read;
+ int skip_checkpoint_write;
+ int no_cache;
+ int tags_ecc_on;
+ int tags_ecc_overridden;
+ int lazy_loading_enabled;
+ int lazy_loading_overridden;
+ int empty_lost_and_found;
+ int empty_lost_and_found_overridden;
+} yaffs_options;
+
+#define MAX_OPT_LEN 30
+static int yaffs_parse_options(yaffs_options *options, const char *options_str)
+{
+ char cur_opt[MAX_OPT_LEN + 1];
+ int p;
+ int error = 0;
+
+ /* Parse through the options which is a comma seperated list */
+
+ while (options_str && *options_str && !error) {
+ memset(cur_opt, 0, MAX_OPT_LEN + 1);
+ p = 0;
+
+ while(*options_str == ',')
+ options_str++;
+
+ while (*options_str && *options_str != ',') {
+ if (p < MAX_OPT_LEN) {
+ cur_opt[p] = *options_str;
+ p++;