netlink: fix for too early rmmod
[safe/jmp/linux-2.6] / drivers / char / misc.c
index 62c99fa..94a136e 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/kmod.h>
-#include <linux/smp_lock.h>
 
 /*
  * Head entry for the doubly linked miscdevice list
@@ -61,9 +60,7 @@ static DEFINE_MUTEX(misc_mtx);
  * Assigned numbers, used for dynamic minors
  */
 #define DYNAMIC_MINORS 64 /* like dynamic majors */
-static unsigned char misc_minors[DYNAMIC_MINORS / 8];
-
-extern int pmu_device_init(void);
+static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
 
 #ifdef CONFIG_PROC_FS
 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -91,7 +88,7 @@ static int misc_seq_show(struct seq_file *seq, void *v)
 }
 
 
-static struct seq_operations misc_seq_ops = {
+static const struct seq_operations misc_seq_ops = {
        .start = misc_seq_start,
        .next  = misc_seq_next,
        .stop  = misc_seq_stop,
@@ -118,8 +115,7 @@ static int misc_open(struct inode * inode, struct file * file)
        struct miscdevice *c;
        int err = -ENODEV;
        const struct file_operations *old_fops, *new_fops = NULL;
-       
-       lock_kernel();
+
        mutex_lock(&misc_mtx);
        
        list_for_each_entry(c, &misc_list, list) {
@@ -157,7 +153,6 @@ static int misc_open(struct inode * inode, struct file * file)
        fops_put(old_fops);
 fail:
        mutex_unlock(&misc_mtx);
-       unlock_kernel();
        return err;
 }
 
@@ -201,24 +196,23 @@ int misc_register(struct miscdevice * misc)
        }
 
        if (misc->minor == MISC_DYNAMIC_MINOR) {
-               int i = DYNAMIC_MINORS;
-               while (--i >= 0)
-                       if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
-                               break;
-               if (i<0) {
+               int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
+               if (i >= DYNAMIC_MINORS) {
                        mutex_unlock(&misc_mtx);
                        return -EBUSY;
                }
-               misc->minor = i;
+               misc->minor = DYNAMIC_MINORS - i - 1;
+               set_bit(i, misc_minors);
        }
 
-       if (misc->minor < DYNAMIC_MINORS)
-               misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
        dev = MKDEV(MISC_MAJOR, misc->minor);
 
        misc->this_device = device_create(misc_class, misc->parent, dev,
                                          misc, "%s", misc->name);
        if (IS_ERR(misc->this_device)) {
+               int i = DYNAMIC_MINORS - misc->minor - 1;
+               if (i < DYNAMIC_MINORS && i >= 0)
+                       clear_bit(i, misc_minors);
                err = PTR_ERR(misc->this_device);
                goto out;
        }
@@ -245,7 +239,7 @@ int misc_register(struct miscdevice * misc)
 
 int misc_deregister(struct miscdevice *misc)
 {
-       int i = misc->minor;
+       int i = DYNAMIC_MINORS - misc->minor - 1;
 
        if (list_empty(&misc->list))
                return -EINVAL;
@@ -253,9 +247,8 @@ int misc_deregister(struct miscdevice *misc)
        mutex_lock(&misc_mtx);
        list_del(&misc->list);
        device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
-       if (i < DYNAMIC_MINORS && i>0) {
-               misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
-       }
+       if (i < DYNAMIC_MINORS && i >= 0)
+               clear_bit(i, misc_minors);
        mutex_unlock(&misc_mtx);
        return 0;
 }
@@ -263,12 +256,14 @@ int misc_deregister(struct miscdevice *misc)
 EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);
 
-static char *misc_nodename(struct device *dev)
+static char *misc_devnode(struct device *dev, mode_t *mode)
 {
        struct miscdevice *c = dev_get_drvdata(dev);
 
-       if (c->devnode)
-               return kstrdup(c->devnode, GFP_KERNEL);
+       if (mode && c->mode)
+               *mode = c->mode;
+       if (c->nodename)
+               return kstrdup(c->nodename, GFP_KERNEL);
        return NULL;
 }
 
@@ -287,7 +282,7 @@ static int __init misc_init(void)
        err = -EIO;
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
                goto fail_printk;
-       misc_class->nodename = misc_nodename;
+       misc_class->devnode = misc_devnode;
        return 0;
 
 fail_printk: