Skip to content

Commit ce63cb6

Browse files
committed
erofs: support unencoded inodes for fileio
Since EROFS only needs to handle read requests in simple contexts, Just directly use vfs_iocb_iter_read() for data I/Os. Reviewed-by: Sandeep Dhavale <[email protected]> Reviewed-by: Chao Yu <[email protected]> Signed-off-by: Gao Xiang <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent fb17675 commit ce63cb6

File tree

6 files changed

+248
-51
lines changed

6 files changed

+248
-51
lines changed

fs/erofs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ erofs-$(CONFIG_EROFS_FS_ZIP) += decompressor.o zmap.o zdata.o zutil.o
77
erofs-$(CONFIG_EROFS_FS_ZIP_LZMA) += decompressor_lzma.o
88
erofs-$(CONFIG_EROFS_FS_ZIP_DEFLATE) += decompressor_deflate.o
99
erofs-$(CONFIG_EROFS_FS_ZIP_ZSTD) += decompressor_zstd.o
10+
erofs-$(CONFIG_EROFS_FS_BACKED_BY_FILE) += fileio.o
1011
erofs-$(CONFIG_EROFS_FS_ONDEMAND) += fscache.o

fs/erofs/data.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map)
132132
if (map->m_la >= inode->i_size) {
133133
/* leave out-of-bound access unmapped */
134134
map->m_flags = 0;
135-
map->m_plen = 0;
135+
map->m_plen = map->m_llen;
136136
goto out;
137137
}
138138

@@ -197,8 +197,13 @@ static void erofs_fill_from_devinfo(struct erofs_map_dev *map,
197197
struct erofs_device_info *dif)
198198
{
199199
map->m_bdev = NULL;
200-
if (dif->file && S_ISBLK(file_inode(dif->file)->i_mode))
201-
map->m_bdev = file_bdev(dif->file);
200+
map->m_fp = NULL;
201+
if (dif->file) {
202+
if (S_ISBLK(file_inode(dif->file)->i_mode))
203+
map->m_bdev = file_bdev(dif->file);
204+
else
205+
map->m_fp = dif->file;
206+
}
202207
map->m_daxdev = dif->dax_dev;
203208
map->m_dax_part_off = dif->dax_part_off;
204209
map->m_fscache = dif->fscache;
@@ -215,6 +220,7 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
215220
map->m_daxdev = EROFS_SB(sb)->dax_dev;
216221
map->m_dax_part_off = EROFS_SB(sb)->dax_part_off;
217222
map->m_fscache = EROFS_SB(sb)->s_fscache;
223+
map->m_fp = EROFS_SB(sb)->fdev;
218224

219225
if (map->m_deviceid) {
220226
down_read(&devs->rwsem);
@@ -250,6 +256,42 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
250256
return 0;
251257
}
252258

259+
/*
260+
* bit 30: I/O error occurred on this folio
261+
* bit 0 - 29: remaining parts to complete this folio
262+
*/
263+
#define EROFS_ONLINEFOLIO_EIO (1 << 30)
264+
265+
void erofs_onlinefolio_init(struct folio *folio)
266+
{
267+
union {
268+
atomic_t o;
269+
void *v;
270+
} u = { .o = ATOMIC_INIT(1) };
271+
272+
folio->private = u.v; /* valid only if file-backed folio is locked */
273+
}
274+
275+
void erofs_onlinefolio_split(struct folio *folio)
276+
{
277+
atomic_inc((atomic_t *)&folio->private);
278+
}
279+
280+
void erofs_onlinefolio_end(struct folio *folio, int err)
281+
{
282+
int orig, v;
283+
284+
do {
285+
orig = atomic_read((atomic_t *)&folio->private);
286+
v = (orig - 1) | (err ? EROFS_ONLINEFOLIO_EIO : 0);
287+
} while (atomic_cmpxchg((atomic_t *)&folio->private, orig, v) != orig);
288+
289+
if (v & ~EROFS_ONLINEFOLIO_EIO)
290+
return;
291+
folio->private = 0;
292+
folio_end_read(folio, !(v & EROFS_ONLINEFOLIO_EIO));
293+
}
294+
253295
static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
254296
unsigned int flags, struct iomap *iomap, struct iomap *srcmap)
255297
{
@@ -399,7 +441,7 @@ static ssize_t erofs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
399441
}
400442

