From patchwork Mon Mar 14 19:16:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 8583631 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 62651C0553 for ; Mon, 14 Mar 2016 19:16:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4677C20270 for ; Mon, 14 Mar 2016 19:16:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E41842021B for ; Mon, 14 Mar 2016 19:16:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755736AbcCNTQg (ORCPT ); Mon, 14 Mar 2016 15:16:36 -0400 Received: from bombadil.infradead.org ([198.137.202.9]:34688 "EHLO bombadil.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755658AbcCNTQg (ORCPT ); Mon, 14 Mar 2016 15:16:36 -0400 Received: from [191.33.151.62] (helo=smtp.w2.samsung.com) by bombadil.infradead.org with esmtpsa (Exim 4.80.1 #2 (Red Hat Linux)) id 1afXyl-0004oJ-3g; Mon, 14 Mar 2016 19:16:35 +0000 Received: from mchehab by smtp.w2.samsung.com with local (Exim 4.86_2) (envelope-from ) id 1afXyg-0008A8-JD; Mon, 14 Mar 2016 16:16:30 -0300 From: Mauro Carvalho Chehab To: Linux Media Mailing List Cc: Mauro Carvalho Chehab , Mauro Carvalho Chehab , Shuah Khan , Javier Martinez Canillas , Laurent Pinchart , Hans Verkuil , Prabhakar Lad Subject: [PATCH] [media] media-device: Don't call notify callbacks holding a spinlock Date: Mon, 14 Mar 2016 16:16:29 -0300 Message-Id: <31ecc9d6d2f29b0bd76c03c516d12aa7d0be2f66.1457982982.git.mchehab@osg.samsung.com> X-Mailer: git-send-email 2.5.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The notify routines may sleep. So, they can't be called in spinlock context. Also, they may want to call other media routines that might be spinning the spinlock, like creating a link. This fixes the following bug: [ 1839.510587] BUG: sleeping function called from invalid context at mm/slub.c:1289 [ 1839.510881] in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe [ 1839.511157] 4 locks held by modprobe/3479: [ 1839.511415] #0: (&dev->mutex){......}, at: [] __driver_attach+0xa3/0x160 [ 1839.512381] #1: (&dev->mutex){......}, at: [] __driver_attach+0xb1/0x160 [ 1839.512388] #2: (register_mutex#5){+.+.+.}, at: [] usb_audio_probe+0x257/0x1c90 [snd_usb_audio] [ 1839.512401] #3: (&(&mdev->lock)->rlock){+.+.+.}, at: [] media_device_register_entity+0x1cb/0x700 [media] [ 1839.512412] CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49 [ 1839.512415] Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015 [ 1839.512417] 0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000 [ 1839.512422] ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000 [ 1839.512427] ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5 [ 1839.512432] Call Trace: [ 1839.512436] [] dump_stack+0x85/0xc4 [ 1839.512440] [] ___might_sleep+0x245/0x3a0 [ 1839.512443] [] __might_sleep+0x95/0x1a0 [ 1839.512446] [] kmem_cache_alloc_trace+0x20e/0x300 [ 1839.512451] [] ? media_add_link+0x4d/0x140 [media] [ 1839.512455] [] media_add_link+0x4d/0x140 [media] [ 1839.512459] [] media_create_pad_link+0xa1/0x600 [media] [ 1839.512463] [] au0828_media_graph_notify+0x173/0x360 [au0828] [ 1839.512467] [] ? media_gobj_create+0x1ba/0x480 [media] [ 1839.512471] [] media_device_register_entity+0x3ab/0x700 [media] Tested with an HVR-950Q, under the following testcases: 1) load au0828 driver first, and then snd-usb-audio; 2) load snd-usb-audio driver first, and then au0828; 3) loading both drivers, and then connecting the device. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 39 ++++++++++++++++++++++------------- drivers/media/media-device.c | 5 +++-- drivers/media/v4l2-core/v4l2-common.c | 8 +++++++ include/media/v4l2-subdev.h | 4 ++++ 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index ff18444e19e4..14004fd7d0fb 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1208,6 +1208,28 @@ static int tvp5150_registered_async(struct v4l2_subdev *sd) return 0; } +static int __maybe_unused tvp5150_pad_init(struct v4l2_subdev *sd) +{ + struct tvp5150 *core = to_tvp5150(sd); + int res; + +#if defined(CONFIG_MEDIA_CONTROLLER) + core->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; + core->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; + core->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; + + sd->entity.function = MEDIA_ENT_F_ATV_DECODER; + + res = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, core->pads); + if (res < 0) + return res; + + sd->entity.ops = &tvp5150_sd_media_ops; +#endif + return 0; +} + + /* ----------------------------------------------------------------------- */ static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { @@ -1246,6 +1268,9 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { }; static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { +#ifdef CONFIG_MEDIA_CONTROLLER + .pad_init = tvp5150_pad_init, +#endif .enum_mbus_code = tvp5150_enum_mbus_code, .enum_frame_size = tvp5150_enum_frame_size, .set_fmt = tvp5150_fill_fmt, @@ -1475,20 +1500,6 @@ static int tvp5150_probe(struct i2c_client *c, v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -#if defined(CONFIG_MEDIA_CONTROLLER) - core->pads[DEMOD_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; - core->pads[DEMOD_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; - core->pads[DEMOD_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; - - sd->entity.function = MEDIA_ENT_F_ATV_DECODER; - - res = media_entity_pads_init(&sd->entity, DEMOD_NUM_PADS, core->pads); - if (res < 0) - return res; - - sd->entity.ops = &tvp5150_sd_media_ops; -#endif - res = tvp5150_detect_version(core); if (res < 0) return res; diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 6ba6e8f982fc..fc3c199e5500 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -587,14 +587,15 @@ int __must_check media_device_register_entity(struct media_device *mdev, media_gobj_create(mdev, MEDIA_GRAPH_PAD, &entity->pads[i].graph_obj); + spin_unlock(&mdev->lock); + /* invoke entity_notify callbacks */ list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) { (notify)->notify(entity, notify->notify_data); } - spin_unlock(&mdev->lock); - mutex_lock(&mdev->graph_mutex); + if (mdev->entity_internal_idx_max >= mdev->pm_count_walk.ent_enum.idx_max) { struct media_entity_graph new = { .top = 0 }; diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 5b808500e7e7..6bcdf557e027 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -112,6 +112,14 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill); void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, const struct v4l2_subdev_ops *ops) { + /* + * Initialize the MC pads - for now, this will be called + * unconditionally, since the current implementation will defer + * the pads initialization until the media_dev is created. + */ + if (v4l2_subdev_has_op(sd, pad, pad_init)) + sd->ops->pad->pad_init(sd); + v4l2_subdev_init(sd, ops); sd->flags |= V4L2_SUBDEV_FL_IS_I2C; /* the owner is the same as the i2c_client's driver owner */ diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 11e2dfec0198..c9bb221029e4 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -572,6 +572,9 @@ struct v4l2_subdev_pad_config { /** * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations * + * @pad_init: callback that initializes the media-controller specific part + * of the subdev driver, creating its pads + * * @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE ioctl handler * code. * @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE ioctl handler @@ -607,6 +610,7 @@ struct v4l2_subdev_pad_config { * may be adjusted by the subdev driver to device capabilities. */ struct v4l2_subdev_pad_ops { + int (*pad_init)(struct v4l2_subdev *sd); int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code);