vhost: fix vhost_vq_access_ok() log check
Subsystems (5)
PATCH 1/1 vhost: fix vhost_vq_access_ok() log check
Commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally:
if (vq->iotlb)
return 1;
return A && B;After the patch the short-circuit logic for A was inverted:
if (A || vq->iotlb)
return A;
return B;The correct logic is:
if (!A || vq->iotlb)
return A;
return B;--- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/vhost/vhost.c +1 -1
@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;return vq_access_ok (vq, vq->num, vq->desc, vq->avail, vq->used);
Signature · 1 line
2.14.3
Quoted 16 lines · Stefan Hajnoczi
Commit
d65026c6c62e7d9616c8ceb5a53b68bcdc050525("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally:if (vq->iotlb) return 1; return A && B;After the patch the short-circuit logic for A was inverted:
if (A || vq->iotlb) return A; return B;The correct logic is:
Quoted 7 lines
if (!A || vq->iotlb) return A; return B;Reported-by [email protected]Cc Jason Wang <[email protected]>Signed-off-by Stefan Hajnoczi <[email protected]>
Quoted 19 lines
--- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)drivers/vhost/vhost.c +1
-1@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;return vq_access_ok (vq, vq->num, vq->desc, vq->avail, vq->used);Signature · 1 line
2.14.3
drivers/vhost/vhost.c int vhost_vq_access_ok(struct vhost_virtqueue *vq) · line 1250
Quoted 7 lines · Stefan Hajnoczi
drivers/vhost/vhost.c +1
-1@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;
That logic is still very non-obvious.
This code already had one bug because of an odd illegible test sequence. Let's not keep the crazy code.
Why not just do the *obvious* thing, and get rid of "ret" entirely, and make the damn thing return a boolean, and then just write it all as
/* Caller should have vq mutex and device mutex */
bool vhost_vq_access_ok(struct vhost_virtqueue *vq)
{
if (!vq_log_access_ok(vq, vq->log_base))
return false;
if (vq->iotlb || vq_access_ok(vq, vq->num, vq->desc,
vq->avail, vq->used);
}which makes the logic obvious: if vq_log_access_ok() fails, then then vhost_vq_access_ok() fails unconditionally.
Otherwise, we need to have an iotlb, or a successful vq_access_ok() check.
Doesn't that all make more sense, and avoid the insane "ret" value use that is really quite subtle?
Linus
Michael S. Tsirkin
maintainerQuoted 31 lines · Linus Torvalds
drivers/vhost/vhost.c int vhost_vq_access_ok(struct vhost_virtqueue *vq) · line 1250
Quoted 7 lines · Stefan Hajnoczi
drivers/vhost/vhost.c +1
-1@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;That logic is still very non-obvious.
This code already had one bug because of an odd illegible test sequence. Let's not keep the crazy code.
Why not just do the *obvious* thing, and get rid of "ret" entirely, and make the damn thing return a boolean, and then just write it all as
/* Caller should have vq mutex and device mutex */ bool vhost_vq_access_ok(struct vhost_virtqueue *vq) { if (!vq_log_access_ok(vq, vq->log_base)) return false; if (vq->iotlb || vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); }which makes the logic obvious: if
vq_log_access_ok()fails, then thenvhost_vq_access_ok()fails unconditionally.
Quoted 6 lines
Otherwise, we need to have an iotlb, or a successful
vq_access_ok()check.Doesn't that all make more sense, and avoid the insane "ret" value use that is really quite subtle?
Linus
I agree it's cleaner.
Stefan, I reposted your patch on netdev (since the breakage got applied there too).
Would you like to self-nak it and post v2? Pls remember to CC netdev.
Signature · 1 line
MST
Michael S. Tsirkin
maintainerQuoted 31 lines · Linus Torvalds
drivers/vhost/vhost.c int vhost_vq_access_ok(struct vhost_virtqueue *vq) · line 1250
Quoted 7 lines · Stefan Hajnoczi
drivers/vhost/vhost.c +1
-1@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;That logic is still very non-obvious.
This code already had one bug because of an odd illegible test sequence. Let's not keep the crazy code.
Why not just do the *obvious* thing, and get rid of "ret" entirely, and make the damn thing return a boolean, and then just write it all as
/* Caller should have vq mutex and device mutex */ bool vhost_vq_access_ok(struct vhost_virtqueue *vq) { if (!vq_log_access_ok(vq, vq->log_base)) return false; if (vq->iotlb || vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); }which makes the logic obvious: if
vq_log_access_ok()fails, then thenvhost_vq_access_ok()fails unconditionally.
Quoted 6 lines
Otherwise, we need to have an iotlb, or a successful
vq_access_ok()check.Doesn't that all make more sense, and avoid the insane "ret" value use that is really quite subtle?
Linus
I agree it's cleaner.
Stefan, I reposted your patch on netdev (since the breakage got applied there too).
Would you like to self-nak it and post v2? Pls remember to CC netdev.
Signature · 1 line
MST
drivers/vhost/vhost.c int vhost_vq_access_ok(struct vhost_virtqueue *vq) · line 1250
Quoted 7 lines · Stefan Hajnoczi
drivers/vhost/vhost.c +1
-1@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;
That logic is still very non-obvious.
This code already had one bug because of an odd illegible test sequence. Let's not keep the crazy code.
Why not just do the *obvious* thing, and get rid of "ret" entirely, and make the damn thing return a boolean, and then just write it all as
/* Caller should have vq mutex and device mutex */
bool vhost_vq_access_ok(struct vhost_virtqueue *vq)
{
if (!vq_log_access_ok(vq, vq->log_base))
return false;
if (vq->iotlb || vq_access_ok(vq, vq->num, vq->desc,
vq->avail, vq->used);
}which makes the logic obvious: if vq_log_access_ok() fails, then then vhost_vq_access_ok() fails unconditionally.
Otherwise, we need to have an iotlb, or a successful vq_access_ok() check.
Doesn't that all make more sense, and avoid the insane "ret" value use that is really quite subtle?
Linus
Michael S. Tsirkin
maintainerPATCH RESEND 1/1 vhost: fix vhost_vq_access_ok() log check
In reply to Stefan HajnocziFrom: Stefan Hajnoczi <[email protected]>
Commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally:
if (vq->iotlb)
return 1;
return A && B;After the patch the short-circuit logic for A was inverted:
if (A || vq->iotlb)
return A;
return B;The correct logic is:
if (!A || vq->iotlb)
return A;
return B;--- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/vhost/vhost.c +1 -1
@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;return vq_access_ok (vq, vq->num, vq->desc, vq->avail, vq->used);
Signature · 1 line
2.14.3
Stefan Hajnoczi
NAKQuoted 22 lines · Michael S. Tsirkin
From: Stefan Hajnoczi <[email protected]>
Commit
d65026c6c62e7d9616c8ceb5a53b68bcdc050525("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally:if (vq->iotlb) return 1; return A && B;After the patch the short-circuit logic for A was inverted:
if (A || vq->iotlb) return A; return B;The correct logic is:
if (!A || vq->iotlb) return A; return B;
Quoted 8 lines
Reported-by [email protected]Cc Jason Wang <[email protected]>Signed-off-by Stefan Hajnoczi <[email protected]>--- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
NACK
I will send a v2 with cleaner logic as suggested by Linus.
Stefan
Stefan Hajnoczi
NAKQuoted 22 lines · Michael S. Tsirkin
From: Stefan Hajnoczi <[email protected]>
Commit
d65026c6c62e7d9616c8ceb5a53b68bcdc050525("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally:if (vq->iotlb) return 1; return A && B;After the patch the short-circuit logic for A was inverted:
if (A || vq->iotlb) return A; return B;The correct logic is:
if (!A || vq->iotlb) return A; return B;
Quoted 8 lines
Reported-by [email protected]Cc Jason Wang <[email protected]>Signed-off-by Stefan Hajnoczi <[email protected]>--- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
NACK
I will send a v2 with cleaner logic as suggested by Linus.
Stefan
Michael S. Tsirkin
maintainerPATCH RESEND 1/1 vhost: fix vhost_vq_access_ok() log check
In reply to Stefan HajnocziFrom: Stefan Hajnoczi <[email protected]>
Commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally:
if (vq->iotlb)
return 1;
return A && B;After the patch the short-circuit logic for A was inverted:
if (A || vq->iotlb)
return A;
return B;The correct logic is:
if (!A || vq->iotlb)
return A;
return B;--- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/vhost/vhost.c +1 -1
@@ -1246,7 +1246,7 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) {int ret =vq_log_access_ok (vq, vq->log_base); -if (ret || vq->iotlb) +if (!ret || vq->iotlb)return ret;return vq_access_ok (vq, vq->num, vq->desc, vq->avail, vq->used);
Signature · 1 line
2.14.3