diff options
author | Ian Abbott <abbotti@mev.co.uk> | 2017-04-20 21:05:14 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-25 21:43:42 +0300 |
commit | 255364f7b8a0fee3fb642b3e1521e943dd67bfb3 (patch) | |
tree | 9b67464441cc98d69eece7d42852637ee3dd89ca /drivers/staging | |
parent | e44adf05b85e5a9d1d224f5ecde1c1c5e5371e36 (diff) | |
download | linux-255364f7b8a0fee3fb642b3e1521e943dd67bfb3.tar.xz |
staging: comedi: support vm_access_process for mmap'd buffer
If a process that has mmap'd a COMEDI buffer is being run under a
debugger such as GDB, the buffer contents are inaccessible from the
debugger. Support the `access()` VM operation to allow the buffer
contents to be accessed by another process.
Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/comedi/comedi_buf.c | 24 | ||||
-rw-r--r-- | drivers/staging/comedi/comedi_fops.c | 15 | ||||
-rw-r--r-- | drivers/staging/comedi/comedi_internal.h | 2 |
3 files changed, 41 insertions, 0 deletions
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index 1e1df89b5018..8e9b30b26810 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -161,6 +161,30 @@ int comedi_buf_map_put(struct comedi_buf_map *bm) return 1; } +/* helper for "access" vm operation */ +int comedi_buf_map_access(struct comedi_buf_map *bm, unsigned long offset, + void *buf, int len, int write) +{ + unsigned int pgoff = offset & ~PAGE_MASK; + unsigned long pg = offset >> PAGE_SHIFT; + int done = 0; + + while (done < len && pg < bm->n_pages) { + int l = min_t(int, len - done, PAGE_SIZE - pgoff); + void *b = bm->page_list[pg].virt_addr + pgoff; + + if (write) + memcpy(b, buf, l); + else + memcpy(buf, b, l); + buf += l; + done += l; + pg++; + pgoff = 0; + } + return done; +} + /* returns s->async->buf_map and increments its kref refcount */ struct comedi_buf_map * comedi_buf_map_from_subdev_get(struct comedi_subdevice *s) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 92d864fc08ac..f191c2a75732 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2165,9 +2165,24 @@ static void comedi_vm_close(struct vm_area_struct *area) comedi_buf_map_put(bm); } +static int comedi_vm_access(struct vm_area_struct *vma, unsigned long addr, + void *buf, int len, int write) +{ + struct comedi_buf_map *bm = vma->vm_private_data; + unsigned long offset = + addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); + + if (len < 0) + return -EINVAL; + if (len > vma->vm_end - addr) + len = vma->vm_end - addr; + return comedi_buf_map_access(bm, offset, buf, len, write); +} + static const struct vm_operations_struct comedi_vm_ops = { .open = comedi_vm_open, .close = comedi_vm_close, + .access = comedi_vm_access, }; static int comedi_mmap(struct file *file, struct vm_area_struct *vma) diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h index 534415e331b6..6246f4a78ca6 100644 --- a/drivers/staging/comedi/comedi_internal.h +++ b/drivers/staging/comedi/comedi_internal.h @@ -29,6 +29,8 @@ void comedi_buf_reset(struct comedi_subdevice *s); bool comedi_buf_is_mmapped(struct comedi_subdevice *s); void comedi_buf_map_get(struct comedi_buf_map *bm); int comedi_buf_map_put(struct comedi_buf_map *bm); +int comedi_buf_map_access(struct comedi_buf_map *bm, unsigned long offset, + void *buf, int len, int write); struct comedi_buf_map *comedi_buf_map_from_subdev_get( struct comedi_subdevice *s); unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s); |