From: Tim Hockin <thockin@sun.com>

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 <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/acct.h>
 #include <linux/blkdev.h>
@@ -33,6 +34,7 @@
 #include <linux/security.h>
 #include <linux/vfs.h>
 #include <linux/writeback.h>		/* for the emergency remount stuff */
+#include <linux/idr.h>
 #include <asm/uaccess.h>
 
 
@@ -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);

_