* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Jerome Glisse @ 2019-03-07 19:17 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: aarcange, kvm, netdev, linux-kernel, virtualization, linux-mm
In-Reply-To: <20190307124700-mutt-send-email-mst@kernel.org>
On Thu, Mar 07, 2019 at 12:56:45PM -0500, Michael S. Tsirkin wrote:
> On Thu, Mar 07, 2019 at 10:47:22AM -0500, Michael S. Tsirkin wrote:
> > On Wed, Mar 06, 2019 at 02:18:12AM -0500, Jason Wang wrote:
> > > +static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
> > > + .invalidate_range = vhost_invalidate_range,
> > > +};
> > > +
> > > void vhost_dev_init(struct vhost_dev *dev,
> > > struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
> > > {
> >
> > I also wonder here: when page is write protected then
> > it does not look like .invalidate_range is invoked.
> >
> > E.g. mm/ksm.c calls
> >
> > mmu_notifier_invalidate_range_start and
> > mmu_notifier_invalidate_range_end but not mmu_notifier_invalidate_range.
> >
> > Similarly, rmap in page_mkclean_one will not call
> > mmu_notifier_invalidate_range.
> >
> > If I'm right vhost won't get notified when page is write-protected since you
> > didn't install start/end notifiers. Note that end notifier can be called
> > with page locked, so it's not as straight-forward as just adding a call.
> > Writing into a write-protected page isn't a good idea.
> >
> > Note that documentation says:
> > it is fine to delay the mmu_notifier_invalidate_range
> > call to mmu_notifier_invalidate_range_end() outside the page table lock.
> > implying it's called just later.
>
> OK I missed the fact that _end actually calls
> mmu_notifier_invalidate_range internally. So that part is fine but the
> fact that you are trying to take page lock under VQ mutex and take same
> mutex within notifier probably means it's broken for ksm and rmap at
> least since these call invalidate with lock taken.
>
> And generally, Andrea told me offline one can not take mutex under
> the notifier callback. I CC'd Andrea for why.
Correct, you _can not_ take mutex or any sleeping lock from within the
invalidate_range callback as those callback happens under the page table
spinlock. You can however do so under the invalidate_range_start call-
back only if it is a blocking allow callback (there is a flag passdown
with the invalidate_range_start callback if you are not allow to block
then return EBUSY and the invalidation will be aborted).
>
> That's a separate issue from set_page_dirty when memory is file backed.
If you can access file back page then i suggest using set_page_dirty
from within a special version of vunmap() so that when you vunmap you
set the page dirty without taking page lock. It is safe to do so
always from within an mmu notifier callback if you had the page map
with write permission which means that the page had write permission
in the userspace pte too and thus it having dirty pte is expected
and calling set_page_dirty on the page is allowed without any lock.
Locking will happen once the userspace pte are tear down through the
page table lock.
> It's because of all these issues that I preferred just accessing
> userspace memory and handling faults. Unfortunately there does not
> appear to exist an API that whitelists a specific driver along the lines
> of "I checked this code for speculative info leaks, don't add barriers
> on data path please".
Maybe it would be better to explore adding such helper then remapping
page into kernel address space ?
Cheers,
Jérôme
^ permalink raw reply
* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Andrea Arcangeli @ 2019-03-07 19:16 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: kvm, netdev, linux-kernel, virtualization, linux-mm,
Jerome Glisse
In-Reply-To: <20190307124700-mutt-send-email-mst@kernel.org>
On Thu, Mar 07, 2019 at 12:56:45PM -0500, Michael S. Tsirkin wrote:
> On Thu, Mar 07, 2019 at 10:47:22AM -0500, Michael S. Tsirkin wrote:
> > On Wed, Mar 06, 2019 at 02:18:12AM -0500, Jason Wang wrote:
> > > +static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
> > > + .invalidate_range = vhost_invalidate_range,
> > > +};
> > > +
> > > void vhost_dev_init(struct vhost_dev *dev,
> > > struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
> > > {
> >
> > I also wonder here: when page is write protected then
> > it does not look like .invalidate_range is invoked.
> >
> > E.g. mm/ksm.c calls
> >
> > mmu_notifier_invalidate_range_start and
> > mmu_notifier_invalidate_range_end but not mmu_notifier_invalidate_range.
> >
> > Similarly, rmap in page_mkclean_one will not call
> > mmu_notifier_invalidate_range.
> >
> > If I'm right vhost won't get notified when page is write-protected since you
> > didn't install start/end notifiers. Note that end notifier can be called
> > with page locked, so it's not as straight-forward as just adding a call.
> > Writing into a write-protected page isn't a good idea.
> >
> > Note that documentation says:
> > it is fine to delay the mmu_notifier_invalidate_range
> > call to mmu_notifier_invalidate_range_end() outside the page table lock.
> > implying it's called just later.
>
> OK I missed the fact that _end actually calls
> mmu_notifier_invalidate_range internally. So that part is fine but the
> fact that you are trying to take page lock under VQ mutex and take same
> mutex within notifier probably means it's broken for ksm and rmap at
> least since these call invalidate with lock taken.
Yes this lock inversion needs more thoughts.
> And generally, Andrea told me offline one can not take mutex under
> the notifier callback. I CC'd Andrea for why.
Yes, the problem then is the ->invalidate_page is called then under PT
lock so it cannot take mutex, you also cannot take the page_lock, it
can at most take a spinlock or trylock_page.
So it must switch back to the _start/_end methods unless you rewrite
the locking.
The difference with _start/_end, is that ->invalidate_range avoids the
_start callback basically, but to avoid the _start callback safely, it
has to be called in between the ptep_clear_flush and the set_pte_at
whenever the pfn changes like during a COW. So it cannot be coalesced
in a single TLB flush that invalidates all sptes in a range like we
prefer for performance reasons for example in KVM. It also cannot
sleep.
In short ->invalidate_range must be really fast (it shouldn't require
to send IPI to all other CPUs like KVM may require during an
invalidate_range_start) and it must not sleep, in order to prefer it
to _start/_end.
I.e. the invalidate of the secondary MMU that walks the linux
pagetables in hardware (in vhost case with GUP in software) has to
happen while the linux pagetable is zero, otherwise a concurrent
hardware pagetable lookup could re-instantiate a mapping to the old
page in between the set_pte_at and the invalidate_range_end (which
internally calls ->invalidate_range). Jerome documented it nicely in
Documentation/vm/mmu_notifier.rst .
Now you don't really walk the pagetable in hardware in vhost, but if
you use gup_fast after usemm() it's similar.
For vhost the invalidate would be really fast, there are no IPI to
deliver at all, the problem is just the mutex.
> That's a separate issue from set_page_dirty when memory is file backed.
Yes. I don't yet know why the ext4 internal __writepage cannot
re-create the bh if they've been freed by the VM and why such race
where the bh are freed for a pinned VM_SHARED ext4 page doesn't even
exist for transient pins like O_DIRECT (does it work by luck?), but
with mmu notifiers there are no long term pins anyway, so this works
normally and it's like the memory isn't pinned. In any case I think
that's a kernel bug in either __writepage or try_to_free_buffers, so I
would ignore it considering qemu will only use anon memory or tmpfs or
hugetlbfs as backing store for the virtio ring. It wouldn't make sense
for qemu to risk triggering I/O on a VM_SHARED ext4, so we shouldn't
be even exposed to what seems to be an orthogonal kernel bug.
I suppose whatever solution will fix the set_page_dirty_lock on
VM_SHARED ext4 for the other places that don't or can't use mmu
notifiers, will then work for vhost too which uses mmu notifiers and
will be less affected from the start if something.
Reading the lwn link about the discussion about the long term GUP pin
from Jan vs set_page_dirty_lock: I can only agree with the last part
where Jerome correctly pointed out at the end that mellanox RDMA got
it right by avoiding completely long term pins by using mmu notifier
and in general mmu notifier is the standard solution to avoid long
term pins. Nothing should ever take long term GUP pins, if it does it
means software is bad or the hardware lacks features to support on
demand paging. Still I don't get why transient pins like O_DIRECT
where mmu notifier would be prohibitive to use (registering into mmu
notifier cannot be done at high frequency, the locking to do so is
massive) cannot end up into the same ext4 _writepage crash as long
term pins: long term or short term transient is a subjective measure
from VM standpoint, the VM won't know the difference, luck will
instead.
> It's because of all these issues that I preferred just accessing
> userspace memory and handling faults. Unfortunately there does not
> appear to exist an API that whitelists a specific driver along the lines
> of "I checked this code for speculative info leaks, don't add barriers
> on data path please".
Yes that's unfortunate, __uaccess_begin_nospec() is now making
prohibitive to frequently access userland code.
I doubt we can do like access_ok() and only check it once. access_ok
checks the virtual address, and if the virtual address is ok doesn't
wrap around and it points to userland in a safe range, it's always
ok. There's no need to run access_ok again if we keep hitting on the
very same address.
__uaccess_begin_nospec() instead is about runtime stuff that can
change the moment copy-user has completed even before returning to
userland, so there's no easy way to do it just once.
On top of skipping the __uaccess_begin_nospec(), the mmu notifier soft
vhost design will further boost the performance by guaranteeing the
use of gigapages TLBs when available (or 2M TLBs worst case) even if
QEMU runs on smaller pages.
Thanks,
Andrea
^ permalink raw reply
* Re: [PATCH v2] vsock/virtio: fix kernel panic from virtio_transport_reset_no_sock
From: Stefano Garzarella @ 2019-03-07 19:12 UTC (permalink / raw)
To: Adalbert Lazăr
Cc: kvm, netdev, linux-kernel, virtualization, Stefan Hajnoczi,
David S . Miller, Alexandru Herghelegiu
In-Reply-To: <20190306101353.9938-1-alazar@bitdefender.com>
On Wed, Mar 6, 2019 at 11:13 AM Adalbert Lazăr <alazar@bitdefender.com> wrote:
>
> Previous to commit 22b5c0b63f32 ("vsock/virtio: fix kernel panic
> after device hot-unplug"), vsock_core_init() was called from
> virtio_vsock_probe(). Now, virtio_transport_reset_no_sock() can be called
> before vsock_core_init() has the chance to run.
>
> [Wed Feb 27 14:17:09 2019] BUG: unable to handle kernel NULL pointer dereference at 0000000000000110
> [Wed Feb 27 14:17:09 2019] #PF error: [normal kernel read fault]
> [Wed Feb 27 14:17:09 2019] PGD 0 P4D 0
> [Wed Feb 27 14:17:09 2019] Oops: 0000 [#1] SMP PTI
> [Wed Feb 27 14:17:09 2019] CPU: 3 PID: 59 Comm: kworker/3:1 Not tainted 5.0.0-rc7-390-generic-hvi #390
> [Wed Feb 27 14:17:09 2019] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
> [Wed Feb 27 14:17:09 2019] Workqueue: virtio_vsock virtio_transport_rx_work [vmw_vsock_virtio_transport]
> [Wed Feb 27 14:17:09 2019] RIP: 0010:virtio_transport_reset_no_sock+0x8c/0xc0 [vmw_vsock_virtio_transport_common]
> [Wed Feb 27 14:17:09 2019] Code: 35 8b 4f 14 48 8b 57 08 31 f6 44 8b 4f 10 44 8b 07 48 8d 7d c8 e8 84 f8 ff ff 48 85 c0 48 89 c3 74 2a e8 f7 31 03 00 48 89 df <48> 8b 80 10 01 00 00 e8 68 fb 69 ed 48 8b 75 f0 65 48 33 34 25 28
> [Wed Feb 27 14:17:09 2019] RSP: 0018:ffffb42701ab7d40 EFLAGS: 00010282
> [Wed Feb 27 14:17:09 2019] RAX: 0000000000000000 RBX: ffff9d79637ee080 RCX: 0000000000000003
> [Wed Feb 27 14:17:09 2019] RDX: 0000000000000001 RSI: 0000000000000002 RDI: ffff9d79637ee080
> [Wed Feb 27 14:17:09 2019] RBP: ffffb42701ab7d78 R08: ffff9d796fae70e0 R09: ffff9d796f403500
> [Wed Feb 27 14:17:09 2019] R10: ffffb42701ab7d90 R11: 0000000000000000 R12: ffff9d7969d09240
> [Wed Feb 27 14:17:09 2019] R13: ffff9d79624e6840 R14: ffff9d7969d09318 R15: ffff9d796d48ff80
> [Wed Feb 27 14:17:09 2019] FS: 0000000000000000(0000) GS:ffff9d796fac0000(0000) knlGS:0000000000000000
> [Wed Feb 27 14:17:09 2019] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [Wed Feb 27 14:17:09 2019] CR2: 0000000000000110 CR3: 0000000427f22000 CR4: 00000000000006e0
> [Wed Feb 27 14:17:09 2019] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [Wed Feb 27 14:17:09 2019] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [Wed Feb 27 14:17:09 2019] Call Trace:
> [Wed Feb 27 14:17:09 2019] virtio_transport_recv_pkt+0x63/0x820 [vmw_vsock_virtio_transport_common]
> [Wed Feb 27 14:17:09 2019] ? kfree+0x17e/0x190
> [Wed Feb 27 14:17:09 2019] ? detach_buf_split+0x145/0x160
> [Wed Feb 27 14:17:09 2019] ? __switch_to_asm+0x40/0x70
> [Wed Feb 27 14:17:09 2019] virtio_transport_rx_work+0xa0/0x106 [vmw_vsock_virtio_transport]
> [Wed Feb 27 14:17:09 2019] NET: Registered protocol family 40
> [Wed Feb 27 14:17:09 2019] process_one_work+0x167/0x410
> [Wed Feb 27 14:17:09 2019] worker_thread+0x4d/0x460
> [Wed Feb 27 14:17:09 2019] kthread+0x105/0x140
> [Wed Feb 27 14:17:09 2019] ? rescuer_thread+0x360/0x360
> [Wed Feb 27 14:17:09 2019] ? kthread_destroy_worker+0x50/0x50
> [Wed Feb 27 14:17:09 2019] ret_from_fork+0x35/0x40
> [Wed Feb 27 14:17:09 2019] Modules linked in: vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common input_leds vsock serio_raw i2c_piix4 mac_hid qemu_fw_cfg autofs4 cirrus ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops virtio_net psmouse drm net_failover pata_acpi virtio_blk failover floppy
>
> Fixes: 22b5c0b63f32 ("vsock/virtio: fix kernel panic after device hot-unplug")
> Reported-by: Alexandru Herghelegiu <aherghelegiu@bitdefender.com>
> Signed-off-by: Adalbert Lazăr <alazar@bitdefender.com>
> Co-developed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
> net/vmw_vsock/virtio_transport_common.c | 22 +++++++++++++++-------
> 1 file changed, 15 insertions(+), 7 deletions(-)
>
Thanks, LGTM!
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> index 3ae3a33da70b..602715fc9a75 100644
> --- a/net/vmw_vsock/virtio_transport_common.c
> +++ b/net/vmw_vsock/virtio_transport_common.c
> @@ -662,6 +662,8 @@ static int virtio_transport_reset(struct vsock_sock *vsk,
> */
> static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt)
> {
> + const struct virtio_transport *t;
> + struct virtio_vsock_pkt *reply;
> struct virtio_vsock_pkt_info info = {
> .op = VIRTIO_VSOCK_OP_RST,
> .type = le16_to_cpu(pkt->hdr.type),
> @@ -672,15 +674,21 @@ static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt)
> if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
> return 0;
>
> - pkt = virtio_transport_alloc_pkt(&info, 0,
> - le64_to_cpu(pkt->hdr.dst_cid),
> - le32_to_cpu(pkt->hdr.dst_port),
> - le64_to_cpu(pkt->hdr.src_cid),
> - le32_to_cpu(pkt->hdr.src_port));
> - if (!pkt)
> + reply = virtio_transport_alloc_pkt(&info, 0,
> + le64_to_cpu(pkt->hdr.dst_cid),
> + le32_to_cpu(pkt->hdr.dst_port),
> + le64_to_cpu(pkt->hdr.src_cid),
> + le32_to_cpu(pkt->hdr.src_port));
> + if (!reply)
> return -ENOMEM;
>
> - return virtio_transport_get_ops()->send_pkt(pkt);
> + t = virtio_transport_get_ops();
> + if (!t) {
> + virtio_transport_free_pkt(reply);
> + return -ENOTCONN;
> + }
> +
> + return t->send_pkt(reply);
> }
>
> static void virtio_transport_wait_close(struct sock *sk, long timeout)
>
--
Stefano Garzarella
Software Engineer @ Red Hat
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Jerome Glisse @ 2019-03-07 19:09 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: aarcange, kvm, netdev, linux-kernel, virtualization, linux-mm
In-Reply-To: <20190307101708-mutt-send-email-mst@kernel.org>
On Thu, Mar 07, 2019 at 10:34:39AM -0500, Michael S. Tsirkin wrote:
> On Thu, Mar 07, 2019 at 10:45:57AM +0800, Jason Wang wrote:
> >
> > On 2019/3/7 上午12:31, Michael S. Tsirkin wrote:
> > > > +static void vhost_set_vmap_dirty(struct vhost_vmap *used)
> > > > +{
> > > > + int i;
> > > > +
> > > > + for (i = 0; i < used->npages; i++)
> > > > + set_page_dirty_lock(used->pages[i]);
> > > This seems to rely on page lock to mark page dirty.
> > >
> > > Could it happen that page writeback will check the
> > > page, find it clean, and then you mark it dirty and then
> > > invalidate callback is called?
> > >
> > >
> >
> > Yes. But does this break anything?
> > The page is still there, we just remove a
> > kernel mapping to it.
> >
> > Thanks
>
> Yes it's the same problem as e.g. RDMA:
> we've just marked the page as dirty without having buffers.
> Eventually writeback will find it and filesystem will complain...
> So if the pages are backed by a non-RAM-based filesystem, it’s all just broken.
>
> one can hope that RDMA guys will fix it in some way eventually.
> For now, maybe add a flag in e.g. VMA that says that there's no
> writeback so it's safe to mark page dirty at any point?
I thought this patch was only for anonymous memory ie not file back ?
If so then set dirty is mostly useless it would only be use for swap
but for this you can use an unlock version to set the page dirty.
Cheers,
Jérôme
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Michael S. Tsirkin @ 2019-03-07 17:56 UTC (permalink / raw)
To: Jason Wang
Cc: aarcange, kvm, netdev, linux-kernel, virtualization, linux-mm,
Jerome Glisse
In-Reply-To: <20190307103503-mutt-send-email-mst@kernel.org>
On Thu, Mar 07, 2019 at 10:47:22AM -0500, Michael S. Tsirkin wrote:
> On Wed, Mar 06, 2019 at 02:18:12AM -0500, Jason Wang wrote:
> > +static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
> > + .invalidate_range = vhost_invalidate_range,
> > +};
> > +
> > void vhost_dev_init(struct vhost_dev *dev,
> > struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
> > {
>
> I also wonder here: when page is write protected then
> it does not look like .invalidate_range is invoked.
>
> E.g. mm/ksm.c calls
>
> mmu_notifier_invalidate_range_start and
> mmu_notifier_invalidate_range_end but not mmu_notifier_invalidate_range.
>
> Similarly, rmap in page_mkclean_one will not call
> mmu_notifier_invalidate_range.
>
> If I'm right vhost won't get notified when page is write-protected since you
> didn't install start/end notifiers. Note that end notifier can be called
> with page locked, so it's not as straight-forward as just adding a call.
> Writing into a write-protected page isn't a good idea.
>
> Note that documentation says:
> it is fine to delay the mmu_notifier_invalidate_range
> call to mmu_notifier_invalidate_range_end() outside the page table lock.
> implying it's called just later.
OK I missed the fact that _end actually calls
mmu_notifier_invalidate_range internally. So that part is fine but the
fact that you are trying to take page lock under VQ mutex and take same
mutex within notifier probably means it's broken for ksm and rmap at
least since these call invalidate with lock taken.
And generally, Andrea told me offline one can not take mutex under
the notifier callback. I CC'd Andrea for why.
That's a separate issue from set_page_dirty when memory is file backed.
It's because of all these issues that I preferred just accessing
userspace memory and handling faults. Unfortunately there does not
appear to exist an API that whitelists a specific driver along the lines
of "I checked this code for speculative info leaks, don't add barriers
on data path please".
> --
> MST
^ permalink raw reply
* Re: [PATCH v2] vsock/virtio: fix kernel panic from virtio_transport_reset_no_sock
From: Stefan Hajnoczi @ 2019-03-07 16:37 UTC (permalink / raw)
To: Adalbert Lazăr
Cc: kvm, netdev, linux-kernel, virtualization, Alexandru Herghelegiu,
David S . Miller, Stefano Garzarella
In-Reply-To: <20190306101353.9938-1-alazar@bitdefender.com>
[-- Attachment #1.1: Type: text/plain, Size: 3938 bytes --]
On Wed, Mar 06, 2019 at 12:13:53PM +0200, Adalbert Lazăr wrote:
> Previous to commit 22b5c0b63f32 ("vsock/virtio: fix kernel panic
> after device hot-unplug"), vsock_core_init() was called from
> virtio_vsock_probe(). Now, virtio_transport_reset_no_sock() can be called
> before vsock_core_init() has the chance to run.
>
> [Wed Feb 27 14:17:09 2019] BUG: unable to handle kernel NULL pointer dereference at 0000000000000110
> [Wed Feb 27 14:17:09 2019] #PF error: [normal kernel read fault]
> [Wed Feb 27 14:17:09 2019] PGD 0 P4D 0
> [Wed Feb 27 14:17:09 2019] Oops: 0000 [#1] SMP PTI
> [Wed Feb 27 14:17:09 2019] CPU: 3 PID: 59 Comm: kworker/3:1 Not tainted 5.0.0-rc7-390-generic-hvi #390
> [Wed Feb 27 14:17:09 2019] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
> [Wed Feb 27 14:17:09 2019] Workqueue: virtio_vsock virtio_transport_rx_work [vmw_vsock_virtio_transport]
> [Wed Feb 27 14:17:09 2019] RIP: 0010:virtio_transport_reset_no_sock+0x8c/0xc0 [vmw_vsock_virtio_transport_common]
> [Wed Feb 27 14:17:09 2019] Code: 35 8b 4f 14 48 8b 57 08 31 f6 44 8b 4f 10 44 8b 07 48 8d 7d c8 e8 84 f8 ff ff 48 85 c0 48 89 c3 74 2a e8 f7 31 03 00 48 89 df <48> 8b 80 10 01 00 00 e8 68 fb 69 ed 48 8b 75 f0 65 48 33 34 25 28
> [Wed Feb 27 14:17:09 2019] RSP: 0018:ffffb42701ab7d40 EFLAGS: 00010282
> [Wed Feb 27 14:17:09 2019] RAX: 0000000000000000 RBX: ffff9d79637ee080 RCX: 0000000000000003
> [Wed Feb 27 14:17:09 2019] RDX: 0000000000000001 RSI: 0000000000000002 RDI: ffff9d79637ee080
> [Wed Feb 27 14:17:09 2019] RBP: ffffb42701ab7d78 R08: ffff9d796fae70e0 R09: ffff9d796f403500
> [Wed Feb 27 14:17:09 2019] R10: ffffb42701ab7d90 R11: 0000000000000000 R12: ffff9d7969d09240
> [Wed Feb 27 14:17:09 2019] R13: ffff9d79624e6840 R14: ffff9d7969d09318 R15: ffff9d796d48ff80
> [Wed Feb 27 14:17:09 2019] FS: 0000000000000000(0000) GS:ffff9d796fac0000(0000) knlGS:0000000000000000
> [Wed Feb 27 14:17:09 2019] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [Wed Feb 27 14:17:09 2019] CR2: 0000000000000110 CR3: 0000000427f22000 CR4: 00000000000006e0
> [Wed Feb 27 14:17:09 2019] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [Wed Feb 27 14:17:09 2019] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [Wed Feb 27 14:17:09 2019] Call Trace:
> [Wed Feb 27 14:17:09 2019] virtio_transport_recv_pkt+0x63/0x820 [vmw_vsock_virtio_transport_common]
> [Wed Feb 27 14:17:09 2019] ? kfree+0x17e/0x190
> [Wed Feb 27 14:17:09 2019] ? detach_buf_split+0x145/0x160
> [Wed Feb 27 14:17:09 2019] ? __switch_to_asm+0x40/0x70
> [Wed Feb 27 14:17:09 2019] virtio_transport_rx_work+0xa0/0x106 [vmw_vsock_virtio_transport]
> [Wed Feb 27 14:17:09 2019] NET: Registered protocol family 40
> [Wed Feb 27 14:17:09 2019] process_one_work+0x167/0x410
> [Wed Feb 27 14:17:09 2019] worker_thread+0x4d/0x460
> [Wed Feb 27 14:17:09 2019] kthread+0x105/0x140
> [Wed Feb 27 14:17:09 2019] ? rescuer_thread+0x360/0x360
> [Wed Feb 27 14:17:09 2019] ? kthread_destroy_worker+0x50/0x50
> [Wed Feb 27 14:17:09 2019] ret_from_fork+0x35/0x40
> [Wed Feb 27 14:17:09 2019] Modules linked in: vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common input_leds vsock serio_raw i2c_piix4 mac_hid qemu_fw_cfg autofs4 cirrus ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops virtio_net psmouse drm net_failover pata_acpi virtio_blk failover floppy
>
> Fixes: 22b5c0b63f32 ("vsock/virtio: fix kernel panic after device hot-unplug")
> Reported-by: Alexandru Herghelegiu <aherghelegiu@bitdefender.com>
> Signed-off-by: Adalbert Lazăr <alazar@bitdefender.com>
> Co-developed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
> net/vmw_vsock/virtio_transport_common.c | 22 +++++++++++++++-------
> 1 file changed, 15 insertions(+), 7 deletions(-)
Excellent, thanks!
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
[-- Attachment #2: Type: text/plain, Size: 183 bytes --]
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Michael S. Tsirkin @ 2019-03-07 15:47 UTC (permalink / raw)
To: Jason Wang; +Cc: aarcange, kvm, netdev, linux-kernel, virtualization, linux-mm
In-Reply-To: <1551856692-3384-6-git-send-email-jasowang@redhat.com>
On Wed, Mar 06, 2019 at 02:18:12AM -0500, Jason Wang wrote:
> +static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
> + .invalidate_range = vhost_invalidate_range,
> +};
> +
> void vhost_dev_init(struct vhost_dev *dev,
> struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
> {
I also wonder here: when page is write protected then
it does not look like .invalidate_range is invoked.
E.g. mm/ksm.c calls
mmu_notifier_invalidate_range_start and
mmu_notifier_invalidate_range_end but not mmu_notifier_invalidate_range.
Similarly, rmap in page_mkclean_one will not call
mmu_notifier_invalidate_range.
If I'm right vhost won't get notified when page is write-protected since you
didn't install start/end notifiers. Note that end notifier can be called
with page locked, so it's not as straight-forward as just adding a call.
Writing into a write-protected page isn't a good idea.
Note that documentation says:
it is fine to delay the mmu_notifier_invalidate_range
call to mmu_notifier_invalidate_range_end() outside the page table lock.
implying it's called just later.
--
MST
^ permalink raw reply
* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Michael S. Tsirkin @ 2019-03-07 15:34 UTC (permalink / raw)
To: Jason Wang; +Cc: aarcange, kvm, netdev, linux-kernel, virtualization, linux-mm
In-Reply-To: <15105894-4ec1-1ed0-1976-7b68ed9eeeda@redhat.com>
On Thu, Mar 07, 2019 at 10:45:57AM +0800, Jason Wang wrote:
>
> On 2019/3/7 上午12:31, Michael S. Tsirkin wrote:
> > > +static void vhost_set_vmap_dirty(struct vhost_vmap *used)
> > > +{
> > > + int i;
> > > +
> > > + for (i = 0; i < used->npages; i++)
> > > + set_page_dirty_lock(used->pages[i]);
> > This seems to rely on page lock to mark page dirty.
> >
> > Could it happen that page writeback will check the
> > page, find it clean, and then you mark it dirty and then
> > invalidate callback is called?
> >
> >
>
> Yes. But does this break anything?
> The page is still there, we just remove a
> kernel mapping to it.
>
> Thanks
Yes it's the same problem as e.g. RDMA:
we've just marked the page as dirty without having buffers.
Eventually writeback will find it and filesystem will complain...
So if the pages are backed by a non-RAM-based filesystem, it’s all just broken.
one can hope that RDMA guys will fix it in some way eventually.
For now, maybe add a flag in e.g. VMA that says that there's no
writeback so it's safe to mark page dirty at any point?
--
MST
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [PATCH net v2] failover: allow name change on IFF_UP slave interfaces
From: Samudrala, Sridhar @ 2019-03-07 4:13 UTC (permalink / raw)
To: Si-Wei Liu, Michael S. Tsirkin, Alexander Duyck,
Stephen Hemminger, Jakub Kicinski, Jiri Pirko, David Miller,
Netdev, virtualization
Cc: boris.ostrovsky, liran.alon
In-Reply-To: <1551928112-32109-1-git-send-email-si-wei.liu@oracle.com>
On 3/6/2019 7:08 PM, Si-Wei Liu wrote:
> When a netdev appears through hot plug then gets enslaved by a failover
> master that is already up and running, the slave will be opened
> right away after getting enslaved. Today there's a race that userspace
> (udev) may fail to rename the slave if the kernel (net_failover)
> opens the slave earlier than when the userspace rename happens.
> Unlike bond or team, the primary slave of failover can't be renamed by
> userspace ahead of time, since the kernel initiated auto-enslavement is
> unable to, or rather, is never meant to be synchronized with the rename
> request from userspace.
>
> As the failover slave interfaces are not designed to be operated
> directly by userspace apps: IP configuration, filter rules with
> regard to network traffic passing and etc., should all be done on master
> interface. In general, userspace apps only care about the
> name of master interface, while slave names are less important as long
> as admin users can see reliable names that may carry
> other information describing the netdev. For e.g., they can infer that
> "ens3nsby" is a standby slave of "ens3", while for a
> name like "eth0" they can't tell which master it belongs to.
>
> Historically the name of IFF_UP interface can't be changed because
> there might be admin script or management software that is already
> relying on such behavior and assumes that the slave name can't be
> changed once UP. But failover is special: with the in-kernel
> auto-enslavement mechanism, the userspace expectation for device
> enumeration and bring-up order is already broken. Previously initramfs
> and various userspace config tools were modified to bypass failover
> slaves because of auto-enslavement and duplicate MAC address. Similarly,
> in case that users care about seeing reliable slave name, the new type
> of failover slaves needs to be taken care of specifically in userspace
> anyway.
>
> It's less risky to lift up the rename restriction on failover slave
> which is already UP. Although it's possible this change may potentially
> break userspace component (most likely configuration scripts or
> management software) that assumes slave name can't be changed while
> UP, it's relatively a limited and controllable set among all userspace
> components, which can be fixed specifically to work with the new naming
> behavior of failover slaves. Userspace component interacting with
> slaves should be changed to operate on failover master instead, as the
> failover slave is dynamic in nature which may come and go at any point.
> The goal is to make the role of failover slaves less relevant, and
> all userspace should only deal with master in the long run.
>
> Fixes: 30c8bd5aa8b2 ("net: Introduce generic failover module")
> Signed-off-by: Si-Wei Liu <si-wei.liu@oracle.com>
> Reviewed-by: Liran Alon <liran.alon@oracle.com>
> Acked-by: Michael S. Tsirkin <mst@redhat.com>
>
> ---
> v1 -> v2:
> - Drop configurable module parameter (Sridhar)
>
>
> include/linux/netdevice.h | 3 +++
> net/core/dev.c | 3 ++-
> net/core/failover.c | 6 +++---
> 3 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 857f8ab..6d9e4e0 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1487,6 +1487,7 @@ struct net_device_ops {
> * @IFF_NO_RX_HANDLER: device doesn't support the rx_handler hook
> * @IFF_FAILOVER: device is a failover master device
> * @IFF_FAILOVER_SLAVE: device is lower dev of a failover master device
> + * @IFF_SLAVE_RENAME_OK: rename is allowed while slave device is running
> */
> enum netdev_priv_flags {
> IFF_802_1Q_VLAN = 1<<0,
> @@ -1518,6 +1519,7 @@ enum netdev_priv_flags {
> IFF_NO_RX_HANDLER = 1<<26,
> IFF_FAILOVER = 1<<27,
> IFF_FAILOVER_SLAVE = 1<<28,
> + IFF_SLAVE_RENAME_OK = 1<<29,
> };
>
> #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
> @@ -1548,6 +1550,7 @@ enum netdev_priv_flags {
> #define IFF_NO_RX_HANDLER IFF_NO_RX_HANDLER
> #define IFF_FAILOVER IFF_FAILOVER
> #define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
> +#define IFF_SLAVE_RENAME_OK IFF_SLAVE_RENAME_OK
>
> /**
> * struct net_device - The DEVICE structure.
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 722d50d..ae070de 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -1180,7 +1180,8 @@ int dev_change_name(struct net_device *dev, const char *newname)
> BUG_ON(!dev_net(dev));
>
> net = dev_net(dev);
> - if (dev->flags & IFF_UP)
> + if (dev->flags & IFF_UP &&
> + !(dev->priv_flags & IFF_SLAVE_RENAME_OK))
> return -EBUSY;
Without the configurable module parameter, i think we don't even need
the new SLAVE_RENAME_OK private flag.
Can't we simply check for IFF_FAILOVER_SLAVE ?
>
> write_seqcount_begin(&devnet_rename_seq);
> diff --git a/net/core/failover.c b/net/core/failover.c
> index 4a92a98..34c5c87 100644
> --- a/net/core/failover.c
> +++ b/net/core/failover.c
> @@ -80,14 +80,14 @@ static int failover_slave_register(struct net_device *slave_dev)
> goto err_upper_link;
> }
>
> - slave_dev->priv_flags |= IFF_FAILOVER_SLAVE;
> + slave_dev->priv_flags |= (IFF_FAILOVER_SLAVE | IFF_SLAVE_RENAME_OK);
>
> if (fops && fops->slave_register &&
> !fops->slave_register(slave_dev, failover_dev))
> return NOTIFY_OK;
>
> netdev_upper_dev_unlink(slave_dev, failover_dev);
> - slave_dev->priv_flags &= ~IFF_FAILOVER_SLAVE;
> + slave_dev->priv_flags &= ~(IFF_FAILOVER_SLAVE | IFF_SLAVE_RENAME_OK);
> err_upper_link:
> netdev_rx_handler_unregister(slave_dev);
> done:
> @@ -121,7 +121,7 @@ int failover_slave_unregister(struct net_device *slave_dev)
>
> netdev_rx_handler_unregister(slave_dev);
> netdev_upper_dev_unlink(slave_dev, failover_dev);
> - slave_dev->priv_flags &= ~IFF_FAILOVER_SLAVE;
> + slave_dev->priv_flags &= ~(IFF_FAILOVER_SLAVE | IFF_SLAVE_RENAME_OK);
>
> if (fops && fops->slave_unregister &&
> !fops->slave_unregister(slave_dev, failover_dev))
>
^ permalink raw reply
* Re: [PATCH] vhost: silence an unused-variable warning
From: Jason Wang @ 2019-03-07 3:00 UTC (permalink / raw)
To: Arnd Bergmann, Michael S. Tsirkin
Cc: kvm, netdev, linux-kernel, virtualization, Stefan Hajnoczi,
David S. Miller
In-Reply-To: <20190306110602.2529137-1-arnd@arndb.de>
On 2019/3/6 下午7:05, Arnd Bergmann wrote:
> On some architectures, the MMU can be disabled, leading to access_ok()
> becoming an empty macro that does not evaluate its size argument,
> which in turn produces an unused-variable warning:
>
> drivers/vhost/vhost.c:1191:9: error: unused variable 's' [-Werror,-Wunused-variable]
> size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
>
> Mark the variable as __maybe_unused to shut up that warning.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/vhost/vhost.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index a2e5dc7716e2..5ace833de746 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -1188,7 +1188,7 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
> struct vring_used __user *used)
>
> {
> - size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
> + size_t s __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
>
> return access_ok(desc, num * sizeof *desc) &&
> access_ok(avail,
Acked-by: Jason Wang <jasowang@redhat.com>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Jason Wang @ 2019-03-07 2:45 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: aarcange, kvm, netdev, linux-kernel, virtualization, linux-mm
In-Reply-To: <20190306092837-mutt-send-email-mst@kernel.org>
On 2019/3/7 上午12:31, Michael S. Tsirkin wrote:
>> +static void vhost_set_vmap_dirty(struct vhost_vmap *used)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < used->npages; i++)
>> + set_page_dirty_lock(used->pages[i]);
> This seems to rely on page lock to mark page dirty.
>
> Could it happen that page writeback will check the
> page, find it clean, and then you mark it dirty and then
> invalidate callback is called?
>
>
Yes. But does this break anything? The page is still there, we just
remove a kernel mapping to it.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 4/5] vhost: introduce helpers to get the size of metadata area
From: Jason Wang @ 2019-03-07 2:42 UTC (permalink / raw)
To: Souptick Joarder
Cc: aarcange, kvm, mst, netdev, linux-kernel, virtualization,
Linux-MM
In-Reply-To: <CAFqt6zYynfCn_SG6w98dHMA5rS6euPb+ihXtQcALE47K0LQb7g@mail.gmail.com>
On 2019/3/7 上午2:43, Souptick Joarder wrote:
> On Wed, Mar 6, 2019 at 12:48 PM Jason Wang <jasowang@redhat.com> wrote:
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
> Is the change log left with any particular reason ?
Nope, will add the log.
Thanks
>> ---
>> drivers/vhost/vhost.c | 46 ++++++++++++++++++++++++++++------------------
>> 1 file changed, 28 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
>> index 2025543..1015464 100644
>> --- a/drivers/vhost/vhost.c
>> +++ b/drivers/vhost/vhost.c
>> @@ -413,6 +413,27 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev)
>> vhost_vq_free_iovecs(dev->vqs[i]);
>> }
>>
>> +static size_t vhost_get_avail_size(struct vhost_virtqueue *vq, int num)
>> +{
>> + size_t event = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
>> +
>> + return sizeof(*vq->avail) +
>> + sizeof(*vq->avail->ring) * num + event;
>> +}
>> +
>> +static size_t vhost_get_used_size(struct vhost_virtqueue *vq, int num)
>> +{
>> + size_t event = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
>> +
>> + return sizeof(*vq->used) +
>> + sizeof(*vq->used->ring) * num + event;
>> +}
>> +
>> +static size_t vhost_get_desc_size(struct vhost_virtqueue *vq, int num)
>> +{
>> + return sizeof(*vq->desc) * num;
>> +}
>> +
>> void vhost_dev_init(struct vhost_dev *dev,
>> struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
>> {
>> @@ -1253,13 +1274,9 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
>> struct vring_used __user *used)
>>
>> {
>> - size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
>> -
>> - return access_ok(desc, num * sizeof *desc) &&
>> - access_ok(avail,
>> - sizeof *avail + num * sizeof *avail->ring + s) &&
>> - access_ok(used,
>> - sizeof *used + num * sizeof *used->ring + s);
>> + return access_ok(desc, vhost_get_desc_size(vq, num)) &&
>> + access_ok(avail, vhost_get_avail_size(vq, num)) &&
>> + access_ok(used, vhost_get_used_size(vq, num));
>> }
>>
>> static void vhost_vq_meta_update(struct vhost_virtqueue *vq,
>> @@ -1311,22 +1328,18 @@ static bool iotlb_access_ok(struct vhost_virtqueue *vq,
>>
>> int vq_meta_prefetch(struct vhost_virtqueue *vq)
>> {
>> - size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
>> unsigned int num = vq->num;
>>
>> if (!vq->iotlb)
>> return 1;
>>
>> return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
>> - num * sizeof(*vq->desc), VHOST_ADDR_DESC) &&
>> + vhost_get_desc_size(vq, num), VHOST_ADDR_DESC) &&
>> iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->avail,
>> - sizeof *vq->avail +
>> - num * sizeof(*vq->avail->ring) + s,
>> + vhost_get_avail_size(vq, num),
>> VHOST_ADDR_AVAIL) &&
>> iotlb_access_ok(vq, VHOST_ACCESS_WO, (u64)(uintptr_t)vq->used,
>> - sizeof *vq->used +
>> - num * sizeof(*vq->used->ring) + s,
>> - VHOST_ADDR_USED);
>> + vhost_get_used_size(vq, num), VHOST_ADDR_USED);
>> }
>> EXPORT_SYMBOL_GPL(vq_meta_prefetch);
>>
>> @@ -1343,13 +1356,10 @@ bool vhost_log_access_ok(struct vhost_dev *dev)
>> static bool vq_log_access_ok(struct vhost_virtqueue *vq,
>> void __user *log_base)
>> {
>> - size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
>> -
>> return vq_memory_access_ok(log_base, vq->umem,
>> vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
>> (!vq->log_used || log_access_ok(log_base, vq->log_addr,
>> - sizeof *vq->used +
>> - vq->num * sizeof *vq->used->ring + s));
>> + vhost_get_used_size(vq, vq->num)));
>> }
>>
>> /* Can we start vq? */
>> --
>> 1.8.3.1
>>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 4/5] vhost: introduce helpers to get the size of metadata area
From: Jason Wang @ 2019-03-07 2:40 UTC (permalink / raw)
To: Christophe de Dinechin
Cc: aarcange, kvm, mst, netdev, linux-kernel, virtualization,
linux-mm
In-Reply-To: <608E47C2-5130-41DE-9D52-02807EBCDD43@dinechin.org>
On 2019/3/6 下午6:56, Christophe de Dinechin wrote:
>> On 6 Mar 2019, at 08:18, Jason Wang<jasowang@redhat.com> wrote:
>>
>> Signed-off-by: Jason Wang<jasowang@redhat.com>
>> ---
>> drivers/vhost/vhost.c | 46 ++++++++++++++++++++++++++++------------------
>> 1 file changed, 28 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
>> index 2025543..1015464 100644
>> --- a/drivers/vhost/vhost.c
>> +++ b/drivers/vhost/vhost.c
>> @@ -413,6 +413,27 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev)
>> vhost_vq_free_iovecs(dev->vqs[i]);
>> }
>>
>> +static size_t vhost_get_avail_size(struct vhost_virtqueue *vq, int num)
> Nit: Any reason not to make `num` unsigned or size_t?
>
Let me use unsigned int to match the definition of vq->num.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 2/5] vhost: fine grain userspace memory accessors
From: Jason Wang @ 2019-03-07 2:38 UTC (permalink / raw)
To: Christophe de Dinechin
Cc: aarcange, KVM list, Michael S. Tsirkin, netdev, open list,
open list:VIRTIO GPU DRIVER, linux-mm
In-Reply-To: <4C1386C5-F153-43DD-8B14-CC752FA5A07A@dinechin.org>
On 2019/3/6 下午6:45, Christophe de Dinechin wrote:
>
>> On 6 Mar 2019, at 08:18, Jason Wang <jasowang@redhat.com> wrote:
>>
>> This is used to hide the metadata address from virtqueue helpers. This
>> will allow to implement a vmap based fast accessing to metadata.
>>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>> drivers/vhost/vhost.c | 94 +++++++++++++++++++++++++++++++++++++++++----------
>> 1 file changed, 77 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
>> index 400aa78..29709e7 100644
>> --- a/drivers/vhost/vhost.c
>> +++ b/drivers/vhost/vhost.c
>> @@ -869,6 +869,34 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
>> ret; \
>> })
>>
>> +static inline int vhost_put_avail_event(struct vhost_virtqueue *vq)
>> +{
>> + return vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
>> + vhost_avail_event(vq));
>> +}
>> +
>> +static inline int vhost_put_used(struct vhost_virtqueue *vq,
>> + struct vring_used_elem *head, int idx,
>> + int count)
>> +{
>> + return vhost_copy_to_user(vq, vq->used->ring + idx, head,
>> + count * sizeof(*head));
>> +}
>> +
>> +static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
>> +
>> +{
>> + return vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
>> + &vq->used->flags);
>> +}
>> +
>> +static inline int vhost_put_used_idx(struct vhost_virtqueue *vq)
>> +
>> +{
>> + return vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
>> + &vq->used->idx);
>> +}
>> +
>> #define vhost_get_user(vq, x, ptr, type) \
>> ({ \
>> int ret; \
>> @@ -907,6 +935,43 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d)
>> mutex_unlock(&d->vqs[i]->mutex);
>> }
>>
>> +static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
>> + __virtio16 *idx)
>> +{
>> + return vhost_get_avail(vq, *idx, &vq->avail->idx);
>> +}
>> +
>> +static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
>> + __virtio16 *head, int idx)
>> +{
>> + return vhost_get_avail(vq, *head,
>> + &vq->avail->ring[idx & (vq->num - 1)]);
>> +}
>> +
>> +static inline int vhost_get_avail_flags(struct vhost_virtqueue *vq,
>> + __virtio16 *flags)
>> +{
>> + return vhost_get_avail(vq, *flags, &vq->avail->flags);
>> +}
>> +
>> +static inline int vhost_get_used_event(struct vhost_virtqueue *vq,
>> + __virtio16 *event)
>> +{
>> + return vhost_get_avail(vq, *event, vhost_used_event(vq));
>> +}
>> +
>> +static inline int vhost_get_used_idx(struct vhost_virtqueue *vq,
>> + __virtio16 *idx)
>> +{
>> + return vhost_get_used(vq, *idx, &vq->used->idx);
>> +}
>> +
>> +static inline int vhost_get_desc(struct vhost_virtqueue *vq,
>> + struct vring_desc *desc, int idx)
>> +{
>> + return vhost_copy_from_user(vq, desc, vq->desc + idx, sizeof(*desc));
>> +}
>> +
>> static int vhost_new_umem_range(struct vhost_umem *umem,
>> u64 start, u64 size, u64 end,
>> u64 userspace_addr, int perm)
>> @@ -1840,8 +1905,7 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
>> static int vhost_update_used_flags(struct vhost_virtqueue *vq)
>> {
>> void __user *used;
>> - if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
>> - &vq->used->flags) < 0)
>> + if (vhost_put_used_flags(vq))
>> return -EFAULT;
>> if (unlikely(vq->log_used)) {
>> /* Make sure the flag is seen before log. */
>> @@ -1858,8 +1922,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
>>
>> static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
>> {
>> - if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
>> - vhost_avail_event(vq)))
>> + if (vhost_put_avail_event(vq))
>> return -EFAULT;
>> if (unlikely(vq->log_used)) {
>> void __user *used;
>> @@ -1895,7 +1958,7 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq)
>> r = -EFAULT;
>> goto err;
>> }
>> - r = vhost_get_used(vq, last_used_idx, &vq->used->idx);
>> + r = vhost_get_used_idx(vq, &last_used_idx);
>> if (r) {
>> vq_err(vq, "Can't access used idx at %p\n",
>> &vq->used->idx);
> From the error case, it looks like you are not entirely encapsulating
> knowledge of what the accessor uses, i.e. it’s not:
>
> vq_err(vq, "Can't access used idx at %p\n",
> &last_user_idx);
>
> Maybe move error message within accessor?
Good catch. Will fix but I still prefer to keep the place of vq_err().
Moving error message (if needed) could be done in the future.
Thanks
>
>> @@ -2094,7 +2157,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
>> last_avail_idx = vq->last_avail_idx;
>>
>> if (vq->avail_idx == vq->last_avail_idx) {
>> - if (unlikely(vhost_get_avail(vq, avail_idx, &vq->avail->idx))) {
>> + if (unlikely(vhost_get_avail_idx(vq, &avail_idx))) {
>> vq_err(vq, "Failed to access avail idx at %p\n",
>> &vq->avail->idx);
>> return -EFAULT;
> Same here.
>
>> @@ -2121,8 +2184,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
>>
>> /* Grab the next descriptor number they're advertising, and increment
>> * the index we've seen. */
>> - if (unlikely(vhost_get_avail(vq, ring_head,
>> - &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
>> + if (unlikely(vhost_get_avail_head(vq, &ring_head, last_avail_idx))) {
>> vq_err(vq, "Failed to read head: idx %d address %p\n",
>> last_avail_idx,
>> &vq->avail->ring[last_avail_idx % vq->num]);
>> @@ -2157,8 +2219,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
>> i, vq->num, head);
>> return -EINVAL;
>> }
>> - ret = vhost_copy_from_user(vq, &desc, vq->desc + i,
>> - sizeof desc);
>> + ret = vhost_get_desc(vq, &desc, i);
>> if (unlikely(ret)) {
>> vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
>> i, vq->desc + i);
>> @@ -2251,7 +2312,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
>>
>> start = vq->last_used_idx & (vq->num - 1);
>> used = vq->used->ring + start;
>> - if (vhost_copy_to_user(vq, used, heads, count * sizeof *used)) {
>> + if (vhost_put_used(vq, heads, start, count)) {
>> vq_err(vq, "Failed to write used");
>> return -EFAULT;
>> }
>> @@ -2293,8 +2354,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
>>
>> /* Make sure buffer is written before we update index. */
>> smp_wmb();
>> - if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
>> - &vq->used->idx)) {
>> + if (vhost_put_used_idx(vq)) {
>> vq_err(vq, "Failed to increment used idx");
>> return -EFAULT;
>> }
>> @@ -2327,7 +2387,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
>>
>> if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
>> __virtio16 flags;
>> - if (vhost_get_avail(vq, flags, &vq->avail->flags)) {
>> + if (vhost_get_avail_flags(vq, &flags)) {
>> vq_err(vq, "Failed to get flags");
>> return true;
>> }
>> @@ -2341,7 +2401,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
>> if (unlikely(!v))
>> return true;
>>
>> - if (vhost_get_avail(vq, event, vhost_used_event(vq))) {
>> + if (vhost_get_used_event(vq, &event)) {
>> vq_err(vq, "Failed to get used event idx");
>> return true;
>> }
>> @@ -2386,7 +2446,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
>> if (vq->avail_idx != vq->last_avail_idx)
>> return false;
>>
>> - r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
>> + r = vhost_get_avail_idx(vq, &avail_idx);
>> if (unlikely(r))
>> return false;
>> vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
>> @@ -2422,7 +2482,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
>> /* They could have slipped one in as we were doing that: make
>> * sure it's written, then check again. */
>> smp_mb();
>> - r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
>> + r = vhost_get_avail_idx(vq, &avail_idx);
>> if (r) {
>> vq_err(vq, "Failed to check avail idx at %p: %d\n",
>> &vq->avail->idx, r);
>> --
>> 1.8.3.1
>>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH net-next] failover: allow name change on IFF_UP slave interfaces
From: Liran Alon @ 2019-03-06 23:36 UTC (permalink / raw)
To: si-wei liu
Cc: Jiri Pirko, Michael S. Tsirkin, Jakub Kicinski,
Samudrala, Sridhar, virtualization, Netdev, boris.ostrovsky,
David Miller
In-Reply-To: <7bc9dc90-6597-4223-c192-55a314ff079f@oracle.com>
> On 6 Mar 2019, at 23:42, si-wei liu <si-wei.liu@oracle.com> wrote:
>
>
>
> On 3/6/2019 1:36 PM, Samudrala, Sridhar wrote:
>>
>> On 3/6/2019 1:26 PM, si-wei liu wrote:
>>>
>>>
>>> On 3/6/2019 4:04 AM, Jiri Pirko wrote:
>>>>> --- a/net/core/failover.c
>>>>> +++ b/net/core/failover.c
>>>>> @@ -16,6 +16,11 @@
>>>>>
>>>>> static LIST_HEAD(failover_list);
>>>>> static DEFINE_SPINLOCK(failover_lock);
>>>>> +static bool slave_rename_ok = true;
>>>>> +
>>>>> +module_param(slave_rename_ok, bool, (S_IRUGO | S_IWUSR));
>>>>> +MODULE_PARM_DESC(slave_rename_ok,
>>>>> + "If set allow renaming the slave when failover master is up");
>>>>>
>>>> No module parameters please. If you need to set something do it using
>>>> rtnl_link_ops. Thanks.
>>>>
>>>>
>>> I understand what you ask for, but without module parameters userspace don't work. During boot (dracut) the virtio netdev gets enslaved earlier than when userspace comes up, so failover has to determine the setting during initialization/creation. This config is not dynamic, at least for the life cycle of a particular failover link it shouldn't be changed. Without module parameter, how does the userspace specify this value during kernel initialization?
>>>
>> Can we enable this by default and not make it configurable via module parameter?
>> Is there any usecase where someone expects rename to fail with failover slaves?
> Probably just cater for those application that assumes fixed name on UP interface?
>
> It's already the default for the configurable. I myself don't think that's a big problem for failover users. So far there's not even QEMU support I think everything can be changed. I don't feel strong to just fix it without introducing configurable. But maybe Michael or others think it differently...
>
> If no one objects, I don't feel strong to make it fixed behavior.
>
> -Siwei
>
I agree we should just remove the module parameter.
-Liran
^ permalink raw reply
* Re: [RFC PATCH net-next] failover: allow name change on IFF_UP slave interfaces
From: Samudrala, Sridhar @ 2019-03-06 21:36 UTC (permalink / raw)
To: si-wei liu, Jiri Pirko
Cc: Michael S. Tsirkin, Jakub Kicinski, Netdev, virtualization,
liran.alon, boris.ostrovsky, David Miller
In-Reply-To: <7d1e79f6-01ff-413d-dac0-ee34258aafec@oracle.com>
[-- Attachment #1.1: Type: text/plain, Size: 1218 bytes --]
On 3/6/2019 1:26 PM, si-wei liu wrote:
>
>
>
> On 3/6/2019 4:04 AM, Jiri Pirko wrote:
>>> --- a/net/core/failover.c
>>> +++ b/net/core/failover.c
>>> @@ -16,6 +16,11 @@
>>>
>>> static LIST_HEAD(failover_list);
>>> static DEFINE_SPINLOCK(failover_lock);
>>> +static bool slave_rename_ok = true;
>>> +
>>> +module_param(slave_rename_ok, bool, (S_IRUGO | S_IWUSR));
>>> +MODULE_PARM_DESC(slave_rename_ok,
>>> + "If set allow renaming the slave when failover master is up");
>> No module parameters please. If you need to set something do it using
>> rtnl_link_ops. Thanks.
>>
> I understand what you ask for, but without module parameters userspace
> don't work. During boot (dracut) the virtio netdev gets enslaved
> earlier than when userspace comes up, so failover has to determine the
> setting during initialization/creation. This config is not dynamic, at
> least for the life cycle of a particular failover link it shouldn't be
> changed. Without module parameter, how does the userspace specify this
> value during kernel initialization?
>
Can we enable this by default and not make it configurable via module
parameter?
Is there any usecase where someone expects rename to fail with failover
slaves?
[-- Attachment #1.2: Type: text/html, Size: 1999 bytes --]
[-- Attachment #2: Type: text/plain, Size: 183 bytes --]
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [PATCH] vsock/virtio: fix kernel panic from virtio_transport_reset_no_sock
From: Adalbert Lazăr @ 2019-03-06 17:25 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: kvm, linux-kernel, virtualization, netdev, David S . Miller,
Stefano Garzarella
In-Reply-To: <20190306170216.GC29057@stefanha-x1.localdomain>
On Wed, 6 Mar 2019 17:02:16 +0000, Stefan Hajnoczi <stefanha@redhat.com> wrote:
> On Wed, Mar 06, 2019 at 11:10:41AM +0200, Adalbert Lazăr wrote:
> > On Wed, 6 Mar 2019 08:41:04 +0000, Stefan Hajnoczi <stefanha@gmail.com> wrote:
> > > On Tue, Mar 05, 2019 at 08:01:45PM +0200, Adalbert Lazăr wrote:
> > > The pkt argument is the received packet that we must reply to.
> > > The reply packet is allocated just before line 680 and must be free
> > > explicitly for return -ENOTCONN.
> > >
> > > You can avoid the leak and make the code easier to read like this:
> > >
> > > struct virtio_vsock_pkt *reply;
> > >
> > > ...
> > >
> > > ------ avoid reusing 'pkt'
> > > v
> > > reply = virtio_transport_alloc_pkt(&info, 0, ...);
> > > if (!reply)
> > > return -ENOMEM;
> > >
> > > t = virtio_transport_get_ops();
> > > if (!t) {
> > > virtio_transport_free_pkt(reply); <-- prevent memory leak
> > > return -ENOTCONN;
> > > }
> > > return t->send_pkt(reply);
> >
> > What do you think about Stefano's suggestion, to move the check above
> > the line were the reply is allocated?
>
> That's fine too.
>
> However a follow up patch to eliminate the confusing way that 'pkt' is
> reused is still warranted. If you are busy I'd be happy to send that
> cleanup.
>
> Stefan
I've got it, a couple of minutes after I've replied :)
The second version[1] should be in your mailbox.
Thank you,
Adalbert
[1]: https://patchwork.kernel.org/patch/10840787/
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [PATCH] vsock/virtio: fix kernel panic from virtio_transport_reset_no_sock
From: Stefan Hajnoczi @ 2019-03-06 17:02 UTC (permalink / raw)
To: Adalbert Lazăr
Cc: kvm, linux-kernel, virtualization, netdev, David S . Miller,
Stefano Garzarella
In-Reply-To: <1551863441.5559.19509.@c1753101230bd75c4bdbfe8f0947046bcaf69c6c>
[-- Attachment #1.1: Type: text/plain, Size: 1201 bytes --]
On Wed, Mar 06, 2019 at 11:10:41AM +0200, Adalbert Lazăr wrote:
> On Wed, 6 Mar 2019 08:41:04 +0000, Stefan Hajnoczi <stefanha@gmail.com> wrote:
> > On Tue, Mar 05, 2019 at 08:01:45PM +0200, Adalbert Lazăr wrote:
> > The pkt argument is the received packet that we must reply to.
> > The reply packet is allocated just before line 680 and must be free
> > explicitly for return -ENOTCONN.
> >
> > You can avoid the leak and make the code easier to read like this:
> >
> > struct virtio_vsock_pkt *reply;
> >
> > ...
> >
> > ------ avoid reusing 'pkt'
> > v
> > reply = virtio_transport_alloc_pkt(&info, 0, ...);
> > if (!reply)
> > return -ENOMEM;
> >
> > t = virtio_transport_get_ops();
> > if (!t) {
> > virtio_transport_free_pkt(reply); <-- prevent memory leak
> > return -ENOTCONN;
> > }
> > return t->send_pkt(reply);
>
> What do you think about Stefano's suggestion, to move the check above
> the line were the reply is allocated?
That's fine too.
However a follow up patch to eliminate the confusing way that 'pkt' is
reused is still warranted. If you are busy I'd be happy to send that
cleanup.
Stefan
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
[-- Attachment #2: Type: text/plain, Size: 183 bytes --]
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [RFC PATCH V2 5/5] vhost: access vq metadata through kernel virtual address
From: Michael S. Tsirkin @ 2019-03-06 16:31 UTC (permalink / raw)
To: Jason Wang; +Cc: aarcange, kvm, netdev, linux-kernel, virtualization, linux-mm
In-Reply-To: <1551856692-3384-6-git-send-email-jasowang@redhat.com>
On Wed, Mar 06, 2019 at 02:18:12AM -0500, Jason Wang wrote:
> It was noticed that the copy_user() friends that was used to access
> virtqueue metdata tends to be very expensive for dataplane
> implementation like vhost since it involves lots of software checks,
> speculation barrier, hardware feature toggling (e.g SMAP). The
> extra cost will be more obvious when transferring small packets since
> the time spent on metadata accessing become more significant.
>
> This patch tries to eliminate those overheads by accessing them
> through kernel virtual address by vmap(). To make the pages can be
> migrated, instead of pinning them through GUP, we use MMU notifiers to
> invalidate vmaps and re-establish vmaps during each round of metadata
> prefetching if necessary. It looks to me .invalidate_range() is
> sufficient for catching this since we don't need extra TLB flush. For
> devices that doesn't use metadata prefetching, the memory accessors
> fallback to normal copy_user() implementation gracefully. The
> invalidation was synchronized with datapath through vq mutex, and in
> order to avoid hold vq mutex during range checking, MMU notifier was
> teared down when trying to modify vq metadata.
>
> Dirty page checking is done by calling set_page_dirty_locked()
> explicitly for the page that used ring stay after each round of
> processing.
>
> Note that this was only done when device IOTLB is not enabled. We
> could use similar method to optimize it in the future.
>
> Tests shows at most about 22% improvement on TX PPS when using
> virtio-user + vhost_net + xdp1 + TAP on 2.6GHz Broadwell:
>
> SMAP on | SMAP off
> Before: 5.0Mpps | 6.6Mpps
> After: 6.1Mpps | 7.4Mpps
>
> Cc: <linux-mm@kvack.org>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/vhost/net.c | 2 +
> drivers/vhost/vhost.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++-
> drivers/vhost/vhost.h | 16 +++
> 3 files changed, 297 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index bf55f99..c276371 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -982,6 +982,7 @@ static void handle_tx(struct vhost_net *net)
> else
> handle_tx_copy(net, sock);
>
> + vq_meta_prefetch_done(vq);
> out:
> mutex_unlock(&vq->mutex);
> }
> @@ -1250,6 +1251,7 @@ static void handle_rx(struct vhost_net *net)
> vhost_net_enable_vq(net, vq);
> out:
> vhost_net_signal_used(nvq);
> + vq_meta_prefetch_done(vq);
> mutex_unlock(&vq->mutex);
> }
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index 1015464..36ccf7c 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -434,6 +434,74 @@ static size_t vhost_get_desc_size(struct vhost_virtqueue *vq, int num)
> return sizeof(*vq->desc) * num;
> }
>
> +static void vhost_uninit_vmap(struct vhost_vmap *map)
> +{
> + if (map->addr) {
> + vunmap(map->unmap_addr);
> + kfree(map->pages);
> + map->pages = NULL;
> + map->npages = 0;
> + }
> +
> + map->addr = NULL;
> + map->unmap_addr = NULL;
> +}
> +
> +static void vhost_invalidate_vmap(struct vhost_virtqueue *vq,
> + struct vhost_vmap *map,
> + unsigned long ustart,
> + size_t size,
> + unsigned long start,
> + unsigned long end)
> +{
> + if (end < ustart || start > ustart - 1 + size)
> + return;
> +
> + dump_stack();
> + mutex_lock(&vq->mutex);
> + vhost_uninit_vmap(map);
> + mutex_unlock(&vq->mutex);
> +}
> +
> +
> +static void vhost_invalidate(struct vhost_dev *dev,
> + unsigned long start, unsigned long end)
> +{
> + int i;
> +
> + for (i = 0; i < dev->nvqs; i++) {
> + struct vhost_virtqueue *vq = dev->vqs[i];
> +
> + vhost_invalidate_vmap(vq, &vq->avail_ring,
> + (unsigned long)vq->avail,
> + vhost_get_avail_size(vq, vq->num),
> + start, end);
> + vhost_invalidate_vmap(vq, &vq->desc_ring,
> + (unsigned long)vq->desc,
> + vhost_get_desc_size(vq, vq->num),
> + start, end);
> + vhost_invalidate_vmap(vq, &vq->used_ring,
> + (unsigned long)vq->used,
> + vhost_get_used_size(vq, vq->num),
> + start, end);
> + }
> +}
> +
> +
> +static void vhost_invalidate_range(struct mmu_notifier *mn,
> + struct mm_struct *mm,
> + unsigned long start, unsigned long end)
> +{
> + struct vhost_dev *dev = container_of(mn, struct vhost_dev,
> + mmu_notifier);
> +
> + vhost_invalidate(dev, start, end);
> +}
> +
> +static const struct mmu_notifier_ops vhost_mmu_notifier_ops = {
> + .invalidate_range = vhost_invalidate_range,
> +};
> +
> void vhost_dev_init(struct vhost_dev *dev,
> struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
> {
Note that
.invalidate_range seems to be called after page lock has
been dropped.
Looking at page dirty below:
> @@ -449,6 +517,7 @@ void vhost_dev_init(struct vhost_dev *dev,
> dev->mm = NULL;
> dev->worker = NULL;
> dev->iov_limit = iov_limit;
> + dev->mmu_notifier.ops = &vhost_mmu_notifier_ops;
> init_llist_head(&dev->work_list);
> init_waitqueue_head(&dev->wait);
> INIT_LIST_HEAD(&dev->read_list);
> @@ -462,6 +531,9 @@ void vhost_dev_init(struct vhost_dev *dev,
> vq->indirect = NULL;
> vq->heads = NULL;
> vq->dev = dev;
> + vq->avail_ring.addr = NULL;
> + vq->used_ring.addr = NULL;
> + vq->desc_ring.addr = NULL;
> mutex_init(&vq->mutex);
> vhost_vq_reset(dev, vq);
> if (vq->handle_kick)
> @@ -542,7 +614,13 @@ long vhost_dev_set_owner(struct vhost_dev *dev)
> if (err)
> goto err_cgroup;
>
> + err = mmu_notifier_register(&dev->mmu_notifier, dev->mm);
> + if (err)
> + goto err_mmu_notifier;
> +
> return 0;
> +err_mmu_notifier:
> + vhost_dev_free_iovecs(dev);
> err_cgroup:
> kthread_stop(worker);
> dev->worker = NULL;
> @@ -633,6 +711,81 @@ static void vhost_clear_msg(struct vhost_dev *dev)
> spin_unlock(&dev->iotlb_lock);
> }
>
> +static int vhost_init_vmap(struct vhost_dev *dev,
> + struct vhost_vmap *map, unsigned long uaddr,
> + size_t size, int write)
> +{
> + struct page **pages;
> + int npages = DIV_ROUND_UP(size, PAGE_SIZE);
> + int npinned;
> + void *vaddr;
> + int err = -EFAULT;
> +
> + err = -ENOMEM;
> + pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
> + if (!pages)
> + goto err_uaddr;
> +
> + err = EFAULT;
> + npinned = get_user_pages_fast(uaddr, npages, write, pages);
> + if (npinned != npages)
> + goto err_gup;
> +
> + vaddr = vmap(pages, npages, VM_MAP, PAGE_KERNEL);
> + if (!vaddr)
> + goto err_gup;
> +
> + map->addr = vaddr + (uaddr & (PAGE_SIZE - 1));
> + map->unmap_addr = vaddr;
> + map->npages = npages;
> + map->pages = pages;
> +
> +err_gup:
> + /* Don't pin pages, mmu notifier will notify us about page
> + * migration.
> + */
> + if (npinned > 0)
> + release_pages(pages, npinned);
> +err_uaddr:
> + return err;
> +}
> +
> +static void vhost_uninit_vq_vmaps(struct vhost_virtqueue *vq)
> +{
> + vhost_uninit_vmap(&vq->avail_ring);
> + vhost_uninit_vmap(&vq->desc_ring);
> + vhost_uninit_vmap(&vq->used_ring);
> +}
> +
> +static int vhost_setup_avail_vmap(struct vhost_virtqueue *vq,
> + unsigned long avail)
> +{
> + return vhost_init_vmap(vq->dev, &vq->avail_ring, avail,
> + vhost_get_avail_size(vq, vq->num), false);
> +}
> +
> +static int vhost_setup_desc_vmap(struct vhost_virtqueue *vq,
> + unsigned long desc)
> +{
> + return vhost_init_vmap(vq->dev, &vq->desc_ring, desc,
> + vhost_get_desc_size(vq, vq->num), false);
> +}
> +
> +static int vhost_setup_used_vmap(struct vhost_virtqueue *vq,
> + unsigned long used)
> +{
> + return vhost_init_vmap(vq->dev, &vq->used_ring, used,
> + vhost_get_used_size(vq, vq->num), true);
> +}
> +
> +static void vhost_set_vmap_dirty(struct vhost_vmap *used)
> +{
> + int i;
> +
> + for (i = 0; i < used->npages; i++)
> + set_page_dirty_lock(used->pages[i]);
This seems to rely on page lock to mark page dirty.
Could it happen that page writeback will check the
page, find it clean, and then you mark it dirty and then
invalidate callback is called?
> +}
> +
> void vhost_dev_cleanup(struct vhost_dev *dev)
> {
> int i;
> @@ -662,8 +815,12 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
> kthread_stop(dev->worker);
> dev->worker = NULL;
> }
> - if (dev->mm)
> + for (i = 0; i < dev->nvqs; i++)
> + vhost_uninit_vq_vmaps(dev->vqs[i]);
> + if (dev->mm) {
> + mmu_notifier_unregister(&dev->mmu_notifier, dev->mm);
> mmput(dev->mm);
> + }
> dev->mm = NULL;
> }
> EXPORT_SYMBOL_GPL(vhost_dev_cleanup);
> @@ -892,6 +1049,16 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
>
> static inline int vhost_put_avail_event(struct vhost_virtqueue *vq)
> {
> + if (!vq->iotlb) {
> + struct vring_used *used = vq->used_ring.addr;
> +
> + if (likely(used)) {
> + *((__virtio16 *)&used->ring[vq->num]) =
> + cpu_to_vhost16(vq, vq->avail_idx);
> + return 0;
> + }
> + }
> +
> return vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
> vhost_avail_event(vq));
> }
> @@ -900,6 +1067,16 @@ static inline int vhost_put_used(struct vhost_virtqueue *vq,
> struct vring_used_elem *head, int idx,
> int count)
> {
> + if (!vq->iotlb) {
> + struct vring_used *used = vq->used_ring.addr;
> +
> + if (likely(used)) {
> + memcpy(used->ring + idx, head,
> + count * sizeof(*head));
> + return 0;
> + }
> + }
> +
> return vhost_copy_to_user(vq, vq->used->ring + idx, head,
> count * sizeof(*head));
> }
> @@ -907,6 +1084,15 @@ static inline int vhost_put_used(struct vhost_virtqueue *vq,
> static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
>
> {
> + if (!vq->iotlb) {
> + struct vring_used *used = vq->used_ring.addr;
> +
> + if (likely(used)) {
> + used->flags = cpu_to_vhost16(vq, vq->used_flags);
> + return 0;
> + }
> + }
> +
> return vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
> &vq->used->flags);
> }
> @@ -914,6 +1100,15 @@ static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
> static inline int vhost_put_used_idx(struct vhost_virtqueue *vq)
>
> {
> + if (!vq->iotlb) {
> + struct vring_used *used = vq->used_ring.addr;
> +
> + if (likely(used)) {
> + used->idx = cpu_to_vhost16(vq, vq->last_used_idx);
> + return 0;
> + }
> + }
> +
> return vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
> &vq->used->idx);
> }
> @@ -959,12 +1154,30 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d)
> static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
> __virtio16 *idx)
> {
> + if (!vq->iotlb) {
> + struct vring_avail *avail = vq->avail_ring.addr;
> +
> + if (likely(avail)) {
> + *idx = avail->idx;
> + return 0;
> + }
> + }
> +
> return vhost_get_avail(vq, *idx, &vq->avail->idx);
> }
>
> static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
> __virtio16 *head, int idx)
> {
> + if (!vq->iotlb) {
> + struct vring_avail *avail = vq->avail_ring.addr;
> +
> + if (likely(avail)) {
> + *head = avail->ring[idx & (vq->num - 1)];
> + return 0;
> + }
> + }
> +
> return vhost_get_avail(vq, *head,
> &vq->avail->ring[idx & (vq->num - 1)]);
> }
> @@ -972,24 +1185,60 @@ static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
> static inline int vhost_get_avail_flags(struct vhost_virtqueue *vq,
> __virtio16 *flags)
> {
> + if (!vq->iotlb) {
> + struct vring_avail *avail = vq->avail_ring.addr;
> +
> + if (likely(avail)) {
> + *flags = avail->flags;
> + return 0;
> + }
> + }
> +
> return vhost_get_avail(vq, *flags, &vq->avail->flags);
> }
>
> static inline int vhost_get_used_event(struct vhost_virtqueue *vq,
> __virtio16 *event)
> {
> + if (!vq->iotlb) {
> + struct vring_avail *avail = vq->avail_ring.addr;
> +
> + if (likely(avail)) {
> + *event = (__virtio16)avail->ring[vq->num];
> + return 0;
> + }
> + }
> +
> return vhost_get_avail(vq, *event, vhost_used_event(vq));
> }
>
> static inline int vhost_get_used_idx(struct vhost_virtqueue *vq,
> __virtio16 *idx)
> {
> + if (!vq->iotlb) {
> + struct vring_used *used = vq->used_ring.addr;
> +
> + if (likely(used)) {
> + *idx = used->idx;
> + return 0;
> + }
> + }
> +
> return vhost_get_used(vq, *idx, &vq->used->idx);
> }
>
> static inline int vhost_get_desc(struct vhost_virtqueue *vq,
> struct vring_desc *desc, int idx)
> {
> + if (!vq->iotlb) {
> + struct vring_desc *d = vq->desc_ring.addr;
> +
> + if (likely(d)) {
> + *desc = *(d + idx);
> + return 0;
> + }
> + }
> +
> return vhost_copy_from_user(vq, desc, vq->desc + idx, sizeof(*desc));
> }
>
> @@ -1330,8 +1579,16 @@ int vq_meta_prefetch(struct vhost_virtqueue *vq)
> {
> unsigned int num = vq->num;
>
> - if (!vq->iotlb)
> + if (!vq->iotlb) {
> + if (unlikely(!vq->avail_ring.addr))
> + vhost_setup_avail_vmap(vq, (unsigned long)vq->avail);
> + if (unlikely(!vq->desc_ring.addr))
> + vhost_setup_desc_vmap(vq, (unsigned long)vq->desc);
> + if (unlikely(!vq->used_ring.addr))
> + vhost_setup_used_vmap(vq, (unsigned long)vq->used);
> +
> return 1;
> + }
>
> return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
> vhost_get_desc_size(vq, num), VHOST_ADDR_DESC) &&
> @@ -1343,6 +1600,15 @@ int vq_meta_prefetch(struct vhost_virtqueue *vq)
> }
> EXPORT_SYMBOL_GPL(vq_meta_prefetch);
>
> +void vq_meta_prefetch_done(struct vhost_virtqueue *vq)
> +{
> + if (vq->iotlb)
> + return;
> + if (likely(vq->used_ring.addr))
> + vhost_set_vmap_dirty(&vq->used_ring);
> +}
> +EXPORT_SYMBOL_GPL(vq_meta_prefetch_done);
> +
> /* Can we log writes? */
> /* Caller should have device mutex but not vq mutex */
> bool vhost_log_access_ok(struct vhost_dev *dev)
> @@ -1483,6 +1749,13 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
>
> mutex_lock(&vq->mutex);
>
> + /* Unregister MMU notifer to allow invalidation callback
> + * can access vq->avail, vq->desc , vq->used and vq->num
> + * without holding vq->mutex.
> + */
> + if (d->mm)
> + mmu_notifier_unregister(&d->mmu_notifier, d->mm);
> +
> switch (ioctl) {
> case VHOST_SET_VRING_NUM:
> /* Resizing ring with an active backend?
> @@ -1499,6 +1772,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
> r = -EINVAL;
> break;
> }
> + vhost_uninit_vq_vmaps(vq);
> vq->num = s.num;
> break;
> case VHOST_SET_VRING_BASE:
> @@ -1581,6 +1855,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
> vq->avail = (void __user *)(unsigned long)a.avail_user_addr;
> vq->log_addr = a.log_guest_addr;
> vq->used = (void __user *)(unsigned long)a.used_user_addr;
> + vhost_uninit_vq_vmaps(vq);
> break;
> case VHOST_SET_VRING_KICK:
> if (copy_from_user(&f, argp, sizeof f)) {
> @@ -1656,6 +1931,8 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
> if (pollstart && vq->handle_kick)
> r = vhost_poll_start(&vq->poll, vq->kick);
>
> + if (d->mm)
> + mmu_notifier_register(&d->mmu_notifier, d->mm);
> mutex_unlock(&vq->mutex);
>
> if (pollstop && vq->handle_kick)
> diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
> index 7a7fc00..146076e 100644
> --- a/drivers/vhost/vhost.h
> +++ b/drivers/vhost/vhost.h
> @@ -12,6 +12,8 @@
> #include <linux/virtio_config.h>
> #include <linux/virtio_ring.h>
> #include <linux/atomic.h>
> +#include <linux/pagemap.h>
> +#include <linux/mmu_notifier.h>
>
> struct vhost_work;
> typedef void (*vhost_work_fn_t)(struct vhost_work *work);
> @@ -80,6 +82,13 @@ enum vhost_uaddr_type {
> VHOST_NUM_ADDRS = 3,
> };
>
> +struct vhost_vmap {
> + void *addr;
> + void *unmap_addr;
> + int npages;
> + struct page **pages;
> +};
> +
> /* The virtqueue structure describes a queue attached to a device. */
> struct vhost_virtqueue {
> struct vhost_dev *dev;
> @@ -90,6 +99,11 @@ struct vhost_virtqueue {
> struct vring_desc __user *desc;
> struct vring_avail __user *avail;
> struct vring_used __user *used;
> +
> + struct vhost_vmap avail_ring;
> + struct vhost_vmap desc_ring;
> + struct vhost_vmap used_ring;
> +
> const struct vhost_umem_node *meta_iotlb[VHOST_NUM_ADDRS];
> struct file *kick;
> struct eventfd_ctx *call_ctx;
> @@ -158,6 +172,7 @@ struct vhost_msg_node {
>
> struct vhost_dev {
> struct mm_struct *mm;
> + struct mmu_notifier mmu_notifier;
> struct mutex mutex;
> struct vhost_virtqueue **vqs;
> int nvqs;
> @@ -210,6 +225,7 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
> unsigned int log_num, u64 len,
> struct iovec *iov, int count);
> int vq_meta_prefetch(struct vhost_virtqueue *vq);
> +void vq_meta_prefetch_done(struct vhost_virtqueue *vq);
>
> struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type);
> void vhost_enqueue_msg(struct vhost_dev *dev,
> --
> 1.8.3.1
^ permalink raw reply
* Re: [RFC PATCH net-next] failover: allow name change on IFF_UP slave interfaces
From: Jiri Pirko @ 2019-03-06 12:04 UTC (permalink / raw)
To: Si-Wei Liu
Cc: Michael S. Tsirkin, Jakub Kicinski, Sridhar Samudrala,
virtualization, liran.alon, Netdev, boris.ostrovsky, David Miller
In-Reply-To: <1551747059-11831-1-git-send-email-si-wei.liu@oracle.com>
Tue, Mar 05, 2019 at 01:50:59AM CET, si-wei.liu@oracle.com wrote:
>When a netdev appears through hot plug then gets enslaved by a failover
>master that is already up and running, the slave will be opened
>right away after getting enslaved. Today there's a race that userspace
>(udev) may fail to rename the slave if the kernel (net_failover)
>opens the slave earlier than when the userspace rename happens.
>Unlike bond or team, the primary slave of failover can't be renamed by
>userspace ahead of time, since the kernel initiated auto-enslavement is
>unable to, or rather, is never meant to be synchronized with the rename
>request from userspace.
>
>As the failover slave interfaces are not designed to be operated
>directly by userspace apps: IP configuration, filter rules with
>regard to network traffic passing and etc., should all be done on master
>interface. In general, userspace apps only care about the
>name of master interface, while slave names are less important as long
>as admin users can see reliable names that may carry
>other information describing the netdev. For e.g., they can infer that
>"ens3nsby" is a standby slave of "ens3", while for a
>name like "eth0" they can't tell which master it belongs to.
>
>Historically the name of IFF_UP interface can't be changed because
>there might be admin script or management software that is already
>relying on such behavior and assumes that the slave name can't be
>changed once UP. But failover is special: with the in-kernel
>auto-enslavement mechanism, the userspace expectation for device
>enumeration and bring-up order is already broken. Previously initramfs
>and various userspace config tools were modified to bypass failover
>slaves because of auto-enslavement and duplicate MAC address. Similarly,
>in case that users care about seeing reliable slave name, the new type
>of failover slaves needs to be taken care of specifically in userspace
>anyway.
>
>For that to work, now introduce a module-level tunable,
>"slave_rename_ok" that allows users to lift up the rename restriction on
>failover slave which is already UP. Although it's possible this change
>potentially break userspace component (most likely configuration scripts
>or management software) that assumes slave name can't be changed while
>UP, it's relatively a limited and controllable set among all userspace
>components, which can be fixed specifically to work with the new naming
>behavior of the failover slave. Userspace component interacting with
>slaves should be changed to operate on failover master instead, as the
>failover slave is dynamic in nature which may come and go at any point.
>The goal is to make the role of failover slaves less relevant, and
>all userspace should only deal with master in the long run. The default
>for the "slave_rename_ok" is set to true(1). If userspace doesn't have
>the right support in place meanwhile users don't care about reliable
>userspace naming, the value can be set to false(0).
>
>Signed-off-by: Si-Wei.Liu@oracle.com
>Reviewed-by: Liran Alon <liran.alon@oracle.com>
>---
> include/linux/netdevice.h | 3 +++
> net/core/dev.c | 3 ++-
> net/core/failover.c | 11 +++++++++--
> 3 files changed, 14 insertions(+), 3 deletions(-)
>
>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>index 857f8ab..6d9e4e0 100644
>--- a/include/linux/netdevice.h
>+++ b/include/linux/netdevice.h
>@@ -1487,6 +1487,7 @@ struct net_device_ops {
> * @IFF_NO_RX_HANDLER: device doesn't support the rx_handler hook
> * @IFF_FAILOVER: device is a failover master device
> * @IFF_FAILOVER_SLAVE: device is lower dev of a failover master device
>+ * @IFF_SLAVE_RENAME_OK: rename is allowed while slave device is running
> */
> enum netdev_priv_flags {
> IFF_802_1Q_VLAN = 1<<0,
>@@ -1518,6 +1519,7 @@ enum netdev_priv_flags {
> IFF_NO_RX_HANDLER = 1<<26,
> IFF_FAILOVER = 1<<27,
> IFF_FAILOVER_SLAVE = 1<<28,
>+ IFF_SLAVE_RENAME_OK = 1<<29,
> };
>
> #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
>@@ -1548,6 +1550,7 @@ enum netdev_priv_flags {
> #define IFF_NO_RX_HANDLER IFF_NO_RX_HANDLER
> #define IFF_FAILOVER IFF_FAILOVER
> #define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
>+#define IFF_SLAVE_RENAME_OK IFF_SLAVE_RENAME_OK
>
> /**
> * struct net_device - The DEVICE structure.
>diff --git a/net/core/dev.c b/net/core/dev.c
>index 722d50d..ae070de 100644
>--- a/net/core/dev.c
>+++ b/net/core/dev.c
>@@ -1180,7 +1180,8 @@ int dev_change_name(struct net_device *dev, const char *newname)
> BUG_ON(!dev_net(dev));
>
> net = dev_net(dev);
>- if (dev->flags & IFF_UP)
>+ if (dev->flags & IFF_UP &&
>+ !(dev->priv_flags & IFF_SLAVE_RENAME_OK))
> return -EBUSY;
>
> write_seqcount_begin(&devnet_rename_seq);
>diff --git a/net/core/failover.c b/net/core/failover.c
>index 4a92a98..1fd8bbb 100644
>--- a/net/core/failover.c
>+++ b/net/core/failover.c
>@@ -16,6 +16,11 @@
>
> static LIST_HEAD(failover_list);
> static DEFINE_SPINLOCK(failover_lock);
>+static bool slave_rename_ok = true;
>+
>+module_param(slave_rename_ok, bool, (S_IRUGO | S_IWUSR));
>+MODULE_PARM_DESC(slave_rename_ok,
>+ "If set allow renaming the slave when failover master is up");
No module parameters please. If you need to set something do it using
rtnl_link_ops. Thanks.
>
> static struct net_device *failover_get_bymac(u8 *mac, struct failover_ops **ops)
> {
>@@ -81,13 +86,15 @@ static int failover_slave_register(struct net_device *slave_dev)
> }
>
> slave_dev->priv_flags |= IFF_FAILOVER_SLAVE;
>+ if (slave_rename_ok)
>+ slave_dev->priv_flags |= IFF_SLAVE_RENAME_OK;
>
> if (fops && fops->slave_register &&
> !fops->slave_register(slave_dev, failover_dev))
> return NOTIFY_OK;
>
> netdev_upper_dev_unlink(slave_dev, failover_dev);
>- slave_dev->priv_flags &= ~IFF_FAILOVER_SLAVE;
>+ slave_dev->priv_flags &= ~(IFF_FAILOVER_SLAVE | IFF_SLAVE_RENAME_OK);
> err_upper_link:
> netdev_rx_handler_unregister(slave_dev);
> done:
>@@ -121,7 +128,7 @@ int failover_slave_unregister(struct net_device *slave_dev)
>
> netdev_rx_handler_unregister(slave_dev);
> netdev_upper_dev_unlink(slave_dev, failover_dev);
>- slave_dev->priv_flags &= ~IFF_FAILOVER_SLAVE;
>+ slave_dev->priv_flags &= ~(IFF_FAILOVER_SLAVE | IFF_SLAVE_RENAME_OK);
>
> if (fops && fops->slave_unregister &&
> !fops->slave_unregister(slave_dev, failover_dev))
>--
>1.8.3.1
>
^ permalink raw reply
* [PATCH] vhost: silence an unused-variable warning
From: Arnd Bergmann @ 2019-03-06 11:05 UTC (permalink / raw)
To: Michael S. Tsirkin, Jason Wang
Cc: kvm, Arnd Bergmann, netdev, linux-kernel, virtualization,
Stefan Hajnoczi, David S. Miller
On some architectures, the MMU can be disabled, leading to access_ok()
becoming an empty macro that does not evaluate its size argument,
which in turn produces an unused-variable warning:
drivers/vhost/vhost.c:1191:9: error: unused variable 's' [-Werror,-Wunused-variable]
size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
Mark the variable as __maybe_unused to shut up that warning.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/vhost/vhost.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index a2e5dc7716e2..5ace833de746 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1188,7 +1188,7 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
struct vring_used __user *used)
{
- size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
+ size_t s __maybe_unused = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
return access_ok(desc, num * sizeof *desc) &&
access_ok(avail,
--
2.20.0
^ permalink raw reply related
* Re: [RFC PATCH V2 4/5] vhost: introduce helpers to get the size of metadata area
From: Christophe de Dinechin @ 2019-03-06 10:56 UTC (permalink / raw)
To: Jason Wang
Cc: aarcange, kvm, mst, netdev, linux-kernel, virtualization,
linux-mm
In-Reply-To: <1551856692-3384-5-git-send-email-jasowang@redhat.com>
> On 6 Mar 2019, at 08:18, Jason Wang <jasowang@redhat.com> wrote:
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/vhost/vhost.c | 46 ++++++++++++++++++++++++++++------------------
> 1 file changed, 28 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index 2025543..1015464 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -413,6 +413,27 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev)
> vhost_vq_free_iovecs(dev->vqs[i]);
> }
>
> +static size_t vhost_get_avail_size(struct vhost_virtqueue *vq, int num)
Nit: Any reason not to make `num` unsigned or size_t?
> +{
> + size_t event = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
> +
> + return sizeof(*vq->avail) +
> + sizeof(*vq->avail->ring) * num + event;
> +}
> +
> +static size_t vhost_get_used_size(struct vhost_virtqueue *vq, int num)
> +{
> + size_t event = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
> +
> + return sizeof(*vq->used) +
> + sizeof(*vq->used->ring) * num + event;
> +}
> +
> +static size_t vhost_get_desc_size(struct vhost_virtqueue *vq, int num)
> +{
> + return sizeof(*vq->desc) * num;
> +}
> +
> void vhost_dev_init(struct vhost_dev *dev,
> struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
> {
> @@ -1253,13 +1274,9 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
> struct vring_used __user *used)
>
> {
> - size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
> -
> - return access_ok(desc, num * sizeof *desc) &&
> - access_ok(avail,
> - sizeof *avail + num * sizeof *avail->ring + s) &&
> - access_ok(used,
> - sizeof *used + num * sizeof *used->ring + s);
> + return access_ok(desc, vhost_get_desc_size(vq, num)) &&
> + access_ok(avail, vhost_get_avail_size(vq, num)) &&
> + access_ok(used, vhost_get_used_size(vq, num));
> }
>
> static void vhost_vq_meta_update(struct vhost_virtqueue *vq,
> @@ -1311,22 +1328,18 @@ static bool iotlb_access_ok(struct vhost_virtqueue *vq,
>
> int vq_meta_prefetch(struct vhost_virtqueue *vq)
> {
> - size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
> unsigned int num = vq->num;
>
> if (!vq->iotlb)
> return 1;
>
> return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc,
> - num * sizeof(*vq->desc), VHOST_ADDR_DESC) &&
> + vhost_get_desc_size(vq, num), VHOST_ADDR_DESC) &&
> iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->avail,
> - sizeof *vq->avail +
> - num * sizeof(*vq->avail->ring) + s,
> + vhost_get_avail_size(vq, num),
> VHOST_ADDR_AVAIL) &&
> iotlb_access_ok(vq, VHOST_ACCESS_WO, (u64)(uintptr_t)vq->used,
> - sizeof *vq->used +
> - num * sizeof(*vq->used->ring) + s,
> - VHOST_ADDR_USED);
> + vhost_get_used_size(vq, num), VHOST_ADDR_USED);
> }
> EXPORT_SYMBOL_GPL(vq_meta_prefetch);
>
> @@ -1343,13 +1356,10 @@ bool vhost_log_access_ok(struct vhost_dev *dev)
> static bool vq_log_access_ok(struct vhost_virtqueue *vq,
> void __user *log_base)
> {
> - size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
> -
> return vq_memory_access_ok(log_base, vq->umem,
> vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
> (!vq->log_used || log_access_ok(log_base, vq->log_addr,
> - sizeof *vq->used +
> - vq->num * sizeof *vq->used->ring + s));
> + vhost_get_used_size(vq, vq->num)));
> }
>
> /* Can we start vq? */
> --
> 1.8.3.1
>
^ permalink raw reply
* Re: [RFC PATCH V2 2/5] vhost: fine grain userspace memory accessors
From: Christophe de Dinechin @ 2019-03-06 10:45 UTC (permalink / raw)
To: Jason Wang
Cc: aarcange, KVM list, Michael S. Tsirkin, netdev, open list,
open list:VIRTIO GPU DRIVER, linux-mm
In-Reply-To: <1551856692-3384-3-git-send-email-jasowang@redhat.com>
> On 6 Mar 2019, at 08:18, Jason Wang <jasowang@redhat.com> wrote:
>
> This is used to hide the metadata address from virtqueue helpers. This
> will allow to implement a vmap based fast accessing to metadata.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/vhost/vhost.c | 94 +++++++++++++++++++++++++++++++++++++++++----------
> 1 file changed, 77 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
> index 400aa78..29709e7 100644
> --- a/drivers/vhost/vhost.c
> +++ b/drivers/vhost/vhost.c
> @@ -869,6 +869,34 @@ static inline void __user *__vhost_get_user(struct vhost_virtqueue *vq,
> ret; \
> })
>
> +static inline int vhost_put_avail_event(struct vhost_virtqueue *vq)
> +{
> + return vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
> + vhost_avail_event(vq));
> +}
> +
> +static inline int vhost_put_used(struct vhost_virtqueue *vq,
> + struct vring_used_elem *head, int idx,
> + int count)
> +{
> + return vhost_copy_to_user(vq, vq->used->ring + idx, head,
> + count * sizeof(*head));
> +}
> +
> +static inline int vhost_put_used_flags(struct vhost_virtqueue *vq)
> +
> +{
> + return vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
> + &vq->used->flags);
> +}
> +
> +static inline int vhost_put_used_idx(struct vhost_virtqueue *vq)
> +
> +{
> + return vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
> + &vq->used->idx);
> +}
> +
> #define vhost_get_user(vq, x, ptr, type) \
> ({ \
> int ret; \
> @@ -907,6 +935,43 @@ static void vhost_dev_unlock_vqs(struct vhost_dev *d)
> mutex_unlock(&d->vqs[i]->mutex);
> }
>
> +static inline int vhost_get_avail_idx(struct vhost_virtqueue *vq,
> + __virtio16 *idx)
> +{
> + return vhost_get_avail(vq, *idx, &vq->avail->idx);
> +}
> +
> +static inline int vhost_get_avail_head(struct vhost_virtqueue *vq,
> + __virtio16 *head, int idx)
> +{
> + return vhost_get_avail(vq, *head,
> + &vq->avail->ring[idx & (vq->num - 1)]);
> +}
> +
> +static inline int vhost_get_avail_flags(struct vhost_virtqueue *vq,
> + __virtio16 *flags)
> +{
> + return vhost_get_avail(vq, *flags, &vq->avail->flags);
> +}
> +
> +static inline int vhost_get_used_event(struct vhost_virtqueue *vq,
> + __virtio16 *event)
> +{
> + return vhost_get_avail(vq, *event, vhost_used_event(vq));
> +}
> +
> +static inline int vhost_get_used_idx(struct vhost_virtqueue *vq,
> + __virtio16 *idx)
> +{
> + return vhost_get_used(vq, *idx, &vq->used->idx);
> +}
> +
> +static inline int vhost_get_desc(struct vhost_virtqueue *vq,
> + struct vring_desc *desc, int idx)
> +{
> + return vhost_copy_from_user(vq, desc, vq->desc + idx, sizeof(*desc));
> +}
> +
> static int vhost_new_umem_range(struct vhost_umem *umem,
> u64 start, u64 size, u64 end,
> u64 userspace_addr, int perm)
> @@ -1840,8 +1905,7 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
> static int vhost_update_used_flags(struct vhost_virtqueue *vq)
> {
> void __user *used;
> - if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags),
> - &vq->used->flags) < 0)
> + if (vhost_put_used_flags(vq))
> return -EFAULT;
> if (unlikely(vq->log_used)) {
> /* Make sure the flag is seen before log. */
> @@ -1858,8 +1922,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
>
> static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
> {
> - if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx),
> - vhost_avail_event(vq)))
> + if (vhost_put_avail_event(vq))
> return -EFAULT;
> if (unlikely(vq->log_used)) {
> void __user *used;
> @@ -1895,7 +1958,7 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq)
> r = -EFAULT;
> goto err;
> }
> - r = vhost_get_used(vq, last_used_idx, &vq->used->idx);
> + r = vhost_get_used_idx(vq, &last_used_idx);
> if (r) {
> vq_err(vq, "Can't access used idx at %p\n",
> &vq->used->idx);
From the error case, it looks like you are not entirely encapsulating
knowledge of what the accessor uses, i.e. it’s not:
vq_err(vq, "Can't access used idx at %p\n",
&last_user_idx);
Maybe move error message within accessor?
> @@ -2094,7 +2157,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
> last_avail_idx = vq->last_avail_idx;
>
> if (vq->avail_idx == vq->last_avail_idx) {
> - if (unlikely(vhost_get_avail(vq, avail_idx, &vq->avail->idx))) {
> + if (unlikely(vhost_get_avail_idx(vq, &avail_idx))) {
> vq_err(vq, "Failed to access avail idx at %p\n",
> &vq->avail->idx);
> return -EFAULT;
Same here.
> @@ -2121,8 +2184,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
>
> /* Grab the next descriptor number they're advertising, and increment
> * the index we've seen. */
> - if (unlikely(vhost_get_avail(vq, ring_head,
> - &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
> + if (unlikely(vhost_get_avail_head(vq, &ring_head, last_avail_idx))) {
> vq_err(vq, "Failed to read head: idx %d address %p\n",
> last_avail_idx,
> &vq->avail->ring[last_avail_idx % vq->num]);
> @@ -2157,8 +2219,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
> i, vq->num, head);
> return -EINVAL;
> }
> - ret = vhost_copy_from_user(vq, &desc, vq->desc + i,
> - sizeof desc);
> + ret = vhost_get_desc(vq, &desc, i);
> if (unlikely(ret)) {
> vq_err(vq, "Failed to get descriptor: idx %d addr %p\n",
> i, vq->desc + i);
> @@ -2251,7 +2312,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
>
> start = vq->last_used_idx & (vq->num - 1);
> used = vq->used->ring + start;
> - if (vhost_copy_to_user(vq, used, heads, count * sizeof *used)) {
> + if (vhost_put_used(vq, heads, start, count)) {
> vq_err(vq, "Failed to write used");
> return -EFAULT;
> }
> @@ -2293,8 +2354,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
>
> /* Make sure buffer is written before we update index. */
> smp_wmb();
> - if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx),
> - &vq->used->idx)) {
> + if (vhost_put_used_idx(vq)) {
> vq_err(vq, "Failed to increment used idx");
> return -EFAULT;
> }
> @@ -2327,7 +2387,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
>
> if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
> __virtio16 flags;
> - if (vhost_get_avail(vq, flags, &vq->avail->flags)) {
> + if (vhost_get_avail_flags(vq, &flags)) {
> vq_err(vq, "Failed to get flags");
> return true;
> }
> @@ -2341,7 +2401,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
> if (unlikely(!v))
> return true;
>
> - if (vhost_get_avail(vq, event, vhost_used_event(vq))) {
> + if (vhost_get_used_event(vq, &event)) {
> vq_err(vq, "Failed to get used event idx");
> return true;
> }
> @@ -2386,7 +2446,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
> if (vq->avail_idx != vq->last_avail_idx)
> return false;
>
> - r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
> + r = vhost_get_avail_idx(vq, &avail_idx);
> if (unlikely(r))
> return false;
> vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
> @@ -2422,7 +2482,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
> /* They could have slipped one in as we were doing that: make
> * sure it's written, then check again. */
> smp_mb();
> - r = vhost_get_avail(vq, avail_idx, &vq->avail->idx);
> + r = vhost_get_avail_idx(vq, &avail_idx);
> if (r) {
> vq_err(vq, "Failed to check avail idx at %p: %d\n",
> &vq->avail->idx, r);
> --
> 1.8.3.1
>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* [PATCH v2] vsock/virtio: fix kernel panic from virtio_transport_reset_no_sock
From: Adalbert Lazăr @ 2019-03-06 10:13 UTC (permalink / raw)
To: Stefan Hajnoczi, David S . Miller, Stefano Garzarella
Cc: kvm, netdev, linux-kernel, virtualization, Adalbert Lazăr,
Alexandru Herghelegiu
Previous to commit 22b5c0b63f32 ("vsock/virtio: fix kernel panic
after device hot-unplug"), vsock_core_init() was called from
virtio_vsock_probe(). Now, virtio_transport_reset_no_sock() can be called
before vsock_core_init() has the chance to run.
[Wed Feb 27 14:17:09 2019] BUG: unable to handle kernel NULL pointer dereference at 0000000000000110
[Wed Feb 27 14:17:09 2019] #PF error: [normal kernel read fault]
[Wed Feb 27 14:17:09 2019] PGD 0 P4D 0
[Wed Feb 27 14:17:09 2019] Oops: 0000 [#1] SMP PTI
[Wed Feb 27 14:17:09 2019] CPU: 3 PID: 59 Comm: kworker/3:1 Not tainted 5.0.0-rc7-390-generic-hvi #390
[Wed Feb 27 14:17:09 2019] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[Wed Feb 27 14:17:09 2019] Workqueue: virtio_vsock virtio_transport_rx_work [vmw_vsock_virtio_transport]
[Wed Feb 27 14:17:09 2019] RIP: 0010:virtio_transport_reset_no_sock+0x8c/0xc0 [vmw_vsock_virtio_transport_common]
[Wed Feb 27 14:17:09 2019] Code: 35 8b 4f 14 48 8b 57 08 31 f6 44 8b 4f 10 44 8b 07 48 8d 7d c8 e8 84 f8 ff ff 48 85 c0 48 89 c3 74 2a e8 f7 31 03 00 48 89 df <48> 8b 80 10 01 00 00 e8 68 fb 69 ed 48 8b 75 f0 65 48 33 34 25 28
[Wed Feb 27 14:17:09 2019] RSP: 0018:ffffb42701ab7d40 EFLAGS: 00010282
[Wed Feb 27 14:17:09 2019] RAX: 0000000000000000 RBX: ffff9d79637ee080 RCX: 0000000000000003
[Wed Feb 27 14:17:09 2019] RDX: 0000000000000001 RSI: 0000000000000002 RDI: ffff9d79637ee080
[Wed Feb 27 14:17:09 2019] RBP: ffffb42701ab7d78 R08: ffff9d796fae70e0 R09: ffff9d796f403500
[Wed Feb 27 14:17:09 2019] R10: ffffb42701ab7d90 R11: 0000000000000000 R12: ffff9d7969d09240
[Wed Feb 27 14:17:09 2019] R13: ffff9d79624e6840 R14: ffff9d7969d09318 R15: ffff9d796d48ff80
[Wed Feb 27 14:17:09 2019] FS: 0000000000000000(0000) GS:ffff9d796fac0000(0000) knlGS:0000000000000000
[Wed Feb 27 14:17:09 2019] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[Wed Feb 27 14:17:09 2019] CR2: 0000000000000110 CR3: 0000000427f22000 CR4: 00000000000006e0
[Wed Feb 27 14:17:09 2019] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[Wed Feb 27 14:17:09 2019] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[Wed Feb 27 14:17:09 2019] Call Trace:
[Wed Feb 27 14:17:09 2019] virtio_transport_recv_pkt+0x63/0x820 [vmw_vsock_virtio_transport_common]
[Wed Feb 27 14:17:09 2019] ? kfree+0x17e/0x190
[Wed Feb 27 14:17:09 2019] ? detach_buf_split+0x145/0x160
[Wed Feb 27 14:17:09 2019] ? __switch_to_asm+0x40/0x70
[Wed Feb 27 14:17:09 2019] virtio_transport_rx_work+0xa0/0x106 [vmw_vsock_virtio_transport]
[Wed Feb 27 14:17:09 2019] NET: Registered protocol family 40
[Wed Feb 27 14:17:09 2019] process_one_work+0x167/0x410
[Wed Feb 27 14:17:09 2019] worker_thread+0x4d/0x460
[Wed Feb 27 14:17:09 2019] kthread+0x105/0x140
[Wed Feb 27 14:17:09 2019] ? rescuer_thread+0x360/0x360
[Wed Feb 27 14:17:09 2019] ? kthread_destroy_worker+0x50/0x50
[Wed Feb 27 14:17:09 2019] ret_from_fork+0x35/0x40
[Wed Feb 27 14:17:09 2019] Modules linked in: vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common input_leds vsock serio_raw i2c_piix4 mac_hid qemu_fw_cfg autofs4 cirrus ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops virtio_net psmouse drm net_failover pata_acpi virtio_blk failover floppy
Fixes: 22b5c0b63f32 ("vsock/virtio: fix kernel panic after device hot-unplug")
Reported-by: Alexandru Herghelegiu <aherghelegiu@bitdefender.com>
Signed-off-by: Adalbert Lazăr <alazar@bitdefender.com>
Co-developed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
net/vmw_vsock/virtio_transport_common.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 3ae3a33da70b..602715fc9a75 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -662,6 +662,8 @@ static int virtio_transport_reset(struct vsock_sock *vsk,
*/
static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt)
{
+ const struct virtio_transport *t;
+ struct virtio_vsock_pkt *reply;
struct virtio_vsock_pkt_info info = {
.op = VIRTIO_VSOCK_OP_RST,
.type = le16_to_cpu(pkt->hdr.type),
@@ -672,15 +674,21 @@ static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt)
if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
return 0;
- pkt = virtio_transport_alloc_pkt(&info, 0,
- le64_to_cpu(pkt->hdr.dst_cid),
- le32_to_cpu(pkt->hdr.dst_port),
- le64_to_cpu(pkt->hdr.src_cid),
- le32_to_cpu(pkt->hdr.src_port));
- if (!pkt)
+ reply = virtio_transport_alloc_pkt(&info, 0,
+ le64_to_cpu(pkt->hdr.dst_cid),
+ le32_to_cpu(pkt->hdr.dst_port),
+ le64_to_cpu(pkt->hdr.src_cid),
+ le32_to_cpu(pkt->hdr.src_port));
+ if (!reply)
return -ENOMEM;
- return virtio_transport_get_ops()->send_pkt(pkt);
+ t = virtio_transport_get_ops();
+ if (!t) {
+ virtio_transport_free_pkt(reply);
+ return -ENOTCONN;
+ }
+
+ return t->send_pkt(reply);
}
static void virtio_transport_wait_close(struct sock *sk, long timeout)
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply related
* Re: [PATCH] vsock/virtio: fix kernel panic from virtio_transport_reset_no_sock
From: Adalbert Lazăr @ 2019-03-06 9:10 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: kvm, netdev, linux-kernel, virtualization, Stefan Hajnoczi,
David S . Miller, Stefano Garzarella
In-Reply-To: <20190306084104.GA22159@stefanha-x1.localdomain>
On Wed, 6 Mar 2019 08:41:04 +0000, Stefan Hajnoczi <stefanha@gmail.com> wrote:
> On Tue, Mar 05, 2019 at 08:01:45PM +0200, Adalbert Lazăr wrote:
>
> Thanks for the patch, Adalbert! Please add a Signed-off-by tag so your
> patch can be merged (see Documentation/process/submitting-patches.rst
> Chapter 11 for details on the Developer's Certificate of Origin).
>
> > static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt)
> > {
> > + const struct virtio_transport *t;
> > struct virtio_vsock_pkt_info info = {
> > .op = VIRTIO_VSOCK_OP_RST,
> > .type = le16_to_cpu(pkt->hdr.type),
> > @@ -680,7 +681,11 @@ static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt)
> > if (!pkt)
> > return -ENOMEM;
> >
> > - return virtio_transport_get_ops()->send_pkt(pkt);
> > + t = virtio_transport_get_ops();
> > + if (!t)
> > + return -ENOTCONN;
>
> pkt is leaked here. This is an easy mistake to make because the code is
> unclear.
Thank you for your kind words :)
> The pkt argument is the received packet that we must reply to.
> The reply packet is allocated just before line 680 and must be free
> explicitly for return -ENOTCONN.
>
> You can avoid the leak and make the code easier to read like this:
>
> struct virtio_vsock_pkt *reply;
>
> ...
>
> ------ avoid reusing 'pkt'
> v
> reply = virtio_transport_alloc_pkt(&info, 0, ...);
> if (!reply)
> return -ENOMEM;
>
> t = virtio_transport_get_ops();
> if (!t) {
> virtio_transport_free_pkt(reply); <-- prevent memory leak
> return -ENOTCONN;
> }
> return t->send_pkt(reply);
What do you think about Stefano's suggestion, to move the check above
the line were the reply is allocated?
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox