mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	Fix deadlock in IO pipeline
In vdev_queue_aggregate() the zio_execute() bypass should not be
called under the vdev queue lock.  This can result in a deadlock
as shown in the stack traces below.
Drop the vdev queue lock then walk the parents of the aggregate IO
to determine the list of component IOs to be bypassed.  This can
be done safely without holding the io_lock since the new aggregate
IO has not yet been returned and its parents cannot change.
---  THREAD 1 ---
arc_read()
  zio_nowait()
    zio_vdev_io_start()
      vdev_queue_io() <--- mutex_enter(vq->vq_lock)
        vdev_queue_io_to_issue()
          vdev_queue_aggregate()
            zio_execute()
              zio_vdev_io_assess()
                zio_wait_for_children() <- mutex_enter(zio->io_lock)
--- THREAD 2 --- (inverse order)
arc_read()
  zio_change_priority() <- mutex_enter(zio->zio_lock)
    vdev_queue_change_io_priority() <- mutex_enter(vq->vq_lock)
Reviewed-by: Tom Caputi <tcaputi@datto.com>
Reviewed-by: Don Brady <don.brady@delphix.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #7307
			
			
This commit is contained in:
		
							parent
							
								
									17dd88352e
								
							
						
					
					
						commit
						a76f3d0437
					
				| @ -517,6 +517,7 @@ static zio_t * | |||||||
| vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) | vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) | ||||||
| { | { | ||||||
| 	zio_t *first, *last, *aio, *dio, *mandatory, *nio; | 	zio_t *first, *last, *aio, *dio, *mandatory, *nio; | ||||||
|  | 	zio_link_t *zl = NULL; | ||||||
| 	uint64_t maxgap = 0; | 	uint64_t maxgap = 0; | ||||||
| 	uint64_t size; | 	uint64_t size; | ||||||
| 	uint64_t limit; | 	uint64_t limit; | ||||||
| @ -665,9 +666,18 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) | |||||||
| 
 | 
 | ||||||
| 		zio_add_child(dio, aio); | 		zio_add_child(dio, aio); | ||||||
| 		vdev_queue_io_remove(vq, dio); | 		vdev_queue_io_remove(vq, dio); | ||||||
|  | 	} while (dio != last); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * We need to drop the vdev queue's lock to avoid a deadlock that we | ||||||
|  | 	 * could encounter since this I/O will complete immediately. | ||||||
|  | 	 */ | ||||||
|  | 	mutex_exit(&vq->vq_lock); | ||||||
|  | 	while ((dio = zio_walk_parents(aio, &zl)) != NULL) { | ||||||
| 		zio_vdev_io_bypass(dio); | 		zio_vdev_io_bypass(dio); | ||||||
| 		zio_execute(dio); | 		zio_execute(dio); | ||||||
| 	} while (dio != last); | 	} | ||||||
|  | 	mutex_enter(&vq->vq_lock); | ||||||
| 
 | 
 | ||||||
| 	return (aio); | 	return (aio); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Brian Behlendorf
						Brian Behlendorf