A group here at IBM has been testing DM multipath and noticed a problem with the DEVICE_WAIT command. In their tests, while performing a DEVICE_WAIT on a multipath device, the command sometimes returns immediately, even though the event-number is correct and no path-failure has occurred to trigger an event. They tracked it down to the "waiting" method, and sent me this patch. I remember some patches in -udm during the 2.6.4/2.6.5 time-frame that switched some wake_up_interruptible()'s to wake_up()'s. I'm not sure if those caused this problem, or if this is unrelated. I'm also not certain if the change to mapped_device->event_nr and the associated locking changes are the right way to go. We can discuss it and see if this works, or if there is a better solution. -Kevin --- a/drivers/md/dm-ioctl.c 10 May 2004 09:20:57 -0000 +++ b/drivers/md/dm-ioctl.c 10 May 2004 17:37:45 -0000 @@ -850,7 +850,6 @@ int r; struct mapped_device *md; struct dm_table *table; - DECLARE_WAITQUEUE(wq, current); md = find_device(param); if (!md) @@ -859,12 +858,10 @@ /* * Wait for a notification event */ - set_current_state(TASK_INTERRUPTIBLE); - if (!dm_add_wait_queue(md, &wq, param->event_nr)) { - schedule(); - dm_remove_wait_queue(md, &wq); + if (dm_wait_event(md, param->event_nr)) { + r = -ERESTARTSYS; + goto out; } - set_current_state(TASK_RUNNING); /* * The userland program is going to want to know what --- a/drivers/md/dm.c 10 May 2004 09:20:57 -0000 +++ b/drivers/md/dm.c 10 May 2004 17:37:45 -0000 @@ -80,7 +80,7 @@ /* * Event handling. */ - uint32_t event_nr; + atomic_t event_nr; wait_queue_head_t eventq; /* @@ -684,6 +684,7 @@ init_rwsem(&md->lock); rwlock_init(&md->map_lock); atomic_set(&md->holders, 1); + atomic_set(&md->event_nr, 0); md->queue = blk_alloc_queue(GFP_KERNEL); if (!md->queue) @@ -753,10 +754,8 @@ { struct mapped_device *md = (struct mapped_device *) context; - down_write(&md->lock); - md->event_nr++; + atomic_inc(&md->event_nr);; wake_up(&md->eventq); - up_write(&md->lock); } static void __set_size(struct gendisk *disk, sector_t size) @@ -1054,35 +1053,13 @@ *---------------------------------------------------------------*/ uint32_t dm_get_event_nr(struct mapped_device *md) { - uint32_t r; - - down_read(&md->lock); - r = md->event_nr; - up_read(&md->lock); - - return r; -} - -int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq, - uint32_t event_nr) -{ - down_write(&md->lock); - if (event_nr != md->event_nr) { - up_write(&md->lock); - return 1; - } - - add_wait_queue(&md->eventq, wq); - up_write(&md->lock); - - return 0; + return atomic_read(&md->event_nr); } -void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq) +int dm_wait_event(struct mapped_device *md, int event_nr) { - down_write(&md->lock); - remove_wait_queue(&md->eventq, wq); - up_write(&md->lock); + return wait_event_interruptible(md->eventq, + (event_nr != atomic_read(&md->event_nr))); } /* --- a/drivers/md/dm.h 10 May 2004 09:20:57 -0000 +++ b/drivers/md/dm.h 10 May 2004 17:37:45 -0000 @@ -81,9 +81,7 @@ * Event functions. */ uint32_t dm_get_event_nr(struct mapped_device *md); -int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq, - uint32_t event_nr); -void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq); +int dm_wait_event(struct mapped_device *md, int event_nr); /* * Info functions.