Skip to content

Commit ef7e7cb

Browse files
joannekoongbrauner
authored andcommitted
fuse: use iomap for writeback
Use iomap for dirty folio writeback in ->writepages(). This allows for granular dirty writeback of large folios. Only the dirty portions of the large folio will be written instead of having to write out the entire folio. For example if there is a 1 MB large folio and only 2 bytes in it are dirty, only the page for those dirty bytes will be written out. .dirty_folio needs to be set to iomap_dirty_folio so that the bitmap iomap uses for dirty tracking correctly reflects dirty regions that need to be written back. Signed-off-by: Joanne Koong <[email protected]> Link: https://lore.kernel.org/[email protected] Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent a4c9ab1 commit ef7e7cb

File tree

1 file changed

+82
-51
lines changed

1 file changed

+82
-51
lines changed

fs/fuse/file.c

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,7 +1833,7 @@ static void fuse_writepage_finish(struct fuse_writepage_args *wpa)
18331833
* scope of the fi->lock alleviates xarray lock
18341834
* contention and noticeably improves performance.
18351835
*/
1836-
folio_end_writeback(ap->folios[i]);
1836+
iomap_finish_folio_write(inode, ap->folios[i], 1);
18371837
dec_wb_stat(&bdi->wb, WB_WRITEBACK);
18381838
wb_writeout_inc(&bdi->wb);
18391839
}
@@ -2020,19 +2020,20 @@ static void fuse_writepage_add_to_bucket(struct fuse_conn *fc,
20202020
}
20212021

20222022
static void fuse_writepage_args_page_fill(struct fuse_writepage_args *wpa, struct folio *folio,
2023-
uint32_t folio_index)
2023+
uint32_t folio_index, loff_t offset, unsigned len)
20242024
{
20252025
struct inode *inode = folio->mapping->host;
20262026
struct fuse_args_pages *ap = &wpa->ia.ap;
20272027

20282028
ap->folios[folio_index] = folio;
2029-
ap->descs[folio_index].offset = 0;
2030-
ap->descs[folio_index].length = folio_size(folio);
2029+
ap->descs[folio_index].offset = offset;
2030+
ap->descs[folio_index].length = len;
20312031

20322032
inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
20332033
}
20342034

20352035
static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio,
2036+
size_t offset,
20362037
struct fuse_file *ff)
20372038
{
20382039
struct inode *inode = folio->mapping->host;
@@ -2045,7 +2046,7 @@ static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio
20452046
return NULL;
20462047

20472048
fuse_writepage_add_to_bucket(fc, wpa);
2048-
fuse_write_args_fill(&wpa->ia, ff, folio_pos(folio), 0);
2049+
fuse_write_args_fill(&wpa->ia, ff, folio_pos(folio) + offset, 0);
20492050
wpa->ia.write.in.write_flags |= FUSE_WRITE_CACHE;
20502051
wpa->inode = inode;
20512052
wpa->ia.ff = ff;
@@ -2071,7 +2072,7 @@ static int fuse_writepage_locked(struct folio *folio)
20712072
if (!ff)
20722073
goto err;
20732074

2074-
wpa = fuse_writepage_args_setup(folio, ff);
2075+
wpa = fuse_writepage_args_setup(folio, 0, ff);
20752076
error = -ENOMEM;
20762077
if (!wpa)
20772078
goto err_writepage_args;
@@ -2080,7 +2081,7 @@ static int fuse_writepage_locked(struct folio *folio)
20802081
ap->num_folios = 1;
20812082

20822083
folio_start_writeback(folio);
2083-
fuse_writepage_args_page_fill(wpa, folio, 0);
2084+
fuse_writepage_args_page_fill(wpa, folio, 0, 0, folio_size(folio));
20842085

20852086
spin_lock(&fi->lock);
20862087
list_add_tail(&wpa->queue_entry, &fi->queued_writes);
@@ -2101,7 +2102,12 @@ struct fuse_fill_wb_data {
21012102
struct fuse_file *ff;
21022103
struct inode *inode;
21032104
unsigned int max_folios;
2104-
unsigned int nr_pages;
2105+
/*
2106+
* nr_bytes won't overflow since fuse_writepage_need_send() caps
2107+
* wb requests to never exceed fc->max_pages (which has an upper bound
2108+
* of U16_MAX).
2109+
*/
2110+
unsigned int nr_bytes;
21052111
};
21062112

21072113
static bool fuse_pages_realloc(struct fuse_fill_wb_data *data)
@@ -2142,22 +2148,30 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
21422148
spin_unlock(&fi->lock);
21432149
}
21442150

