Skip to content

Commit 989e294

Browse files
fs/ntfs3: improve readahead for bitmap initialization and large directory scans
Previously sequential reads operations relied solely on single-page reads, causing the block layer to perform many synchronous I/O requests, especially for large volumes or large directories. This patch introduces explicit readahead via page_cache_sync_readahead() and file_ra_state to reduce I/O latency and improve sequential throughput. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
1 parent 4248f56 commit 989e294

6 files changed

Lines changed: 79 additions & 25 deletions

File tree

fs/ntfs3/bitmap.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,8 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
508508
size_t wpos, wbit, iw, vbo;
509509
struct buffer_head *bh = NULL;
510510
CLST lcn, clen;
511+
struct file_ra_state *ra;
512+
struct address_space *mapping = sb->s_bdev->bd_mapping;
511513

512514
wnd->uptodated = 0;
513515
wnd->extent_max = 0;
@@ -516,6 +518,13 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
516518

517519
vbo = 0;
518520

521+
/* Allocate in memory instead of stack. Not critical if failed. */
522+
ra = kzalloc(sizeof(*ra), GFP_NOFS);
523+
if (ra) {
524+
file_ra_state_init(ra, mapping);
525+
ra->ra_pages = (wnd->nbits / 8 + PAGE_SIZE - 1) >> PAGE_SHIFT;
526+
}
527+
519528
for (iw = 0; iw < wnd->nwnd; iw++) {
520529
if (iw + 1 == wnd->nwnd)
521530
wbits = wnd->bits_last;
@@ -552,6 +561,13 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
552561
len = ((u64)clen << cluster_bits) - off;
553562
}
554563

564+
if (ra) {
565+
pgoff_t idx = lbo >> PAGE_SHIFT;
566+
if (!ra_has_index(ra, idx))
567+
page_cache_sync_readahead(mapping, ra, NULL,
568+
idx, 1);
569+
}
570+
555571
bh = ntfs_bread(sb, lbo >> sb->s_blocksize_bits);
556572
if (!bh) {
557573
err = -EIO;
@@ -638,6 +654,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
638654
}
639655

640656
out:
657+
kfree(ra);
641658
return err;
642659
}
643660

fs/ntfs3/dir.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -487,8 +487,8 @@ static int ntfs_readdir(struct file *file, struct dir_context *ctx)
487487
goto out;
488488
}
489489

490-
err = indx_read(&ni->dir, ni, bit << ni->dir.idx2vbn_bits,
491-
&node);
490+
err = indx_read_ra(&ni->dir, ni, bit << ni->dir.idx2vbn_bits,
491+
&node, &file->f_ra);
492492
if (err)
493493
goto out;
494494

fs/ntfs3/fslog.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,8 @@ struct ntfs_log {
10741074
u32 client_undo_commit;
10751075

10761076
struct restart_info rst_info, rst_info2;
1077+
1078+
struct file_ra_state read_ahead;
10771079
};
10781080

10791081
static inline u32 lsn_to_vbo(struct ntfs_log *log, const u64 lsn)
@@ -1164,8 +1166,8 @@ static int read_log_page(struct ntfs_log *log, u32 vbo,
11641166

11651167
page_buf = page_off ? log->one_page_buf : *buffer;
11661168

1167-
err = ntfs_read_run_nb(ni->mi.sbi, &ni->file.run, page_vbo, page_buf,
1168-
log->page_size, NULL);
1169+
err = ntfs_read_run_nb_ra(ni->mi.sbi, &ni->file.run, page_vbo, page_buf,
1170+
log->page_size, NULL, &log->read_ahead);
11691171
if (err)
11701172
goto out;
11711173

fs/ntfs3/fsntfs.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,11 +1164,13 @@ struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
11641164
return ntfs_bread(sb, lbo >> sb->s_blocksize_bits);
11651165
}
11661166

