/* simple helper to fault in pages and copy. This should go away * and be replaced with calls into generic code. */ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, int write_bytes, struct page **prepared_pages, struct iov_iter *i) { size_t copied = 0; int pg = 0; int offset = pos & (PAGE_CACHE_SIZE - 1); int total_copied = 0; while (write_bytes > 0) { size_t count = min_t(size_t, PAGE_CACHE_SIZE - offset, write_bytes); struct page *page = prepared_pages[pg]; /* * Copy data from userspace to the current page * * Disable pagefault to avoid recursive lock since * the pages are already locked */ pagefault_disable(); copied = iov_iter_copy_from_user_atomic(page, i, offset, count); pagefault_enable(); /* Flush processor's dcache for this page */ flush_dcache_page(page); /* * if we get a partial write, we can end up with * partially up to date pages. These add * a lot of complexity, so make sure they don't * happen by forcing this copy to be retried. * * The rest of the btrfs_file_write code will fall * back to page at a time copies after we return 0. */ if (!PageUptodate(page) && copied < count) copied = 0; iov_iter_advance(i, copied); write_bytes -= copied; total_copied += copied; /* Return to btrfs_file_aio_write to fault page */ if (unlikely(copied == 0)) { break; } if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { offset += copied; } else { pg++; offset = 0; } } return total_copied; }
/* simple helper to fault in pages and copy. This should go away * and be replaced with calls into generic code. */ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, int write_bytes, struct page **prepared_pages, struct iov_iter *i) { size_t copied = 0; int pg = 0; int offset = pos & (PAGE_CACHE_SIZE - 1); int total_copied = 0; while (write_bytes > 0) { size_t count = min_t(size_t, PAGE_CACHE_SIZE - offset, write_bytes); struct page *page = prepared_pages[pg]; /* * Copy data from userspace to the current page * * Disable pagefault to avoid recursive lock since * the pages are already locked */ pagefault_disable(); copied = iov_iter_copy_from_user_atomic(page, i, offset, count); pagefault_enable(); /* Flush processor's dcache for this page */ flush_dcache_page(page); iov_iter_advance(i, copied); write_bytes -= copied; total_copied += copied; /* Return to btrfs_file_aio_write to fault page */ if (unlikely(copied == 0)) { break; } if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { offset += copied; } else { pg++; offset = 0; } } return total_copied; }