- yaffs_get_n_free_chunks(dev) *
- (dev->nDataBytesPerChunk / sb->s_blocksize);
- }
-
- buf->f_files = 0;
- buf->f_ffree = 0;
- buf->f_bavail = buf->f_bfree;
-
- yaffs_gross_unlock(dev);
- return 0;
-}
-
-
-
-static void yaffs_flush_inodes(struct super_block *sb)
-{
- struct inode *iptr;
- yaffs_Object *obj;
-
- list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
- obj = yaffs_InodeToObject(iptr);
- if(obj){
- T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
- obj->objectId));
- yaffs_flush_file(obj,1,0);
- }
- }
-}
-
-
-static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
-{
- yaffs_Device *dev = yaffs_SuperToDevice(sb);
- if(!dev)
- return;
-
- yaffs_flush_inodes(sb);
- yaffs_update_dirty_dirs(dev);
- yaffs_flush_whole_cache(dev);
- if(do_checkpoint)
- yaffs_checkpoint_save(dev);
-}
-
-
-static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
-{
- unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
- struct yaffs_LinuxContext *context = yaffs_dev_to_lc(dev);
- unsigned scatteredFree = 0; /* Free chunks not in an erased block */
-
- if(erasedChunks < dev->nFreeChunks)
- scatteredFree = (dev->nFreeChunks - erasedChunks);
-
- if(!context->bgRunning)
- return 0;
- else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
- return 0;
- else if(erasedChunks > dev->nFreeChunks/2)
- return 0;
- else if(erasedChunks > dev->nFreeChunks/4)
- return 1;
- else
- return 2;
-}
-
-static int yaffs_do_sync_fs(struct super_block *sb,
- int request_checkpoint)
-{
-
- yaffs_Device *dev = yaffs_SuperToDevice(sb);
- unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
- unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
- int do_checkpoint;
-
- T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
- (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
- gc_urgent,
- sb->s_dirt ? "dirty" : "clean",
- request_checkpoint ? "checkpoint requested" : "no checkpoint",
- oneshot_checkpoint ? " one-shot" : "" ));
-
- yaffs_gross_lock(dev);
- do_checkpoint = ((request_checkpoint && !gc_urgent) ||
- oneshot_checkpoint) &&
- !dev->isCheckpointed;
-
- if (sb->s_dirt || do_checkpoint) {
- yaffs_flush_super(sb, !dev->isCheckpointed && do_checkpoint);
- sb->s_dirt = 0;
- if(oneshot_checkpoint)
- yaffs_auto_checkpoint &= ~4;
- }
- yaffs_gross_unlock(dev);
-
- return 0;
-}
-
-/*
- * 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_Device *dev = (yaffs_Device *)data;
- struct yaffs_LinuxContext *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 gcResult;
- 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->bgRunning){
- 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->isCheckpointed){
- urgency = yaffs_bg_gc_urgency(dev);
- gcResult = 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