Received: by 2002:a05:6a10:8a4d:0:0:0:0 with SMTP id dn13csp906393pxb; Fri, 13 Aug 2021 08:54:11 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz/3GmGmr+4PDfcCzNqq1rawkgdbsgMS6uBWfTFleKBpBZFoWPuk0JIBDSEi1gkKtWmcnl2 X-Received: by 2002:a17:906:899:: with SMTP id n25mr3140835eje.543.1628870051503; Fri, 13 Aug 2021 08:54:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1628870051; cv=none; d=google.com; s=arc-20160816; b=S5www1BZ+cY3djSGsISW+rijZetXhsVzo8ZeSpY/QzoVVFJ101PeVOqPOdyStTaGEa c9Las6izr6/WXKwXwrqEnxqBDDXK0uuiFv4RxdqgHkX6fAiLg751Q5ZG7q4ENPB5/6/Z mzmp/kOOIHyPGqVl0Tk2a7w2T8a+YuT8+v3o8jHB0wqDyHzpuZStNaeu4qxZK5dr7onW m4FDM0OcOdNpRMKk6e6rU9R2DF2T1wKSP2xX5jhKioJmelOOs1K4ApUl8dgLUFNgc3YI txF6wyfdpUhVYH64kNhN+J5852GTvfCdwJAtq933f+u1SDgRGNxl5SWe6pIf2dE4Y/AT CCDg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:mail-followup-to:message-id:subject:cc:to:from:date :dkim-signature; bh=ztLJ/Z+w/7lJ5b/Gbdd/xzcgAKq8QbJW4xzGVnxKtmU=; b=xtiJ/2dhMRvjR4Cx959YtPEdVIIWYYAe+dz2VG5mhzdgXvihnqOOGz2Bn8+hiDq4HF /px07JNxhOS/M1TzODGJyszulZXLHA92UPLe7HMiJLY1KnNkfzHmaneFoxSqo44viZoe pXLAZ1gv6KxENurv3uFWsWGsDgmzv6QdKRdqvt2cd3sB9cJAv2uqMqLtpozhyQRnqq44 YGOF+zot+iktDTxh8y8JXbzg6csC3M4ZI7VjU/oXhToKArgwnIXYgNB81wO0W4bkZsg3 OFnFSlW54/WgNU4xOkraU5eIPLYmFAT9AIec1UVrvAtj9i7DrIUXD7IqEmWB35uV6yD0 LKgQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=VLZcmBZF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id r17si1997711edv.508.2021.08.13.08.53.46; Fri, 13 Aug 2021 08:54:11 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=VLZcmBZF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241344AbhHMPtr (ORCPT + 99 others); Fri, 13 Aug 2021 11:49:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55638 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241343AbhHMPtq (ORCPT ); Fri, 13 Aug 2021 11:49:46 -0400 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 432E6C061756 for ; Fri, 13 Aug 2021 08:49:19 -0700 (PDT) Received: by mail-wm1-x329.google.com with SMTP id f12-20020a05600c4e8c00b002e6bdd6ffe2so4181441wmq.5 for ; Fri, 13 Aug 2021 08:49:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=date:from:to:cc:subject:message-id:mail-followup-to:references :mime-version:content-disposition:in-reply-to; bh=ztLJ/Z+w/7lJ5b/Gbdd/xzcgAKq8QbJW4xzGVnxKtmU=; b=VLZcmBZFpeecdhW43NS93mX0TUmD4RRZFXTte21P4ljJ+Z7SqAEHsmih2/viWCa1GP XVqRC/eooDWii6hMe82zSBMDH6wlIfLabTRJlHlFKI61nAn+zF70v7+G5m/naoRvhdK+ 5gFnIMW2IYCWa7XmwgHY22kW4jd9UYnpwT7M0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id :mail-followup-to:references:mime-version:content-disposition :in-reply-to; bh=ztLJ/Z+w/7lJ5b/Gbdd/xzcgAKq8QbJW4xzGVnxKtmU=; b=CLg8LIc7+I2MPXbeFD2hb79ceSm50StcMvcj7EVtH+Zye4fF+vQ41u48u44pp0ZBMw NB8IrScyUJ2NStFah4a+frVQm0tVSILEloJar5N0wluSLsKhbh1tLoGfZ/qe40dJjRJj qsmHTDaan5lDVQ0zlu8l1BGjvFZltG736KEkR2E4HbDcz/EmKfAGWauyakmF9b/lDIPy 8YxCIwunhvg5PngfRgZOnlxfNXI7P2l36yY52NlFB2BIQxPpmwW5T06mYuTFUo0YTxfs 4BWTWO1s34OOx2hgwGpwVjH5pBWfWd9zgpdJbGEsK/WIuxqtSlOwcQCGnrHfjtLqVUH4 yvDw== X-Gm-Message-State: AOAM530me+qg4ITEa8+s2qG3CsltLFOr5wEVe+DUviP0+4BPe8u/iBHz lgwZOPQ1EQAn+jf8SNXs9NqEnQ== X-Received: by 2002:a1c:27c2:: with SMTP id n185mr3213014wmn.20.1628869757778; Fri, 13 Aug 2021 08:49:17 -0700 (PDT) Received: from phenom.ffwll.local ([2a02:168:57f4:0:efd0:b9e5:5ae6:c2fa]) by smtp.gmail.com with ESMTPSA id l38sm1699851wmp.15.2021.08.13.08.49.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 13 Aug 2021 08:49:16 -0700 (PDT) Date: Fri, 13 Aug 2021 17:49:14 +0200 From: Daniel Vetter To: Desmond Cheong Zhi Xi Cc: maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, daniel@ffwll.ch, sumit.semwal@linaro.org, christian.koenig@amd.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, intel-gfx@lists.freedesktop.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org, Daniel Vetter Subject: Re: [PATCH 1/2] drm: avoid races with modesetting rights Message-ID: Mail-Followup-To: Desmond Cheong Zhi Xi , maarten.lankhorst@linux.intel.com, mripard@kernel.org, tzimmermann@suse.de, airlied@linux.ie, sumit.semwal@linaro.org, christian.koenig@amd.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org, intel-gfx@lists.freedesktop.org, skhan@linuxfoundation.org, gregkh@linuxfoundation.org, linux-kernel-mentees@lists.linuxfoundation.org References: <20210813085450.32494-1-desmondcheongzx@gmail.com> <20210813085450.32494-2-desmondcheongzx@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20210813085450.32494-2-desmondcheongzx@gmail.com> X-Operating-System: Linux phenom 5.10.0-7-amd64 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, Aug 13, 2021 at 04:54:49PM +0800, Desmond Cheong Zhi Xi wrote: > In drm_client_modeset.c and drm_fb_helper.c, > drm_master_internal_{acquire,release} are used to avoid races with DRM > userspace. These functions hold onto drm_device.master_mutex while > committing, and bail if there's already a master. > > However, ioctls can still race between themselves. A > time-of-check-to-time-of-use error can occur if an ioctl that changes > the modeset has its rights revoked after it validates its permissions, > but before it completes. > > There are three ioctls that can affect modesetting permissions: > > - DROP_MASTER ioctl removes rights for a master and its leases > > - REVOKE_LEASE ioctl revokes rights for a specific lease > > - SET_MASTER ioctl sets the device master if the master role hasn't > been acquired yet > > All these races can be avoided by introducing an SRCU that acts as a > barrier for ioctls that can change modesetting permissions. Processes > that perform modesetting should hold a read lock on the new > drm_device.master_barrier_srcu, and ioctls that change these > permissions should call synchronize_srcu before returning. > > This ensures that any process that might have seen old permissions are > flushed out before DROP_MASTER/REVOKE_LEASE/SET_MASTER ioctls return > to userspace. > > Reported-by: Daniel Vetter > Signed-off-by: Desmond Cheong Zhi Xi This looks pretty solid, but I think there's one gap where we can still race. Scenario. Process A has a drm fd with master rights and two threads: - thread 1 does a long-running display operation (like a modeset or whatever) - thread 2 does a drop-master Then we start a new process B, which acquires master in drm_open (there is no other one left). This is like setmaster ioctl, but your DRM_MASTER_FLUSH bit doesn't work there. The other thing is that for modeset stuff (which this all is) srcu is probably massive overkill, and a simple rwsem should be good enough too. Maybe even better, since the rwsem guarantees that no new reader can start once you try to acquire the write side. Finally, and this is a bit a bikeshed: I don't like much how DRM_MASTER_FLUSH leaks the need of these very few places into the very core drm_ioctl function. One idea I had was to use task_work in a special function, roughly void master_flush() { down_write(master_rwsem); up_write(master_rwms); } void drm_master_flush() { init_task_work(fpriv->master_flush_work, master_flush) task_work_add(fpriv->master_flush_work); /* if task_work_add fails we're exiting, at which point the lack * of master flush doesn't matter); } And maybe put a comment above the function explaining why and how this works. We could even do a drm_master_unlock_and_flush helper, since that's really what everyone wants, and it would make it very clear which master state changes need this flush. Instead of setting a flag bit in an ioctl table very far away ... Thoughts? -Daniel > --- > drivers/gpu/drm/drm_auth.c | 17 ++++++++++++++--- > drivers/gpu/drm/drm_client_modeset.c | 10 ++++++---- > drivers/gpu/drm/drm_drv.c | 2 ++ > drivers/gpu/drm/drm_fb_helper.c | 20 ++++++++++++-------- > drivers/gpu/drm/drm_internal.h | 5 +++-- > drivers/gpu/drm/drm_ioctl.c | 25 +++++++++++++++++++++---- > include/drm/drm_device.h | 11 +++++++++++ > include/drm/drm_ioctl.h | 7 +++++++ > 8 files changed, 76 insertions(+), 21 deletions(-) > > diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c > index 60a6b21474b1..004506608e76 100644 > --- a/drivers/gpu/drm/drm_auth.c > +++ b/drivers/gpu/drm/drm_auth.c > @@ -29,6 +29,7 @@ > */ > > #include > +#include > > #include > #include > @@ -448,21 +449,31 @@ void drm_master_put(struct drm_master **master) > EXPORT_SYMBOL(drm_master_put); > > /* Used by drm_client and drm_fb_helper */ > -bool drm_master_internal_acquire(struct drm_device *dev) > +bool drm_master_internal_acquire(struct drm_device *dev, int *idx) > { > + *idx = srcu_read_lock(&dev->master_barrier_srcu); > + > mutex_lock(&dev->master_mutex); > if (dev->master) { > mutex_unlock(&dev->master_mutex); > + srcu_read_unlock(&dev->master_barrier_srcu, *idx); > return false; > } > + mutex_unlock(&dev->master_mutex); > > return true; > } > EXPORT_SYMBOL(drm_master_internal_acquire); > > /* Used by drm_client and drm_fb_helper */ > -void drm_master_internal_release(struct drm_device *dev) > +void drm_master_internal_release(struct drm_device *dev, int idx) > { > - mutex_unlock(&dev->master_mutex); > + srcu_read_unlock(&dev->master_barrier_srcu, idx); > } > EXPORT_SYMBOL(drm_master_internal_release); > + > +/* Used by drm_ioctl */ > +void drm_master_flush(struct drm_device *dev) > +{ > + synchronize_srcu(&dev->master_barrier_srcu); > +} > diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c > index ced09c7c06f9..9885f36f71b7 100644 > --- a/drivers/gpu/drm/drm_client_modeset.c > +++ b/drivers/gpu/drm/drm_client_modeset.c > @@ -1165,13 +1165,14 @@ int drm_client_modeset_commit(struct drm_client_dev *client) > { > struct drm_device *dev = client->dev; > int ret; > + int idx; > > - if (!drm_master_internal_acquire(dev)) > + if (!drm_master_internal_acquire(dev, &idx)) > return -EBUSY; > > ret = drm_client_modeset_commit_locked(client); > > - drm_master_internal_release(dev); > + drm_master_internal_release(dev, idx); > > return ret; > } > @@ -1215,8 +1216,9 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode) > { > struct drm_device *dev = client->dev; > int ret = 0; > + int idx; > > - if (!drm_master_internal_acquire(dev)) > + if (!drm_master_internal_acquire(dev, &idx)) > return -EBUSY; > > mutex_lock(&client->modeset_mutex); > @@ -1226,7 +1228,7 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode) > drm_client_modeset_dpms_legacy(client, mode); > mutex_unlock(&client->modeset_mutex); > > - drm_master_internal_release(dev); > + drm_master_internal_release(dev, idx); > > return ret; > } > diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c > index 7a5097467ba5..c313f0674db3 100644 > --- a/drivers/gpu/drm/drm_drv.c > +++ b/drivers/gpu/drm/drm_drv.c > @@ -574,6 +574,7 @@ static void drm_dev_init_release(struct drm_device *dev, void *res) > mutex_destroy(&dev->clientlist_mutex); > mutex_destroy(&dev->filelist_mutex); > mutex_destroy(&dev->struct_mutex); > + cleanup_srcu_struct(&dev->master_barrier_srcu); > drm_legacy_destroy_members(dev); > } > > @@ -612,6 +613,7 @@ static int drm_dev_init(struct drm_device *dev, > mutex_init(&dev->filelist_mutex); > mutex_init(&dev->clientlist_mutex); > mutex_init(&dev->master_mutex); > + init_srcu_struct(&dev->master_barrier_srcu); > > ret = drmm_add_action(dev, drm_dev_init_release, NULL); > if (ret) > diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c > index 3ab078321045..0d594bc15f18 100644 > --- a/drivers/gpu/drm/drm_fb_helper.c > +++ b/drivers/gpu/drm/drm_fb_helper.c > @@ -1116,13 +1116,14 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) > struct drm_fb_helper *fb_helper = info->par; > struct drm_device *dev = fb_helper->dev; > int ret; > + int idx; > > if (oops_in_progress) > return -EBUSY; > > mutex_lock(&fb_helper->lock); > > - if (!drm_master_internal_acquire(dev)) { > + if (!drm_master_internal_acquire(dev, &idx)) { > ret = -EBUSY; > goto unlock; > } > @@ -1136,7 +1137,7 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) > ret = setcmap_legacy(cmap, info); > mutex_unlock(&fb_helper->client.modeset_mutex); > > - drm_master_internal_release(dev); > + drm_master_internal_release(dev, idx); > unlock: > mutex_unlock(&fb_helper->lock); > > @@ -1160,9 +1161,10 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, > struct drm_device *dev = fb_helper->dev; > struct drm_crtc *crtc; > int ret = 0; > + int idx; > > mutex_lock(&fb_helper->lock); > - if (!drm_master_internal_acquire(dev)) { > + if (!drm_master_internal_acquire(dev, &idx)) { > ret = -EBUSY; > goto unlock; > } > @@ -1204,7 +1206,7 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd, > ret = -ENOTTY; > } > > - drm_master_internal_release(dev); > + drm_master_internal_release(dev, idx); > unlock: > mutex_unlock(&fb_helper->lock); > return ret; > @@ -1474,12 +1476,13 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, > struct drm_fb_helper *fb_helper = info->par; > struct drm_device *dev = fb_helper->dev; > int ret; > + int idx; > > if (oops_in_progress) > return -EBUSY; > > mutex_lock(&fb_helper->lock); > - if (!drm_master_internal_acquire(dev)) { > + if (!drm_master_internal_acquire(dev, &idx)) { > ret = -EBUSY; > goto unlock; > } > @@ -1489,7 +1492,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, > else > ret = pan_display_legacy(var, info); > > - drm_master_internal_release(dev); > + drm_master_internal_release(dev, idx); > unlock: > mutex_unlock(&fb_helper->lock); > > @@ -1948,6 +1951,7 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config); > int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) > { > int err = 0; > + int idx; > > if (!drm_fbdev_emulation || !fb_helper) > return 0; > @@ -1959,13 +1963,13 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) > return err; > } > > - if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) { > + if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev, &idx)) { > fb_helper->delayed_hotplug = true; > mutex_unlock(&fb_helper->lock); > return err; > } > > - drm_master_internal_release(fb_helper->dev); > + drm_master_internal_release(fb_helper->dev, idx); > > drm_dbg_kms(fb_helper->dev, "\n"); > > diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h > index 17f3548c8ed2..578fd2769913 100644 > --- a/drivers/gpu/drm/drm_internal.h > +++ b/drivers/gpu/drm/drm_internal.h > @@ -142,8 +142,9 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, > struct drm_file *file_priv); > int drm_master_open(struct drm_file *file_priv); > void drm_master_release(struct drm_file *file_priv); > -bool drm_master_internal_acquire(struct drm_device *dev); > -void drm_master_internal_release(struct drm_device *dev); > +bool drm_master_internal_acquire(struct drm_device *dev, int *idx); > +void drm_master_internal_release(struct drm_device *dev, int idx); > +void drm_master_flush(struct drm_device *dev); > > /* drm_sysfs.c */ > extern struct class *drm_class; > diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c > index be4a52dc4d6f..eb4ec3fab7d1 100644 > --- a/drivers/gpu/drm/drm_ioctl.c > +++ b/drivers/gpu/drm/drm_ioctl.c > @@ -600,8 +600,10 @@ static const struct drm_ioctl_desc drm_ioctls[] = { > DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), > DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH), > > - DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, 0), > - DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, 0), > + DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, > + DRM_MASTER_FLUSH), > + DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, > + DRM_MASTER_FLUSH), > > DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY), > DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), > @@ -722,7 +724,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = { > DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, DRM_MASTER), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_LIST_LESSEES, drm_mode_list_lessees_ioctl, DRM_MASTER), > DRM_IOCTL_DEF(DRM_IOCTL_MODE_GET_LEASE, drm_mode_get_lease_ioctl, DRM_MASTER), > - DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, DRM_MASTER), > + DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, > + DRM_MASTER | DRM_MASTER_FLUSH), > }; > > #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) > @@ -781,13 +784,17 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, > struct drm_file *file_priv = file->private_data; > struct drm_device *dev = file_priv->minor->dev; > int retcode; > + int idx; > > if (drm_dev_is_unplugged(dev)) > return -ENODEV; > > + if (unlikely(flags & DRM_MASTER)) > + idx = srcu_read_lock(&dev->master_barrier_srcu); > + > retcode = drm_ioctl_permit(flags, file_priv); > if (unlikely(retcode)) > - return retcode; > + goto release_master; > > /* Enforce sane locking for modern driver ioctls. */ > if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) || > @@ -798,6 +805,16 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, > retcode = func(dev, kdata, file_priv); > mutex_unlock(&drm_global_mutex); > } > + > +release_master: > + if (unlikely(flags & DRM_MASTER)) > + srcu_read_unlock(&dev->master_barrier_srcu, idx); > + /* After flushing, processes are guaranteed to see the new master/lease > + * permissions, and any process which might have seen the old > + * permissions is guaranteed to have finished. > + */ > + if (unlikely(flags & DRM_MASTER_FLUSH)) > + drm_master_flush(dev); > return retcode; > } > EXPORT_SYMBOL(drm_ioctl_kernel); > diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h > index 604b1d1b2d72..0ac5fdb375f8 100644 > --- a/include/drm/drm_device.h > +++ b/include/drm/drm_device.h > @@ -111,6 +111,17 @@ struct drm_device { > */ > struct drm_master *master; > > + /** > + * @master_barrier_srcu: > + * > + * Used to synchronize modesetting rights between multiple users. Users > + * that can change the modeset or display state must hold an > + * srcu_read_lock() on @master_barrier_srcu, and ioctls that can change > + * modesetting rights should call synchronize_srcu() before returning > + * to userspace. > + */ > + struct srcu_struct master_barrier_srcu; > + > /** > * @driver_features: per-device driver features > * > diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h > index afb27cb6a7bd..13a68cdcea36 100644 > --- a/include/drm/drm_ioctl.h > +++ b/include/drm/drm_ioctl.h > @@ -130,6 +130,13 @@ enum drm_ioctl_flags { > * not set DRM_AUTH because they do not require authentication. > */ > DRM_RENDER_ALLOW = BIT(5), > + /** > + * @DRM_MASTER_FLUSH: > + * > + * This must be set for any ioctl which can change the modesetting > + * permissions for DRM users. > + */ > + DRM_MASTER_FLUSH = BIT(6), > }; > > /** > -- > 2.25.1 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch