From: Matt Roper <matthew.d.roper@intel.com>
To: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Intel Graphics Development <intel-gfx@lists.freedesktop.org>,
DRI Development <dri-devel@lists.freedesktop.org>
Subject: Re: [PATCH 5/8] drm: trylock modest locking for fbdev panics
Date: Wed, 30 Jul 2014 08:56:07 -0700 [thread overview]
Message-ID: <20140730155607.GU16114@intel.com> (raw)
In-Reply-To: <1406669543-31213-6-git-send-email-daniel.vetter@ffwll.ch>
On Tue, Jul 29, 2014 at 11:32:20PM +0200, Daniel Vetter wrote:
> In the fbdev code we want to do trylocks only to avoid deadlocks and
> other ugly issues. Thus far we've only grabbed the overall modeset
> lock, but that already failed to exclude a pile of potential
> concurrent operations. With proper atomic support this will be worse.
>
> So add a trylock mode to the modeset locking code which attempts all
> locks only with trylocks, if possible. We need to track this in the
> locking functions themselves and can't restrict this to drivers since
> driver-private w/w mutexes must be treated the same way.
>
> There's still the issue that other driver private locks aren't handled
> here at all, but well can't have everything. With this we will at
> least not regress, even once atomic allows lots of concurrent kms
> activity.
>
> Aside: We should move the acquire context to stack-based allocation in
> the callers to get rid of that awful WARN_ON(kmalloc_failed) control
> flow which just blows up when memory is short. But that's material for
> separate patches.
>
> v2:
> - Fix logic inversion fumble in the fb helper.
> - Add proper kerneldoc.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
> drivers/gpu/drm/drm_fb_helper.c | 10 +++----
> drivers/gpu/drm/drm_modeset_lock.c | 56 ++++++++++++++++++++++++++++++--------
> include/drm/drm_modeset_lock.h | 6 ++++
> 3 files changed, 55 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 3144db9dc0f1..841e039ba028 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -419,11 +419,11 @@ static bool drm_fb_helper_force_kernel_mode(void)
> if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
> continue;
>
> - /* NOTE: we use lockless flag below to avoid grabbing other
> - * modeset locks. So just trylock the underlying mutex
> - * directly:
> + /*
> + * NOTE: Use trylock mode to avoid deadlocks and sleeping in
> + * panic context.
> */
> - if (!mutex_trylock(&dev->mode_config.mutex)) {
> + if (__drm_modeset_lock_all(dev, true) != 0) {
> error = true;
> continue;
> }
Can we succeed locking config->mutex and connection_mutex inside
__drm_modeset_lock_all(), but then fail to lock one of the CRTC mutexes
in drm_modeset_lock_all_crtcs()? If so, __drm_modeset_lock_all() will
return -EBUSY, but not drop the locks it acquired, and then it seems
like we can return from the function here without ever dropping locks.
Matt
> @@ -432,7 +432,7 @@ static bool drm_fb_helper_force_kernel_mode(void)
> if (ret)
> error = true;
>
> - mutex_unlock(&dev->mode_config.mutex);
> + drm_modeset_unlock_all(dev);
> }
> return error;
> }
> diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
> index 4d2aa549c614..acfe187609b0 100644
> --- a/drivers/gpu/drm/drm_modeset_lock.c
> +++ b/drivers/gpu/drm/drm_modeset_lock.c
> @@ -57,26 +57,37 @@
>
>
> /**
> - * drm_modeset_lock_all - take all modeset locks
> - * @dev: drm device
> + * __drm_modeset_lock_all - internal helper to grab all modeset locks
> + * @dev: DRM device
> + * @trylock: trylock mode for atomic contexts
> *
> - * This function takes all modeset locks, suitable where a more fine-grained
> - * scheme isn't (yet) implemented. Locks must be dropped with
> - * drm_modeset_unlock_all.
> + * This is a special version of drm_modeset_lock_all() which can also be used in
> + * atomic contexts. Then @trylock must be set to true.
> + *
> + * Returns:
> + * 0 on success or negative error code on failure.
> */
> -void drm_modeset_lock_all(struct drm_device *dev)
> +int __drm_modeset_lock_all(struct drm_device *dev,
> + bool trylock)
> {
> struct drm_mode_config *config = &dev->mode_config;
> struct drm_modeset_acquire_ctx *ctx;
> int ret;
>
> - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> - if (WARN_ON(!ctx))
> - return;
> + ctx = kzalloc(sizeof(*ctx),
> + trylock ? GFP_ATOMIC : GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
>
> - mutex_lock(&config->mutex);
> + if (trylock) {
> + if (!mutex_trylock(&config->mutex))
> + return -EBUSY;
> + } else {
> + mutex_lock(&config->mutex);
> + }
>
> drm_modeset_acquire_init(ctx, 0);
> + ctx->trylock_only = trylock;
>
> retry:
> ret = drm_modeset_lock(&config->connection_mutex, ctx);
> @@ -95,13 +106,29 @@ retry:
>
> drm_warn_on_modeset_not_all_locked(dev);
>
> - return;
> + return 0;
>
> fail:
> if (ret == -EDEADLK) {
> drm_modeset_backoff(ctx);
> goto retry;
> }
> +
> + return ret;
> +}
> +EXPORT_SYMBOL(__drm_modeset_lock_all);
> +
> +/**
> + * drm_modeset_lock_all - take all modeset locks
> + * @dev: drm device
> + *
> + * This function takes all modeset locks, suitable where a more fine-grained
> + * scheme isn't (yet) implemented. Locks must be dropped with
> + * drm_modeset_unlock_all.
> + */
> +void drm_modeset_lock_all(struct drm_device *dev)
> +{
> + WARN_ON(__drm_modeset_lock_all(dev, false) != 0);
> }
> EXPORT_SYMBOL(drm_modeset_lock_all);
>
> @@ -287,7 +314,12 @@ static inline int modeset_lock(struct drm_modeset_lock *lock,
>
> WARN_ON(ctx->contended);
>
> - if (interruptible && slow) {
> + if (ctx->trylock_only) {
> + if (!ww_mutex_trylock(&lock->mutex))
> + return -EBUSY;
> + else
> + return 0;
> + } else if (interruptible && slow) {
> ret = ww_mutex_lock_slow_interruptible(&lock->mutex, &ctx->ww_ctx);
> } else if (interruptible) {
> ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
> diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
> index d38e1508f11a..a3f736d24382 100644
> --- a/include/drm/drm_modeset_lock.h
> +++ b/include/drm/drm_modeset_lock.h
> @@ -53,6 +53,11 @@ struct drm_modeset_acquire_ctx {
> * list of held locks (drm_modeset_lock)
> */
> struct list_head locked;
> +
> + /**
> + * Trylock mode, use only for panic handlers!
> + */
> + bool trylock_only;
> };
>
> /**
> @@ -123,6 +128,7 @@ struct drm_device;
> struct drm_crtc;
>
> void drm_modeset_lock_all(struct drm_device *dev);
> +int __drm_modeset_lock_all(struct drm_device *dev, bool trylock);
> void drm_modeset_unlock_all(struct drm_device *dev);
> void drm_modeset_lock_crtc(struct drm_crtc *crtc);
> void drm_modeset_unlock_crtc(struct drm_crtc *crtc);
> --
> 2.0.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Matt Roper
Graphics Software Engineer
IoTG Platform Enabling & Development
Intel Corporation
(916) 356-2795
next prev parent reply other threads:[~2014-07-30 15:56 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-29 21:32 [PATCH 0/8] atomic prep work Daniel Vetter
2014-07-29 21:32 ` [PATCH 1/8] drm: Add drm_plane/connector_index Daniel Vetter
2014-07-29 22:59 ` [Intel-gfx] " Matt Roper
2014-07-30 8:31 ` [PATCH] " Daniel Vetter
2014-07-29 21:32 ` [PATCH 2/8] drm: Move modeset_lock_all helpers to drm_modeset_lock.[hc] Daniel Vetter
2014-07-29 23:27 ` Dave Airlie
2014-07-29 21:32 ` [PATCH 3/8] drm: Handle legacy per-crtc locking with full acquire ctx Daniel Vetter
2014-07-29 23:28 ` Dave Airlie
2014-07-30 8:34 ` [PATCH] " Daniel Vetter
2014-07-29 21:32 ` [PATCH 4/8] drm: Move ->old_fb from crtc to plane Daniel Vetter
2014-07-29 23:30 ` Dave Airlie
2014-07-29 23:46 ` [Intel-gfx] " Matt Roper
2014-07-30 8:14 ` Daniel Vetter
2014-07-30 8:34 ` [PATCH] " Daniel Vetter
2014-07-29 21:32 ` [PATCH 5/8] drm: trylock modest locking for fbdev panics Daniel Vetter
2014-07-30 15:56 ` Matt Roper [this message]
2014-07-30 16:12 ` Daniel Vetter
2014-07-29 21:32 ` [PATCH 6/8] drm: Add a plane->reset hook Daniel Vetter
2014-07-29 21:32 ` [PATCH 7/8] drm/irq: Implement a generic vblank_wait function Daniel Vetter
2014-07-30 2:59 ` Michel Dänzer
2014-07-30 8:22 ` Daniel Vetter
2014-07-30 8:32 ` Michel Dänzer
2014-07-30 14:20 ` Thierry Reding
2014-07-30 14:36 ` [Intel-gfx] " Ville Syrjälä
2014-07-30 15:07 ` Daniel Vetter
2014-07-30 15:21 ` [Intel-gfx] " Thierry Reding
2014-07-31 1:14 ` Michel Dänzer
2014-07-31 7:54 ` Daniel Vetter
2014-07-31 8:56 ` Michel Dänzer
2014-07-31 9:46 ` Daniel Vetter
2014-07-30 9:25 ` [PATCH] " Daniel Vetter
2014-07-30 9:52 ` Michel Dänzer
2014-07-30 14:24 ` [PATCH 7/8] " Thierry Reding
2014-07-30 15:06 ` Daniel Vetter
2014-07-30 15:10 ` Thierry Reding
2014-07-29 21:32 ` [PATCH 8/8] drm/i915: Use generic vblank wait Daniel Vetter
2014-07-30 9:25 ` [PATCH] " Daniel Vetter
2014-07-30 13:36 ` [PATCH] drm: Docbook fixes Daniel Vetter
2014-08-05 2:51 ` [Intel-gfx] " Dave Airlie
2014-08-05 7:28 ` Daniel Vetter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140730155607.GU16114@intel.com \
--to=matthew.d.roper@intel.com \
--cc=daniel.vetter@ffwll.ch \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.