On Mon, Jan 22, 2024 at 07:07:21PM +0800, Yi Sun wrote: > In some cases, it is necessary to wait for all requests to become complete > status before performing other operations. Otherwise, these requests will never > be processed successfully. > > For example, when the virtio device is in hibernation, the virtqueues > will be deleted. It must be ensured that virtqueue is not in use before being deleted. > Otherwise the requests in the virtqueue will be lost. This function can ensure > that all requests have been taken out of the virtqueues. > > Prepare for fixing this kind of issue by introducing > blk_mq_tagset_wait_request_completed(). Does blk_mq_freeze_queue() not work for your use case? I think that should work unless you have some driver specific requests entered that don't ever get released. > +static bool blk_mq_tagset_count_inflight_rqs(struct request *rq, void *data) > +{ > + unsigned int *count = data; > + > + if (blk_mq_request_started(rq) && !blk_mq_request_completed(rq)) > + (*count)++; > + return true; > +} > + > +/** > + * blk_mq_tagset_wait_request_completed - Wait for all inflight requests > + * to become completed. > + * > + * Note: This function has to be run after all IO queues are shutdown. > + */ > +void blk_mq_tagset_wait_request_completed(struct blk_mq_tag_set *tagset) > +{ > + while (true) { > + unsigned int count = 0; > + > + blk_mq_tagset_busy_iter(tagset, > + blk_mq_tagset_count_inflight_rqs, &count); If the tagset is shared, then one active user can prevent this from ever completing. It sounds like your use case cares about just one specific request_queue, not all of them. > + if (!count) > + break; > + msleep(20); > + } > +} > +EXPORT_SYMBOL(blk_mq_tagset_wait_request_completed);