Received: by 2002:ac0:a594:0:0:0:0:0 with SMTP id m20-v6csp2790421imm; Wed, 16 May 2018 20:30:50 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqxxxx3ByHcaxU0GihgYqfrjqjtjlHTyP/eNtfpuwVx9qmNAo6nLvRYsH+t4eRanX4f4O3K X-Received: by 2002:a63:b51d:: with SMTP id y29-v6mr1019647pge.406.1526527850747; Wed, 16 May 2018 20:30:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526527850; cv=none; d=google.com; s=arc-20160816; b=ResTjVDilFxpTPhn8Z8nyYinUDTk8d2ZGOq+Fr8hZHSfAum+giWS+i7cJ9u9maR8Tv 0AuBjr1NJr6slg1oE4AS7IKNHusx/EdDR2YjYLb0iyK3xqZ0Z9StW8uQWz4+rrWl/PoK bwX0GnWx2FTiyID5Kc3W6WKglAYeJzEJdx8jWu3riciSxZpeNPy9WMEEfAp74YzcSKMD hDAR/5O59U0N3uO1EACZHx7m0qCKCvs5UqsqYmhrwEURAI9UWpaOoWIkMOm8vAT1muKQ 1CPHxJbTQJR/AAOpVL6jGroWAlWDJt7AePz6VDIN89C7eC+2LpgmM9gwZvjtLgmTCXF/ N+Jg== 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=13Bl4JzsF9iCWrjLV3xMnxkumpK0gQwHq5J10JJjNls=; b=QkHOrTWbUvG3U1NVlLBXI6fldpPQ3a6CIJds7kQwfN1PrGPKDdPps8chIfYckvTZ+q z1F0zHjVs2qCqpGXVlhP+YofzAASi4NrE0GvFSjqLbxE7gKdsfnopTAAUHKRLvfsCldJ LHqh3dYE5Aplz1T1D4cPPjJNc64OoVlWlW2WhEH13V1xCR3QcNkXP+3zm4DAqfklFEYS lLFKCSZsbSBYyrfO5ZCd19Hu3d5tQ5yJLvlFB1di03wNkLvJitBZmKgw3jQio16rFtSg ChrZiRwM7OBsasXsBPF6OGKKsfxMkVpjlWILiVSyv5YXHZVCK4alaesqxaMvn5gEmZL5 tZHQ== 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 99-v6si3649736plc.362.2018.05.16.20.30.36; Wed, 16 May 2018 20:30:50 -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 S1751986AbeEQDaX (ORCPT + 99 others); Wed, 16 May 2018 23:30:23 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44936 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751844AbeEQDaW (ORCPT ); Wed, 16 May 2018 23:30:22 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 225AEA0E41; Thu, 17 May 2018 03:30:22 +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 8C5951001925; Thu, 17 May 2018 03:30:19 +0000 (UTC) Subject: [PATCH v3] 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 21:30:19 -0600 Message-ID: <20180517031746.32242.17768.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.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Thu, 17 May 2018 03:30:22 +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. Using mdev_list to prevent duplicates means that we can remove mdev_parent.lock, but in order not to serialize mdev device creation and removal globally, we add mdev_device.active which allows UUIDs to be reserved such that we can drop the mdev_list_lock before the mdev device is fully in place. NB. there was never intended to be any serialization guarantee provided by the mdev core with respect to creation and removal of mdev devices, mdev_parent.lock provided this only as a side-effect of the implementation for locking the namespace per parent. That serialization is now removed. Signed-off-by: Alex Williamson --- v3: Rework locking and add a field to mdev_device so we can track completed instances vs those added to reserve the namespace. drivers/vfio/mdev/mdev_core.c | 94 +++++++++++++------------------------- drivers/vfio/mdev/mdev_private.h | 2 - 2 files changed, 34 insertions(+), 62 deletions(-) diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 126991046eb7..55ea9d34ec69 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,21 +283,26 @@ 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)) { + mutex_unlock(&mdev_list_lock); + return -EEXIST; + } } mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) { - ret = -ENOMEM; - goto create_err; + mutex_unlock(&mdev_list_lock); + return -ENOMEM; } memcpy(&mdev->uuid, &uuid, sizeof(uuid_le)); + list_add(&mdev->next, &mdev_list); + mutex_unlock(&mdev_list_lock); + mdev->parent = parent; kref_init(&mdev->ref); @@ -352,21 +328,18 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) } mdev->type_kobj = kobj; + mdev->active = true; 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); - - return ret; + return 0; create_failed: device_unregister(&mdev->dev); create_err: - mutex_unlock(&parent->lock); + mutex_lock(&mdev_list_lock); + list_del(&mdev->next); + mutex_unlock(&mdev_list_lock); mdev_put_parent(parent); return ret; } @@ -377,44 +350,43 @@ int mdev_device_remove(struct device *dev, bool force_remove) struct mdev_parent *parent; struct mdev_type *type; int ret; - bool found = false; mdev = to_mdev_device(dev); mutex_lock(&mdev_list_lock); list_for_each_entry(tmp, &mdev_list, next) { - if (tmp == mdev) { - found = true; + if (tmp == mdev) break; - } } - if (found) - list_del(&mdev->next); + if (tmp != mdev) { + mutex_unlock(&mdev_list_lock); + return -ENODEV; + } - mutex_unlock(&mdev_list_lock); + if (!mdev->active) { + mutex_unlock(&mdev_list_lock); + return -EAGAIN; + } - if (!found) - return -ENODEV; + mdev->active = false; + mutex_unlock(&mdev_list_lock); 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); - + mdev->active = true; return ret; } + mutex_lock(&mdev_list_lock); + list_del(&mdev->next); + mutex_unlock(&mdev_list_lock); + mdev_remove_sysfs_files(dev, type); device_unregister(dev); - mutex_unlock(&parent->lock); mdev_put_parent(parent); return 0; diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index a9cefd70a705..b5819b7d7ef7 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; @@ -34,6 +33,7 @@ struct mdev_device { struct kref ref; struct list_head next; struct kobject *type_kobj; + bool active; }; #define to_mdev_device(dev) container_of(dev, struct mdev_device, dev)