Skip to contentSkip to conversation

Reduce number of KOBJ_REMOVE events

PATCH In review Zdenek Kabelac 2 participants 7 messages Jul 22, 2011 – Jul 26, 2011

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Reduce number of KOBJ_REMOVE events

Author: Zdenek Kabelac <[email protected]>
Date:   Fri Jul 22 15:02:17 2011 +0200

Reduce number of KOBJ_REMOVE events

For now udev recieves 3 event for removal of DM logical volumes. (1 for bdi and 2 for same block kobject). Reason is dm device generates its own kobject event with approriate env parameter and block layer sends another KOBJ_REMOVE event on its own unconditionaly for the same kobject. As for now only the kobject cleanup checks that the REMOVE event has been already sent and avoids duplicate REMOVE event.

The patch for kobject_uevent_env() which has been testing for duplicate REMOVE event did not passed into the mainline (yet?):

https://www.redhat.com/archives/dm-devel/2010-March/msg00107.html

I'm proposing alternative way around to always use kobject cleanup routine for sending REMOVE event if it was not send by the module - so it makes the code few lines shorter.

This patch removes single appearencies of kobject_uevent() prior kobject removal.

block/blk-integrity.c +0 -1
index 129b9e2..431f401 100644
@@ -439,7 +439,6 @@ void blk_integrity_unregister(struct gendisk *disk)
 
 	bi = disk->integrity;
 
-	kobject_uevent(&bi->kobj, KOBJ_REMOVE);
 	kobject_del(&bi->kobj);
 	kobject_put(&bi->kobj);
 	disk->integrity = NULL;
block/blk-sysfs.c +0 -2
index d935bd8..a50472d 100644
@@ -521,7 +521,6 @@ int blk_register_queue(struct gendisk *disk)
 
 	ret = elv_register_queue(q);
 	if (ret) {
-		kobject_uevent(&q->kobj, KOBJ_REMOVE);
 		kobject_del(&q->kobj);
 		blk_trace_remove_sysfs(dev);
 		kobject_put(&dev->kobj);
@@ -541,7 +540,6 @@ void blk_unregister_queue(struct gendisk *disk)
 	if (q->request_fn)
 		elv_unregister_queue(q);
 
-	kobject_uevent(&q->kobj, KOBJ_REMOVE);
 	kobject_del(&q->kobj);
 	blk_trace_remove_sysfs(disk_to_dev(disk));
 	kobject_put(&disk_to_dev(disk)->kobj);
block/elevator.c +0 -1
index b0b38ce..a8d912b 100644
@@ -892,7 +892,6 @@ EXPORT_SYMBOL(elv_register_queue);
 
 static void __elv_unregister_queue(struct elevator_queue *e)
 {
-	kobject_uevent(&e->kobj, KOBJ_REMOVE);
 	kobject_del(&e->kobj);
 	e->registered = 0;
 }
drivers/base/core.c +0 -2
index bc8729d..8c9af0d 100644
@@ -1013,7 +1013,6 @@ done:
  ueventattrError:
 	device_remove_file(dev, &uevent_attr);
  attrError:
-	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
  Error:
 	cleanup_device_parent(dev);
@@ -1132,7 +1131,6 @@ void device_del(struct device *dev)
 	 */
 	if (platform_notify_remove)
 		platform_notify_remove(dev);
-	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 	cleanup_device_parent(dev);
 	kobject_del(&dev->kobj);
 	put_device(parent);
mm/slub.c +0 -1
index 35f351f..3c77956 100644
@@ -4720,7 +4720,6 @@ static void sysfs_slab_remove(struct kmem_cache *s)
 		 */
 		return;
 
-	kobject_uevent(&s->kobj, KOBJ_REMOVE);
 	kobject_del(&s->kobj);
 	kobject_put(&s->kobj);
 }
net/bridge/br_if.c +0 -1
index 1bacca4..f20a945 100644
@@ -153,7 +153,6 @@ static void del_nbp(struct net_bridge_port *p)
 
 	br_multicast_del_port(p);
 
-	kobject_uevent(&p->kobj, KOBJ_REMOVE);
 	kobject_del(&p->kobj);
 
 	br_netpoll_disable(p);
#1 lore raw
Quoted 9 lines · Zdenek Kabelac

For now udev recieves 3 event for removal of DM logical volumes. (1 for bdi and 2 for same block kobject). Reason is dm device generates its own kobject event with approriate env parameter and block layer sends another KOBJ_REMOVE event on its own unconditionaly for the same kobject. As for now only the kobject cleanup checks that the REMOVE event has been already sent and avoids duplicate REMOVE event.

The patch for kobject_uevent_env() which has been testing for duplicate REMOVE event did not passed into the mainline (yet?):

No, it's wasn't merged. Subsystems should really not send their own 'add' or 'remove' events. These are properties of the driver core.

Quoted 3 lines

I'm proposing alternative way around to always use kobject cleanup routine for sending REMOVE event if it was not send by the module - so it makes the code few lines shorter.

The events the core creates are only sent out at release() not at del(), so we would delay 'remove' events when we keep the device pinned but it's not valid anymore. We can not do that today, we would need to move the core-created 'remove' events to del().

For device-mapper, I would prefer to add a '.dev_uevent' callback to the 'block' class let this callback check 'struct block_device_operations' for a possibly specified '.uevent' callback and call it.

Then have 'dm_blk_dops' add '.uevent' and let the core call into the dm code to the needed properties to the 'remove' event, instead of sending its own, and see the duplication.

Let me know if you need more details.

Thanks,
Kay

#2 lore raw

Dne 25.7.2011 02:18, Kay Sievers napsal(a):

Quoted 25 lines · Zdenek Kabelac
Quoted 10 lines

For now udev recieves 3 event for removal of DM logical volumes. (1 for bdi and 2 for same block kobject). Reason is dm device generates its own kobject event with approriate env parameter and block layer sends another KOBJ_REMOVE event on its own unconditionaly for the same kobject. As for now only the kobject cleanup checks that the REMOVE event has been already sent and avoids duplicate REMOVE event.

The patch for kobject_uevent_env() which has been testing for duplicate REMOVE event did not passed into the mainline (yet?):

No, it's wasn't merged. Subsystems should really not send their own 'add' or 'remove' events. These are properties of the driver core.

Quoted 3 lines

I'm proposing alternative way around to always use kobject cleanup routine for sending REMOVE event if it was not send by the module - so it makes the code few lines shorter.

The events the core creates are only sent out at release() not at del(), so we would delay 'remove' events when we keep the device pinned but it's not valid anymore. We can not do that today, we would need to move the core-created 'remove' events to del().

Quoted 7 lines

For device-mapper, I would prefer to add a '.dev_uevent' callback to the 'block' class let this callback check 'struct block_device_operations' for a possibly specified '.uevent' callback and call it.

Then have 'dm_blk_dops' add '.uevent' and let the core call into the dm code to the needed properties to the 'remove' event, instead of sending its own, and see the duplication.

Sounds like complex solution - maybe it would be easier to just register some environment variable on dm code side - like kobject_add_env() - so it would take envs from this internal kobject list and after sending uevent it would implicitly clear this list.

So in dm case dm-uevent would just register env(cookie) for KOBJ_REMOVE and would left kobject_uevent() on block layer ?

Also I'm aware that remove event would be delayed by leaving it on kobject_cleanup(), but since you mentioned 'del()' as a better place - why not move this implicit uvent call there - since most kernel driver writers probably do not want to be bothered with uvents?

Zdenek

#3 lore raw
Quoted 29 lines · Zdenek Kabelac

Dne 25.7.2011 02:18, Kay Sievers napsal(a):

Quoted 28 lines · Zdenek Kabelac
Quoted 10 lines