401443
/* for uncompressed (aligned) files and raw access for other files */
402-
const struct address_space_operations erofs_raw_access_aops = {
444+
const struct address_space_operations erofs_aops = {
403445
.read_folio = erofs_read_folio,
404446
.readahead = erofs_readahead,
405447
.bmap = erofs_bmap,

fs/erofs/fileio.c

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (C) 2024, Alibaba Cloud
4+
*/
5+
#include "internal.h"
6+
#include <trace/events/erofs.h>
7+
8+
struct erofs_fileio_rq {
9+
struct bio_vec bvecs[BIO_MAX_VECS];
10+
struct bio bio;
11+
struct kiocb iocb;
12+
};
13+
14+
struct erofs_fileio {
15+
struct erofs_map_blocks map;
16+
struct erofs_map_dev dev;
17+
struct erofs_fileio_rq *rq;
18+
};
19+
20+
static void erofs_fileio_ki_complete(struct kiocb *iocb, long ret)
21+
{
22+
struct erofs_fileio_rq *rq =
23+
container_of(iocb, struct erofs_fileio_rq, iocb);
24+
struct folio_iter fi;
25+
26+
DBG_BUGON(rq->bio.bi_end_io);
27+
if (ret > 0) {
28+
if (ret != rq->bio.bi_iter.bi_size) {
29+
bio_advance(&rq->bio, ret);
30+
zero_fill_bio(&rq->bio);
31+
}
32+
ret = 0;
33+
}
34+
bio_for_each_folio_all(fi, &rq->bio) {
35+
DBG_BUGON(folio_test_uptodate(fi.folio));
36+
erofs_onlinefolio_end(fi.folio, ret);
37+
}
38+
bio_uninit(&rq->bio);
39+
kfree(rq);
40+
}
41+
42+
static void erofs_fileio_rq_submit(struct erofs_fileio_rq *rq)
43+
{
44+
struct iov_iter iter;
45+
int ret;
46+
47+
if (!rq)
48+
return;
49+
rq->iocb.ki_pos = rq->bio.bi_iter.bi_sector << SECTOR_SHIFT;
50+
rq->iocb.ki_ioprio = get_current_ioprio();
51+
rq->iocb.ki_complete = erofs_fileio_ki_complete;
52+
rq->iocb.ki_flags = (rq->iocb.ki_filp->f_mode & FMODE_CAN_ODIRECT) ?
53+
IOCB_DIRECT : 0;
54+
iov_iter_bvec(&iter, ITER_DEST, rq->bvecs, rq->bio.bi_vcnt,
55+
rq->bio.bi_iter.bi_size);
56+
ret = vfs_iocb_iter_read(rq->iocb.ki_filp, &rq->iocb, &iter);
57+
if (ret != -EIOCBQUEUED)
58+
erofs_fileio_ki_complete(&rq->iocb, ret);
59+
}
60+
61+
static struct erofs_fileio_rq *erofs_fileio_rq_alloc(struct erofs_map_dev *mdev)
62+
{
63+
struct erofs_fileio_rq *rq = kzalloc(sizeof(*rq),
64+
GFP_KERNEL | __GFP_NOFAIL);
65+
66+
bio_init(&rq->bio, NULL, rq->bvecs, BIO_MAX_VECS, REQ_OP_READ);
67+
rq->iocb.ki_filp = mdev->m_fp;
68+
return rq;
69+
}
70+
71+
static int erofs_fileio_scan_folio(struct erofs_fileio *io, struct folio *folio)
72+
{
73+
struct inode *inode = folio_inode(folio);
74+
struct erofs_map_blocks *map = &io->map;
75+
unsigned int cur = 0, end = folio_size(folio), len, attached = 0;
76+
loff_t pos = folio_pos(folio), ofs;
77+
struct iov_iter iter;
78+
struct bio_vec bv;
79+
int err = 0;
80+
81+
erofs_onlinefolio_init(folio);
82+
while (cur < end) {
83+
if (!in_range(pos + cur, map->m_la, map->m_llen)) {
84+
map->m_la = pos + cur;
85+
map->m_llen = end - cur;
86+
err = erofs_map_blocks(inode, map);
87+
if (err)
88+
break;
89+
}
90+
91+
ofs = folio_pos(folio) + cur - map->m_la;
92+
len = min_t(loff_t, map->m_llen - ofs, end - cur);
93+
if (map->m_flags & EROFS_MAP_META) {
94+
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
95+
void *src;
96+
97+
src = erofs_read_metabuf(&buf, inode->i_sb,
98+
map->m_pa + ofs, EROFS_KMAP);
99+
if (IS_ERR(src)) {
100+
err = PTR_ERR(src);
101+
break;
102+
}
103+
bvec_set_folio(&bv, folio, len, cur);
104+
iov_iter_bvec(&iter, ITER_DEST, &bv, 1, len);
105+
if (copy_to_iter(src, len, &iter) != len) {
106+
erofs_put_metabuf(&buf);
107+
err = -EIO;
108+
break;
109+
}
110+
erofs_put_metabuf(&buf);
111+
} else if (!(map->m_flags & EROFS_MAP_MAPPED)) {
112+
folio_zero_segment(folio, cur, cur + len);
113+
attached = 0;
114+
} else {
115+
if (io->rq && (map->m_pa + ofs != io->dev.m_pa ||
116+
map->m_deviceid != io->dev.m_deviceid)) {
117+
io_retry:
118+
erofs_fileio_rq_submit(io->rq);
119+
io->rq = NULL;
120+
}
121+
122+
if (!io->rq) {
123+
io->dev = (struct erofs_map_dev) {
124+
.m_pa = io->map.m_pa + ofs,
125+
.m_deviceid = io->map.m_deviceid,
126+
};
127+
err = erofs_map_dev(inode->i_sb, &io->dev);
128+
if (err)
129+
break;
130+
io->rq = erofs_fileio_rq_alloc(&io->dev);
131+
io->rq->bio.bi_iter.bi_sector = io->dev.m_pa >> 9;
132+
attached = 0;
133+
}
134+
if (!attached++)
135+
erofs_onlinefolio_split(folio);
136+
if (!bio_add_folio(&io->rq->bio, folio, len, cur))
137+
goto io_retry;
138+
io->dev.m_pa += len;
139+
}
140+
cur += len;
141+
}
142+
erofs_onlinefolio_end(folio, err);
143+
return err;
144+
}
145+
146+
static int erofs_fileio_read_folio(struct file *file, struct folio *folio)
147+
{
148+
struct erofs_fileio io = {};
149+
int err;
150+
151+
trace_erofs_read_folio(folio, true);
152+
err = erofs_fileio_scan_folio(&io, folio);
153+
erofs_fileio_rq_submit(io.rq);
154+
return err;
155+
}
156+
157+
static void erofs_fileio_readahead(struct readahead_control *rac)
158+
{
159+
struct inode *inode = rac->mapping->host;
160+
struct erofs_fileio io = {};
161+
struct folio *folio;
162+
int err;
163+
164+
trace_erofs_readpages(inode, readahead_index(rac),
165+
readahead_count(rac), true);
166+
while ((folio = readahead_folio(rac))) {
167+
err = erofs_fileio_scan_folio(&io, folio);
168+
if (err && err != -EINTR)
169+
erofs_err(inode->i_sb, "readahead error at folio %lu @ nid %llu",
170+
folio->index, EROFS_I(inode)->nid);
171+
}
172+
erofs_fileio_rq_submit(io.rq);
173+
}
174+
175+
const struct address_space_operations erofs_fileio_aops = {
176+
.read_folio = erofs_fileio_read_folio,
177+
.readahead = erofs_fileio_readahead,
178+
};

fs/erofs/inode.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,14 @@ static int erofs_fill_inode(struct inode *inode)
250250
}
251251

252252
mapping_set_large_folios(inode->i_mapping);
253-
if (erofs_is_fileio_mode(EROFS_SB(inode->i_sb))) {
254-
/* XXX: data I/Os will be implemented in the following patches */
255-
err = -EOPNOTSUPP;
256-
} else if (erofs_inode_is_data_compressed(vi->datalayout)) {
253+
if (erofs_inode_is_data_compressed(vi->datalayout)) {
257254
#ifdef CONFIG_EROFS_FS_ZIP
255+
#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
256+
if (erofs_is_fileio_mode(EROFS_SB(inode->i_sb))) {
257+
err = -EOPNOTSUPP;
258+
goto out_unlock;
259+
}
260+
#endif
258261
DO_ONCE_LITE_IF(inode->i_blkbits != PAGE_SHIFT,
259262
erofs_info, inode->i_sb,
260263
"EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!");
@@ -263,10 +266,14 @@ static int erofs_fill_inode(struct inode *inode)
263266
err = -EOPNOTSUPP;
264267
#endif
265268
} else {
266-
inode->i_mapping->a_ops = &erofs_raw_access_aops;
269+
inode->i_mapping->a_ops = &erofs_aops;
267270
#ifdef CONFIG_EROFS_FS_ONDEMAND
268271
if (erofs_is_fscache_mode(inode->i_sb))
269272
inode->i_mapping->a_ops = &erofs_fscache_access_aops;
273+
#endif
274+
#ifdef CONFIG_EROFS_FS_BACKED_BY_FILE
275+
if (erofs_is_fileio_mode(EROFS_SB(inode->i_sb)))
276+
inode->i_mapping->a_ops = &erofs_fileio_aops;
270277
#endif
271278
}
272279
out_unlock:

fs/erofs/internal.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ struct erofs_map_dev {
372372
struct erofs_fscache *m_fscache;
373373
struct block_device *m_bdev;
374374
struct dax_device *m_daxdev;
375+
struct file *m_fp;
375376
u64 m_dax_part_off;
376377

377378
erofs_off_t m_pa;
@@ -380,7 +381,8 @@ struct erofs_map_dev {
380381

381382
extern const struct super_operations erofs_sops;
382383

383-
extern const struct address_space_operations erofs_raw_access_aops;
384+
extern const struct address_space_operations erofs_aops;
385+
extern const struct address_space_operations erofs_fileio_aops;
384386
extern const struct address_space_operations z_erofs_aops;
385387
extern const struct address_space_operations erofs_fscache_access_aops;
386388

@@ -411,6 +413,9 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *dev);
411413
int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
412414
u64 start, u64 len);
413415
int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map);
416+
void erofs_onlinefolio_init(struct folio *folio);
417+
void erofs_onlinefolio_split(struct folio *folio);
418+
void erofs_onlinefolio_end(struct folio *folio, int err);
414419
struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid);
415420
int erofs_getattr(struct mnt_idmap *idmap, const struct path *path,
416421
struct kstat *stat, u32 request_mask,

0 commit comments

Comments
 (0)