fuse: remove pages for requests and exclusively use folios

All fuse requests use folios instead of pages for transferring data.
Remove pages from the requests and exclusively use folios.

No functional changes.

[SzM: rename back folio_descs -> descs, etc.]

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Joanne Koong 2024-10-24 10:18:09 -07:00 committed by Miklos Szeredi
parent 3b97c3652d
commit 68bfb7eb7f
8 changed files with 90 additions and 154 deletions

View File

@ -460,10 +460,9 @@ static int cuse_send_init(struct cuse_conn *cc)
ap->args.out_args[1].size = CUSE_INIT_INFO_MAX;
ap->args.out_argvar = true;
ap->args.out_pages = true;
ap->uses_folios = true;
ap->num_folios = 1;
ap->folios = &ia->folio;
ap->folio_descs = &ia->desc;
ap->descs = &ia->desc;
ia->folio = folio;
ia->desc.length = ap->args.out_args[1].size;
ap->args.end = cuse_process_init_reply;

View File

@ -1028,41 +1028,27 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,
struct fuse_req *req = cs->req;
struct fuse_args_pages *ap = container_of(req->args, typeof(*ap), args);
if (ap->uses_folios) {
for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) {
int err;
unsigned int offset = ap->folio_descs[i].offset;
unsigned int count = min(nbytes, ap->folio_descs[i].length);
struct page *orig, *pagep;
for (i = 0; i < ap->num_folios && (nbytes || zeroing); i++) {
int err;
unsigned int offset = ap->descs[i].offset;
unsigned int count = min(nbytes, ap->descs[i].length);
struct page *orig, *pagep;
orig = pagep = &ap->folios[i]->page;
orig = pagep = &ap->folios[i]->page;
err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
if (err)
return err;
err = fuse_copy_page(cs, &pagep, offset, count, zeroing);
if (err)
return err;
nbytes -= count;
nbytes -= count;
/*
* fuse_copy_page may have moved a page from a pipe
* instead of copying into our given page, so update
* the folios if it was replaced.
*/
if (pagep != orig)
ap->folios[i] = page_folio(pagep);
}
} else {
for (i = 0; i < ap->num_pages && (nbytes || zeroing); i++) {
int err;
unsigned int offset = ap->descs[i].offset;
unsigned int count = min(nbytes, ap->descs[i].length);
err = fuse_copy_page(cs, &ap->pages[i], offset, count, zeroing);
if (err)
return err;
nbytes -= count;
}
/*
* fuse_copy_page may have moved a page from a pipe instead of
* copying into our given page, so update the folios if it was
* replaced.
*/
if (pagep != orig)
ap->folios[i] = page_folio(pagep);
}
return 0;
}
@ -1761,7 +1747,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
num_pages = min(num_pages, fc->max_pages);
args_size += num_pages * (sizeof(ap->folios[0]) + sizeof(ap->folio_descs[0]));
args_size += num_pages * (sizeof(ap->folios[0]) + sizeof(ap->descs[0]));
ra = kzalloc(args_size, GFP_KERNEL);
if (!ra)
@ -1769,8 +1755,7 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
ap = &ra->ap;
ap->folios = (void *) (ra + 1);
ap->folio_descs = (void *) (ap->folios + num_pages);
ap->uses_folios = true;
ap->descs = (void *) (ap->folios + num_pages);
args = &ap->args;
args->nodeid = outarg->nodeid;
@ -1791,8 +1776,8 @@ static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
this_num = min_t(unsigned, num, PAGE_SIZE - offset);
ap->folios[ap->num_folios] = folio;
ap->folio_descs[ap->num_folios].offset = offset;
ap->folio_descs[ap->num_folios].length = this_num;
ap->descs[ap->num_folios].offset = offset;
ap->descs[ap->num_folios].length = this_num;
ap->num_folios++;
cur_pages++;

View File

@ -1590,10 +1590,9 @@ static int fuse_readlink_page(struct inode *inode, struct folio *folio)
struct fuse_mount *fm = get_fuse_mount(inode);
struct fuse_folio_desc desc = { .length = PAGE_SIZE - 1 };
struct fuse_args_pages ap = {
.uses_folios = true,
.num_folios = 1,
.folios = &folio,
.folio_descs = &desc,
.descs = &desc,
};
char *link;
ssize_t res;

View File

@ -742,7 +742,7 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
kref_put(&io->refcnt, fuse_io_release);
}
static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
static struct fuse_io_args *fuse_io_alloc(struct fuse_io_priv *io,
unsigned int nfolios)
{
struct fuse_io_args *ia;
@ -750,9 +750,8 @@ static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
ia = kzalloc(sizeof(*ia), GFP_KERNEL);
if (ia) {
ia->io = io;
ia->ap.uses_folios = true;
ia->ap.folios = fuse_folios_alloc(nfolios, GFP_KERNEL,
&ia->ap.folio_descs);
&ia->ap.descs);
if (!ia->ap.folios) {
kfree(ia);
ia = NULL;
@ -761,7 +760,7 @@ static struct fuse_io_args *fuse_io_folios_alloc(struct fuse_io_priv *io,
return ia;
}
static void fuse_io_folios_free(struct fuse_io_args *ia)
static void fuse_io_free(struct fuse_io_args *ia)
{
kfree(ia->ap.folios);
kfree(ia);
@ -797,7 +796,7 @@ static void fuse_aio_complete_req(struct fuse_mount *fm, struct fuse_args *args,
fuse_release_user_pages(&ia->ap, err ?: nres, io->should_dirty);
fuse_aio_complete(io, err, pos);
fuse_io_folios_free(ia);
fuse_io_free(ia);
}
static ssize_t fuse_async_req_send(struct fuse_mount *fm,
@ -880,10 +879,9 @@ static int fuse_do_readfolio(struct file *file, struct folio *folio)
struct fuse_io_args ia = {
.ap.args.page_zeroing = true,
.ap.args.out_pages = true,
.ap.uses_folios = true,
.ap.num_folios = 1,
.ap.folios = &folio,
.ap.folio_descs = &desc,
.ap.descs = &desc,
};
ssize_t res;
u64 attr_ver;
@ -962,7 +960,7 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args,
if (ia->ff)
fuse_file_put(ia->ff, false);
fuse_io_folios_free(ia);
fuse_io_free(ia);
}
static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
@ -983,7 +981,7 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
/* Don't overflow end offset */
if (pos + (count - 1) == LLONG_MAX) {
count--;
ap->folio_descs[ap->num_folios - 1].length--;
ap->descs[ap->num_folios - 1].length--;
}
WARN_ON((loff_t) (pos + count) < 0);
@ -1044,7 +1042,7 @@ static void fuse_readahead(struct readahead_control *rac)
*/
break;
ia = fuse_io_folios_alloc(NULL, cur_pages);
ia = fuse_io_alloc(NULL, cur_pages);
if (!ia)
return;
ap = &ia->ap;
@ -1052,7 +1050,7 @@ static void fuse_readahead(struct readahead_control *rac)
while (ap->num_folios < cur_pages) {
folio = readahead_folio(rac);
ap->folios[ap->num_folios] = folio;
ap->folio_descs[ap->num_folios].length = folio_size(folio);
ap->descs[ap->num_folios].length = folio_size(folio);
ap->num_folios++;
}
fuse_send_readpages(ia, rac->file);
@ -1186,7 +1184,7 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,
err = -EIO;
short_write = ia->write.out.size < count;
offset = ap->folio_descs[0].offset;
offset = ap->descs[0].offset;
count = ia->write.out.size;
for (i = 0; i < ap->num_folios; i++) {
struct folio *folio = ap->folios[i];
@ -1224,7 +1222,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
int err;
ap->args.in_pages = true;
ap->folio_descs[0].offset = offset;
ap->descs[0].offset = offset;
do {
size_t tmp;
@ -1261,7 +1259,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_io_args *ia,
err = 0;
ap->folios[ap->num_folios] = folio;
ap->folio_descs[ap->num_folios].length = tmp;
ap->descs[ap->num_folios].length = tmp;
ap->num_folios++;
nr_pages++;
@ -1318,8 +1316,7 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
unsigned int nr_pages = fuse_wr_pages(pos, iov_iter_count(ii),
fc->max_pages);
ap->uses_folios = true;
ap->folios = fuse_folios_alloc(nr_pages, GFP_KERNEL, &ap->folio_descs);
ap->folios = fuse_folios_alloc(nr_pages, GFP_KERNEL, &ap->descs);
if (!ap->folios) {
err = -ENOMEM;
break;
@ -1564,13 +1561,13 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
/* Currently, all folios in FUSE are one page */
nfolios = DIV_ROUND_UP(ret, PAGE_SIZE);
ap->folio_descs[ap->num_folios].offset = start;
fuse_folio_descs_length_init(ap->folio_descs, ap->num_folios, nfolios);
ap->descs[ap->num_folios].offset = start;
fuse_folio_descs_length_init(ap->descs, ap->num_folios, nfolios);
for (i = 0; i < nfolios; i++)
ap->folios[i + ap->num_folios] = page_folio(pages[i]);
ap->num_folios += nfolios;
ap->folio_descs[ap->num_folios - 1].length -=
ap->descs[ap->num_folios - 1].length -=
(PAGE_SIZE - ret) & (PAGE_SIZE - 1);
nr_pages += nfolios;
}
@ -1614,14 +1611,14 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
bool fopen_direct_io = ff->open_flags & FOPEN_DIRECT_IO;
max_pages = iov_iter_npages(iter, fc->max_pages);
ia = fuse_io_folios_alloc(io, max_pages);
ia = fuse_io_alloc(io, max_pages);
if (!ia)
return -ENOMEM;
if (fopen_direct_io && fc->direct_io_allow_mmap) {
res = filemap_write_and_wait_range(mapping, pos, pos + count - 1);
if (res) {
fuse_io_folios_free(ia);
fuse_io_free(ia);
return res;
}
}
@ -1636,7 +1633,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
if (fopen_direct_io && write) {
res = invalidate_inode_pages2_range(mapping, idx_from, idx_to);
if (res) {
fuse_io_folios_free(ia);
fuse_io_free(ia);
return res;
}
}
@ -1663,7 +1660,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
if (!io->async || nres < 0) {
fuse_release_user_pages(&ia->ap, nres, io->should_dirty);
fuse_io_folios_free(ia);
fuse_io_free(ia);
}
ia = NULL;
if (nres < 0) {
@ -1682,13 +1679,13 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
}
if (count) {
max_pages = iov_iter_npages(iter, fc->max_pages);
ia = fuse_io_folios_alloc(io, max_pages);
ia = fuse_io_alloc(io, max_pages);
if (!ia)
break;
}
}
if (ia)
fuse_io_folios_free(ia);
fuse_io_free(ia);
if (res > 0)
*ppos = pos;
@ -2093,8 +2090,7 @@ static struct fuse_writepage_args *fuse_writepage_args_alloc(void)
if (wpa) {
ap = &wpa->ia.ap;
ap->num_folios = 0;
ap->uses_folios = true;
ap->folios = fuse_folios_alloc(1, GFP_NOFS, &ap->folio_descs);
ap->folios = fuse_folios_alloc(1, GFP_NOFS, &ap->descs);
if (!ap->folios) {
kfree(wpa);
wpa = NULL;
@ -2127,8 +2123,8 @@ static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struc
folio_copy(tmp_folio, folio);
ap->folios[folio_index] = tmp_folio;
ap->folio_descs[folio_index].offset = 0;
ap->folio_descs[folio_index].length = PAGE_SIZE;
ap->descs[folio_index].offset = 0;
ap->descs[folio_index].length = PAGE_SIZE;
inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
node_stat_add_folio(tmp_folio, NR_WRITEBACK_TEMP);
@ -2234,10 +2230,10 @@ static bool fuse_pages_realloc(struct fuse_fill_wb_data *data)
return false;
memcpy(folios, ap->folios, sizeof(struct folio *) * ap->num_folios);
memcpy(descs, ap->folio_descs, sizeof(struct fuse_folio_desc) * ap->num_folios);
memcpy(descs, ap->descs, sizeof(struct fuse_folio_desc) * ap->num_folios);
kfree(ap->folios);
ap->folios = folios;
ap->folio_descs = descs;
ap->descs = descs;
data->max_folios = nfolios;
return true;

View File

@ -285,12 +285,6 @@ struct fuse_arg {
void *value;
};
/** FUSE page descriptor */
struct fuse_page_desc {
unsigned int length;
unsigned int offset;
};
/** FUSE folio descriptor */
struct fuse_folio_desc {
unsigned int length;
@ -325,19 +319,9 @@ struct fuse_args {
struct fuse_args_pages {
struct fuse_args args;
union {
struct {
struct page **pages;
struct fuse_page_desc *descs;
unsigned int num_pages;
};
struct {
struct folio **folios;
struct fuse_folio_desc *folio_descs;
unsigned int num_folios;
};
};
bool uses_folios;
struct folio **folios;
struct fuse_folio_desc *descs;
unsigned int num_folios;
};
struct fuse_release_args {

View File

@ -251,12 +251,12 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);
err = -ENOMEM;
ap.folios = fuse_folios_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.folio_descs);
ap.folios = fuse_folios_alloc(fm->fc->max_pages, GFP_KERNEL, &ap.descs);
iov_page = (struct iovec *) __get_free_page(GFP_KERNEL);
if (!ap.folios || !iov_page)
goto out;
fuse_folio_descs_length_init(ap.folio_descs, 0, fm->fc->max_pages);
fuse_folio_descs_length_init(ap.descs, 0, fm->fc->max_pages);
/*
* If restricted, initialize IO parameters as encoded in @cmd.
@ -306,7 +306,6 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
err = -ENOMEM;
if (max_pages > fm->fc->max_pages)
goto out;
ap.uses_folios = true;
while (ap.num_folios < max_pages) {
ap.folios[ap.num_folios] = folio_alloc(GFP_KERNEL | __GFP_HIGHMEM, 0);
if (!ap.folios[ap.num_folios])

View File

@ -346,10 +346,9 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
plus = fuse_use_readdirplus(inode, ctx);
ap->args.out_pages = true;
ap->uses_folios = true;
ap->num_folios = 1;
ap->folios = &folio;
ap->folio_descs = &desc;
ap->descs = &desc;
if (plus) {
attr_version = fuse_get_attr_version(fm->fc);
fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,

View File

@ -765,7 +765,6 @@ static void virtio_fs_request_complete(struct fuse_req *req,
struct fuse_args *args;
struct fuse_args_pages *ap;
unsigned int len, i, thislen;
struct page *page;
struct folio *folio;
/*
@ -778,29 +777,15 @@ static void virtio_fs_request_complete(struct fuse_req *req,
if (args->out_pages && args->page_zeroing) {
len = args->out_args[args->out_numargs - 1].size;
ap = container_of(args, typeof(*ap), args);
if (ap->uses_folios) {
for (i = 0; i < ap->num_folios; i++) {
thislen = ap->folio_descs[i].length;
if (len < thislen) {
WARN_ON(ap->folio_descs[i].offset);
folio = ap->folios[i];
folio_zero_segment(folio, len, thislen);
len = 0;
} else {
len -= thislen;
}
}
} else {
for (i = 0; i < ap->num_pages; i++) {
thislen = ap->descs[i].length;
if (len < thislen) {
WARN_ON(ap->descs[i].offset);
page = ap->pages[i];
zero_user_segment(page, len, thislen);
len = 0;
} else {
len -= thislen;
}
for (i = 0; i < ap->num_folios; i++) {
thislen = ap->descs[i].length;
if (len < thislen) {
WARN_ON(ap->descs[i].offset);
folio = ap->folios[i];
folio_zero_segment(folio, len, thislen);
len = 0;
} else {
len -= thislen;
}
}
}
@ -1287,22 +1272,16 @@ static void virtio_fs_send_interrupt(struct fuse_iqueue *fiq, struct fuse_req *r
}
/* Count number of scatter-gather elements required */
static unsigned int sg_count_fuse_pages(struct fuse_args_pages *ap,
unsigned int total_len)
static unsigned int sg_count_fuse_folios(struct fuse_folio_desc *folio_descs,
unsigned int num_folios,
unsigned int total_len)
{
unsigned int i;
unsigned int this_len;
if (ap->uses_folios) {
for (i = 0; i < ap->num_folios && total_len; i++) {
this_len = min(ap->folio_descs[i].length, total_len);
total_len -= this_len;
}
} else {
for (i = 0; i < ap->num_pages && total_len; i++) {
this_len = min(ap->descs[i].length, total_len);
total_len -= this_len;
}
for (i = 0; i < num_folios && total_len; i++) {
this_len = min(folio_descs[i].length, total_len);
total_len -= this_len;
}
return i;
@ -1320,7 +1299,8 @@ static unsigned int sg_count_fuse_req(struct fuse_req *req)
if (args->in_pages) {
size = args->in_args[args->in_numargs - 1].size;
total_sgs += sg_count_fuse_pages(ap, size);
total_sgs += sg_count_fuse_folios(ap->descs, ap->num_folios,
size);
}
if (!test_bit(FR_ISREPLY, &req->flags))
@ -1333,35 +1313,28 @@ static unsigned int sg_count_fuse_req(struct fuse_req *req)
if (args->out_pages) {
size = args->out_args[args->out_numargs - 1].size;
total_sgs += sg_count_fuse_pages(ap, size);
total_sgs += sg_count_fuse_folios(ap->descs, ap->num_folios,
size);
}
return total_sgs;
}
/* Add pages/folios to scatter-gather list and return number of elements used */
static unsigned int sg_init_fuse_pages(struct scatterlist *sg,
struct fuse_args_pages *ap,
unsigned int total_len)
/* Add folios to scatter-gather list and return number of elements used */
static unsigned int sg_init_fuse_folios(struct scatterlist *sg,
struct folio **folios,
struct fuse_folio_desc *folio_descs,
unsigned int num_folios,
unsigned int total_len)
{
unsigned int i;
unsigned int this_len;
if (ap->uses_folios) {
for (i = 0; i < ap->num_folios && total_len; i++) {
sg_init_table(&sg[i], 1);
this_len = min(ap->folio_descs[i].length, total_len);
sg_set_folio(&sg[i], ap->folios[i], this_len,
ap->folio_descs[i].offset);
total_len -= this_len;
}
} else {
for (i = 0; i < ap->num_pages && total_len; i++) {
sg_init_table(&sg[i], 1);
this_len = min(ap->descs[i].length, total_len);
sg_set_page(&sg[i], ap->pages[i], this_len, ap->descs[i].offset);
total_len -= this_len;
}
for (i = 0; i < num_folios && total_len; i++) {
sg_init_table(&sg[i], 1);
this_len = min(folio_descs[i].length, total_len);
sg_set_folio(&sg[i], folios[i], this_len, folio_descs[i].offset);
total_len -= this_len;
}
return i;
@ -1385,8 +1358,10 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg,
sg_init_one(&sg[total_sgs++], argbuf, len);
if (argpages)
total_sgs += sg_init_fuse_pages(&sg[total_sgs], ap,
args[numargs - 1].size);
total_sgs += sg_init_fuse_folios(&sg[total_sgs],
ap->folios, ap->descs,
ap->num_folios,
args[numargs - 1].size);
if (len_used)
*len_used = len;