thunderbolt: Add tb_property_copy_dir()
authorMika Westerberg <mika.westerberg@linux.intel.com>
Fri, 8 Jan 2021 12:38:24 +0000 (14:38 +0200)
committerMika Westerberg <mika.westerberg@linux.intel.com>
Thu, 18 Mar 2021 15:25:31 +0000 (18:25 +0300)
This function takes a deep copy of the properties. We need this in order
to support more dynamic properties per XDomain connection as required by
the USB4 inter-domain service spec.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
drivers/thunderbolt/property.c
include/linux/thunderbolt.h

index d5b0cdb..dc555cd 100644 (file)
@@ -501,6 +501,77 @@ ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,
        return ret < 0 ? ret : 0;
 }
 
+/**
+ * tb_property_copy_dir() - Take a deep copy of directory
+ * @dir: Directory to copy
+ *
+ * This function takes a deep copy of @dir and returns back the copy. In
+ * case of error returns %NULL. The resulting directory needs to be
+ * released by calling tb_property_free_dir().
+ */
+struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir)
+{
+       struct tb_property *property, *p = NULL;
+       struct tb_property_dir *d;
+
+       if (!dir)
+               return NULL;
+
+       d = tb_property_create_dir(dir->uuid);
+       if (!d)
+               return NULL;
+
+       list_for_each_entry(property, &dir->properties, list) {
+               struct tb_property *p;
+
+               p = tb_property_alloc(property->key, property->type);
+               if (!p)
+                       goto err_free;
+
+               p->length = property->length;
+
+               switch (property->type) {
+               case TB_PROPERTY_TYPE_DIRECTORY:
+                       p->value.dir = tb_property_copy_dir(property->value.dir);
+                       if (!p->value.dir)
+                               goto err_free;
+                       break;
+
+               case TB_PROPERTY_TYPE_DATA:
+                       p->value.data = kmemdup(property->value.data,
+                                               property->length * 4,
+                                               GFP_KERNEL);
+                       if (!p->value.data)
+                               goto err_free;
+                       break;
+
+               case TB_PROPERTY_TYPE_TEXT:
+                       p->value.text = kzalloc(p->length * 4, GFP_KERNEL);
+                       if (!p->value.text)
+                               goto err_free;
+                       strcpy(p->value.text, property->value.text);
+                       break;
+
+               case TB_PROPERTY_TYPE_VALUE:
+                       p->value.immediate = property->value.immediate;
+                       break;
+
+               default:
+                       break;
+               }
+
+               list_add_tail(&p->list, &d->properties);
+       }
+
+       return d;
+
+err_free:
+       kfree(p);
+       tb_property_free_dir(d);
+
+       return NULL;
+}
+
 /**
  * tb_property_add_immediate() - Add immediate property to directory
  * @parent: Directory to add the property
index 7ec9771..003a9ad 100644 (file)
@@ -146,6 +146,7 @@ struct tb_property_dir *tb_property_parse_dir(const u32 *block,
                                              size_t block_len);
 ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,
                               size_t block_len);
+struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir);
 struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid);
 void tb_property_free_dir(struct tb_property_dir *dir);
 int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,