On Thu, Oct 14, 2021 at 09:06:51AM +0200, David Hildenbrand wrote:
> On 14.10.21 07:29, Raphael Norwitz wrote:
> > On Wed, Oct 13, 2021 at 11:51:24AM +0200, David Hildenbrand wrote:
> >> On 13.10.21 11:48, Stefan Hajnoczi wrote:
> >>> On Tue, Oct 12, 2021 at 08:38:32PM +0200, David Hildenbrand wrote:
> >>>> We end up not closing the file descriptor, resulting in leaking one
> >>>> file descriptor for each VHOST_USER_REM_MEM_REG message.
> >>>>
> >>>> Fixes: 875b9fd97b34 ("Support individual region unmap in libvhost-user")
> >>>> Cc: Michael S. Tsirkin <m...@redhat.com>
> >>>> Cc: Raphael Norwitz <raphael.norw...@nutanix.com>
> >>>> Cc: "Marc-André Lureau" <marcandre.lur...@redhat.com>
> >>>> Cc: Stefan Hajnoczi <stefa...@redhat.com>
> >>>> Cc: Paolo Bonzini <pbonz...@redhat.com>
> >>>> Cc: Coiby Xu <coiby...@gmail.com>
> >>>> Signed-off-by: David Hildenbrand <da...@redhat.com>
> >>>> ---
> >>>>   subprojects/libvhost-user/libvhost-user.c | 2 ++
> >>>>   1 file changed, 2 insertions(+)
> >>>>
> >>>> diff --git a/subprojects/libvhost-user/libvhost-user.c 
> >>>> b/subprojects/libvhost-user/libvhost-user.c
> >>>> index bf09693255..bb5c3b3280 100644
> >>>> --- a/subprojects/libvhost-user/libvhost-user.c
> >>>> +++ b/subprojects/libvhost-user/libvhost-user.c
> >>>> @@ -839,6 +839,8 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
> >>>>           vu_panic(dev, "Specified region not found\n");
> >>>>       }
> >>>> +    close(vmsg->fds[0]);
> >>>
> >>> Does anything check that exactly 1 fd was received? For example,
> >>> vu_set_log_fd_exec() does:
> >>>
> >>>    if (vmsg->fd_num != 1) {
> >>>        vu_panic(dev, "Invalid log_fd message");
> >>>        return false;
> >>>    }
> >>>
> >>> I think that's necessary both to make vhost-user master development
> >>> easier and because fds[] is not initialized to -1.
> > 
> > Ack - will add that.
> > 
> >>
> >> Similarly, vu_add_mem_reg() assumes exactly one was sent AFAIKS.
> > 
> > Ack
> > 
> >>
> >> If we panic, do we still have to call vmsg_close_fds() ?
> >>
> > 
> > I think so. What else will close the FDs?
> > 
> > AFAICT a vu_panic does not imply that the overall process has to die if 
> > that's
> > what you mean. What if one process is exposing multiple devices and only 
> > one of
> > them panics?
> 
> So IIUC, you'll send some patches to tackle the fd checks?
>

Yes

> While at it, we might want to simplify VHOST_USER_REM_MEM_REG. 
> I have a patch there that needs tweaking to cover the point Stefan raised
> regarding duplicate ranges. We might want to do the memmove within the loop
> instead and drop the "break" to process all elements.
> 
>

Sure - let me include this in the series.

> commit 34d71b6531c74a61442432b37e5829a76a7017c5
> Author: David Hildenbrand <da...@redhat.com>
> Date:   Tue Oct 12 13:25:43 2021 +0200
> 
>     libvhost-user: Simplify VHOST_USER_REM_MEM_REG
>     
>     Let's avoid having to manually copy all elements. Copy only the ones
>     necessary to close the hole and perform the operation in-place without
>     a second array.
>     
>     Signed-off-by: David Hildenbrand <da...@redhat.com>
> 
> diff --git a/subprojects/libvhost-user/libvhost-user.c 
> b/subprojects/libvhost-user/libvhost-user.c
> index 7b0e40256e..499c31dc68 100644
> --- a/subprojects/libvhost-user/libvhost-user.c
> +++ b/subprojects/libvhost-user/libvhost-user.c
> @@ -796,10 +796,8 @@ static inline bool reg_equal(VuDevRegion *vudev_reg,
>  
>  static bool
>  vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
> -    int i, j;
> -    bool found = false;
> -    VuDevRegion shadow_regions[VHOST_USER_MAX_RAM_SLOTS] = {};
>      VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
> +    int i;
>  
>      DPRINT("Removing region:\n");
>      DPRINT("    guest_phys_addr: 0x%016"PRIx64"\n",
> @@ -811,28 +809,27 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
>      DPRINT("    mmap_offset      0x%016"PRIx64"\n",
>             msg_region->mmap_offset);
>  
> -    for (i = 0, j = 0; i < dev->nregions; i++) {
> -        if (!reg_equal(&dev->regions[i], msg_region)) {
> -            shadow_regions[j].gpa = dev->regions[i].gpa;
> -            shadow_regions[j].size = dev->regions[i].size;
> -            shadow_regions[j].qva = dev->regions[i].qva;
> -            shadow_regions[j].mmap_addr = dev->regions[i].mmap_addr;
> -            shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset;
> -            j++;
> -        } else {
> -            found = true;
> +    for (i = 0; i < dev->nregions; i++) {
> +        if (reg_equal(&dev->regions[i], msg_region)) {
>              VuDevRegion *r = &dev->regions[i];
>              void *m = (void *) (uintptr_t) r->mmap_addr;
>  
>              if (m) {
>                  munmap(m, r->size + r->mmap_offset);
>              }
> +            break;
>          }
>      }
>  
> -    if (found) {
> -        memcpy(dev->regions, shadow_regions,
> -               sizeof(VuDevRegion) * VHOST_USER_MAX_RAM_SLOTS);
> +    if (i < dev->nregions) {
> +        /*
> +         * Shift all affected entries by 1 to close the hole at index i and
> +         * zero out the last entry.
> +         */
> +        memmove(dev->regions + i, dev->regions + i + 1,
> +               sizeof(VuDevRegion) * (dev->nregions - i - 1));
> +        memset(dev->regions + dev->nregions - 1, 0,
> +               sizeof(VuDevRegion));
>          DPRINT("Successfully removed a region\n");
>          dev->nregions--;
>          vmsg_set_reply_u64(vmsg, 0);
> 
> 
> 
> On a related note, I proposed in a RFC series to increase the memslot count:
> 
> https://lore.kernel.org/all/20211013103330.26869-1-da...@redhat.com/T/#mbaa35cebb311e7ab9c029f9f99fb2ba41e993b9f
>

Thanks for pointing that out. I don't see any problem with bumping the
memslot count. I don't expect it will conflict with anything I'm doing
but will keep it in mind.

> -- 
> Thanks,
> 
> David / dhildenb
> 

Reply via email to