diff -rup linux-2.4.24.orig/fs/inode.c linux-2.4.24.new/fs/inode.c --- linux-2.4.24.orig/fs/inode.c Fri Nov 28 21:26:21 2003 +++ linux-2.4.24.new/fs/inode.c Tue Mar 16 13:24:35 2004 @@ -471,7 +471,7 @@ void sync_inodes(kdev_t dev) } } -static void try_to_sync_unused_inodes(void * arg) +static void try_to_sync_unused_inodes(void) { struct super_block * sb; int nr_inodes = inodes_stat.nr_unused; @@ -490,7 +490,8 @@ static void try_to_sync_unused_inodes(vo spin_unlock(&inode_lock); } -static struct tq_struct unused_inodes_flush_task; +static DECLARE_WAIT_QUEUE_HEAD(kinoded_wait) ; +static atomic_t kinoded_goal = ATOMIC_INIT(0) ; /** * write_inode_now - write an inode to disk @@ -753,7 +754,7 @@ int invalidate_device(kdev_t dev, int do !inode_has_buffers(inode)) #define INODE(entry) (list_entry(entry, struct inode, i_list)) -void prune_icache(int goal) +static void _prune_icache(int goal) { LIST_HEAD(list); struct list_head *entry, *freeable = &list; @@ -787,35 +788,24 @@ void prune_icache(int goal) spin_unlock(&inode_lock); dispose_list(freeable); - - /* - * If we didn't freed enough clean inodes schedule - * a sync of the dirty inodes, we cannot do it - * from here or we're either synchronously dogslow - * or we deadlock with oom. - */ + kmem_cache_shrink(inode_cachep); if (goal) - schedule_task(&unused_inodes_flush_task); + try_to_sync_unused_inodes(); +} + +void prune_icache(int goal) { + atomic_add(goal, &kinoded_goal); + if (atomic_read(&kinoded_goal) > 16) { + wake_up_interruptible(&kinoded_wait); + } } int shrink_icache_memory(int priority, int gfp_mask) { int count = 0; - - /* - * Nasty deadlock avoidance.. - * - * We may hold various FS locks, and we don't - * want to recurse into the FS that called us - * in clear_inode() and friends.. - */ - if (!(gfp_mask & __GFP_FS)) - return 0; - count = inodes_stat.nr_unused / priority; - prune_icache(count); - return kmem_cache_shrink(inode_cachep); + return 0; } /* @@ -1198,6 +1188,35 @@ int bmap(struct inode * inode, int block return res; } +int kinoded(void *startup) { + + struct task_struct *tsk = current; + int goal ; + + daemonize(); + strcpy(tsk->comm, "kinoded"); + + /* avoid getting signals */ + spin_lock_irq(&tsk->sigmask_lock); + flush_signals(tsk); + sigfillset(&tsk->blocked); + recalc_sigpending(tsk); + spin_unlock_irq(&tsk->sigmask_lock); + + printk("kinoded started\n") ; + complete((struct completion *)startup); + while(1) { + wait_event_interruptible(kinoded_wait, + atomic_read(&kinoded_goal)); + while((goal = atomic_read(&kinoded_goal))) { + _prune_icache(goal); + atomic_sub(goal, &kinoded_goal); + if (current->need_resched) + schedule(); + } + } +} + /* * Initialize the hash tables. */ @@ -1249,8 +1268,17 @@ void __init inode_init(unsigned long mem NULL); if (!inode_cachep) panic("cannot create inode slab cache"); +} - unused_inodes_flush_task.routine = try_to_sync_unused_inodes; +/* we need to start a thread, and inode_init happens too early for that +** to work. So, add a second init func through module_init +*/ +static int __init inode_mod_init(void) +{ + static struct completion startup __initdata = COMPLETION_INITIALIZER(startup); + kernel_thread(kinoded, &startup, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + wait_for_completion(&startup); + return 0; } /** @@ -1344,3 +1372,5 @@ void remove_dquot_ref(struct super_block } #endif + +module_init(inode_mod_init) ; .