For now udev recieves 3 event for removal of DM logical volumes. (1 for bdi and 2 for same block kobject). Reason is dm device generates its own kobject event with approriate env parameter and block layer sends another KOBJ_REMOVE event on its own unconditionaly for the same kobject. As for now only the kobject cleanup checks that the REMOVE event has been already sent and avoids duplicate REMOVE event.

The patch for kobject_uevent_env() which has been testing for duplicate REMOVE event did not passed into the mainline (yet?):

No, it's wasn't merged. Subsystems should really not send their own 'add' or 'remove' events. These are properties of the driver core.

Quoted 3 lines

I'm proposing alternative way around to always use kobject cleanup routine for sending REMOVE event if it was not send by the module - so it makes the code few lines shorter.

The events the core creates are only sent out at release() not at del(), so we would delay 'remove' events when we keep the device pinned but it's not valid anymore. We can not do that today, we would need to move the core-created 'remove' events to del().

For device-mapper, I would prefer to add a '.dev_uevent' callback to the 'block' class let this callback check 'struct block_device_operations' for a possibly specified '.uevent' callback and call it.

Quoted 5 lines
Quoted 3 lines

Then have 'dm_blk_dops' add '.uevent' and let the core call into the dm code to the needed properties to the 'remove' event, instead of sending its own, and see the duplication.

Sounds like complex solution

I don't think so, It's clean, ~30 lines long, and technically correct, I expect.

Quoted 4 lines

maybe it would be easier to just register some
environment variable on dm code side - like kobject_add_env() - so it would take envs from this internal kobject list and after sending uevent it would implicitly clear this list.

So we would keep allocated per-event-type variables in the kobject, to send when 'remove' is finally called? The callbacks are just much simpler , I guess.

Quoted 6 lines

So in dm case  dm-uevent would just register  env(cookie) for KOBJ_REMOVE and would left kobject_uevent() on block layer ?

Also I'm aware that remove event would be delayed by leaving it on kobject_cleanup(), but since you mentioned 'del()' as a better place - why not move this implicit uvent call there.

It's probably not wrong to do that, but I don't remember now why we added it to release() that time.

Quoted 2 lines

since most kernel driver writers
probably do not want to be bothered with uvents?

I guess, most drivers use devices not raw kobjects, which send events on their own, and don't need anything here.

Kay

#4 lore raw

Dne 25.7.2011 14:17, Kay Sievers napsal(a):

Quoted 30 lines · Zdenek Kabelac
Quoted 29 lines

Dne 25.7.2011 02:18, Kay Sievers napsal(a):

Quoted 28 lines · Zdenek Kabelac
Quoted 10 lines

For now udev recieves 3 event for removal of DM logical volumes. (1 for bdi and 2 for same block kobject). Reason is dm device generates its own kobject event with approriate env parameter and block layer sends another KOBJ_REMOVE event on its own unconditionaly for the same kobject. As for now only the kobject cleanup checks that the REMOVE event has been already sent and avoids duplicate REMOVE event.

The patch for kobject_uevent_env() which has been testing for duplicate REMOVE event did not passed into the mainline (yet?):

No, it's wasn't merged. Subsystems should really not send their own 'add' or 'remove' events. These are properties of the driver core.

Quoted 3 lines

I'm proposing alternative way around to always use kobject cleanup routine for sending REMOVE event if it was not send by the module - so it makes the code few lines shorter.

The events the core creates are only sent out at release() not at del(), so we would delay 'remove' events when we keep the device pinned but it's not valid anymore. We can not do that today, we would need to move the core-created 'remove' events to del().

For device-mapper, I would prefer to add a '.dev_uevent' callback to the 'block' class let this callback check 'struct block_device_operations' for a possibly specified '.uevent' callback and call it.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Then have 'dm_blk_dops' add '.uevent' and let the core call into the dm code to the needed properties to the 'remove' event, instead of sending its own, and see the duplication.

Sounds like complex solution