2145-
static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
2146-
struct fuse_args_pages *ap,
2151+
static bool fuse_writepage_need_send(struct fuse_conn *fc, loff_t pos,
2152+
unsigned len, struct fuse_args_pages *ap,
21472153
struct fuse_fill_wb_data *data)
21482154
{
2155+
struct folio *prev_folio;
2156+
struct fuse_folio_desc prev_desc;
2157+
unsigned bytes = data->nr_bytes + len;
2158+
loff_t prev_pos;
2159+
21492160
WARN_ON(!ap->num_folios);
21502161

21512162
/* Reached max pages */
2152-
if (data->nr_pages + folio_nr_pages(folio) > fc->max_pages)
2163+
if ((bytes + PAGE_SIZE - 1) >> PAGE_SHIFT > fc->max_pages)
21532164
return true;
21542165

21552166
/* Reached max write bytes */
2156-
if ((data->nr_pages * PAGE_SIZE) + folio_size(folio) > fc->max_write)
2167+
if (bytes > fc->max_write)
21572168
return true;
21582169

21592170
/* Discontinuity */
2160-
if (folio_next_index(ap->folios[ap->num_folios - 1]) != folio->index)
2171+
prev_folio = ap->folios[ap->num_folios - 1];
2172+
prev_desc = ap->descs[ap->num_folios - 1];
2173+
prev_pos = folio_pos(prev_folio) + prev_desc.offset + prev_desc.length;
2174+
if (prev_pos != pos)
21612175
return true;
21622176

21632177
/* Need to grow the pages array? If so, did the expansion fail? */
@@ -2167,85 +2181,102 @@ static bool fuse_writepage_need_send(struct fuse_conn *fc, struct folio *folio,
21672181
return false;
21682182
}
21692183

2170-
static int fuse_writepages_fill(struct folio *folio,
2171-
struct writeback_control *wbc, void *_data)
2184+
static ssize_t fuse_iomap_writeback_range(struct iomap_writepage_ctx *wpc,
2185+
struct folio *folio, u64 pos,
2186+
unsigned len, u64 end_pos)
21722187
{
2173-
struct fuse_fill_wb_data *data = _data;
2188+
struct fuse_fill_wb_data *data = wpc->wb_ctx;
21742189
struct fuse_writepage_args *wpa = data->wpa;
21752190
struct fuse_args_pages *ap = &wpa->ia.ap;
21762191
struct inode *inode = data->inode;
21772192
struct fuse_inode *fi = get_fuse_inode(inode);
21782193
struct fuse_conn *fc = get_fuse_conn(inode);
2179-
int err;
2194+
loff_t offset = offset_in_folio(folio, pos);
2195+
2196+
WARN_ON_ONCE(!data);
2197+
/* len will always be page aligned */
2198+
WARN_ON_ONCE(len & (PAGE_SIZE - 1));
21802199

21812200
if (!data->ff) {
2182-
err = -EIO;
21832201
data->ff = fuse_write_file_get(fi);
21842202
if (!data->ff)
2185-
goto out_unlock;
2203+
return -EIO;
21862204
}
21872205

2188-
if (wpa && fuse_writepage_need_send(fc, folio, ap, data)) {
2206+
if (wpa && fuse_writepage_need_send(fc, pos, len, ap, data)) {
21892207
fuse_writepages_send(data);
21902208
data->wpa = NULL;
2191-
data->nr_pages = 0;
2209+
data->nr_bytes = 0;
21922210
}
21932211

21942212
if (data->wpa == NULL) {
2195-
err = -ENOMEM;
2196-
wpa = fuse_writepage_args_setup(folio, data->ff);
2213+
wpa = fuse_writepage_args_setup(folio, offset, data->ff);
21972214
if (!wpa)
2198-
goto out_unlock;
2215+
return -ENOMEM;
21992216
fuse_file_get(wpa->ia.ff);
22002217
data->max_folios = 1;
22012218
ap = &wpa->ia.ap;
22022219
}
2203-
folio_start_writeback(folio);
22042220

2205-
fuse_writepage_args_page_fill(wpa, folio, ap->num_folios);
2206-
data->nr_pages += folio_nr_pages(folio);
2221+
iomap_start_folio_write(inode, folio, 1);
2222+
fuse_writepage_args_page_fill(wpa, folio, ap->num_folios,
2223+
offset, len);
2224+
data->nr_bytes += len;
22072225

2208-
err = 0;
22092226
ap->num_folios++;
22102227
if (!data->wpa)
22112228
data->wpa = wpa;
2212-
out_unlock:
2213-
folio_unlock(folio);
22142229

2215-
return err;
2230+
return len;
2231+
}
2232+
2233+
static int fuse_iomap_writeback_submit(struct iomap_writepage_ctx *wpc,
2234+
int error)
2235+
{
2236+
struct fuse_fill_wb_data *data = wpc->wb_ctx;
2237+
2238+
WARN_ON_ONCE(!data);
2239+
2240+
if (data->wpa) {
2241+
WARN_ON(!data->wpa->ia.ap.num_folios);
2242+
fuse_writepages_send(data);
2243+
}
2244+
2245+
if (data->ff)
2246+
fuse_file_put(data->ff, false);
2247+
2248+
return error;
22162249
}
22172250

2251+
static const struct iomap_writeback_ops fuse_writeback_ops = {
2252+
.writeback_range = fuse_iomap_writeback_range,
2253+
.writeback_submit = fuse_iomap_writeback_submit,
2254+
};
2255+
22182256
static int fuse_writepages(struct address_space *mapping,
22192257
struct writeback_control *wbc)
22202258
{
22212259
struct inode *inode = mapping->host;
22222260
struct fuse_conn *fc = get_fuse_conn(inode);
2223-
struct fuse_fill_wb_data data;
2224-
int err;
2261+
struct fuse_fill_wb_data data = {
2262+
.inode = inode,
2263+
};
2264+
struct iomap_writepage_ctx wpc = {
2265+
.inode = inode,
2266+
.iomap.type = IOMAP_MAPPED,
2267+
.wbc = wbc,
2268+
.ops = &fuse_writeback_ops,
2269+
.wb_ctx = &data,
2270+
};
22252271

2226-
err = -EIO;
22272272
if (fuse_is_bad(inode))
2228-
goto out;
2273+
return -EIO;
22292274

22302275
if (wbc->sync_mode == WB_SYNC_NONE &&
22312276
fc->num_background >= fc->congestion_threshold)
22322277
return 0;
22332278

2234-
data.inode = inode;
2235-
data.wpa = NULL;
2236-
data.ff = NULL;
2237-
data.nr_pages = 0;
2238-
2239-
err = write_cache_pages(mapping, wbc, fuse_writepages_fill, &data);
2240-
if (data.wpa) {
2241-
WARN_ON(!data.wpa->ia.ap.num_folios);
2242-
fuse_writepages_send(&data);
2243-
}
2244-
if (data.ff)
2245-
fuse_file_put(data.ff, false);
2246-
2247-
out:
2248-
return err;
2279+
return iomap_writepages(&wpc);
22492280
}
22502281

22512282
static int fuse_launder_folio(struct folio *folio)
@@ -3105,7 +3136,7 @@ static const struct address_space_operations fuse_file_aops = {
31053136
.readahead = fuse_readahead,
31063137
.writepages = fuse_writepages,
31073138
.launder_folio = fuse_launder_folio,
3108-
.dirty_folio = filemap_dirty_folio,
3139+
.dirty_folio = iomap_dirty_folio,
31093140
.release_folio = iomap_release_folio,
31103141
.migrate_folio = filemap_migrate_folio,
31113142
.bmap = fuse_bmap,

0 commit comments

Comments
 (0)