diff options
Diffstat (limited to 'fs/char_dev.c')
| -rw-r--r-- | fs/char_dev.c | 48 | 
1 files changed, 27 insertions, 21 deletions
diff --git a/fs/char_dev.c b/fs/char_dev.c index e5b9df993b9..f77f7702fab 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -59,7 +59,7 @@ static struct char_device_struct {  } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];  /* index in the above */ -static inline int major_to_index(int major) +static inline int major_to_index(unsigned major)  {  	return major % CHRDEV_MAJOR_HASH_SIZE;  } @@ -272,7 +272,7 @@ int __register_chrdev(unsigned int major, unsigned int baseminor,  	cd = __register_chrdev_region(major, baseminor, count, name);  	if (IS_ERR(cd))  		return PTR_ERR(cd); -	 +  	cdev = cdev_alloc();  	if (!cdev)  		goto out2; @@ -280,7 +280,7 @@ int __register_chrdev(unsigned int major, unsigned int baseminor,  	cdev->owner = fops->owner;  	cdev->ops = fops;  	kobject_set_name(&cdev->kobj, "%s", name); -		 +  	err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);  	if (err)  		goto out; @@ -368,6 +368,7 @@ void cdev_put(struct cdev *p)   */  static int chrdev_open(struct inode *inode, struct file *filp)  { +	const struct file_operations *fops;  	struct cdev *p;  	struct cdev *new = NULL;  	int ret = 0; @@ -400,12 +401,13 @@ static int chrdev_open(struct inode *inode, struct file *filp)  		return ret;  	ret = -ENXIO; -	filp->f_op = fops_get(p->ops); -	if (!filp->f_op) +	fops = fops_get(p->ops); +	if (!fops)  		goto out_cdev_put; +	replace_fops(filp, fops);  	if (filp->f_op->open) { -		ret = filp->f_op->open(inode,filp); +		ret = filp->f_op->open(inode, filp);  		if (ret)  			goto out_cdev_put;  	} @@ -417,18 +419,6 @@ static int chrdev_open(struct inode *inode, struct file *filp)  	return ret;  } -int cdev_index(struct inode *inode) -{ -	int idx; -	struct kobject *kobj; - -	kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); -	if (!kobj) -		return -1; -	kobject_put(kobj); -	return idx; -} -  void cd_forget(struct inode *inode)  {  	spin_lock(&cdev_lock); @@ -483,9 +473,19 @@ static int exact_lock(dev_t dev, void *data)   */  int cdev_add(struct cdev *p, dev_t dev, unsigned count)  { +	int error; +  	p->dev = dev;  	p->count = count; -	return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); + +	error = kobj_map(cdev_map, dev, count, NULL, +			 exact_match, exact_lock, p); +	if (error) +		return error; + +	kobject_get(p->kobj.parent); + +	return 0;  }  static void cdev_unmap(dev_t dev, unsigned count) @@ -510,14 +510,20 @@ void cdev_del(struct cdev *p)  static void cdev_default_release(struct kobject *kobj)  {  	struct cdev *p = container_of(kobj, struct cdev, kobj); +	struct kobject *parent = kobj->parent; +  	cdev_purge(p); +	kobject_put(parent);  }  static void cdev_dynamic_release(struct kobject *kobj)  {  	struct cdev *p = container_of(kobj, struct cdev, kobj); +	struct kobject *parent = kobj->parent; +  	cdev_purge(p);  	kfree(p); +	kobject_put(parent);  }  static struct kobj_type ktype_cdev_default = { @@ -570,7 +576,8 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)  void __init chrdev_init(void)  {  	cdev_map = kobj_map_init(base_probe, &chrdevs_lock); -	bdi_init(&directly_mappable_cdev_bdi); +	if (bdi_init(&directly_mappable_cdev_bdi)) +		panic("Failed to init directly mappable cdev bdi");  } @@ -582,7 +589,6 @@ EXPORT_SYMBOL(cdev_init);  EXPORT_SYMBOL(cdev_alloc);  EXPORT_SYMBOL(cdev_del);  EXPORT_SYMBOL(cdev_add); -EXPORT_SYMBOL(cdev_index);  EXPORT_SYMBOL(__register_chrdev);  EXPORT_SYMBOL(__unregister_chrdev);  EXPORT_SYMBOL(directly_mappable_cdev_bdi);  | 