I don't think so, It's clean, ~30 lines long, and technically correct, I expect.

Well then I've probably not fully understand your idea here - I guess it would then simpler written by you?

Quoted 8 lines
Quoted 4 lines

maybe it would be easier to just register some
environment variable on dm code side - like kobject_add_env() - so it would take envs from this internal kobject list and after sending uevent it would implicitly clear this list.

So we would keep allocated per-event-type variables in the kobject, to send when 'remove' is finally called? The callbacks are just much simpler , I guess.

No - nothing so complex - kobject would have the list - and you would be able to add some env param to this list - the nearest kobject_uevent() would just splice those parameters to the env list it wants to send (something like 10 lines of code). The only user would be probably dm so far - and it would check it wants to send REMOVE - and in this case it would add env to kobject and would skip kobject_uvent.

On the other hand, it would probably extended kobject struct size without big use case - so Milan's solution that checks whether REMOVE has been already sent and skip all future REMOVE events seems by far the simplest here.

I think your proposal also requires struct extension to store callback somewhere ?

Quoted 9 lines
Quoted 6 lines

So in dm case dm-uevent would just register env(cookie) for KOBJ_REMOVE and would left kobject_uevent() on block layer ?

Also I'm aware that remove event would be delayed by leaving it on kobject_cleanup(), but since you mentioned 'del()' as a better place - why not move this implicit uvent call there.

It's probably not wrong to do that, but I don't remember now why we added it to release() that time.

del() looks like the best natural place here - and safe few lines of code ;)

Zdenek

#5 lore raw
Quoted 9 lines · Zdenek Kabelac

Dne 25.7.2011 14:17, Kay Sievers napsal(a):

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Then have 'dm_blk_dops' add '.uevent' and let the core call into the dm code to the needed properties to the 'remove' event, instead of sending its own, and see the duplication.

Sounds like complex solution

I don't think so, It's clean, ~30 lines long, and technically correct, I expect.

In include/linux/blkdev.h add:
int (*uevent) (struct gendisk *, struct kobj_uevent_env *env);
to
struct block_device_operations

In block/genhd.c add:
.uevent = block_uevent;
to
struct class block_class
and have the block_uevent() callback check for an existing uevent() in the block_device_operations, call it when it's specified.

In drivers/md/dm.c add:
.dm_uevent;
to
struct block_device_operations dm_blk_dops
and add all the needed variables there, instead of sending out a faked device 'remove' event.

Quoted 9 lines
Quoted 8 lines
Quoted 4 lines

maybe it would be easier to just register some
environment variable on dm code side - like kobject_add_env() - so it would take envs from this internal kobject list and after sending uevent it would implicitly clear this list.

So we would keep allocated per-event-type variables in the kobject, to send when 'remove' is finally called? The callbacks are just much simpler , I guess.

Quoted 6 lines

No - nothing so complex - kobject would have the list - and you would be able to add some env param to this list - the nearest  kobject_uevent() would just splice those parameters to the env list it wants to send (something like 10 lines of code). The only user would be probably dm so far - and it would check it wants to send REMOVE - and in this case it would add env to kobject and would skip kobject_uvent.

We don't want to encourage anybody to mess around with events that way. We also don't want to keep track of subsystem specific event properties in the core kobject. It's just wrong to send 'remove' from a driver that uses 'struct device'. It should be changed in dm, not worked-around in the core.

Quoted 3 lines

On the other hand, it would probably extended kobject struct size without big use case - so Milan's solution that checks whether REMOVE has been already sent and skip all future REMOVE events seems by far the simplest here.

Yeah, I see the logic, but it doesn't make sending additional 'remove' events any more correct. We don't want to encourage anybody with code in the core to do this. 'Add' and 'remove' is nothing struct device user should send on their own.

Quoted 1 line

I think your proposal also requires struct extension to store callback somewhere ?

Yeah, it's a block subsys callback, a pointer per block driver, not per device, nothing that really matters, and it's looks generally useful.

