[PATCH] block: don't embed integrity_kobj into gendisk

From: Thomas Weißschuh
Date: Thu Mar 09 2023 - 15:24:02 EST


A struct kobject is only supposed to be embedded into objects which
lifetime it will manage.
Objects of type struct gendisk however are refcounted by their part0
block_device.
Therefore the integrity_kobj should not be embedded but split into its
own independently managed object.

This will also provide a proper .release function for the ktype which
avoid warnings like the following:
kobject: 'integrity' (000000005198bea8): does not have a release() function, it is broken and must be fixed.

While modifying blk_integrity_del() also drop the explicit call to
kobject_uevent(KOBJ_REMOVE) as the driver care will do this
automatically.

Reported-by: Mirsad Todorovac <mirsad.todorovac@xxxxxxxxxxxx>
Link: https://lore.kernel.org/lkml/60b2b66c-22c9-1d38-ed1c-7b7d95e32720@xxxxxxxxxxxx/
Signed-off-by: Thomas Weißschuh <linux@xxxxxxxxxxxxxx>
---
block/blk-integrity.c | 32 ++++++++++++++++++++++++--------
include/linux/blkdev.h | 2 +-
2 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 8f01d786f5cb..40adf33f5535 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -218,10 +218,15 @@ struct integrity_sysfs_entry {
ssize_t (*store)(struct blk_integrity *, const char *, size_t);
};

+static inline struct gendisk *integrity_kobj_to_disk(struct kobject *kobj)
+{
+ return dev_to_disk(kobj_to_dev(kobj->parent));
+}
+
static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr,
char *page)
{
- struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj);
+ struct gendisk *disk = integrity_kobj_to_disk(kobj);
struct blk_integrity *bi = &disk->queue->integrity;
struct integrity_sysfs_entry *entry =
container_of(attr, struct integrity_sysfs_entry, attr);
@@ -233,7 +238,7 @@ static ssize_t integrity_attr_store(struct kobject *kobj,
struct attribute *attr, const char *page,
size_t count)
{
- struct gendisk *disk = container_of(kobj, struct gendisk, integrity_kobj);
+ struct gendisk *disk = integrity_kobj_to_disk(kobj);
struct blk_integrity *bi = &disk->queue->integrity;
struct integrity_sysfs_entry *entry =
container_of(attr, struct integrity_sysfs_entry, attr);
@@ -356,9 +361,15 @@ static const struct sysfs_ops integrity_ops = {
.store = &integrity_attr_store,
};

+static void integrity_release(struct kobject *kobj)
+{
+ kfree(kobj);
+}
+
static const struct kobj_type integrity_ktype = {
.default_groups = integrity_groups,
.sysfs_ops = &integrity_ops,
+ .release = integrity_release,
};

static blk_status_t blk_integrity_nop_fn(struct blk_integrity_iter *iter)
@@ -442,16 +453,21 @@ int blk_integrity_add(struct gendisk *disk)
{
int ret;

- ret = kobject_init_and_add(&disk->integrity_kobj, &integrity_ktype,
+ disk->integrity_kobj = kmalloc(sizeof(*disk->integrity_kobj), GFP_KERNEL);
+ if (!disk->integrity_kobj)
+ return -ENOMEM;
+
+ ret = kobject_init_and_add(disk->integrity_kobj, &integrity_ktype,
&disk_to_dev(disk)->kobj, "%s", "integrity");
- if (!ret)
- kobject_uevent(&disk->integrity_kobj, KOBJ_ADD);
+ if (ret)
+ kobject_put(disk->integrity_kobj);
+ else
+ kobject_uevent(disk->integrity_kobj, KOBJ_ADD);
+
return ret;
}

void blk_integrity_del(struct gendisk *disk)
{
- kobject_uevent(&disk->integrity_kobj, KOBJ_REMOVE);
- kobject_del(&disk->integrity_kobj);
- kobject_put(&disk->integrity_kobj);
+ kobject_put(disk->integrity_kobj);
}
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index d1aee08f8c18..2fbfb3277a2b 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -164,7 +164,7 @@ struct gendisk {
atomic_t sync_io; /* RAID */
struct disk_events *ev;
#ifdef CONFIG_BLK_DEV_INTEGRITY
- struct kobject integrity_kobj;
+ struct kobject *integrity_kobj;
#endif /* CONFIG_BLK_DEV_INTEGRITY */

#ifdef CONFIG_BLK_DEV_ZONED

---
base-commit: 44889ba56cbb3d51154660ccd15818bc77276696
change-id: 20230309-kobj_release-gendisk_integrity-e26c0bc126aa

Best regards,
--
Thomas Weißschuh <linux@xxxxxxxxxxxxxx>