Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

comedi: access buffer data page-by-page

The aim is to get rid of the `prealloc_buf` member of `struct
comedi_async` and access the buffer contents on a page-by-page basis
using the addresses in the `virt_addr` member of `struct
comedi_buf_page`. This will allow us to eliminate a `vmap()` that maps
the whole buffer.

Since the buffer pages have non-consecutive `virt_addr` addresses in
virtual memory (except for drivers using DMA), change the loops that
access buffer data to access it page-by-page.

Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
Link: https://lore.kernel.org/r/20250415114008.5977-3-abbotti@mev.co.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ian Abbott and committed by
Greg Kroah-Hartman
e7199b6b cb0dde4d

+96 -48
+38 -29
drivers/comedi/comedi_buf.c
··· 365 365 unsigned int num_bytes) 366 366 { 367 367 struct comedi_async *async = s->async; 368 + struct comedi_buf_page *buf_page_list = async->buf_map->page_list; 368 369 unsigned int count = 0; 369 370 const unsigned int num_sample_bytes = comedi_bytes_per_sample(s); 370 371 ··· 377 376 /* don't munge partial samples */ 378 377 num_bytes -= num_bytes % num_sample_bytes; 379 378 while (count < num_bytes) { 380 - int block_size = num_bytes - count; 381 - unsigned int buf_end; 379 + /* 380 + * Do not munge beyond page boundary. 381 + * Note: prealloc_bufsz is a multiple of PAGE_SIZE. 382 + */ 383 + unsigned int page = async->munge_ptr >> PAGE_SHIFT; 384 + unsigned int offset = offset_in_page(async->munge_ptr); 385 + unsigned int block_size = 386 + min(num_bytes - count, PAGE_SIZE - offset); 382 387 383 - buf_end = async->prealloc_bufsz - async->munge_ptr; 384 - if (block_size > buf_end) 385 - block_size = buf_end; 386 - 387 - s->munge(s->device, s, 388 - async->prealloc_buf + async->munge_ptr, 388 + s->munge(s->device, s, buf_page_list[page].virt_addr + offset, 389 389 block_size, async->munge_chan); 390 390 391 391 /* ··· 399 397 async->munge_chan %= async->cmd.chanlist_len; 400 398 async->munge_count += block_size; 401 399 async->munge_ptr += block_size; 402 - async->munge_ptr %= async->prealloc_bufsz; 400 + if (async->munge_ptr == async->prealloc_bufsz) 401 + async->munge_ptr = 0; 403 402 count += block_size; 404 403 } 405 404 ··· 561 558 const void *data, unsigned int num_bytes) 562 559 { 563 560 struct comedi_async *async = s->async; 561 + struct comedi_buf_page *buf_page_list = async->buf_map->page_list; 564 562 unsigned int write_ptr = async->buf_write_ptr; 565 563 566 564 while (num_bytes) { 567 - unsigned int block_size; 565 + /* 566 + * Do not copy beyond page boundary. 567 + * Note: prealloc_bufsz is a multiple of PAGE_SIZE. 568 + */ 569 + unsigned int page = write_ptr >> PAGE_SHIFT; 570 + unsigned int offset = offset_in_page(write_ptr); 571 + unsigned int block_size = min(num_bytes, PAGE_SIZE - offset); 568 572 569 - if (write_ptr + num_bytes > async->prealloc_bufsz) 570 - block_size = async->prealloc_bufsz - write_ptr; 571 - else 572 - block_size = num_bytes; 573 - 574 - memcpy(async->prealloc_buf + write_ptr, data, block_size); 573 + memcpy(buf_page_list[page].virt_addr + offset, 574 + data, block_size); 575 575 576 576 data += block_size; 577 577 num_bytes -= block_size; 578 - 579 - write_ptr = 0; 578 + write_ptr += block_size; 579 + if (write_ptr == async->prealloc_bufsz) 580 + write_ptr = 0; 580 581 } 581 582 } 582 583 583 584 static void comedi_buf_memcpy_from(struct comedi_subdevice *s, 584 585 void *dest, unsigned int nbytes) 585 586 { 586 - void *src; 587 587 struct comedi_async *async = s->async; 588 + struct comedi_buf_page *buf_page_list = async->buf_map->page_list; 588 589 unsigned int read_ptr = async->buf_read_ptr; 589 590 590 591 while (nbytes) { 591 - unsigned int block_size; 592 + /* 593 + * Do not copy beyond page boundary. 594 + * Note: prealloc_bufsz is a multiple of PAGE_SIZE. 595 + */ 596 + unsigned int page = read_ptr >> PAGE_SHIFT; 597 + unsigned int offset = offset_in_page(read_ptr); 598 + unsigned int block_size = min(nbytes, PAGE_SIZE - offset); 592 599 593 - src = async->prealloc_buf + read_ptr; 594 - 595 - if (nbytes >= async->prealloc_bufsz - read_ptr) 596 - block_size = async->prealloc_bufsz - read_ptr; 597 - else 598 - block_size = nbytes; 599 - 600 - memcpy(dest, src, block_size); 600 + memcpy(dest, buf_page_list[page].virt_addr + offset, 601 + block_size); 601 602 nbytes -= block_size; 602 603 dest += block_size; 603 - read_ptr = 0; 604 + read_ptr += block_size; 605 + if (read_ptr == async->prealloc_bufsz) 606 + read_ptr = 0; 604 607 } 605 608 } 606 609
+58 -19
drivers/comedi/comedi_fops.c
··· 2475 2475 return mask; 2476 2476 } 2477 2477 2478 + static unsigned int comedi_buf_copy_to_user(struct comedi_subdevice *s, 2479 + void __user *dest, unsigned int src_offset, unsigned int n) 2480 + { 2481 + struct comedi_buf_map *bm = s->async->buf_map; 2482 + struct comedi_buf_page *buf_page_list = bm->page_list; 2483 + unsigned int page = src_offset >> PAGE_SHIFT; 2484 + unsigned int offset = offset_in_page(src_offset); 2485 + 2486 + while (n) { 2487 + unsigned int copy_amount = min(n, PAGE_SIZE - offset); 2488 + unsigned int uncopied; 2489 + 2490 + uncopied = copy_to_user(dest, buf_page_list[page].virt_addr + 2491 + offset, copy_amount); 2492 + copy_amount -= uncopied; 2493 + n -= copy_amount; 2494 + if (uncopied) 2495 + break; 2496 + 2497 + dest += copy_amount; 2498 + page++; 2499 + if (page == bm->n_pages) 2500 + page = 0; /* buffer wraparound */ 2501 + offset = 0; 2502 + } 2503 + return n; 2504 + } 2505 + 2506 + static unsigned int comedi_buf_copy_from_user(struct comedi_subdevice *s, 2507 + unsigned int dst_offset, const void __user *src, unsigned int n) 2508 + { 2509 + struct comedi_buf_map *bm = s->async->buf_map; 2510 + struct comedi_buf_page *buf_page_list = bm->page_list; 2511 + unsigned int page = dst_offset >> PAGE_SHIFT; 2512 + unsigned int offset = offset_in_page(dst_offset); 2513 + 2514 + while (n) { 2515 + unsigned int copy_amount = min(n, PAGE_SIZE - offset); 2516 + unsigned int uncopied; 2517 + 2518 + uncopied = copy_from_user(buf_page_list[page].virt_addr + 2519 + offset, src, copy_amount); 2520 + copy_amount -= uncopied; 2521 + n -= copy_amount; 2522 + if (uncopied) 2523 + break; 2524 + 2525 + src += copy_amount; 2526 + page++; 2527 + if (page == bm->n_pages) 2528 + page = 0; /* buffer wraparound */ 2529 + offset = 0; 2530 + } 2531 + return n; 2532 + } 2533 + 2478 2534 static ssize_t comedi_write(struct file *file, const char __user *buf, 2479 2535 size_t nbytes, loff_t *offset) 2480 2536 { ··· 2572 2516 add_wait_queue(&async->wait_head, &wait); 2573 2517 while (count == 0 && !retval) { 2574 2518 unsigned int runflags; 2575 - unsigned int wp, n1, n2; 2576 2519 2577 2520 set_current_state(TASK_INTERRUPTIBLE); 2578 2521 ··· 2610 2555 } 2611 2556 2612 2557 set_current_state(TASK_RUNNING); 2613 - wp = async->buf_write_ptr; 2614 - n1 = min(n, async->prealloc_bufsz - wp); 2615 - n2 = n - n1; 2616 - m = copy_from_user(async->prealloc_buf + wp, buf, n1); 2617 - if (m) 2618 - m += n2; 2619 - else if (n2) 2620 - m = copy_from_user(async->prealloc_buf, buf + n1, n2); 2558 + m = comedi_buf_copy_from_user(s, async->buf_write_ptr, buf, n); 2621 2559 if (m) { 2622 2560 n -= m; 2623 2561 retval = -EFAULT; ··· 2699 2651 2700 2652 add_wait_queue(&async->wait_head, &wait); 2701 2653 while (count == 0 && !retval) { 2702 - unsigned int rp, n1, n2; 2703 - 2704 2654 set_current_state(TASK_INTERRUPTIBLE); 2705 2655 2706 2656 m = comedi_buf_read_n_available(s); ··· 2735 2689 } 2736 2690 2737 2691 set_current_state(TASK_RUNNING); 2738 - rp = async->buf_read_ptr; 2739 - n1 = min(n, async->prealloc_bufsz - rp); 2740 - n2 = n - n1; 2741 - m = copy_to_user(buf, async->prealloc_buf + rp, n1); 2742 - if (m) 2743 - m += n2; 2744 - else if (n2) 2745 - m = copy_to_user(buf + n1, async->prealloc_buf, n2); 2692 + m = comedi_buf_copy_to_user(s, buf, async->buf_read_ptr, n); 2746 2693 if (m) { 2747 2694 n -= m; 2748 2695 retval = -EFAULT;