Quoted 11 lines
Quoted 9 lines
Quoted 6 lines

So in dm case  dm-uevent would just register  env(cookie) for KOBJ_REMOVE and would left kobject_uevent() on block layer ?

Also I'm aware that remove event would be delayed by leaving it on kobject_cleanup(), but since you mentioned 'del()' as a better place - why not move this implicit uvent call there.

It's probably not wrong to do that, but I don't remember now why we added it to release() that time.

del() looks like the best natural place here - and safe few lines of code ;)

Yeah, but again, raw kobjects never send any event, not even 'add'. It's up the caller to take care of that, if these events are needed. Many things rightfully never send any event.

The code in the core exists only for the un-common use case that the caller does send 'add' but does not clean-up the objects properly, and would introduce an asymmetry with that. We don't want to encourage anything like that.

The code isn't there to allow additional 'remove' events or to leave the cleanup to the core in general.

Thanks,
Kay

#6 lore raw
Quoted 23 lines · Kay Sievers
Quoted 9 lines · Zdenek Kabelac

Dne 25.7.2011 14:17, Kay Sievers napsal(a):

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

Then have 'dm_blk_dops' add '.uevent' and let the core call into the dm code to the needed properties to the 'remove' event, instead of sending its own, and see the duplication.

Sounds like complex solution

I don't think so, It's clean, ~30 lines long, and technically correct, I expect.

In include/linux/blkdev.h add:
int (*uevent) (struct gendisk *, struct kobj_uevent_env *env);
to
struct block_device_operations

In block/genhd.c add:
.uevent = block_uevent;
to
struct class block_class
and have the block_uevent() callback check for an existing uevent() in the block_device_operations, call it when it's specified.

Quoted 6 lines

In drivers/md/dm.c add:
.dm_uevent;
to
struct block_device_operations dm_blk_dops
and add all the needed variables there, instead of sending out a faked device 'remove' event.

Here is the code to illustrate, and fix the issue of needing to send any 'remove' for a device from a driver.

Thanks,
Kay

block/genhd.c +13 -0
index 6024b82..c2e9714 100644
@@ -1097,8 +1097,21 @@ static void disk_release(struct device *dev)
 	free_part_info(&disk->part0);
 	kfree(disk);
 }
+
+static int block_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+
+	if (!disk->fops)
+		return 0;
+	if (disk->fops->uevent)
+		return disk->fops->uevent(disk, env);
+	return 0;
+}
+
 struct class block_class = {
 	.name		= "block",
+	.dev_uevent	= block_uevent,
 };
 
 static char *block_devnode(struct device *dev, mode_t *mode)
drivers/md/dm.c +6 -0
index 0cf68b4..22e486e 100644
@@ -2682,11 +2682,17 @@ void dm_free_md_mempools(struct dm_md_mempools *pools)
 	kfree(pools);
 }
 
+static int dm_uevent(struct gendisk *disk, struct kobj_uevent_env *env)
+{
+	return add_uevent_var(env, "COOKIE_MONSTER=1");
+}
+
 static const struct block_device_operations dm_blk_dops = {
 	.open = dm_blk_open,
 	.release = dm_blk_close,
 	.ioctl = dm_blk_ioctl,
 	.getgeo = dm_blk_getgeo,
+	.uevent = dm_uevent,
 	.owner = THIS_MODULE
 };
 
include/linux/blkdev.h +1 -0
index 1a23722..6dbd69e 100644
@@ -1300,6 +1300,7 @@ struct block_device_operations {
 						void **, unsigned long *);
 	unsigned int (*check_events) (struct gendisk *disk,
 				      unsigned int clearing);
+	int (*uevent) (struct gendisk *, struct kobj_uevent_env *env);
 	/* ->media_changed() is DEPRECATED, use ->check_events() instead */
 	int (*media_changed) (struct gendisk *);
 	void (*unlock_native_capacity) (struct gendisk *);