diff options
Diffstat (limited to 'drivers/media/v4l2-core/v4l2-device.c')
| -rw-r--r-- | drivers/media/v4l2-core/v4l2-device.c | 18 | 
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 02d1b632711..015f92aab44 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -158,7 +158,17 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,  	/* Warn if we apparently re-register a subdev */  	WARN_ON(sd->v4l2_dev != NULL); -	if (!try_module_get(sd->owner)) +	/* +	 * The reason to acquire the module here is to avoid unloading +	 * a module of sub-device which is registered to a media +	 * device. To make it possible to unload modules for media +	 * devices that also register sub-devices, do not +	 * try_module_get() such sub-device owners. +	 */ +	sd->owner_v4l2_dev = v4l2_dev->dev && v4l2_dev->dev->driver && +		sd->owner == v4l2_dev->dev->driver->owner; + +	if (!sd->owner_v4l2_dev && !try_module_get(sd->owner))  		return -ENODEV;  	sd->v4l2_dev = v4l2_dev; @@ -192,7 +202,8 @@ error_unregister:  	if (sd->internal_ops && sd->internal_ops->unregistered)  		sd->internal_ops->unregistered(sd);  error_module: -	module_put(sd->owner); +	if (!sd->owner_v4l2_dev) +		module_put(sd->owner);  	sd->v4l2_dev = NULL;  	return err;  } @@ -280,6 +291,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)  	}  #endif  	video_unregister_device(sd->devnode); -	module_put(sd->owner); +	if (!sd->owner_v4l2_dev) +		module_put(sd->owner);  }  EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);  | 
