Commit 317efce9 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[media] v4l: Reset subdev v4l2_dev field to NULL if registration fails



When subdev registration fails the subdev v4l2_dev field is left to a
non-NULL value. Later calls to v4l2_device_unregister_subdev() will
consider the subdev as registered and will module_put() the subdev
module without any matching module_get().
Fix this by setting the subdev v4l2_dev field to NULL in
v4l2_device_register_subdev() when the function fails.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: stable@vger.kernel.org
Acked-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 90271964
Loading
Loading
Loading
Loading
+14 −16
Original line number Diff line number Diff line
@@ -159,31 +159,21 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
	sd->v4l2_dev = v4l2_dev;
	if (sd->internal_ops && sd->internal_ops->registered) {
		err = sd->internal_ops->registered(sd);
		if (err) {
			module_put(sd->owner);
			return err;
		}
		if (err)
			goto error_module;
	}

	/* This just returns 0 if either of the two args is NULL */
	err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL);
	if (err) {
		if (sd->internal_ops && sd->internal_ops->unregistered)
			sd->internal_ops->unregistered(sd);
		module_put(sd->owner);
		return err;
	}
	if (err)
		goto error_unregister;

#if defined(CONFIG_MEDIA_CONTROLLER)
	/* Register the entity. */
	if (v4l2_dev->mdev) {
		err = media_device_register_entity(v4l2_dev->mdev, entity);
		if (err < 0) {
			if (sd->internal_ops && sd->internal_ops->unregistered)
				sd->internal_ops->unregistered(sd);
			module_put(sd->owner);
			return err;
		}
		if (err < 0)
			goto error_unregister;
	}
#endif

@@ -192,6 +182,14 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
	spin_unlock(&v4l2_dev->lock);

	return 0;

error_unregister:
	if (sd->internal_ops && sd->internal_ops->unregistered)
		sd->internal_ops->unregistered(sd);
error_module:
	module_put(sd->owner);
	sd->v4l2_dev = NULL;
	return err;
}
EXPORT_SYMBOL_GPL(v4l2_device_register_subdev);