On Fri, 29 Dec 2017 16:24:20 +0300
"Kirill A. Shutemov" <[email protected]> wrote:
> Looks like MON_IOCT_RING_SIZE reallocates ring buffer without any
> serialization wrt mon_bin_vma_fault(). By the time of get_page() the page
> may be freed.
Okay. Who knew that you could fork while holding an open descriptor. :-)
> The patch below seems help the crash to go away, but I *think* more work
> is required. For instance, after ring buffer reallocation the old pages
> will stay mapped. Nothing pulls them.
You know, this bothered me all these years too, but I was assured
back in the day (as much as I can remember), that doing get_page()
in the .fault() is just the right thing. In my defense, you can
see other drivers doing it, such as:
./drivers/char/agp/alpha-agp.c
./drivers/hsi/clients/cmt_speech.c
I'd appreciate insight from someone who knows how VM subsystem works.
Now, about the code:
> diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
> index f6ae753ab99b..ac168fecf04f 100644
> --- a/drivers/usb/mon/mon_bin.c
> +++ b/drivers/usb/mon/mon_bin.c
> @@ -1228,15 +1228,24 @@ static void mon_bin_vma_close(struct vm_area_struct
> *vma)
> static int mon_bin_vma_fault(struct vm_fault *vmf)
> {
> struct mon_reader_bin *rp = vmf->vma->vm_private_data;
> - unsigned long offset, chunk_idx;
> + unsigned long offset, chunk_idx, flags;
> struct page *pageptr;
>
> + mutex_lock(&rp->fetch_lock);
> + spin_lock_irqsave(&rp->b_lock, flags);
> offset = vmf->pgoff << PAGE_SHIFT;
> - if (offset >= rp->b_size)
> + if (offset >= rp->b_size) {
> + spin_unlock_irqrestore(&rp->b_lock, flags);
> + mutex_unlock(&rp->fetch_lock);
> return VM_FAULT_SIGBUS;
> + }
> chunk_idx = offset / CHUNK_SIZE;
> +
> pageptr = rp->b_vec[chunk_idx].pg;
> get_page(pageptr);
> + spin_unlock_irqrestore(&rp->b_lock, flags);
> + mutex_unlock(&rp->fetch_lock);
> +
> vmf->page = pageptr;
> return 0;
> }
I think that grabbing the spinlock is not really necessary in
this case. The ->b_lock is designed for things that are accessed
from interrupts that Host Controller Driver serves -- mostly
various pointers. By defintion it's not covering things that
are related to re-allocation. Now, the re-allocation itself
grabs it, because it resets indexes into the new buffer, but
does not appear to apply here, does it now?
-- Pete
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html