iommu: Use C99 flexible array in fwspec
authorRobin Murphy <robin.murphy@arm.com>
Thu, 13 Feb 2020 14:00:21 +0000 (14:00 +0000)
committerJoerg Roedel <jroedel@suse.de>
Fri, 28 Feb 2020 15:20:04 +0000 (16:20 +0100)
Although the 1-element array was a typical pre-C99 way to implement
variable-length structures, and indeed is a fundamental construct in the
APIs of certain other popular platforms, there's no good reason for it
here (and in particular the sizeof() trick is far too "clever" for its
own good). We can just as easily implement iommu_fwspec's preallocation
behaviour using a standard flexible array member, so let's make it look
the way most readers would expect.

Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/iommu.c
include/linux/iommu.h

index 3e3528436e0b220b8714470675bf9b1eefb673bb..660eea8d1d2fb3edc080ccac0a1f05e4005378ff 100644 (file)
@@ -2405,7 +2405,8 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
        if (fwspec)
                return ops == fwspec->ops ? 0 : -EINVAL;
 
-       fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
+       /* Preallocate for the overwhelmingly common case of 1 ID */
+       fwspec = kzalloc(struct_size(fwspec, ids, 1), GFP_KERNEL);
        if (!fwspec)
                return -ENOMEM;
 
@@ -2432,15 +2433,15 @@ EXPORT_SYMBOL_GPL(iommu_fwspec_free);
 int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
 {
        struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-       size_t size;
-       int i;
+       int i, new_num;
 
        if (!fwspec)
                return -EINVAL;
 
-       size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
-       if (size > sizeof(*fwspec)) {
-               fwspec = krealloc(fwspec, size, GFP_KERNEL);
+       new_num = fwspec->num_ids + num_ids;
+       if (new_num > 1) {
+               fwspec = krealloc(fwspec, struct_size(fwspec, ids, new_num),
+                                 GFP_KERNEL);
                if (!fwspec)
                        return -ENOMEM;
 
@@ -2450,7 +2451,7 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
        for (i = 0; i < num_ids; i++)
                fwspec->ids[fwspec->num_ids + i] = ids[i];
 
-       fwspec->num_ids += num_ids;
+       fwspec->num_ids = new_num;
        return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
index d1b5f4d98569de91c6982300cdadc9a92a8f5a4a..4d1ba76c9a642104efb560e69f53c7b7f10d37ba 100644 (file)
@@ -592,7 +592,7 @@ struct iommu_fwspec {
        u32                     flags;
        u32                     num_pasid_bits;
        unsigned int            num_ids;
-       u32                     ids[1];
+       u32                     ids[];
 };
 
 /* ATS is supported */