mirror of
https://github.com/qemu/qemu.git
synced 2024-11-30 23:33:51 +08:00
nbd/server: Honor FUA request on NBD_CMD_TRIM
The NBD spec states that since trim requests can affect disk contents, then they should allow for FUA semantics just like writes for ensuring the disk has settled before returning. As bdrv_[co_]pdiscard() does not support a flags argument, we can't pass FUA down the block layer stack, and must therefore emulate it with a flush at the NBD layer. Note that in all reality, generic well-behaved clients will never send TRIM+FUA (in fact, qemu as a client never does, and we have no intention to plumb flags into bdrv_pdiscard). This is because the NBD protocol states that it is unspecified to READ a trimmed area (you might read stale data, all zeroes, or even random unrelated data) without first rewriting it, and even the experimental BLOCK_STATUS extension states that TRIM need not affect reported status. Thus, in the general case, a client cannot tell the difference between an arbitrary server that ignores TRIM, a server that had a power outage without flushing to disk, and a server that actually affected the disk before returning; so waiting for the trim actions to flush to disk makes little sense. However, for a specific client and server pair, where the client knows the server treats TRIM'd areas as guaranteed reads-zero, waiting for a flush makes sense, hence why the protocol documents that FUA is valid on trim. So, even though the NBD protocol doesn't have a way for the server to advertise what effects (if any) TRIM will actually have, and thus any client that relies on specific effects is probably in error, we can at least support a client that requests TRIM+FUA. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <20180307225732.155835-1-eblake@redhat.com>
This commit is contained in:
parent
6f302e6093
commit
65529782f8
@ -1638,6 +1638,9 @@ static coroutine_fn int nbd_handle_request(NBDClient *client,
|
||||
case NBD_CMD_TRIM:
|
||||
ret = blk_co_pdiscard(exp->blk, request->from + exp->dev_offset,
|
||||
request->len);
|
||||
if (ret == 0 && request->flags & NBD_CMD_FLAG_FUA) {
|
||||
ret = blk_co_flush(exp->blk);
|
||||
}
|
||||
return nbd_send_generic_reply(client, request->handle, ret,
|
||||
"discard failed", errp);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user