summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/ntfs/compress.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index 6b78a8efe3ac..006b8831836c 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -1258,11 +1258,11 @@ static int ntfs_compress_block(const char *inbuf, const int bufsize,
}
static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages,
- int pages_per_cb)
+ int pages_per_cb, unsigned int page_offset)
{
struct ntfs_volume *vol = ni->vol;
- char *outbuf = NULL, *pbuf, *inbuf;
- u32 compsz, p, insz = pages_per_cb << PAGE_SHIFT;
+ char *outbuf = NULL, *pbuf, *inbuf, *in_mapping;
+ u32 compsz, p, insz = ni->itype.compressed.block_size;
s32 rounded, bio_size;
int sz;
unsigned int bsz;
@@ -1284,14 +1284,15 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages,
loff_t new_length;
s64 new_vcn;
- inbuf = vmap(pages, pages_per_cb, VM_MAP, PAGE_KERNEL_RO);
- if (!inbuf)
+ in_mapping = vmap(pages, pages_per_cb, VM_MAP, PAGE_KERNEL_RO);
+ if (!in_mapping)
return -ENOMEM;
+ inbuf = in_mapping + page_offset;
/* may need 2 extra bytes per block and 2 more bytes */
pages_disk = kcalloc(pages_count, sizeof(struct page *), GFP_NOFS);
if (!pages_disk) {
- vunmap(inbuf);
+ vunmap(in_mapping);
return -ENOMEM;
}
@@ -1361,7 +1362,9 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages,
err = 0;
goto out;
} else {
+ memcpy(outbuf, inbuf, insz);
bio_size = insz;
+ pages = pages_disk;
}
new_vcn = ntfs_bytes_to_cluster(vol,
@@ -1420,7 +1423,8 @@ setup_bio:
GFP_NOIO);
bio->bi_iter.bi_sector =
ntfs_bytes_to_sector(vol,
- ntfs_cluster_to_bytes(vol, bio_lcn + i));
+ ntfs_cluster_to_bytes(vol, bio_lcn) +
+ ((s64)i << PAGE_SHIFT));
}
if (!bio_add_page(bio, pages[i], page_size, 0)) {
@@ -1437,7 +1441,8 @@ setup_bio:
err = submit_bio_wait(bio);
bio_put(bio);
out:
- vunmap(outbuf);
+ if (outbuf)
+ vunmap(outbuf);
for (i = 0; i < pages_count; i++) {
pg = pages_disk[i];
if (pg) {
@@ -1446,7 +1451,7 @@ out:
}
}
kfree(pages_disk);
- vunmap(inbuf);
+ vunmap(in_mapping);
NInoSetFileNameDirty(ni);
mark_mft_record_dirty(ni);
@@ -1458,12 +1463,15 @@ int ntfs_compress_write(struct ntfs_inode *ni, loff_t pos, size_t count,
{
struct folio *folio;
struct page **pages = NULL, *page;
- int pages_per_cb = ni->itype.compressed.block_size >> PAGE_SHIFT;
+ int pages_per_cb;
int cb_size = ni->itype.compressed.block_size, cb_off, err = 0;
int i, ip;
size_t written = 0;
struct address_space *mapping = VFS_I(ni)->i_mapping;
+ pages_per_cb = DIV_ROUND_UP(offset_in_page(pos & ~(cb_size - 1)) +
+ cb_size, PAGE_SIZE);
+
pages = kmalloc_array(pages_per_cb, sizeof(struct page *), GFP_NOFS);
if (!pages)
return -ENOMEM;
@@ -1471,6 +1479,7 @@ int ntfs_compress_write(struct ntfs_inode *ni, loff_t pos, size_t count,
while (count) {
pgoff_t index;
size_t copied, bytes;
+ unsigned int page_offset;
int off;
off = pos & (cb_size - 1);
@@ -1479,6 +1488,8 @@ int ntfs_compress_write(struct ntfs_inode *ni, loff_t pos, size_t count,
bytes = count;
cb_off = pos & ~(cb_size - 1);
+ page_offset = offset_in_page(cb_off);
+ pages_per_cb = DIV_ROUND_UP(page_offset + cb_size, PAGE_SIZE);
index = cb_off >> PAGE_SHIFT;
if (unlikely(fault_in_iov_iter_readable(from, bytes))) {
@@ -1527,7 +1538,7 @@ int ntfs_compress_write(struct ntfs_inode *ni, loff_t pos, size_t count,
}
}
- err = ntfs_write_cb(ni, pos, pages, pages_per_cb);
+ err = ntfs_write_cb(ni, pos, pages, pages_per_cb, page_offset);
for (i = 0; i < pages_per_cb; i++) {
folio = page_folio(pages[i]);