-/*
- * yaffs background thread functions .
- * yaffs_bg_thread_fn() the thread function
- * yaffs_bg_start() launches the background thread.
- * yaffs_bg_stop() cleans up the background thread.
- *
- * NB:
- * The thread should only run after the yaffs is initialised
- * The thread should be stopped before yaffs is unmounted.
- * The thread should not do any writing while the fs is in read only.
- */
-
-#ifdef YAFFS_COMPILE_BACKGROUND
-
-void yaffs_background_waker(unsigned long data)
-{
- wake_up_process((struct task_struct *)data);
-}
-
-static int yaffs_bg_thread_fn(void *data)
-{
- yaffs_dev_t *dev = (yaffs_dev_t *)data;
- struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
- unsigned long now = jiffies;
- unsigned long next_dir_update = now;
- unsigned long next_gc = now;
- unsigned long expires;
- unsigned int urgency;
-
- int gc_result;
- struct timer_list timer;
-
- T(YAFFS_TRACE_BACKGROUND,
- (TSTR("yaffs_background starting for dev %p\n"),
- (void *)dev));
-
-#ifdef YAFFS_COMPILE_FREEZER
- set_freezable();
-#endif
- while(context->bg_running){
- T(YAFFS_TRACE_BACKGROUND,
- (TSTR("yaffs_background\n")));
-
- if(kthread_should_stop())
- break;
-
-#ifdef YAFFS_COMPILE_FREEZER
- if(try_to_freeze())
- continue;
-#endif
- yaffs_gross_lock(dev);
-
- now = jiffies;
-
- if(time_after(now, next_dir_update) && yaffs_bg_enable){
- yaffs_update_dirty_dirs(dev);
- next_dir_update = now + HZ;
- }
-
- if(time_after(now,next_gc) && yaffs_bg_enable){
- if(!dev->is_checkpointed){
- urgency = yaffs_bg_gc_urgency(dev);
- gc_result = yaffs_bg_gc(dev, urgency);
- if(urgency > 1)
- next_gc = now + HZ/20+1;
- else if(urgency > 0)
- next_gc = now + HZ/10+1;
- else
- next_gc = now + HZ * 2;
- } else /*
- * gc not running so set to next_dir_update
- * to cut down on wake ups
- */
- next_gc = next_dir_update;
- }
- yaffs_gross_unlock(dev);
-#if 1
- expires = next_dir_update;
- if (time_before(next_gc,expires))
- expires = next_gc;
- if(time_before(expires,now))
- expires = now + HZ;
-
- Y_INIT_TIMER(&timer);
- timer.expires = expires+1;
- timer.data = (unsigned long) current;
- timer.function = yaffs_background_waker;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_timer(&timer);
- schedule();
- del_timer_sync(&timer);
-#else
- msleep(10);
-#endif
- }
-
- return 0;
-}
-
-static int yaffs_bg_start(yaffs_dev_t *dev)
-{
- int retval = 0;
- struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
-
- if(dev->read_only)
- return -1;
-
- context->bg_running = 1;
-
- context->bg_thread = kthread_run(yaffs_bg_thread_fn,
- (void *)dev,"yaffs-bg-%d",context->mount_id);
-
- if(IS_ERR(context->bg_thread)){
- retval = PTR_ERR(context->bg_thread);
- context->bg_thread = NULL;
- context->bg_running = 0;
- }
- return retval;
-}
-
-static void yaffs_bg_stop(yaffs_dev_t *dev)
-{
- struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
-
- ctxt->bg_running = 0;
-
- if( ctxt->bg_thread){
- kthread_stop(ctxt->bg_thread);
- ctxt->bg_thread = NULL;
- }
-}
-#else
-static int yaffs_bg_thread_fn(void *data)
-{
- return 0;
-}
-
-static int yaffs_bg_start(yaffs_dev_t *dev)
-{
- return 0;
-}
-
-static void yaffs_bg_stop(yaffs_dev_t *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_obj_t *obj;
- yaffs_dev_t *dev = yaffs_super_to_dev(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_gross_lock(dev);
-
- obj = yaffs_find_by_number(dev, inode->i_ino);
-
- yaffs_fill_inode_from_obj(inode, obj);
-
- yaffs_gross_unlock(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_obj_t *obj;
- yaffs_dev_t *dev = yaffs_super_to_dev(inode->i_sb);
-
- T(YAFFS_TRACE_OS,
- (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
-
- if(current != yaffs_dev_to_lc(dev)->readdir_process)
- yaffs_gross_lock(dev);
-
- obj = yaffs_find_by_number(dev, inode->i_ino);
-
- yaffs_fill_inode_from_obj(inode, obj);
-
- if(current != yaffs_dev_to_lc(dev)->readdir_process)
- yaffs_gross_unlock(dev);
-}
-
-#endif
-
-static YLIST_HEAD(yaffs_context_list);
-struct semaphore yaffs_context_lock;