1167-
int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
1168-
u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb)
1167+
int ntfs_read_run_nb_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
1168+
u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb,
1169+
struct file_ra_state *ra)
11691170
{
11701171
int err;
11711172
struct super_block *sb = sbi->sb;
1173+
struct address_space *mapping = sb->s_bdev->bd_mapping;
11721174
u32 blocksize = sb->s_blocksize;
11731175
u8 cluster_bits = sbi->cluster_bits;
11741176
u32 off = vbo & sbi->cluster_mask;
@@ -1208,10 +1210,22 @@ int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
12081210
nb->bytes = bytes;
12091211
}
12101212

1213+
if (ra && !ra->ra_pages)
1214+
file_ra_state_init(ra, mapping);
1215+
12111216
for (;;) {
12121217
u32 len32 = len >= bytes ? bytes : len;
12131218
sector_t block = lbo >> sb->s_blocksize_bits;
12141219

1220+
if (ra) {
1221+
pgoff_t index = lbo >> PAGE_SHIFT;
1222+
if (!ra_has_index(ra, index)) {
1223+
page_cache_sync_readahead(mapping, ra, NULL,
1224+
index, 1);
1225+
ra->prev_pos = (loff_t)index << PAGE_SHIFT;
1226+
}
1227+
}
1228+
12151229
do {
12161230
u32 op = blocksize - off;
12171231

@@ -1282,11 +1296,11 @@ int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
12821296
*
12831297
* Return: < 0 if error, 0 if ok, -E_NTFS_FIXUP if need to update fixups.
12841298
*/
1285-
int ntfs_read_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
1286-
struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
1287-
struct ntfs_buffers *nb)
1299+
int ntfs_read_bh_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
1300+
u64 vbo, struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
1301+
struct ntfs_buffers *nb, struct file_ra_state *ra)
12881302
{
1289-
int err = ntfs_read_run_nb(sbi, run, vbo, rhdr, bytes, nb);
1303+
int err = ntfs_read_run_nb_ra(sbi, run, vbo, rhdr, bytes, nb, ra);
12901304

12911305
if (err)
12921306
return err;
@@ -1347,8 +1361,7 @@ int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
13471361
wait_on_buffer(bh);
13481362

13491363
lock_buffer(bh);
1350-
if (!buffer_uptodate(bh))
1351-
{
1364+
if (!buffer_uptodate(bh)) {
13521365
memset(bh->b_data, 0, blocksize);
13531366
set_buffer_uptodate(bh);
13541367
}

fs/ntfs3/index.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,17 +1026,18 @@ static int indx_write(struct ntfs_index *indx, struct ntfs_inode *ni,
10261026
}
10271027

10281028
/*
1029-
* indx_read
1029+
* indx_read_ra
10301030
*
10311031
* If ntfs_readdir calls this function
10321032
* inode is shared locked and no ni_lock.
10331033
* Use rw_semaphore for read/write access to alloc_run.
10341034
*/
1035-
int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn,
1036-
struct indx_node **node)
1035+
int indx_read_ra(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn,
1036+
struct indx_node **node, struct file_ra_state *ra)
10371037
{
10381038
int err;
10391039
struct INDEX_BUFFER *ib;
1040+
struct ntfs_sb_info *sbi = ni->mi.sbi;
10401041
struct runs_tree *run = &indx->alloc_run;
10411042
struct rw_semaphore *lock = &indx->run_lock;
10421043
u64 vbo = (u64)vbn << indx->vbn2vbo_bits;
@@ -1062,7 +1063,7 @@ int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn,
10621063
}
10631064

10641065
down_read(lock);
1065-
err = ntfs_read_bh(ni->mi.sbi, run, vbo, &ib->rhdr, bytes, &in->nb);
1066+
err = ntfs_read_bh_ra(sbi, run, vbo, &ib->rhdr, bytes, &in->nb, ra);
10661067
up_read(lock);
10671068
if (!err)
10681069
goto ok;
@@ -1082,7 +1083,7 @@ int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn,
10821083
goto out;
10831084

10841085
down_read(lock);
1085-
err = ntfs_read_bh(ni->mi.sbi, run, vbo, &ib->rhdr, bytes, &in->nb);
1086+
err = ntfs_read_bh_ra(sbi, run, vbo, &ib->rhdr, bytes, &in->nb, ra);
10861087
up_read(lock);
10871088
if (err == -E_NTFS_FIXUP)
10881089
goto ok;
@@ -1098,7 +1099,7 @@ int indx_read(struct ntfs_index *indx, struct ntfs_inode *ni, CLST vbn,
10981099
}
10991100

11001101
if (err == -E_NTFS_FIXUP) {
1101-
ntfs_write_bh(ni->mi.sbi, &ib->rhdr, &in->nb, 0);
1102+
ntfs_write_bh(sbi, &ib->rhdr, &in->nb, 0);
11021103
err = 0;
11031104
}
11041105

fs/ntfs3/ntfs_fs.h

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -625,11 +625,27 @@ int ntfs_sb_write_run(struct ntfs_sb_info *sbi, const struct runs_tree *run,
625625
u64 vbo, const void *buf, size_t bytes, int sync);
626626
struct buffer_head *ntfs_bread_run(struct ntfs_sb_info *sbi,
627627
const struct runs_tree *run, u64 vbo);
628-
int ntfs_read_run_nb(struct ntfs_sb_info *sbi, const struct runs_tree *run,
629-
u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb);
630-
int ntfs_read_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
631-
struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
632-
struct ntfs_buffers *nb);
628+
int ntfs_read_run_nb_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
629+
u64 vbo, void *buf, u32 bytes, struct ntfs_buffers *nb,
630+
struct file_ra_state *ra);
631+
static inline int ntfs_read_run_nb(struct ntfs_sb_info *sbi,
632+
const struct runs_tree *run, u64 vbo,
633+
void *buf, u32 bytes,
634+
struct ntfs_buffers *nb)
635+
{
636+
return ntfs_read_run_nb_ra(sbi, run, vbo, buf, bytes, nb, NULL);
637+
}
638+
int ntfs_read_bh_ra(struct ntfs_sb_info *sbi, const struct runs_tree *run,
639+
u64 vbo, struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
640+
struct ntfs_buffers *nb, struct file_ra_state *ra);
641+
static inline int ntfs_read_bh(struct ntfs_sb_info *sbi,
642+
const struct runs_tree *run, u64 vbo,
643+
struct NTFS_RECORD_HEADER *rhdr, u32 bytes,
644+
struct ntfs_buffers *nb)
645+
{
646+
return ntfs_read_bh_ra(sbi, run, vbo, rhdr, bytes, nb, NULL);
647+
}
648+
633649
int ntfs_get_bh(struct ntfs_sb_info *sbi, const struct runs_tree *run, u64 vbo,
634650
u32 bytes, struct ntfs_buffers *nb);
635651
int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
@@ -695,8 +711,13 @@ int indx_init(struct ntfs_index *indx, struct ntfs_sb_info *sbi,
695711
const struct ATTRIB *attr, enum index_mutex_classed type);
696712
struct INDEX_ROOT *indx_get_root(struct ntfs_index *indx, struct ntfs_inode *ni,
697713
struct ATTRIB **attr, struct mft_inode **mi);
698-
int indx_read(struct ntfs_index *idx, struct ntfs_inode *ni, CLST vbn,
699-
struct indx_node **node);
714+
int indx_read_ra(struct ntfs_index *idx, struct ntfs_inode *ni, CLST vbn,
715+
struct indx_node **node, struct file_ra_state *ra);
716+
static inline int indx_read(struct ntfs_index *idx, struct ntfs_inode *ni,
717+
CLST vbn, struct indx_node **node)
718+
{
719+
return indx_read_ra(idx, ni, vbn, node, NULL);
720+
}
700721
int indx_find(struct ntfs_index *indx, struct ntfs_inode *dir,
701722
const struct INDEX_ROOT *root, const void *Key, size_t KeyLen,
702723
const void *param, int *diff, struct NTFS_DE **entry,

0 commit comments

Comments
 (0)