IOMMU Fixes for Linux v4.13-rc6
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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJZor4gAAoJECvwRC2XARrj3CUP/3/rhNhHfuvq0C+Nz+ikzZSg xavSSbZztC3SQnr9bgky5TP8Djf9zXzD6DiEGhJoOr98K7R/nvFyaR1NfYnIwHi3 ofngfOcEuuNzInO9L0huHlkqlbUxEwcWTi/QbrFm+W2iL6vOgYejlspFLXAPviDo BlSzJTHzeyXJPZqKDuKB2oO+fVk/xor7KEelsh5fsRrBwFl/JclH5SwIusv4ORfJ sY+02Z8MfLx5+NUvSDj/APoGOlYn0T+XipvduIp2wDtQBmDvN332KWqB1JnAKVdM j27l0BnHABbe5TjQMzj3opAl2v2ZsUqRzolfJdvrh8Gr3gLT1LyMn8A3CRzelBDI jzNsPp9BG2z8enUrppy6yZwv95uxEvNrwrc7jmX46UK12Gf7eBlNGLSe4u+5Ctj5 5e6Eui5y5g/4/DW+BbXt+DjYZHwqJdC1+KAI9XR6sMPRweEmdLhclqgtYhTjGGX9 w2swhpWjcZ7bte8EF/Mlg2Dl6//WTcqFBeyZbHe+HwzWP33EIXpHdfwJCtWpfD/+ lvdDvI2DUrDUiMVcJwnYrWbRuHtdE/fjI0BtmYA01JL0Oe4+kxB3vS4MnlmH8ENc i7KThAEDdyrqeX1DTPmef1YTuhprGAB/pj2GYGe/93QDXMDOPMG3pvYm6Up02MzD a2UNL/JvCEQloABXFyIM =/lXQ -----END PGP SIGNATURE----- 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
This commit is contained in:
Коммит
2c25833c42
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче