Mike Marshall <hubcap@xxxxxxxxxxxx> wrote: > /* allocate an array of bio_vecs. */ > bvs = kzalloc(npages * (sizeof(struct bio_vec)), GFP_KERNEL); > Better to use kcalloc() here as it has overflow checking. > /* hook the bio_vecs to the pages. */ > for (i = 0; i < npages; i++) { > bvs[i].bv_page = pages[i]; > bvs[i].bv_len = PAGE_SIZE; > bvs[i].bv_offset = 0; > } > > iov_iter_bvec(&iter, READ, bvs, npages, npages * PAGE_SIZE); > > /* read in the pages. */ > ret = wait_for_direct_io(ORANGEFS_IO_READ, inode, &offset, &iter, > npages * PAGE_SIZE, inode->i_size, NULL, NULL, file); > > /* clean up. */ > for (i = 0; i < npages; i++) { > SetPageUptodate(bvs[i].bv_page); > unlock_page(bvs[i].bv_page); > put_page(bvs[i].bv_page); > } > kfree(pages); > kfree(bvs); > } Could you try ITER_XARRAY instead of ITER_BVEC: https://lore.kernel.org/linux-fsdevel/161653786033.2770958.14154191921867463240.stgit@xxxxxxxxxxxxxxxxxxxxxx/T/#u Setting the iterator looks like: iov_iter_xarray(&iter, READ, &mapping->i_pages, offset, npages * PAGE_SIZE); The xarray iterator will handle THPs, but I'm not sure if bvecs will. Cleanup afterwards would look something like: static void afs_file_read_done(struct afs_read *req) { struct afs_vnode *vnode = req->vnode; struct page *page; pgoff_t index = req->pos >> PAGE_SHIFT; pgoff_t last = index + req->nr_pages - 1; XA_STATE(xas, &vnode->vfs_inode.i_mapping->i_pages, index); if (iov_iter_count(req->iter) > 0) { /* The read was short - clear the excess buffer. */ _debug("afterclear %zx %zx %llx/%llx", req->iter->iov_offset, iov_iter_count(req->iter), req->actual_len, req->len); iov_iter_zero(iov_iter_count(req->iter), req->iter); } rcu_read_lock(); xas_for_each(&xas, page, last) { page_endio(page, false, 0); put_page(page); } rcu_read_unlock(); task_io_account_read(req->len); req->cleanup = NULL; } David