Skip to content

Commit f35590e

Browse files
fs/ntfs3: remove ntfs_bio_pages and use page cache for compressed I/O
Replace the use of ntfs_bio_pages with the disk page cache for reading and writing compressed files. This slightly improves performance when reading compressed data and simplifies the I/O logic. When an XPRESS or LZX compressed file is opened for writing, it is now decompressed into a normal file before modification. A new argument (`int copy`) is added to ni_read_frame() to handle writing of decompressed and mapped data. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
1 parent c3856bb commit f35590e

6 files changed

Lines changed: 114 additions & 192 deletions

File tree

fs/ntfs3/attrib.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,7 +1457,6 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
14571457
pgoff_t index = vbo[i] >> PAGE_SHIFT;
14581458

14591459
if (index != folio->index) {
1460-
struct page *page = &folio->page;
14611460
u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1);
14621461
u64 to = min(from + PAGE_SIZE, wof_size);
14631462

@@ -1467,8 +1466,7 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
14671466
if (err)
14681467
goto out1;
14691468

1470-
err = ntfs_bio_pages(sbi, run, &page, 1, from,
1471-
to - from, REQ_OP_READ);
1469+
err = ntfs_read_run(sbi, run, addr, from, to - from);
14721470
if (err) {
14731471
folio->index = -1;
14741472
goto out1;

fs/ntfs3/file.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static int ntfs_ioctl_get_volume_label(struct ntfs_sb_info *sbi, u8 __user *buf)
5959

6060
static int ntfs_ioctl_set_volume_label(struct ntfs_sb_info *sbi, u8 __user *buf)
6161
{
62-
u8 user[FSLABEL_MAX] = {0};
62+
u8 user[FSLABEL_MAX] = { 0 };
6363
int len;
6464

6565
if (!capable(CAP_SYS_ADMIN))
@@ -1039,7 +1039,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
10391039

10401040
if (!frame_uptodate && off) {
10411041
err = ni_read_frame(ni, frame_vbo, pages,
1042-
pages_per_frame);
1042+
pages_per_frame, 0);
10431043
if (err) {
10441044
for (ip = 0; ip < pages_per_frame; ip++) {
10451045
folio = page_folio(pages[ip]);
@@ -1104,7 +1104,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
11041104

11051105
if (off || (to < i_size && (to & (frame_size - 1)))) {
11061106
err = ni_read_frame(ni, frame_vbo, pages,
1107-
pages_per_frame);
1107+
pages_per_frame, 0);
11081108
if (err) {
11091109
for (ip = 0; ip < pages_per_frame;
11101110
ip++) {

fs/ntfs3/frecord.c

Lines changed: 39 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,7 @@ int ni_readpage_cmpr(struct ntfs_inode *ni, struct folio *folio)
21052105
pages[i] = pg;
21062106
}
21072107

2108-
err = ni_read_frame(ni, frame_vbo, pages, pages_per_frame);
2108+
err = ni_read_frame(ni, frame_vbo, pages, pages_per_frame, 0);
21092109

21102110
out1:
21112111
for (i = 0; i < pages_per_frame; i++) {
@@ -2175,17 +2175,9 @@ int ni_decompress_file(struct ntfs_inode *ni)
21752175
*/
21762176
index = 0;
21772177
for (vbo = 0; vbo < i_size; vbo += bytes) {
2178-
u32 nr_pages;
21792178
bool new;
21802179

2181-
if (vbo + frame_size > i_size) {
2182-
bytes = i_size - vbo;
2183-
nr_pages = (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
2184-
} else {
2185-
nr_pages = pages_per_frame;
2186-
bytes = frame_size;
2187-
}
2188-
2180+
bytes = vbo + frame_size > i_size ? (i_size - vbo) : frame_size;
21892181
end = bytes_to_cluster(sbi, vbo + bytes);
21902182

21912183
for (vcn = vbo >> sbi->cluster_bits; vcn < end; vcn += clen) {
@@ -2210,15 +2202,7 @@ int ni_decompress_file(struct ntfs_inode *ni)
22102202
pages[i] = pg;
22112203
}
22122204

2213-
err = ni_read_frame(ni, vbo, pages, pages_per_frame);
2214-
2215-
if (!err) {
2216-
down_read(&ni->file.run_lock);
2217-
err = ntfs_bio_pages(sbi, &ni->file.run, pages,
2218-
nr_pages, vbo, bytes,
2219-
REQ_OP_WRITE);
2220-
up_read(&ni->file.run_lock);
2221-
}
2205+
err = ni_read_frame(ni, vbo, pages, pages_per_frame, 1);
22222206

22232207
for (i = 0; i < pages_per_frame; i++) {
22242208
unlock_page(pages[i]);
@@ -2408,20 +2392,19 @@ static int decompress_lzx_xpress(struct ntfs_sb_info *sbi, const char *cmpr,
24082392
* Pages - Array of locked pages.
24092393
*/
24102394
int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
2411-
u32 pages_per_frame)
2395+
u32 pages_per_frame, int copy)
24122396
{
24132397
int err;
24142398
struct ntfs_sb_info *sbi = ni->mi.sbi;
24152399
u8 cluster_bits = sbi->cluster_bits;
24162400
char *frame_ondisk = NULL;
24172401
char *frame_mem = NULL;
2418-
struct page **pages_disk = NULL;
24192402
struct ATTR_LIST_ENTRY *le = NULL;
24202403
struct runs_tree *run = &ni->file.run;
24212404
u64 valid_size = ni->i_valid;
24222405
u64 vbo_disk;
24232406
size_t unc_size;
2424-
u32 frame_size, i, npages_disk, ondisk_size;
2407+
u32 frame_size, i, ondisk_size;
24252408
struct page *pg;
24262409
struct ATTRIB *attr;
24272410
CLST frame, clst_data;
@@ -2513,7 +2496,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
25132496
err = attr_wof_frame_info(ni, attr, run, frame64, frames,
25142497
frame_bits, &ondisk_size, &vbo_data);
25152498
if (err)
2516-
goto out2;
2499+
goto out1;
25172500

25182501
if (frame64 == frames) {
25192502
unc_size = 1 + ((i_size - 1) & (frame_size - 1));
@@ -2524,7 +2507,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
25242507

25252508
if (ondisk_size > frame_size) {
25262509
err = -EINVAL;
2527-
goto out2;
2510+
goto out1;
25282511
}
25292512

25302513
if (!attr->non_res) {
@@ -2545,10 +2528,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
25452528
ARRAY_SIZE(WOF_NAME), run, vbo_disk,
25462529
vbo_data + ondisk_size);
25472530
if (err)
2548-
goto out2;
2549-
npages_disk = (ondisk_size + (vbo_disk & (PAGE_SIZE - 1)) +
2550-
PAGE_SIZE - 1) >>
2551-
PAGE_SHIFT;
2531+
goto out1;
25522532
#endif
25532533
} else if (is_attr_compressed(attr)) {
25542534
/* LZNT compression. */
@@ -2582,60 +2562,37 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
25822562
if (clst_data >= NTFS_LZNT_CLUSTERS) {
25832563
/* Frame is not compressed. */
25842564
down_read(&ni->file.run_lock);
2585-
err = ntfs_bio_pages(sbi, run, pages, pages_per_frame,
2586-
frame_vbo, ondisk_size,
2587-
REQ_OP_READ);
2565+
err = ntfs_read_run(sbi, run, frame_mem, frame_vbo,
2566+
ondisk_size);
25882567
up_read(&ni->file.run_lock);
25892568
goto out1;
25902569
}
25912570
vbo_disk = frame_vbo;
2592-
npages_disk = (ondisk_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
25932571
} else {
25942572
__builtin_unreachable();
25952573
err = -EINVAL;
25962574
goto out1;
25972575
}
25982576

2599-
pages_disk = kcalloc(npages_disk, sizeof(*pages_disk), GFP_NOFS);
2600-
if (!pages_disk) {
2577+
/* Allocate memory to read compressed data to. */
2578+
frame_ondisk = kvmalloc(ondisk_size, GFP_KERNEL);
2579+
if (!frame_ondisk) {
26012580
err = -ENOMEM;
2602-
goto out2;
2603-
}
2604-
2605-
for (i = 0; i < npages_disk; i++) {
2606-
pg = alloc_page(GFP_KERNEL);
2607-
if (!pg) {
2608-
err = -ENOMEM;
2609-
goto out3;
2610-
}
2611-
pages_disk[i] = pg;
2612-
lock_page(pg);
2581+
goto out1;
26132582
}
26142583

26152584
/* Read 'ondisk_size' bytes from disk. */
26162585
down_read(&ni->file.run_lock);
2617-
err = ntfs_bio_pages(sbi, run, pages_disk, npages_disk, vbo_disk,
2618-
ondisk_size, REQ_OP_READ);
2586+
err = ntfs_read_run(sbi, run, frame_ondisk, vbo_disk, ondisk_size);
26192587
up_read(&ni->file.run_lock);
26202588
if (err)
2621-
goto out3;
2622-
2623-
/*
2624-
* To simplify decompress algorithm do vmap for source and target pages.
2625-
*/
2626-
frame_ondisk = vmap(pages_disk, npages_disk, VM_MAP, PAGE_KERNEL_RO);
2627-
if (!frame_ondisk) {
2628-
err = -ENOMEM;
2629-
goto out3;
2630-
}
2589+
goto out2;
26312590

2632-
/* Decompress: Frame_ondisk -> frame_mem. */
26332591
#ifdef CONFIG_NTFS3_LZX_XPRESS
26342592
if (run != &ni->file.run) {
26352593
/* LZX or XPRESS */
2636-
err = decompress_lzx_xpress(
2637-
sbi, frame_ondisk + (vbo_disk & (PAGE_SIZE - 1)),
2638-
ondisk_size, frame_mem, unc_size, frame_size);
2594+
err = decompress_lzx_xpress(sbi, frame_ondisk, ondisk_size,
2595+
frame_mem, unc_size, frame_size);
26392596
} else
26402597
#endif
26412598
{
@@ -2653,24 +2610,21 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
26532610
memset(frame_mem + ok, 0, frame_size - ok);
26542611
}
26552612

2656-
vunmap(frame_ondisk);
2657-
2658-
out3:
2659-
for (i = 0; i < npages_disk; i++) {
2660-
pg = pages_disk[i];
2661-
if (pg) {
2662-
unlock_page(pg);
2663-
put_page(pg);
2664-
}
2665-
}
2666-
kfree(pages_disk);
2667-
26682613
out2:
2614+
kvfree(frame_ondisk);
2615+
out1:
26692616
#ifdef CONFIG_NTFS3_LZX_XPRESS
26702617
if (run != &ni->file.run)
26712618
run_free(run);
2619+
if (!err && copy) {
2620+
/* We are called from 'ni_decompress_file' */
2621+
/* Copy decompressed LZX or XPRESS data into new place. */
2622+
down_read(&ni->file.run_lock);
2623+
err = ntfs_write_run(sbi, &ni->file.run, frame_mem, frame_vbo,
2624+
frame_size);
2625+
up_read(&ni->file.run_lock);
2626+
}
26722627
#endif
2673-
out1:
26742628
vunmap(frame_mem);
26752629
out:
26762630
for (i = 0; i < pages_per_frame; i++) {
@@ -2697,13 +2651,10 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
26972651
u64 frame_vbo = folio_pos(folio);
26982652
CLST frame = frame_vbo >> frame_bits;
26992653
char *frame_ondisk = NULL;
2700-
struct page **pages_disk = NULL;
27012654
struct ATTR_LIST_ENTRY *le = NULL;
27022655
char *frame_mem;
27032656
struct ATTRIB *attr;
27042657
struct mft_inode *mi;
2705-
u32 i;
2706-
struct page *pg;
27072658
size_t compr_size, ondisk_size;
27082659
struct lznt *lznt;
27092660

@@ -2738,34 +2689,18 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
27382689
goto out;
27392690
}
27402691

2741-
pages_disk = kcalloc(pages_per_frame, sizeof(struct page *), GFP_NOFS);
2742-
if (!pages_disk) {
2743-
err = -ENOMEM;
2744-
goto out;
2745-
}
2746-
2747-
for (i = 0; i < pages_per_frame; i++) {
2748-
pg = alloc_page(GFP_KERNEL);
2749-
if (!pg) {
2750-
err = -ENOMEM;
2751-
goto out1;
2752-
}
2753-
pages_disk[i] = pg;
2754-
lock_page(pg);
2755-
}
2756-
2757-
/* To simplify compress algorithm do vmap for source and target pages. */
2758-
frame_ondisk = vmap(pages_disk, pages_per_frame, VM_MAP, PAGE_KERNEL);
2692+
/* Allocate memory to write compressed data to. */
2693+
frame_ondisk = kvmalloc(frame_size, GFP_KERNEL);
27592694
if (!frame_ondisk) {
27602695
err = -ENOMEM;
2761-
goto out1;
2696+
goto out;
27622697
}
27632698

27642699
/* Map in-memory frame for read-only. */
27652700
frame_mem = vmap(pages, pages_per_frame, VM_MAP, PAGE_KERNEL_RO);
27662701
if (!frame_mem) {
27672702
err = -ENOMEM;
2768-
goto out2;
2703+
goto out1;
27692704
}
27702705

27712706
mutex_lock(&sbi->compress.mtx_lznt);
@@ -2781,7 +2716,7 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
27812716
if (!lznt) {
27822717
mutex_unlock(&sbi->compress.mtx_lznt);
27832718
err = -ENOMEM;
2784-
goto out3;
2719+
goto out2;
27852720
}
27862721

27872722
sbi->compress.lznt = lznt;
@@ -2818,25 +2753,16 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages,
28182753
goto out2;
28192754

28202755
down_read(&ni->file.run_lock);
2821-
err = ntfs_bio_pages(sbi, &ni->file.run,
2822-
ondisk_size < frame_size ? pages_disk : pages,
2823-
pages_per_frame, frame_vbo, ondisk_size,
2824-
REQ_OP_WRITE);
2756+
err = ntfs_write_run(sbi, &ni->file.run,
2757+
ondisk_size < frame_size ? frame_ondisk :
2758+
frame_mem,
2759+
frame_vbo, ondisk_size);
28252760
up_read(&ni->file.run_lock);
28262761

2827-
out3:
2828-
vunmap(frame_mem);
28292762
out2:
2830-
vunmap(frame_ondisk);
2763+
vunmap(frame_mem);
28312764
out1:
2832-
for (i = 0; i < pages_per_frame; i++) {
2833-
pg = pages_disk[i];
2834-
if (pg) {
2835-
unlock_page(pg);
2836-
put_page(pg);
2837-
}
2838-
}
2839-
kfree(pages_disk);
2765+
kvfree(frame_ondisk);
28402766
out:
28412767
return err;
28422768
}

0 commit comments

Comments
 (0)