> -----Original Message----- > From: Alex Williamson <alex.williamson@xxxxxxxxxx> > Sent: Tuesday, August 27, 2019 7:15 AM > To: Parav Pandit <parav@xxxxxxxxxxxx> > Cc: Jiri Pirko <jiri@xxxxxxxxxxxx>; kwankhede@xxxxxxxxxx; > cohuck@xxxxxxxxxx; davem@xxxxxxxxxxxxx; kvm@xxxxxxxxxxxxxxx; linux- > kernel@xxxxxxxxxxxxxxx; netdev@xxxxxxxxxxxxxxx > Subject: Re: [PATCH 1/4] mdev: Introduce sha1 based mdev alias > > On Mon, 26 Aug 2019 15:41:16 -0500 > Parav Pandit <parav@xxxxxxxxxxxx> wrote: > > > Whenever a parent requests to generate mdev alias, generate a mdev > > alias. > > It is an optional attribute that parent can request to generate for > > each of its child mdev. > > mdev alias is generated using sha1 from the mdev name. > > > > Signed-off-by: Parav Pandit <parav@xxxxxxxxxxxx> > > --- > > drivers/vfio/mdev/mdev_core.c | 98 > +++++++++++++++++++++++++++++++- > > drivers/vfio/mdev/mdev_private.h | 5 +- > > drivers/vfio/mdev/mdev_sysfs.c | 13 +++-- > > include/linux/mdev.h | 4 ++ > > 4 files changed, 111 insertions(+), 9 deletions(-) > > > > diff --git a/drivers/vfio/mdev/mdev_core.c > > b/drivers/vfio/mdev/mdev_core.c index b558d4cfd082..e825ff38b037 > > 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; > > @@ -164,6 +168,18 @@ int mdev_register_device(struct device *dev, const > struct mdev_parent_ops *ops) > > goto add_dev_err; > > } > > > > + 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) { > > + ret = -EINVAL; > > + goto add_dev_err; > > + } > > + } > > This looks like a sanity check, it could be done outside of the > parent_list_lock, even before we get a parent device reference. > Yes. > I think we're using a callback for get_alias_length() rather than a fixed field > to support the mtty module option added in patch 4, right? Right. I will move the check outside. > Its utility is rather limited with no args. I could imagine that if a parent > wanted to generate an alias that could be incorporated into a string with the > parent device name that it would be useful to call this with the parent > device as an arg. I guess we can save that until a user comes along though. > Right. We save until user arrives. I suggest you review the extra complexity I added here for vendor driven alias length, which I think we should do when an actual user comes along. > There doesn't seem to be anything serializing use of alias_hash. > Each sha1 calculation is happening on the new descriptor allocated and initialized using crypto_shash_init(). So it appears to me that each hash calculation can occur in parallel on the individual desc. > > + > > parent = kzalloc(sizeof(*parent), GFP_KERNEL); > > if (!parent) { > > ret = -ENOMEM; > > @@ -259,6 +275,7 @@ static void mdev_device_free(struct mdev_device > *mdev) > > mutex_unlock(&mdev_list_lock); > > > > dev_dbg(&mdev->dev, "MDEV: destroying\n"); > > + kvfree(mdev->alias); > > kfree(mdev); > > } > > > > @@ -269,18 +286,86 @@ 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 = 0; > > + > > + /* Align to multiple of 2 as bin2hex will generate > > + * even number of bytes. > > + */ > > Comment style for non-networking code please. Ack. > > > + alias_len = roundup(max_alias_len, 2); > > + alias = kvzalloc(alias_len + 1, GFP_KERNEL); > > The size we're generating here should be small enough to just use kzalloc(), Ack. > probably below too. > Descriptor size is 96 bytes long. kvzalloc is more optimal. > > + if (!alias) > > + return NULL; > > + > > + /* Allocate and init descriptor */ > > + hash_desc = kvzalloc(sizeof(*hash_desc) + > > + crypto_shash_descsize(alias_hash), > > + GFP_KERNEL); > > + if (!hash_desc) > > + goto desc_err; > > + > > + hash_desc->tfm = alias_hash; > > + > > + digest_size = crypto_shash_digestsize(alias_hash); > > + > > + digest = kvzalloc(digest_size, GFP_KERNEL); > > + if (!digest) { > > + ret = -ENOMEM; > > + goto digest_err; > > + } > > + crypto_shash_init(hash_desc); > > + crypto_shash_update(hash_desc, uuid, UUID_STRING_LEN); > > + crypto_shash_final(hash_desc, digest); > > + bin2hex(&alias[0], digest, > > &alias[0], ie. alias Ack. > > > + min_t(unsigned int, digest_size, alias_len / 2)); > > + /* When alias length is odd, zero out and additional last byte > > + * that bin2hex has copied. > > + */ > > + if (max_alias_len % 2) > > + alias[max_alias_len] = 0; > > Doesn't this give us a null terminated string for odd numbers but not even > numbers? Probably best to define that we always provide a null terminated > string then we could do this unconditionally. > > > + > > + kvfree(digest); > > + kvfree(hash_desc); > > + return alias; > > + > > +digest_err: > > + kvfree(hash_desc); > > +desc_err: > > + kvfree(alias); > > + return NULL; > > +} > > + > > +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); > > + unsigned int alias_len = 0; > > + const char *alias = NULL; > > > > parent = mdev_get_parent(type->parent); > > if (!parent) > > return -EINVAL; > > > > + if (parent->ops->get_alias_length) > > + alias_len = parent->ops->get_alias_length(); > > + if (alias_len) { > > Why isn't this nested into the branch above? > I will nest it. No specific reason to not nest it. > > + alias = generate_alias(uuid_str, alias_len); > > + if (!alias) { > > + ret = -ENOMEM; > > Could use an ERR_PTR and propagate an errno. > generate_alias() only returns one error type ENOMEM. When we add more error types, ERR_PTR is useful. > > + goto alias_fail; > > + } > > + } > > + > > mutex_lock(&mdev_list_lock); > > > > /* Check for duplicate */ > > @@ -300,6 +385,8 @@ int mdev_device_create(struct kobject *kobj, > > } > > > > guid_copy(&mdev->uuid, uuid); > > + mdev->alias = alias; > > + alias = NULL; > > A comment justifying this null'ing might help prevent it getting culled as > some point. It appears arbitrary at first look. Thanks, > Ack. I will add it. > Alex