Re: [PATCH 12/15] block: switch polling to be bio based

Ming Lei
2021-05-13T01:24:34Z

On Wed, May 12, 2021 at 03:15:42PM +0200, Christoph Hellwig wrote:
> Replace the blk_poll interface that requires the caller to keep a queue
> and cookie from the submissions with polling based on the bio.
>
> Polling for the bio itself leads to a few advantages:
>
> - the cookie construction can made entirely private in blk-mq.c
> - the caller does not need to remember the request_queue and cookie
> separately and thus sidesteps their lifetime issues
> - keeping the device and the cookie inside the bio allows to trivially
> support polling BIOs remapping by stacking drivers
> - a lot of code to propagate the cookie back up the submission path can
> be removed entirely.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>

...

> +
> +/*
> + * Helper to implement file_operations.iopoll. Requires the bio to be stored
> + * in iocb->private, and cleared before freeing the bio.
> + */
> +int iocb_bio_iopoll(struct kiocb *kiocb, unsigned int flags)
> +{
> + struct bio *bio;
> + int ret = 0;
> +
> + /*
> + * Note: the bio cache only uses SLAB_TYPESAFE_BY_RCU, so bio can
> + * point to a freshly allocated bio at this point. If that happens
> + * we have a few cases to consider:
> + *
> + * 1) the bio is beeing initialized and bi_bdev is NULL. We can just
> + * simply nothing in this case
> + * 2) the bio points to a not poll enabled device. bio_poll will catch
> + * this and return 0
> + * 3) the bio points to a poll capable device, including but not
> + * limited to the one that the original bio pointed to. In this
> + * case we will call into the actual poll method and poll for I/O,
> + * even if we don't need to, but it won't cause harm either.
> + *
> + * For cases 2) and 3) above the RCU grace period ensures that the
> + * bi_bdev is still allocated, and because partitions hold a reference
> + * to the whole device bdev and thus disk it is still valid.
> + */
> + rcu_read_lock();
> + bio = READ_ONCE(kiocb->private);
> + if (bio && bio->bi_bdev)
> + ret = bio_poll(bio, flags);

The bio can be re-allocated from another IO path & bdev after checking on
bio->bi_bdev in the above code, then this bio is freed, its ->bi_bdev is freed,
same with its associated disk/hw queues/request queue.

Both bdev and request queue are freed via rcu, but disk/hw queues are freed
immediately, so there is still UAF risk in bio_poll().

Thanks,
Ming