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.

drm/i915: Refactor shmem_pwrite() to use kiocb and write_iter

Refactors shmem_pwrite() to replace the ->write_begin/end logic
with a write_iter-based implementation using kiocb and iov_iter.

While kernel_write() was considered, it caused about 50% performance
regression. vfs_write() is not exported for kernel use. Therefore,
file->f_op->write_iter() is called directly with a synchronously
initialized kiocb to preserve performance and remove write_begin
usage.

Performance results use gem_pwrite on Intel CPU i7-10700
(average of 10 runs):

- ./gem_pwrite --run-subtest bench -s 16384
Before: 0.205s, After: 0.214s

- ./gem_pwrite --run-subtest bench -s 524288
Before: 6.1021s, After: 4.8047s

Part of a series refactoring address_space_operations write_begin and
write_end callbacks to use struct kiocb for passing write context and
flags.

Signed-off-by: Taotao Chen <chentaotao@didiglobal.com>
Link: https://lore.kernel.org/20250716093559.217344-3-chentaotao@didiglobal.com
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Taotao Chen and committed by
Christian Brauner
048832a3 e7b840fd

+19 -57
+19 -57
drivers/gpu/drm/i915/gem/i915_gem_shmem.c
··· 6 6 #include <linux/pagevec.h> 7 7 #include <linux/shmem_fs.h> 8 8 #include <linux/swap.h> 9 + #include <linux/uio.h> 9 10 10 11 #include <drm/drm_cache.h> 11 12 ··· 401 400 shmem_pwrite(struct drm_i915_gem_object *obj, 402 401 const struct drm_i915_gem_pwrite *arg) 403 402 { 404 - struct address_space *mapping = obj->base.filp->f_mapping; 405 - const struct address_space_operations *aops = mapping->a_ops; 406 403 char __user *user_data = u64_to_user_ptr(arg->data_ptr); 407 - u64 remain; 408 - loff_t pos; 409 - unsigned int pg; 404 + struct file *file = obj->base.filp; 405 + struct kiocb kiocb; 406 + struct iov_iter iter; 407 + ssize_t written; 408 + u64 size = arg->size; 410 409 411 410 /* Caller already validated user args */ 412 411 GEM_BUG_ON(!access_ok(user_data, arg->size)); ··· 429 428 if (obj->mm.madv != I915_MADV_WILLNEED) 430 429 return -EFAULT; 431 430 432 - /* 433 - * Before the pages are instantiated the object is treated as being 434 - * in the CPU domain. The pages will be clflushed as required before 435 - * use, and we can freely write into the pages directly. If userspace 436 - * races pwrite with any other operation; corruption will ensue - 437 - * that is userspace's prerogative! 438 - */ 431 + if (size > MAX_RW_COUNT) 432 + return -EFBIG; 439 433 440 - remain = arg->size; 441 - pos = arg->offset; 442 - pg = offset_in_page(pos); 434 + if (!file->f_op->write_iter) 435 + return -EINVAL; 443 436 444 - do { 445 - unsigned int len, unwritten; 446 - struct folio *folio; 447 - void *data, *vaddr; 448 - int err; 449 - char __maybe_unused c; 437 + init_sync_kiocb(&kiocb, file); 438 + kiocb.ki_pos = arg->offset; 439 + iov_iter_ubuf(&iter, ITER_SOURCE, (void __user *)user_data, size); 450 440 451 - len = PAGE_SIZE - pg; 452 - if (len > remain) 453 - len = remain; 441 + written = file->f_op->write_iter(&kiocb, &iter); 442 + BUG_ON(written == -EIOCBQUEUED); 454 443 455 - /* Prefault the user page to reduce potential recursion */ 456 - err = __get_user(c, user_data); 457 - if (err) 458 - return err; 444 + if (written != size) 445 + return -EIO; 459 446 460 - err = __get_user(c, user_data + len - 1); 461 - if (err) 462 - return err; 463 - 464 - err = aops->write_begin(obj->base.filp, mapping, pos, len, 465 - &folio, &data); 466 - if (err < 0) 467 - return err; 468 - 469 - vaddr = kmap_local_folio(folio, offset_in_folio(folio, pos)); 470 - pagefault_disable(); 471 - unwritten = __copy_from_user_inatomic(vaddr, user_data, len); 472 - pagefault_enable(); 473 - kunmap_local(vaddr); 474 - 475 - err = aops->write_end(obj->base.filp, mapping, pos, len, 476 - len - unwritten, folio, data); 477 - if (err < 0) 478 - return err; 479 - 480 - /* We don't handle -EFAULT, leave it to the caller to check */ 481 - if (unwritten) 482 - return -ENODEV; 483 - 484 - remain -= len; 485 - user_data += len; 486 - pos += len; 487 - pg = 0; 488 - } while (remain); 447 + if (written < 0) 448 + return written; 489 449 490 450 return 0; 491 451 }