Skip to content

Commit

Permalink
Merge tag 'iommu-fixes-v4.13-rc6' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/joro/iommu

Pull IOMMU fix from Joerg Roedel:
 "Another fix, this time in common IOMMU sysfs code.

  In the conversion from the old iommu sysfs-code to the
  iommu_device_register interface, I missed to update the release path
  for the struct device associated with an IOMMU. It freed the 'struct
  device', which was a pointer before, but is now embedded in another
  struct.

  Freeing from the middle of allocated memory had all kinds of nasty
  side effects when an IOMMU was unplugged. Unfortunatly nobody
  unplugged and IOMMU until now, so this was not discovered earlier. The
  fix is to make the 'struct device' a pointer again"

* tag 'iommu-fixes-v4.13-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu: Fix wrong freeing of iommu_device->dev
  • Loading branch information
Linus Torvalds committed Aug 28, 2017
2 parents 80f73b2 + 2926a2a commit 2c25833
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 15 deletions.
4 changes: 3 additions & 1 deletion drivers/iommu/amd_iommu_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,9 @@ struct amd_iommu {

static inline struct amd_iommu *dev_to_amd_iommu(struct device *dev)
{
return container_of(dev, struct amd_iommu, iommu.dev);
struct iommu_device *iommu = dev_to_iommu_device(dev);

return container_of(iommu, struct amd_iommu, iommu);
}

#define ACPIHID_UID_LEN 256
Expand Down
4 changes: 3 additions & 1 deletion drivers/iommu/intel-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4736,7 +4736,9 @@ static void intel_disable_iommus(void)

static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
{
return container_of(dev, struct intel_iommu, iommu.dev);
struct iommu_device *iommu_dev = dev_to_iommu_device(dev);

return container_of(iommu_dev, struct intel_iommu, iommu);
}

static ssize_t intel_iommu_show_version(struct device *dev,
Expand Down
32 changes: 20 additions & 12 deletions drivers/iommu/iommu-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,32 +62,40 @@ int iommu_device_sysfs_add(struct iommu_device *iommu,
va_list vargs;
int ret;

device_initialize(&iommu->dev);
iommu->dev = kzalloc(sizeof(*iommu->dev), GFP_KERNEL);
if (!iommu->dev)
return -ENOMEM;

iommu->dev.class = &iommu_class;
iommu->dev.parent = parent;
iommu->dev.groups = groups;
device_initialize(iommu->dev);

iommu->dev->class = &iommu_class;
iommu->dev->parent = parent;
iommu->dev->groups = groups;

va_start(vargs, fmt);
ret = kobject_set_name_vargs(&iommu->dev.kobj, fmt, vargs);
ret = kobject_set_name_vargs(&iommu->dev->kobj, fmt, vargs);
va_end(vargs);
if (ret)
goto error;

ret = device_add(&iommu->dev);
ret = device_add(iommu->dev);
if (ret)
goto error;

dev_set_drvdata(iommu->dev, iommu);

return 0;

error:
put_device(&iommu->dev);
put_device(iommu->dev);
return ret;
}

void iommu_device_sysfs_remove(struct iommu_device *iommu)
{
device_unregister(&iommu->dev);
dev_set_drvdata(iommu->dev, NULL);
device_unregister(iommu->dev);
iommu->dev = NULL;
}
/*
* IOMMU drivers can indicate a device is managed by a given IOMMU using
Expand All @@ -102,14 +110,14 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link)
if (!iommu || IS_ERR(iommu))
return -ENODEV;

ret = sysfs_add_link_to_group(&iommu->dev.kobj, "devices",
ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices",
&link->kobj, dev_name(link));
if (ret)
return ret;

ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev.kobj, "iommu");
ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu");
if (ret)
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices",
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices",
dev_name(link));

return ret;
Expand All @@ -121,5 +129,5 @@ void iommu_device_unlink(struct iommu_device *iommu, struct device *link)
return;

sysfs_remove_link(&link->kobj, "iommu");
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices", dev_name(link));
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link));
}
12 changes: 11 additions & 1 deletion include/linux/iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ struct iommu_device {
struct list_head list;
const struct iommu_ops *ops;
struct fwnode_handle *fwnode;
struct device dev;
struct device *dev;
};

int iommu_device_register(struct iommu_device *iommu);
Expand All @@ -265,6 +265,11 @@ static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
iommu->fwnode = fwnode;
}

static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
{
return (struct iommu_device *)dev_get_drvdata(dev);
}

#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */
#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */
#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */
Expand Down Expand Up @@ -589,6 +594,11 @@ static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
{
}

static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
{
return NULL;
}

static inline void iommu_device_unregister(struct iommu_device *iommu)
{
}
Expand Down

0 comments on commit 2c25833

Please sign in to comment.