From: Tim Hockin Remove the max_anon via dynamically allocation. We also change the idr_pre_get() interface to take a gfp mask, which should have always been there. --- fs/super.c | 28 ++++++++++++++++++++-------- include/linux/fs.h | 1 + include/linux/idr.h | 2 +- init/main.c | 1 + kernel/posix-timers.c | 2 +- lib/idr.c | 12 ++++++------ 6 files changed, 30 insertions(+), 16 deletions(-) diff -puN fs/super.c~increase-max_anon fs/super.c --- 25/fs/super.c~increase-max_anon 2004-02-11 19:20:16.000000000 -0800 +++ 25-akpm/fs/super.c 2004-02-11 19:20:16.000000000 -0800 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include /* for the emergency remount stuff */ +#include #include @@ -536,22 +538,26 @@ void emergency_remount(void) * filesystems which don't use real block-devices. -- jrs */ -enum {Max_anon = 256}; -static unsigned long unnamed_dev_in_use[Max_anon/(8*sizeof(unsigned long))]; +static struct idr unnamed_dev_idr; static spinlock_t unnamed_dev_lock = SPIN_LOCK_UNLOCKED;/* protects the above */ int set_anon_super(struct super_block *s, void *data) { int dev; + spin_lock(&unnamed_dev_lock); - dev = find_first_zero_bit(unnamed_dev_in_use, Max_anon); - if (dev == Max_anon) { + if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0) { spin_unlock(&unnamed_dev_lock); - return -EMFILE; + return -ENOMEM; } - set_bit(dev, unnamed_dev_in_use); + dev = idr_get_new(&unnamed_dev_idr, NULL); spin_unlock(&unnamed_dev_lock); - s->s_dev = MKDEV(0, dev); + + if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { + idr_remove(&unnamed_dev_idr, dev); + return -EMFILE; + } + s->s_dev = MKDEV(0, dev & MINORMASK); return 0; } @@ -560,14 +566,20 @@ EXPORT_SYMBOL(set_anon_super); void kill_anon_super(struct super_block *sb) { int slot = MINOR(sb->s_dev); + generic_shutdown_super(sb); spin_lock(&unnamed_dev_lock); - clear_bit(slot, unnamed_dev_in_use); + idr_remove(&unnamed_dev_idr, slot); spin_unlock(&unnamed_dev_lock); } EXPORT_SYMBOL(kill_anon_super); +void __init unnamed_dev_init(void) +{ + idr_init(&unnamed_dev_idr); +} + void kill_litter_super(struct super_block *sb) { if (sb->s_root) diff -puN include/linux/fs.h~increase-max_anon include/linux/fs.h --- 25/include/linux/fs.h~increase-max_anon 2004-02-11 19:20:16.000000000 -0800 +++ 25-akpm/include/linux/fs.h 2004-02-11 19:20:16.000000000 -0800 @@ -1051,6 +1051,7 @@ struct super_block *sget(struct file_sys void *data); struct super_block *get_sb_pseudo(struct file_system_type *, char *, struct super_operations *ops, unsigned long); +void unnamed_dev_init(void); /* Alas, no aliases. Too much hassle with bringing module.h everywhere */ #define fops_get(fops) \ diff -puN include/linux/idr.h~increase-max_anon include/linux/idr.h --- 25/include/linux/idr.h~increase-max_anon 2004-02-11 19:20:16.000000000 -0800 +++ 25-akpm/include/linux/idr.h 2004-02-11 19:20:16.000000000 -0800 @@ -58,7 +58,7 @@ struct idr { */ void *idr_find(struct idr *idp, int id); -int idr_pre_get(struct idr *idp); +int idr_pre_get(struct idr *idp, unsigned gfp_mask); int idr_get_new(struct idr *idp, void *ptr); void idr_remove(struct idr *idp, int id); void idr_init(struct idr *idp); diff -puN init/main.c~increase-max_anon init/main.c --- 25/init/main.c~increase-max_anon 2004-02-11 19:20:16.000000000 -0800 +++ 25-akpm/init/main.c 2004-02-11 19:20:16.000000000 -0800 @@ -473,6 +473,7 @@ asmlinkage void __init start_kernel(void fork_init(num_physpages); proc_caches_init(); buffer_init(); + unnamed_dev_init(); security_scaffolding_startup(); vfs_caches_init(num_physpages); radix_tree_init(); diff -puN kernel/posix-timers.c~increase-max_anon kernel/posix-timers.c --- 25/kernel/posix-timers.c~increase-max_anon 2004-02-11 19:20:16.000000000 -0800 +++ 25-akpm/kernel/posix-timers.c 2004-02-11 19:20:16.000000000 -0800 @@ -426,7 +426,7 @@ sys_timer_create(clockid_t which_clock, spin_lock_init(&new_timer->it_lock); do { - if (unlikely(!idr_pre_get(&posix_timers_id))) { + if (unlikely(!idr_pre_get(&posix_timers_id, GFP_KERNEL))) { error = -EAGAIN; new_timer->it_id = (timer_t)-1; goto out; diff -puN lib/idr.c~increase-max_anon lib/idr.c --- 25/lib/idr.c~increase-max_anon 2004-02-11 19:20:16.000000000 -0800 +++ 25-akpm/lib/idr.c 2004-02-11 19:20:16.000000000 -0800 @@ -62,13 +62,13 @@ * to the rest of the functions. The structure is defined in the * header. - * int idr_pre_get(struct idr *idp) + * int idr_pre_get(struct idr *idp, unsigned gfp_mask) * This function should be called prior to locking and calling the * following function. It pre allocates enough memory to satisfy the - * worst possible allocation. It can sleep, so must not be called - * with any spinlocks held. If the system is REALLY out of memory - * this function returns 0, other wise 1. + * worst possible allocation. Unless gfp_mask is GFP_ATOMIC, it can + * sleep, so must not be called with any spinlocks held. If the system is + * REALLY out of memory this function returns 0, other wise 1. * int idr_get_new(struct idr *idp, void *ptr); @@ -135,11 +135,11 @@ static inline void free_layer(struct idr spin_unlock(&idp->lock); } -int idr_pre_get(struct idr *idp) +int idr_pre_get(struct idr *idp, unsigned gfp_mask) { while (idp->id_free_cnt < idp->layers + 1) { struct idr_layer *new; - new = kmem_cache_alloc(idr_layer_cache, GFP_KERNEL); + new = kmem_cache_alloc(idr_layer_cache, gfp_mask); if(new == NULL) return (0); free_layer(idp, new); _