diff options
Diffstat (limited to 'fs/ntfs3/frecord.c')
| -rw-r--r-- | fs/ntfs3/frecord.c | 219 |
1 files changed, 78 insertions, 141 deletions
diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 8f9fe1d7a690..641ddaf8d4a0 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -325,8 +325,10 @@ bool ni_add_subrecord(struct ntfs_inode *ni, CLST rno, struct mft_inode **mi) mi_get_ref(&ni->mi, &m->mrec->parent_ref); - ni_add_mi(ni, m); - *mi = m; + *mi = ni_ins_mi(ni, &ni->mi_tree, m->rno, &m->node); + if (*mi != m) + mi_put(m); + return true; } @@ -767,7 +769,7 @@ int ni_create_attr_list(struct ntfs_inode *ni) * Skip estimating exact memory requirement. * Looks like one record_size is always enough. */ - le = kmalloc(al_aligned(rs), GFP_NOFS); + le = kzalloc(al_aligned(rs), GFP_NOFS); if (!le) return -ENOMEM; @@ -1015,9 +1017,9 @@ insert_ext: out2: ni_remove_mi(ni, mi); - mi_put(mi); out1: + mi_put(mi); ntfs_mark_rec_free(sbi, rno, is_mft); out: @@ -2020,6 +2022,29 @@ out: return err; } +static struct page *ntfs_lock_new_page(struct address_space *mapping, + pgoff_t index, gfp_t gfp) +{ + struct folio *folio = __filemap_get_folio(mapping, index, + FGP_LOCK | FGP_ACCESSED | FGP_CREAT, gfp); + struct page *page; + + if (IS_ERR(folio)) + return ERR_CAST(folio); + + if (!folio_test_uptodate(folio)) + return folio_file_page(folio, index); + + /* Use a temporary page to avoid data corruption */ + folio_unlock(folio); + folio_put(folio); + page = alloc_page(gfp); + if (!page) + return ERR_PTR(-ENOMEM); + __SetPageLocked(page); + return page; +} + /* * ni_readpage_cmpr * @@ -2074,15 +2099,15 @@ int ni_readpage_cmpr(struct ntfs_inode *ni, struct folio *folio) if (i == idx) continue; - pg = find_or_create_page(mapping, index, gfp_mask); - if (!pg) { - err = -ENOMEM; + pg = ntfs_lock_new_page(mapping, index, gfp_mask); + if (IS_ERR(pg)) { + err = PTR_ERR(pg); goto out1; } pages[i] = pg; } - err = ni_read_frame(ni, frame_vbo, pages, pages_per_frame); + err = ni_read_frame(ni, frame_vbo, pages, pages_per_frame, 0); out1: for (i = 0; i < pages_per_frame; i++) { @@ -2152,17 +2177,9 @@ int ni_decompress_file(struct ntfs_inode *ni) */ index = 0; for (vbo = 0; vbo < i_size; vbo += bytes) { - u32 nr_pages; bool new; - if (vbo + frame_size > i_size) { - bytes = i_size - vbo; - nr_pages = (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; - } else { - nr_pages = pages_per_frame; - bytes = frame_size; - } - + bytes = vbo + frame_size > i_size ? (i_size - vbo) : frame_size; end = bytes_to_cluster(sbi, vbo + bytes); for (vcn = vbo >> sbi->cluster_bits; vcn < end; vcn += clen) { @@ -2175,27 +2192,19 @@ int ni_decompress_file(struct ntfs_inode *ni) for (i = 0; i < pages_per_frame; i++, index++) { struct page *pg; - pg = find_or_create_page(mapping, index, gfp_mask); - if (!pg) { + pg = ntfs_lock_new_page(mapping, index, gfp_mask); + if (IS_ERR(pg)) { while (i--) { unlock_page(pages[i]); put_page(pages[i]); } - err = -ENOMEM; + err = PTR_ERR(pg); goto out; } pages[i] = pg; } - err = ni_read_frame(ni, vbo, pages, pages_per_frame); - - if (!err) { - down_read(&ni->file.run_lock); - err = ntfs_bio_pages(sbi, &ni->file.run, pages, - nr_pages, vbo, bytes, - REQ_OP_WRITE); - up_read(&ni->file.run_lock); - } + err = ni_read_frame(ni, vbo, pages, pages_per_frame, 1); for (i = 0; i < pages_per_frame; i++) { unlock_page(pages[i]); @@ -2385,20 +2394,19 @@ out2: * Pages - Array of locked pages. */ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, - u32 pages_per_frame) + u32 pages_per_frame, int copy) { int err; struct ntfs_sb_info *sbi = ni->mi.sbi; u8 cluster_bits = sbi->cluster_bits; char *frame_ondisk = NULL; char *frame_mem = NULL; - struct page **pages_disk = NULL; struct ATTR_LIST_ENTRY *le = NULL; struct runs_tree *run = &ni->file.run; u64 valid_size = ni->i_valid; u64 vbo_disk; size_t unc_size; - u32 frame_size, i, npages_disk, ondisk_size; + u32 frame_size, i, ondisk_size; struct page *pg; struct ATTRIB *attr; CLST frame, clst_data; @@ -2407,9 +2415,6 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, * To simplify decompress algorithm do vmap for source * and target pages. */ - for (i = 0; i < pages_per_frame; i++) - kmap(pages[i]); - frame_size = pages_per_frame << PAGE_SHIFT; frame_mem = vmap(pages, pages_per_frame, VM_MAP, PAGE_KERNEL); if (!frame_mem) { @@ -2493,7 +2498,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, err = attr_wof_frame_info(ni, attr, run, frame64, frames, frame_bits, &ondisk_size, &vbo_data); if (err) - goto out2; + goto out1; if (frame64 == frames) { unc_size = 1 + ((i_size - 1) & (frame_size - 1)); @@ -2504,7 +2509,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, if (ondisk_size > frame_size) { err = -EINVAL; - goto out2; + goto out1; } if (!attr->non_res) { @@ -2525,10 +2530,7 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, ARRAY_SIZE(WOF_NAME), run, vbo_disk, vbo_data + ondisk_size); if (err) - goto out2; - npages_disk = (ondisk_size + (vbo_disk & (PAGE_SIZE - 1)) + - PAGE_SIZE - 1) >> - PAGE_SHIFT; + goto out1; #endif } else if (is_attr_compressed(attr)) { /* LZNT compression. */ @@ -2562,61 +2564,37 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, if (clst_data >= NTFS_LZNT_CLUSTERS) { /* Frame is not compressed. */ down_read(&ni->file.run_lock); - err = ntfs_bio_pages(sbi, run, pages, pages_per_frame, - frame_vbo, ondisk_size, - REQ_OP_READ); + err = ntfs_read_run(sbi, run, frame_mem, frame_vbo, + ondisk_size); up_read(&ni->file.run_lock); goto out1; } vbo_disk = frame_vbo; - npages_disk = (ondisk_size + PAGE_SIZE - 1) >> PAGE_SHIFT; } else { __builtin_unreachable(); err = -EINVAL; goto out1; } - pages_disk = kcalloc(npages_disk, sizeof(*pages_disk), GFP_NOFS); - if (!pages_disk) { + /* Allocate memory to read compressed data to. */ + frame_ondisk = kvmalloc(ondisk_size, GFP_KERNEL); + if (!frame_ondisk) { err = -ENOMEM; - goto out2; - } - - for (i = 0; i < npages_disk; i++) { - pg = alloc_page(GFP_KERNEL); - if (!pg) { - err = -ENOMEM; - goto out3; - } - pages_disk[i] = pg; - lock_page(pg); - kmap(pg); + goto out1; } /* Read 'ondisk_size' bytes from disk. */ down_read(&ni->file.run_lock); - err = ntfs_bio_pages(sbi, run, pages_disk, npages_disk, vbo_disk, - ondisk_size, REQ_OP_READ); + err = ntfs_read_run(sbi, run, frame_ondisk, vbo_disk, ondisk_size); up_read(&ni->file.run_lock); if (err) - goto out3; - - /* - * To simplify decompress algorithm do vmap for source and target pages. - */ - frame_ondisk = vmap(pages_disk, npages_disk, VM_MAP, PAGE_KERNEL_RO); - if (!frame_ondisk) { - err = -ENOMEM; - goto out3; - } + goto out2; - /* Decompress: Frame_ondisk -> frame_mem. */ #ifdef CONFIG_NTFS3_LZX_XPRESS if (run != &ni->file.run) { /* LZX or XPRESS */ - err = decompress_lzx_xpress( - sbi, frame_ondisk + (vbo_disk & (PAGE_SIZE - 1)), - ondisk_size, frame_mem, unc_size, frame_size); + err = decompress_lzx_xpress(sbi, frame_ondisk, ondisk_size, + frame_mem, unc_size, frame_size); } else #endif { @@ -2634,30 +2612,25 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages, memset(frame_mem + ok, 0, frame_size - ok); } - vunmap(frame_ondisk); - -out3: - for (i = 0; i < npages_disk; i++) { - pg = pages_disk[i]; - if (pg) { - kunmap(pg); - unlock_page(pg); - put_page(pg); - } - } - kfree(pages_disk); - out2: + kvfree(frame_ondisk); +out1: #ifdef CONFIG_NTFS3_LZX_XPRESS if (run != &ni->file.run) run_free(run); + if (!err && copy) { + /* We are called from 'ni_decompress_file' */ + /* Copy decompressed LZX or XPRESS data into new place. */ + down_read(&ni->file.run_lock); + err = ntfs_write_run(sbi, &ni->file.run, frame_mem, frame_vbo, + frame_size); + up_read(&ni->file.run_lock); + } #endif -out1: vunmap(frame_mem); out: for (i = 0; i < pages_per_frame; i++) { pg = pages[i]; - kunmap(pg); SetPageUptodate(pg); } @@ -2680,13 +2653,10 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages, u64 frame_vbo = folio_pos(folio); CLST frame = frame_vbo >> frame_bits; char *frame_ondisk = NULL; - struct page **pages_disk = NULL; struct ATTR_LIST_ENTRY *le = NULL; char *frame_mem; struct ATTRIB *attr; struct mft_inode *mi; - u32 i; - struct page *pg; size_t compr_size, ondisk_size; struct lznt *lznt; @@ -2721,38 +2691,18 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages, goto out; } - pages_disk = kcalloc(pages_per_frame, sizeof(struct page *), GFP_NOFS); - if (!pages_disk) { - err = -ENOMEM; - goto out; - } - - for (i = 0; i < pages_per_frame; i++) { - pg = alloc_page(GFP_KERNEL); - if (!pg) { - err = -ENOMEM; - goto out1; - } - pages_disk[i] = pg; - lock_page(pg); - kmap(pg); - } - - /* To simplify compress algorithm do vmap for source and target pages. */ - frame_ondisk = vmap(pages_disk, pages_per_frame, VM_MAP, PAGE_KERNEL); + /* Allocate memory to write compressed data to. */ + frame_ondisk = kvmalloc(frame_size, GFP_KERNEL); if (!frame_ondisk) { err = -ENOMEM; - goto out1; + goto out; } - for (i = 0; i < pages_per_frame; i++) - kmap(pages[i]); - /* Map in-memory frame for read-only. */ frame_mem = vmap(pages, pages_per_frame, VM_MAP, PAGE_KERNEL_RO); if (!frame_mem) { err = -ENOMEM; - goto out2; + goto out1; } mutex_lock(&sbi->compress.mtx_lznt); @@ -2768,7 +2718,7 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages, if (!lznt) { mutex_unlock(&sbi->compress.mtx_lznt); err = -ENOMEM; - goto out3; + goto out2; } sbi->compress.lznt = lznt; @@ -2805,30 +2755,16 @@ int ni_write_frame(struct ntfs_inode *ni, struct page **pages, goto out2; down_read(&ni->file.run_lock); - err = ntfs_bio_pages(sbi, &ni->file.run, - ondisk_size < frame_size ? pages_disk : pages, - pages_per_frame, frame_vbo, ondisk_size, - REQ_OP_WRITE); + err = ntfs_write_run(sbi, &ni->file.run, + ondisk_size < frame_size ? frame_ondisk : + frame_mem, + frame_vbo, ondisk_size); up_read(&ni->file.run_lock); -out3: - vunmap(frame_mem); - out2: - for (i = 0; i < pages_per_frame; i++) - kunmap(pages[i]); - - vunmap(frame_ondisk); + vunmap(frame_mem); out1: - for (i = 0; i < pages_per_frame; i++) { - pg = pages_disk[i]; - if (pg) { - kunmap(pg); - unlock_page(pg); - put_page(pg); - } - } - kfree(pages_disk); + kvfree(frame_ondisk); out: return err; } @@ -3026,8 +2962,8 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, err = ni_add_name(new_dir_ni, ni, new_de); if (!err) { err = ni_remove_name(dir_ni, ni, de, &de2, &undo); - WARN_ON(err && ni_remove_name(new_dir_ni, ni, new_de, &de2, - &undo)); + WARN_ON(err && + ni_remove_name(new_dir_ni, ni, new_de, &de2, &undo)); } /* @@ -3127,7 +3063,8 @@ static bool ni_update_parent(struct ntfs_inode *ni, struct NTFS_DUP_INFO *dup, if (attr) { const struct REPARSE_POINT *rp; - rp = resident_data_ex(attr, sizeof(struct REPARSE_POINT)); + rp = resident_data_ex(attr, + sizeof(struct REPARSE_POINT)); /* If ATTR_REPARSE exists 'rp' can't be NULL. */ if (rp) dup->extend_data = rp->ReparseTag; |
