diff mbox series

[net-next,07/19] vfio/mdev: Introduce sha1 based mdev alias

Message ID 20191107160834.21087-7-parav@mellanox.com (mailing list archive)
State New, archived
Headers show
Series Mellanox, mlx5 sub function support | expand

Commit Message

Parav Pandit Nov. 7, 2019, 4:08 p.m. UTC
Some vendor drivers want an identifier for an mdev device that is
shorter than the UUID, due to length restrictions in the consumers of
that identifier.

Add a callback that allows a vendor driver to request an alias of a
specified length to be generated for an mdev device. If generated,
that alias is checked for collisions.

It is an optional attribute.
mdev alias is generated using sha1 from the mdev name.

Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Parav Pandit <parav@mellanox.com>
---
 drivers/vfio/mdev/mdev_core.c    | 123 ++++++++++++++++++++++++++++++-
 drivers/vfio/mdev/mdev_private.h |   5 +-
 drivers/vfio/mdev/mdev_sysfs.c   |  13 ++--
 include/linux/mdev.h             |   4 +
 4 files changed, 135 insertions(+), 10 deletions(-)

Comments

Jiri Pirko Nov. 8, 2019, 11:04 a.m. UTC | #1
Thu, Nov 07, 2019 at 05:08:22PM CET, parav@mellanox.com wrote:
>Some vendor drivers want an identifier for an mdev device that is
>shorter than the UUID, due to length restrictions in the consumers of
>that identifier.
>
>Add a callback that allows a vendor driver to request an alias of a
>specified length to be generated for an mdev device. If generated,
>that alias is checked for collisions.
>
>It is an optional attribute.
>mdev alias is generated using sha1 from the mdev name.
>
>Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
>Signed-off-by: Parav Pandit <parav@mellanox.com>
>---
> drivers/vfio/mdev/mdev_core.c    | 123 ++++++++++++++++++++++++++++++-
> drivers/vfio/mdev/mdev_private.h |   5 +-
> drivers/vfio/mdev/mdev_sysfs.c   |  13 ++--
> include/linux/mdev.h             |   4 +
> 4 files changed, 135 insertions(+), 10 deletions(-)
>
>diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
>index b558d4cfd082..3bdff0469607 100644
>--- a/drivers/vfio/mdev/mdev_core.c
>+++ b/drivers/vfio/mdev/mdev_core.c
>@@ -10,9 +10,11 @@

[...]


