diff options
Diffstat (limited to 'drivers/char/misc.c')
| -rw-r--r-- | drivers/char/misc.c | 81 |
1 files changed, 37 insertions, 44 deletions
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 62c99fa59e2..ffa97d261cf 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -40,7 +40,6 @@ #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> -#include <linux/slab.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> @@ -49,7 +48,7 @@ #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> -#include <linux/smp_lock.h> +#include <linux/gfp.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, @@ -117,9 +114,8 @@ static int misc_open(struct inode * inode, struct file * file) int minor = iminor(inode); struct miscdevice *c; int err = -ENODEV; - const struct file_operations *old_fops, *new_fops = NULL; - - lock_kernel(); + const struct file_operations *new_fops = NULL; + mutex_lock(&misc_mtx); list_for_each_entry(c, &misc_list, list) { @@ -145,19 +141,13 @@ static int misc_open(struct inode * inode, struct file * file) } err = 0; - old_fops = file->f_op; - file->f_op = new_fops; + replace_fops(file, new_fops); if (file->f_op->open) { - err=file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } + file->private_data = c; + err = file->f_op->open(inode,file); } - fops_put(old_fops); fail: mutex_unlock(&misc_mtx); - unlock_kernel(); return err; } @@ -166,6 +156,7 @@ static struct class *misc_class; static const struct file_operations misc_fops = { .owner = THIS_MODULE, .open = misc_open, + .llseek = noop_llseek, }; /** @@ -186,39 +177,40 @@ static const struct file_operations misc_fops = { int misc_register(struct miscdevice * misc) { - struct miscdevice *c; dev_t dev; int err = 0; INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); - list_for_each_entry(c, &misc_list, list) { - if (c->minor == misc->minor) { - mutex_unlock(&misc_mtx); - return -EBUSY; - } - } 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) { - mutex_unlock(&misc_mtx); - return -EBUSY; + int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); + if (i >= DYNAMIC_MINORS) { + err = -EBUSY; + goto out; + } + misc->minor = DYNAMIC_MINORS - i - 1; + set_bit(i, misc_minors); + } else { + struct miscdevice *c; + + list_for_each_entry(c, &misc_list, list) { + if (c->minor == misc->minor) { + err = -EBUSY; + goto out; + } } - misc->minor = i; } - 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,17 +237,16 @@ 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)) + if (WARN_ON(list_empty(&misc->list))) return -EINVAL; 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 +254,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, umode_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 +280,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: |
