Skip to content

Commit 2c25833

Browse files
committed
Merge tag 'iommu-fixes-v4.13-rc6' of git://git.kernel.org/pub/scm/linux/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
2 parents 80f73b2 + 2926a2a commit 2c25833

File tree

4 files changed

+37
-15
lines changed

4 files changed

+37
-15
lines changed

drivers/iommu/amd_iommu_types.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,9 @@ struct amd_iommu {
574574

575575
static inline struct amd_iommu *dev_to_amd_iommu(struct device *dev)
576576
{
577-
return container_of(dev, struct amd_iommu, iommu.dev);
577+
struct iommu_device *iommu = dev_to_iommu_device(dev);
578+
579+
return container_of(iommu, struct amd_iommu, iommu);
578580
}
579581

580582
#define ACPIHID_UID_LEN 256

drivers/iommu/intel-iommu.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4736,7 +4736,9 @@ static void intel_disable_iommus(void)
47364736

47374737
static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
47384738
{
4739-
return container_of(dev, struct intel_iommu, iommu.dev);
4739+
struct iommu_device *iommu_dev = dev_to_iommu_device(dev);
4740+
4741+
return container_of(iommu_dev, struct intel_iommu, iommu);
47404742
}
47414743

47424744
static ssize_t intel_iommu_show_version(struct device *dev,

drivers/iommu/iommu-sysfs.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,32 +62,40 @@ int iommu_device_sysfs_add(struct iommu_device *iommu,
6262
va_list vargs;
6363
int ret;
6464

65-
device_initialize(&iommu->dev);
65+
iommu->dev = kzalloc(sizeof(*iommu->dev), GFP_KERNEL);
66+
if (!iommu->dev)
67+
return -ENOMEM;
6668

67-
iommu->dev.class = &iommu_class;
68-
iommu->dev.parent = parent;
69-
iommu->dev.groups = groups;
69+
device_initialize(iommu->dev);
70+
71+
iommu->dev->class = &iommu_class;
72+
iommu->dev->parent = parent;
73+
iommu->dev->groups = groups;
7074

7175
va_start(vargs, fmt);
72-
ret = kobject_set_name_vargs(&iommu->dev.kobj, fmt, vargs);
76+
ret = kobject_set_name_vargs(&iommu->dev->kobj, fmt, vargs);
7377
va_end(vargs);
7478
if (ret)
7579
goto error;
7680

77-
ret = device_add(&iommu->dev);
81+
ret = device_add(iommu->dev);
7882
if (ret)
7983
goto error;
8084

85+
dev_set_drvdata(iommu->dev, iommu);
86+
8187
return 0;
8288

8389
error:
84-
put_device(&iommu->dev);
90+
put_device(iommu->dev);
8591
return ret;
8692
}
8793

8894
void iommu_device_sysfs_remove(struct iommu_device *iommu)
8995
{
90-
device_unregister(&iommu->dev);
96+
dev_set_drvdata(iommu->dev, NULL);
97+
device_unregister(iommu->dev);
98+
iommu->dev = NULL;
9199
}
92100
/*
93101
* IOMMU drivers can indicate a device is managed by a given IOMMU using
@@ -102,14 +110,14 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link)
102110
if (!iommu || IS_ERR(iommu))
103111
return -ENODEV;
104112

105-
ret = sysfs_add_link_to_group(&iommu->dev.kobj, "devices",
113+
ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices",
106114
&link->kobj, dev_name(link));
107115
if (ret)
108116
return ret;
109117

110-
ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev.kobj, "iommu");
118+
ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu");
111119
if (ret)
112-
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices",
120+
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices",
113121
dev_name(link));
114122

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

123131
sysfs_remove_link(&link->kobj, "iommu");
124-
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices", dev_name(link));
132+
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link));
125133
}

include/linux/iommu.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ struct iommu_device {
240240
struct list_head list;
241241
const struct iommu_ops *ops;
242242
struct fwnode_handle *fwnode;
243-
struct device dev;
243+
struct device *dev;
244244
};
245245

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

268+
static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
269+
{
270+
return (struct iommu_device *)dev_get_drvdata(dev);
271+
}
272+
268273
#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */
269274
#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */
270275
#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */
@@ -589,6 +594,11 @@ static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
589594
{
590595
}
591596

597+
static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
598+
{
599+
return NULL;
600+
}
601+
592602
static inline void iommu_device_unregister(struct iommu_device *iommu)
593603
{
594604
}

0 commit comments

Comments
 (0)