On Wed, Mar 24, 2021 at 07:07:27AM +0000, Johannes Thumshirn wrote: > >> if (iov_iter_is_bvec(iter)) { > >> - if (WARN_ON_ONCE(bio_op(bio) == REQ_OP_ZONE_APPEND)) > >> - return -EINVAL; > >> + if (bio_op(bio) == REQ_OP_ZONE_APPEND) { > >> + struct request_queue *q = bio->bi_bdev->bd_disk->queue; > >> + unsigned int max_append = > >> + queue_max_zone_append_sectors(q) << 9; > >> + > >> + if (WARN_ON_ONCE(iter->count > max_append)) > >> + return -EINVAL; > >> + } > > > > That is not correct. bio_iov_iter_get_pages just fills the bio as far > > as we can, and then returns 0 for the next call to continue. Basically > > what you want here is a partial version of bio_iov_bvec_set. > > > > Isn't that what I did? The above is checking if we have REQ_OP_ZONE_APPEND and > then returns EINVAL if iter->count is bigger than queue_max_zone_append_sectors(). > If the check doesn't fail, its going to call bio_iov_bvec_set(). And that is the problem. It should not fail, the payload is decoupled from the max_append size. Doing the proper thing is not too hard as described above - make sure the bi_iter points to only the chunk of iter passed in that fits, and only advance the passed in iter by that amount.