Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp2136841imm; Wed, 16 May 2018 08:25:00 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqFVLNUxNc8FVFysuOJxxes0sg34XsE0Gp74iMwZ8XSDE8hImRT4ElT++Au4pt5rLGJHDsd X-Received: by 2002:a62:f17:: with SMTP id x23-v6mr1412604pfi.3.1526484300778; Wed, 16 May 2018 08:25:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526484300; cv=none; d=google.com; s=arc-20160816; b=CZJItJ1P/0JY4sjQiPhyL6KMwvo2V5Fo7OShTFxMwr2tajzgunTr2X2r2UUuNB7QnJ iHehfNOjlTCzxGcuXg43BoUVdI6iUWAzHfbz7gVO+p+zWaUD3bDTNH1Xj3z2pDq4r/eL 6uvntgUf+o18hJUfFviEESmYt4oaLE6S8f5S2cZBDjcuOmJC0VnyJI9SYiBJ0ebTfUhx ZHCvgdbxAVMv07zrAbowT9CWKxfOBkFsHbGFjJ7hHA2k/ZzYhSrx/a6pHPjp791SCNCX QVSKp7nNtmco94kKGy3DKDcJbZweQGOf8trG9aWn5SnICy4DErpiwfrIxTYoYI1QVtEk AbqQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:message-id:date:cc:to:from:subject :arc-authentication-results; bh=vYc1w7I+cBQztATEFjYZechIXpdM0Pb+mDBA6xlq788=; b=NV++B4hZmx7m1hizm5LUPbMI7nJETDLRLbxk4yf9c5pgq63Y2Fjkksk/COA4nCCJP7 Fyu/VW0uAwTCf4f6eXjUs39iRfRIJLU7ihzaXIGbrV6BQiA1+5f/I+hX6PMh+VaZfBYW 2QQtdo1pYnJLK+vPinsJHMegViZ1KmZf14idWOEaOSVarOOZDdTQCO7lpIIqpXq6VUYj RMUhcSuUXhZ/cUH3M85q3sGq0w1kXOMsrKIg3OID+XC6jK4PkZkofzR1D4TbK90ttAeh 6sLo2sxd/54i6TA7k3+aQ2C9rJE+v6ANZHiKS3dsspLXmaU0vU7eCQjmuoQfcWzXGQVH NtGQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r12-v6si2999085pfd.193.2018.05.16.08.24.44; Wed, 16 May 2018 08:25:00 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752506AbeEPPX5 (ORCPT + 99 others); Wed, 16 May 2018 11:23:57 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57546 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752038AbeEPPXx (ORCPT ); Wed, 16 May 2018 11:23:53 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 85DAA3110751; Wed, 16 May 2018 15:23:53 +0000 (UTC) Received: from gimli.home (ovpn-116-135.phx2.redhat.com [10.3.116.135]) by smtp.corp.redhat.com (Postfix) with ESMTP id 485155D9C9; Wed, 16 May 2018 15:23:44 +0000 (UTC) Subject: [PATCH v2] vfio/mdev: Check globally for duplicate devices From: Alex Williamson To: kwankhede@nvidia.com Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, alex.williamson@redhat.com, cohuck@redhat.com Date: Wed, 16 May 2018 09:23:43 -0600 Message-ID: <20180516152228.12123.34883.stgit@gimli.home> User-Agent: StGit/0.18-102-gdf9f MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.40]); Wed, 16 May 2018 15:23:53 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When we create an mdev device, we check for duplicates against the parent device and return -EEXIST if found, but the mdev device namespace is global since we'll link all devices from the bus. We do catch this later in sysfs_do_create_link_sd() to return -EEXIST, but with it comes a kernel warning and stack trace for trying to create duplicate sysfs links, which makes it an undesirable response. Therefore we should really be looking for duplicates across all mdev parent devices, or as implemented here, against our mdev device list. Notably, mdev_parent.lock really only seems to be serializing device creation and removal per parent. I'm not sure if this is necessary, mdev vendor drivers could easily provide this serialization if it is required, but a side-effect of holding the mdev_list_lock to protect the namespace is actually greater serialization across the create and remove paths, so mdev_parent.lock is removed. If we can show that vendor drivers handle the create/remove paths themselves, perhaps we can refine the locking granularity. Reviewed-by: Cornelia Huck Signed-off-by: Alex Williamson --- v2: Remove unnecessary ret init per Cornelia's review drivers/vfio/mdev/mdev_core.c | 77 +++++++++----------------------------- drivers/vfio/mdev/mdev_private.h | 1 2 files changed, 19 insertions(+), 59 deletions(-) diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 126991046eb7..aaab3ef93e1c 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -66,34 +66,6 @@ uuid_le mdev_uuid(struct mdev_device *mdev) } EXPORT_SYMBOL(mdev_uuid); -static int _find_mdev_device(struct device *dev, void *data) -{ - struct mdev_device *mdev; - - if (!dev_is_mdev(dev)) - return 0; - - mdev = to_mdev_device(dev); - - if (uuid_le_cmp(mdev->uuid, *(uuid_le *)data) == 0) - return 1; - - return 0; -} - -static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid) -{ - struct device *dev; - - dev = device_find_child(parent->dev, &uuid, _find_mdev_device); - if (dev) { - put_device(dev); - return true; - } - - return false; -} - /* Should be called holding parent_list_lock */ static struct mdev_parent *__find_parent_device(struct device *dev) { @@ -221,7 +193,6 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) } kref_init(&parent->ref); - mutex_init(&parent->lock); parent->dev = dev; parent->ops = ops; @@ -304,7 +275,7 @@ static void mdev_device_release(struct device *dev) int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) { int ret; - struct mdev_device *mdev; + struct mdev_device *mdev, *tmp; struct mdev_parent *parent; struct mdev_type *type = to_mdev_type(kobj); @@ -312,12 +283,14 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) if (!parent) return -EINVAL; - mutex_lock(&parent->lock); + mutex_lock(&mdev_list_lock); /* Check for duplicate */ - if (mdev_device_exist(parent, uuid)) { - ret = -EEXIST; - goto create_err; + list_for_each_entry(tmp, &mdev_list, next) { + if (!uuid_le_cmp(tmp->uuid, uuid)) { + ret = -EEXIST; + goto create_err; + } } mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); @@ -354,9 +327,6 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) mdev->type_kobj = kobj; dev_dbg(&mdev->dev, "MDEV: created\n"); - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); list_add(&mdev->next, &mdev_list); mutex_unlock(&mdev_list_lock); @@ -366,7 +336,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) device_unregister(&mdev->dev); create_err: - mutex_unlock(&parent->lock); + mutex_unlock(&mdev_list_lock); mdev_put_parent(parent); return ret; } @@ -382,6 +352,7 @@ int mdev_device_remove(struct device *dev, bool force_remove) mdev = to_mdev_device(dev); mutex_lock(&mdev_list_lock); + list_for_each_entry(tmp, &mdev_list, next) { if (tmp == mdev) { found = true; @@ -389,35 +360,25 @@ int mdev_device_remove(struct device *dev, bool force_remove) } } - if (found) - list_del(&mdev->next); - - mutex_unlock(&mdev_list_lock); - - if (!found) - return -ENODEV; + if (!found) { + ret = -ENODEV; + goto out; + } type = to_mdev_type(mdev->type_kobj); parent = mdev->parent; - mutex_lock(&parent->lock); ret = mdev_device_remove_ops(mdev, force_remove); - if (ret) { - mutex_unlock(&parent->lock); - - mutex_lock(&mdev_list_lock); - list_add(&mdev->next, &mdev_list); - mutex_unlock(&mdev_list_lock); - - return ret; - } + if (ret) + goto out; + list_del(&mdev->next); mdev_remove_sysfs_files(dev, type); device_unregister(dev); - mutex_unlock(&parent->lock); mdev_put_parent(parent); - - return 0; +out: + mutex_unlock(&mdev_list_lock); + return ret; } static int __init mdev_init(void) diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index a9cefd70a705..85bb268c91be 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -20,7 +20,6 @@ struct mdev_parent { struct device *dev; const struct mdev_parent_ops *ops; struct kref ref; - struct mutex lock; struct list_head next; struct kset *mdev_types_kset; struct list_head type_list;