>-int mdev_device_create(struct kobject *kobj,
>-		       struct device *dev, const guid_t *uuid)
>+static const char *
>+generate_alias(const char *uuid, unsigned int max_alias_len)
>+{
>+	struct shash_desc *hash_desc;
>+	unsigned int digest_size;
>+	unsigned char *digest;
>+	unsigned int alias_len;
>+	char *alias;
>+	int ret;
>+
>+	/*
>+	 * Align to multiple of 2 as bin2hex will generate
>+	 * even number of bytes.
>+	 */
>+	alias_len = roundup(max_alias_len, 2);

This is odd, see below.


>+	alias = kzalloc(alias_len + 1, GFP_KERNEL);
>+	if (!alias)
>+		return ERR_PTR(-ENOMEM);
>+
>+	/* Allocate and init descriptor */
>+	hash_desc = kvzalloc(sizeof(*hash_desc) +
>+			     crypto_shash_descsize(alias_hash),
>+			     GFP_KERNEL);
>+	if (!hash_desc) {
>+		ret = -ENOMEM;
>+		goto desc_err;
>+	}
>+
>+	hash_desc->tfm = alias_hash;
>+
>+	digest_size = crypto_shash_digestsize(alias_hash);
>+
>+	digest = kzalloc(digest_size, GFP_KERNEL);
>+	if (!digest) {
>+		ret = -ENOMEM;
>+		goto digest_err;
>+	}
>+	ret = crypto_shash_init(hash_desc);
>+	if (ret)
>+		goto hash_err;
>+
>+	ret = crypto_shash_update(hash_desc, uuid, UUID_STRING_LEN);
>+	if (ret)
>+		goto hash_err;
>+
>+	ret = crypto_shash_final(hash_desc, digest);
>+	if (ret)
>+		goto hash_err;
>+
>+	bin2hex(alias, digest, min_t(unsigned int, digest_size, alias_len / 2));
>+	/*
>+	 * When alias length is odd, zero out an additional last byte
>+	 * that bin2hex has copied.
>+	 */
>+	if (max_alias_len % 2)
>+		alias[max_alias_len] = 0;
>+
>+	kfree(digest);
>+	kvfree(hash_desc);
>+	return alias;
>+
>+hash_err:
>+	kfree(digest);
>+digest_err:
>+	kvfree(hash_desc);
>+desc_err:
>+	kfree(alias);
>+	return ERR_PTR(ret);
>+}
>+
>+int mdev_device_create(struct kobject *kobj, struct device *dev,
>+		       const char *uuid_str, const guid_t *uuid)
> {
> 	int ret;
> 	struct mdev_device *mdev, *tmp;
> 	struct mdev_parent *parent;
> 	struct mdev_type *type = to_mdev_type(kobj);
>+	const char *alias = NULL;
> 
> 	parent = mdev_get_parent(type->parent);
> 	if (!parent)
> 		return -EINVAL;
> 
>+	if (parent->ops->get_alias_length) {
>+		unsigned int alias_len;
>+
>+		alias_len = parent->ops->get_alias_length();
>+		if (alias_len) {

I think this should be with WARN_ON. Driver should not never return such
0 and if it does, it's a bug.

Also I think this check should be extended by checking value is multiple
of 2. Then you can avoid the roundup() above. No need to allow even len.


>+			alias = generate_alias(uuid_str, alias_len);
>+			if (IS_ERR(alias)) {
>+				ret = PTR_ERR(alias);
>+				goto alias_fail;
>+			}
>+		}
>+	}
> 	mutex_lock(&mdev_list_lock);
> 
> 	/* Check for duplicate */


[...]

>diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c
>index 7570c7602ab4..43afe0e80b76 100644
>--- a/drivers/vfio/mdev/mdev_sysfs.c
>+++ b/drivers/vfio/mdev/mdev_sysfs.c
>@@ -63,15 +63,18 @@ static ssize_t create_store(struct kobject *kobj, struct device *dev,
> 		return -ENOMEM;
> 
> 	ret = guid_parse(str, &uuid);
>-	kfree(str);
> 	if (ret)
>-		return ret;
>+		goto err;
> 
>-	ret = mdev_device_create(kobj, dev, &uuid);
>+	ret = mdev_device_create(kobj, dev, str, &uuid);

Why to pass the same thing twice? Move the guid_parse() call to the
beginning of mdev_device_create() function.


> 	if (ret)
>-		return ret;
>+		goto err;
> 
>-	return count;
>+	ret = count;
>+
>+err:
>+	kfree(str);
>+	return ret;
> }
> 
> MDEV_TYPE_ATTR_WO(create);

[...]
Cornelia Huck Nov. 8, 2019, 11:10 a.m. UTC | #2
On Thu,  7 Nov 2019 10:08:22 -0600
Parav Pandit <parav@mellanox.com> wrote:

> Some vendor drivers want an identifier for an mdev device that is
> shorter than the UUID, due to length restrictions in the consumers of
> that identifier.
> 
> Add a callback that allows a vendor driver to request an alias of a
> specified length to be generated for an mdev device. If generated,
> that alias is checked for collisions.
> 
> It is an optional attribute.
> mdev alias is generated using sha1 from the mdev name.
> 
> Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
> Signed-off-by: Parav Pandit <parav@mellanox.com>
> ---
>  drivers/vfio/mdev/mdev_core.c    | 123 ++++++++++++++++++++++++++++++-
>  drivers/vfio/mdev/mdev_private.h |   5 +-
>  drivers/vfio/mdev/mdev_sysfs.c   |  13 ++--
>  include/linux/mdev.h             |   4 +
>  4 files changed, 135 insertions(+), 10 deletions(-)

Is this (or any of the other mdev alias patches) different from what I
reviewed in the past?
Parav Pandit Nov. 8, 2019, 3:59 p.m. UTC | #3
> -----Original Message-----
> From: Jiri Pirko <jiri@resnulli.us>
> Sent: Friday, November 8, 2019 5:05 AM
> To: Parav Pandit <parav@mellanox.com>
> Cc: alex.williamson@redhat.com; davem@davemloft.net;
> kvm@vger.kernel.org; netdev@vger.kernel.org; Saeed Mahameed
> <saeedm@mellanox.com>; kwankhede@nvidia.com; leon@kernel.org;
> cohuck@redhat.com; Jiri Pirko <jiri@mellanox.com>; linux-
> rdma@vger.kernel.org
> Subject: Re: [PATCH net-next 07/19] vfio/mdev: Introduce sha1 based mdev
> alias
> 
> Thu, Nov 07, 2019 at 05:08:22PM CET, parav@mellanox.com wrote:
> >Some vendor drivers want an identifier for an mdev device that is
> >shorter than the UUID, due to length restrictions in the consumers of
> >that identifier.
> >
> >Add a callback that allows a vendor driver to request an alias of a
> >specified length to be generated for an mdev device. If generated, that
> >alias is checked for collisions.
> >
> >It is an optional attribute.
> >mdev alias is generated using sha1 from the mdev name.
> >
> >Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
> >Signed-off-by: Parav Pandit <parav@mellanox.com>
> >---
> > drivers/vfio/mdev/mdev_core.c    | 123
> ++++++++++++++++++++++++++++++-
> > drivers/vfio/mdev/mdev_private.h |   5 +-
> > drivers/vfio/mdev/mdev_sysfs.c   |  13 ++--
> > include/linux/mdev.h             |   4 +
> > 4 files changed, 135 insertions(+), 10 deletions(-)
> >
> >diff --git a/drivers/vfio/mdev/mdev_core.c
> >b/drivers/vfio/mdev/mdev_core.c index b558d4cfd082..3bdff0469607
> 100644
> >--- a/drivers/vfio/mdev/mdev_core.c
> >+++ b/drivers/vfio/mdev/mdev_core.c
> >@@ -10,9 +10,11 @@
> 
> [...]
> 
> 
> >-int mdev_device_create(struct kobject *kobj,
> >-		       struct device *dev, const guid_t *uuid)
> >+static const char *
> >+generate_alias(const char *uuid, unsigned int max_alias_len) {
> >+	struct shash_desc *hash_desc;
> >+	unsigned int digest_size;
> >+	unsigned char *digest;
> >+	unsigned int alias_len;
> >+	char *alias;
> >+	int ret;
> >+
> >+	/*
> >+	 * Align to multiple of 2 as bin2hex will generate
> >+	 * even number of bytes.
> >+	 */
> >+	alias_len = roundup(max_alias_len, 2);
> 
> This is odd, see below.
> 
> 
> >+	alias = kzalloc(alias_len + 1, GFP_KERNEL);
> >+	if (!alias)
> >+		return ERR_PTR(-ENOMEM);
> >+
> >+	/* Allocate and init descriptor */
> >+	hash_desc = kvzalloc(sizeof(*hash_desc) +
> >+			     crypto_shash_descsize(alias_hash),
> >+			     GFP_KERNEL);
> >+	if (!hash_desc) {
> >+		ret = -ENOMEM;
> >+		goto desc_err;
> >+	}
> >+
> >+	hash_desc->tfm = alias_hash;
> >+
> >+	digest_size = crypto_shash_digestsize(alias_hash);
> >+
> >+	digest = kzalloc(digest_size, GFP_KERNEL);
> >+	if (!digest) {
> >+		ret = -ENOMEM;
> >+		goto digest_err;
> >+	}
> >+	ret = crypto_shash_init(hash_desc);
> >+	if (ret)
> >+		goto hash_err;
> >+
> >+	ret = crypto_shash_update(hash_desc, uuid, UUID_STRING_LEN);
> >+	if (ret)
> >+		goto hash_err;
> >+
> >+	ret = crypto_shash_final(hash_desc, digest);
> >+	if (ret)
> >+		goto hash_err;
> >+
> >+	bin2hex(alias, digest, min_t(unsigned int, digest_size, alias_len / 2));
> >+	/*
> >+	 * When alias length is odd, zero out an additional last byte
> >+	 * that bin2hex has copied.
> >+	 */
> >+	if (max_alias_len % 2)
> >+		alias[max_alias_len] = 0;
> >+
> >+	kfree(digest);
> >+	kvfree(hash_desc);
> >+	return alias;
> >+
> >+hash_err:
> >+	kfree(digest);
> >+digest_err:
> >+	kvfree(hash_desc);
> >+desc_err:
> >+	kfree(alias);
> >+	return ERR_PTR(ret);
> >+}
> >+
> >+int mdev_device_create(struct kobject *kobj, struct device *dev,
> >+		       const char *uuid_str, const guid_t *uuid)
> > {
> > 	int ret;
> > 	struct mdev_device *mdev, *tmp;
> > 	struct mdev_parent *parent;
> > 	struct mdev_type *type = to_mdev_type(kobj);
> >+	const char *alias = NULL;
> >
> > 	parent = mdev_get_parent(type->parent);
> > 	if (!parent)
> > 		return -EINVAL;
> >
> >+	if (parent->ops->get_alias_length) {
> >+		unsigned int alias_len;
> >+
> >+		alias_len = parent->ops->get_alias_length();
> >+		if (alias_len) {
> 
> I think this should be with WARN_ON. Driver should not never return such
> 0 and if it does, it's a bug.
>
Ok. will add it.
 
> Also I think this check should be extended by checking value is multiple of 2.
Do you mean driver must set alias length as always multiple of 2? Why?

> Then you can avoid the roundup() above. No need to allow even len.
Did you mean "no need to allow odd"? or? 
 
> 
> [...]
> 
> >diff --git a/drivers/vfio/mdev/mdev_sysfs.c
> >b/drivers/vfio/mdev/mdev_sysfs.c index 7570c7602ab4..43afe0e80b76
> >100644
> >--- a/drivers/vfio/mdev/mdev_sysfs.c
> >+++ b/drivers/vfio/mdev/mdev_sysfs.c
> >@@ -63,15 +63,18 @@ static ssize_t create_store(struct kobject *kobj,
> struct device *dev,
> > 		return -ENOMEM;
> >
> > 	ret = guid_parse(str, &uuid);
> >-	kfree(str);
> > 	if (ret)
> >-		return ret;
> >+		goto err;
> >
> >-	ret = mdev_device_create(kobj, dev, &uuid);
> >+	ret = mdev_device_create(kobj, dev, str, &uuid);
> 
> Why to pass the same thing twice? Move the guid_parse() call to the
> beginning of mdev_device_create() function.
>
Because alias should be unique and need to hold the lock while searching for duplicate.
So it is not done twice, and moving guid_parse() won't help due to need of lock.
 
> 
> > 	if (ret)
> >-		return ret;
> >+		goto err;
> >
> >-	return count;
> >+	ret = count;
> >+
> >+err:
> >+	kfree(str);
> >+	return ret;
> > }
> >
> > MDEV_TYPE_ATTR_WO(create);
> 
> [...]
Parav Pandit Nov. 8, 2019, 4:03 p.m. UTC | #4
Hi Cornelia,

> -----Original Message-----
> From: Cornelia Huck <cohuck@redhat.com>
> Sent: Friday, November 8, 2019 5:11 AM
> To: Parav Pandit <parav@mellanox.com>
> Cc: alex.williamson@redhat.com; davem@davemloft.net;
> kvm@vger.kernel.org; netdev@vger.kernel.org; Saeed Mahameed
> <saeedm@mellanox.com>; kwankhede@nvidia.com; leon@kernel.org; Jiri
> Pirko <jiri@mellanox.com>; linux-rdma@vger.kernel.org
> Subject: Re: [PATCH net-next 07/19] vfio/mdev: Introduce sha1 based mdev
> alias
> 
> On Thu,  7 Nov 2019 10:08:22 -0600
> Parav Pandit <parav@mellanox.com> wrote:
> 
> > Some vendor drivers want an identifier for an mdev device that is
> > shorter than the UUID, due to length restrictions in the consumers of
> > that identifier.
> >
> > Add a callback that allows a vendor driver to request an alias of a
> > specified length to be generated for an mdev device. If generated,
> > that alias is checked for collisions.
> >
> > It is an optional attribute.
> > mdev alias is generated using sha1 from the mdev name.
> >
> > Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
> > Signed-off-by: Parav Pandit <parav@mellanox.com>
> > ---
> >  drivers/vfio/mdev/mdev_core.c    | 123
> ++++++++++++++++++++++++++++++-
> >  drivers/vfio/mdev/mdev_private.h |   5 +-
> >  drivers/vfio/mdev/mdev_sysfs.c   |  13 ++--
> >  include/linux/mdev.h             |   4 +
> >  4 files changed, 135 insertions(+), 10 deletions(-)
> 
> Is this (or any of the other mdev alias patches) different from what I
> reviewed in the past?

No. It is not. They are same as what you already reviewed.
Jiri Pirko Nov. 8, 2019, 4:28 p.m. UTC | #5
Fri, Nov 08, 2019 at 04:59:53PM CET, parav@mellanox.com wrote:

[...]

>> >+	if (parent->ops->get_alias_length) {
>> >+		unsigned int alias_len;
>> >+
>> >+		alias_len = parent->ops->get_alias_length();
>> >+		if (alias_len) {
>> 
>> I think this should be with WARN_ON. Driver should not never return such
>> 0 and if it does, it's a bug.
>>
>Ok. will add it.
> 
>> Also I think this check should be extended by checking value is multiple of 2.
>Do you mean driver must set alias length as always multiple of 2? Why?

Why not? Why would driver want to have even len? If say 11 is too long,
it should return 10. The last byte for even is set by your code
to '0' anyway...


>
>> Then you can avoid the roundup() above. No need to allow even len.
>Did you mean "no need to allow odd"? or? 

Yes, odd.


> 
>> 
>> [...]
>> 
>> >diff --git a/drivers/vfio/mdev/mdev_sysfs.c
>> >b/drivers/vfio/mdev/mdev_sysfs.c index 7570c7602ab4..43afe0e80b76
>> >100644
>> >--- a/drivers/vfio/mdev/mdev_sysfs.c
>> >+++ b/drivers/vfio/mdev/mdev_sysfs.c
>> >@@ -63,15 +63,18 @@ static ssize_t create_store(struct kobject *kobj,
>> struct device *dev,
>> > 		return -ENOMEM;
>> >
>> > 	ret = guid_parse(str, &uuid);
>> >-	kfree(str);
>> > 	if (ret)
>> >-		return ret;
>> >+		goto err;
>> >
>> >-	ret = mdev_device_create(kobj, dev, &uuid);
>> >+	ret = mdev_device_create(kobj, dev, str, &uuid);
>> 
>> Why to pass the same thing twice? Move the guid_parse() call to the
>> beginning of mdev_device_create() function.
>>
>Because alias should be unique and need to hold the lock while searching for duplicate.
>So it is not done twice, and moving guid_parse() won't help due to need of lock.

I'm not saying anything about a lock. Not sure why do you think so.
I'm saying that you pass the same value in 2 args. That's it.
Better to pass it as char* only and process it inside.
If by guid_parse() or otherwise, does not matter. That is my point.

> 
>> 
>> > 	if (ret)
>> >-		return ret;
>> >+		goto err;
>> >
>> >-	return count;
>> >+	ret = count;
>> >+
>> >+err:
>> >+	kfree(str);
>> >+	return ret;
>> > }
>> >
>> > MDEV_TYPE_ATTR_WO(create);
>> 
>> [...]
diff mbox series

Patch

diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index b558d4cfd082..3bdff0469607 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -10,9 +10,11 @@ 
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/uuid.h>
 #include <linux/sysfs.h>
 #include <linux/mdev.h>
+#include <crypto/hash.h>
 
 #include "mdev_private.h"
 
@@ -27,6 +29,8 @@  static struct class_compat *mdev_bus_compat_class;
 static LIST_HEAD(mdev_list);
 static DEFINE_MUTEX(mdev_list_lock);
 
+static struct crypto_shash *alias_hash;
+
 struct device *mdev_parent_dev(struct mdev_device *mdev)
 {
 	return mdev->parent->dev;
@@ -150,6 +154,16 @@  int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
 	if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups)
 		return -EINVAL;
 
+	if (ops->get_alias_length) {
+		unsigned int digest_size;
+		unsigned int aligned_len;
+
+		aligned_len = roundup(ops->get_alias_length(), 2);
+		digest_size = crypto_shash_digestsize(alias_hash);
+		if (aligned_len / 2 > digest_size)
+			return -EINVAL;
+	}
+
 	dev = get_device(dev);
 	if (!dev)
 		return -EINVAL;
@@ -259,6 +273,7 @@  static void mdev_device_free(struct mdev_device *mdev)
 	mutex_unlock(&mdev_list_lock);
 
 	dev_dbg(&mdev->dev, "MDEV: destroying\n");
+	kfree(mdev->alias);
 	kfree(mdev);
 }
 
@@ -269,18 +284,101 @@  static void mdev_device_release(struct device *dev)
 	mdev_device_free(mdev);
 }
 
-int mdev_device_create(struct kobject *kobj,
-		       struct device *dev, const guid_t *uuid)
+static const char *
+generate_alias(const char *uuid, unsigned int max_alias_len)
+{
+	struct shash_desc *hash_desc;
+	unsigned int digest_size;
+	unsigned char *digest;
+	unsigned int alias_len;
+	char *alias;
+	int ret;
+
+	/*
+	 * Align to multiple of 2 as bin2hex will generate
+	 * even number of bytes.
+	 */
+	alias_len = roundup(max_alias_len, 2);
+	alias = kzalloc(alias_len + 1, GFP_KERNEL);
+	if (!alias)
+		return ERR_PTR(-ENOMEM);
+
+	/* Allocate and init descriptor */
+	hash_desc = kvzalloc(sizeof(*hash_desc) +
+			     crypto_shash_descsize(alias_hash),
+			     GFP_KERNEL);
+	if (!hash_desc) {
+		ret = -ENOMEM;
+		goto desc_err;
+	}
+
+	hash_desc->tfm = alias_hash;
+
+	digest_size = crypto_shash_digestsize(alias_hash);
+
+	digest = kzalloc(digest_size, GFP_KERNEL);
+	if (!digest) {
+		ret = -ENOMEM;
+		goto digest_err;
+	}
+	ret = crypto_shash_init(hash_desc);
+	if (ret)
+		goto hash_err;
+
+	ret = crypto_shash_update(hash_desc, uuid, UUID_STRING_LEN);
+	if (ret)
+		goto hash_err;
+
+	ret = crypto_shash_final(hash_desc, digest);
+	if (ret)
+		goto hash_err;
+
+	bin2hex(alias, digest, min_t(unsigned int, digest_size, alias_len / 2));
+	/*
+	 * When alias length is odd, zero out an additional last byte
+	 * that bin2hex has copied.
+	 */
+	if (max_alias_len % 2)
+		alias[max_alias_len] = 0;
+
+	kfree(digest);
+	kvfree(hash_desc);
+	return alias;
+
+hash_err:
+	kfree(digest);
+digest_err:
+	kvfree(hash_desc);
+desc_err:
+	kfree(alias);
+	return ERR_PTR(ret);
+}
+
+int mdev_device_create(struct kobject *kobj, struct device *dev,
+		       const char *uuid_str, const guid_t *uuid)
 {
 	int ret;
 	struct mdev_device *mdev, *tmp;
 	struct mdev_parent *parent;
 	struct mdev_type *type = to_mdev_type(kobj);
+	const char *alias = NULL;
 
 	parent = mdev_get_parent(type->parent);
 	if (!parent)
 		return -EINVAL;
 
+	if (parent->ops->get_alias_length) {
+		unsigned int alias_len;
+
+		alias_len = parent->ops->get_alias_length();
+		if (alias_len) {
+			alias = generate_alias(uuid_str, alias_len);
+			if (IS_ERR(alias)) {
+				ret = PTR_ERR(alias);
+				goto alias_fail;
+			}
+		}
+	}
 	mutex_lock(&mdev_list_lock);
 
 	/* Check for duplicate */
@@ -300,6 +398,12 @@  int mdev_device_create(struct kobject *kobj,
 	}
 
 	guid_copy(&mdev->uuid, uuid);
+	mdev->alias = alias;
+	/*
+	 * At this point alias memory is owned by the mdev.
+	 * Mark it NULL, so that only mdev can free it.
+	 */
+	alias = NULL;
 	list_add(&mdev->next, &mdev_list);
 	mutex_unlock(&mdev_list_lock);
 
@@ -346,6 +450,8 @@  int mdev_device_create(struct kobject *kobj,
 	up_read(&parent->unreg_sem);
 	put_device(&mdev->dev);
 mdev_fail:
+	kfree(alias);
+alias_fail:
 	mdev_put_parent(parent);
 	return ret;
 }
@@ -406,7 +512,17 @@  EXPORT_SYMBOL(mdev_get_iommu_device);
 
 static int __init mdev_init(void)
 {
-	return mdev_bus_register();
+	int ret;
+
+	alias_hash = crypto_alloc_shash("sha1", 0, 0);
+	if (!alias_hash)
+		return -ENOMEM;
+
+	ret = mdev_bus_register();
+	if (ret)
+		crypto_free_shash(alias_hash);
+
+	return ret;
 }
 
 static void __exit mdev_exit(void)
@@ -415,6 +531,7 @@  static void __exit mdev_exit(void)
 		class_compat_unregister(mdev_bus_compat_class);
 
 	mdev_bus_unregister();
+	crypto_free_shash(alias_hash);
 }
 
 module_init(mdev_init)
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h
index 7d922950caaf..078fdaf7836e 100644
--- a/drivers/vfio/mdev/mdev_private.h
+++ b/drivers/vfio/mdev/mdev_private.h
@@ -32,6 +32,7 @@  struct mdev_device {
 	struct list_head next;
 	struct kobject *type_kobj;
 	struct device *iommu_device;
+	const char *alias;
 	bool active;
 };
 
@@ -57,8 +58,8 @@  void parent_remove_sysfs_files(struct mdev_parent *parent);
 int  mdev_create_sysfs_files(struct device *dev, struct mdev_type *type);
 void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type);
 
-int  mdev_device_create(struct kobject *kobj,
-			struct device *dev, const guid_t *uuid);
+int mdev_device_create(struct kobject *kobj, struct device *dev,
+		       const char *uuid_str, const guid_t *uuid);
 int  mdev_device_remove(struct device *dev);
 
 #endif /* MDEV_PRIVATE_H */
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c
index 7570c7602ab4..43afe0e80b76 100644
--- a/drivers/vfio/mdev/mdev_sysfs.c
+++ b/drivers/vfio/mdev/mdev_sysfs.c
@@ -63,15 +63,18 @@  static ssize_t create_store(struct kobject *kobj, struct device *dev,
 		return -ENOMEM;
 
 	ret = guid_parse(str, &uuid);
-	kfree(str);
 	if (ret)
-		return ret;
+		goto err;
 
-	ret = mdev_device_create(kobj, dev, &uuid);
+	ret = mdev_device_create(kobj, dev, str, &uuid);
 	if (ret)
-		return ret;
+		goto err;
 
-	return count;
+	ret = count;
+
+err:
+	kfree(str);
+	return ret;
 }
 
 MDEV_TYPE_ATTR_WO(create);
diff --git a/include/linux/mdev.h b/include/linux/mdev.h
index 0ce30ca78db0..06e162361df9 100644
--- a/include/linux/mdev.h
+++ b/include/linux/mdev.h
@@ -72,6 +72,9 @@  struct device *mdev_get_iommu_device(struct device *dev);
  * @mmap:		mmap callback
  *			@mdev: mediated device structure
  *			@vma: vma structure
+ * @get_alias_length:	Optional: If a non-zero alias length is returned,
+ *			generate an alias for this parent's mdevs based upon
+ *			the mdev device name.
  * Parent device that support mediated device should be registered with mdev
  * module with mdev_parent_ops structure.
  **/
@@ -92,6 +95,7 @@  struct mdev_parent_ops {
 	long	(*ioctl)(struct mdev_device *mdev, unsigned int cmd,
 			 unsigned long arg);
 	int	(*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma);
+	unsigned int (*get_alias_length)(void);
 };
 
 /* interface for exporting mdev supported type attributes */