mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-28 16:53:49 +00:00
Changes for 6.13-rc1
Fixed: additional checks have been added to address issues identified by syzbot. Refactored: continuation of the transition from 'page' to 'folio'. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEh0DEKNP0I9IjwfWEqbAzH4MkB7YFAmdIUsgACgkQqbAzH4Mk B7aCBxAAjtDG7HvYLGtTI2xns1eYoUAqHeXCa5CfflBxNqjsD5n3mdU4LzTXb0MM jtnZxG+jwpvdau9Rgagkja2b9/cLCu2wyc4Jj/0+5IFkq7rpbj7p6HsvEb0+sZsU r+GuPJ7Q2j3H7MvgJ32aXh05iAIHrKVEpJXNaK1+K/hljMpBkPsspaxuzwU3l7Jy bQ7NU8lMyrlwfAiTwn9XGVqrmUVBu7U778lDorkUI/ZdychhFaE8LXcDSuTZsHIA uTYxZ0nWROWXIEciqi9NzYCV7cVSBq67xg5NmQ21JHOYE2iPDWUn35R8wuj85haX 4Cw+bCmxiekLGmseHWi4KcZSQV5yrGYyoeibC9WsKYBw9e0/UPW2tHxmnPorhtf7 lbjl9CVUm7eboN7UMwzjcHQU2/6PyyVjy7ok3Aa9jljLhQz3vD45Dwsk16FB58zv W1rl3K1QplJn8rrfDQaCsyFUwjfC70Py9u8Wj6sue257zmgbK6karJCqZtSIxvnC Olp//HGmPARiDVhpNdqWvSuWI3t9/a2NfKJ6asPfnjdrN2fpH2gGd1RypkI2eeEt jsdq3lX8B/fAnOuGTAbjsmjz2pDrcVpHPrW0aPd8SqB5S64hKRzeHGliW/YWgPg0 T8AgceeXGsir0XDgyB4KO1oR38+MNnbUyc+POzGWygZjEgYzAjA= =xhIC -----END PGP SIGNATURE----- Merge tag 'ntfs3_for_6.13' of https://github.com/Paragon-Software-Group/linux-ntfs3 Pull ntfs3 updates from Konstantin Komarov: - additional checks to address issues identified by syzbot - continuation of the transition from 'page' to 'folio' * tag 'ntfs3_for_6.13' of https://github.com/Paragon-Software-Group/linux-ntfs3: fs/ntfs3: Accumulated refactoring changes fs/ntfs3: Switch to folio to release resources fs/ntfs3: Add check in ntfs_extend_initialized_size fs/ntfs3: Add more checks in mi_enum_attr (part 2) fs/ntfs3: Equivalent transition from page to folio fs/ntfs3: Fix case when unmarked clusters intersect with zone fs/ntfs3: Fix warning in ni_fiemap
This commit is contained in:
commit
1fdae000a3
@ -977,7 +977,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
|
||||
|
||||
/* Check for compressed frame. */
|
||||
err = attr_is_frame_compressed(ni, attr_b, vcn >> NTFS_LZNT_CUNIT,
|
||||
&hint);
|
||||
&hint, run);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1521,16 +1521,16 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
* attr_is_frame_compressed - Used to detect compressed frame.
|
||||
*
|
||||
* attr - base (primary) attribute segment.
|
||||
* run - run to use, usually == &ni->file.run.
|
||||
* Only base segments contains valid 'attr->nres.c_unit'
|
||||
*/
|
||||
int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
CLST frame, CLST *clst_data)
|
||||
CLST frame, CLST *clst_data, struct runs_tree *run)
|
||||
{
|
||||
int err;
|
||||
u32 clst_frame;
|
||||
CLST clen, lcn, vcn, alen, slen, vcn_next;
|
||||
size_t idx;
|
||||
struct runs_tree *run;
|
||||
|
||||
*clst_data = 0;
|
||||
|
||||
@ -1542,7 +1542,6 @@ int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
|
||||
clst_frame = 1u << attr->nres.c_unit;
|
||||
vcn = frame * clst_frame;
|
||||
run = &ni->file.run;
|
||||
|
||||
if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
|
||||
err = attr_load_runs_vcn(ni, attr->type, attr_name(attr),
|
||||
@ -1678,7 +1677,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = attr_is_frame_compressed(ni, attr_b, frame, &clst_data);
|
||||
err = attr_is_frame_compressed(ni, attr_b, frame, &clst_data, run);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -710,20 +710,17 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
{
|
||||
int err = 0;
|
||||
struct super_block *sb = wnd->sb;
|
||||
size_t bits0 = bits;
|
||||
u32 wbits = 8 * sb->s_blocksize;
|
||||
size_t iw = bit >> (sb->s_blocksize_bits + 3);
|
||||
u32 wbit = bit & (wbits - 1);
|
||||
struct buffer_head *bh;
|
||||
u32 op;
|
||||
|
||||
while (iw < wnd->nwnd && bits) {
|
||||
u32 tail, op;
|
||||
|
||||
for (; iw < wnd->nwnd && bits; iw++, bit += op, bits -= op, wbit = 0) {
|
||||
if (iw + 1 == wnd->nwnd)
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = min_t(u32, tail, bits);
|
||||
op = min_t(u32, wbits - wbit, bits);
|
||||
|
||||
bh = wnd_map(wnd, iw);
|
||||
if (IS_ERR(bh)) {
|
||||
@ -736,20 +733,15 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
ntfs_bitmap_clear_le(bh->b_data, wbit, op);
|
||||
|
||||
wnd->free_bits[iw] += op;
|
||||
wnd->total_zeroes += op;
|
||||
|
||||
set_buffer_uptodate(bh);
|
||||
mark_buffer_dirty(bh);
|
||||
unlock_buffer(bh);
|
||||
put_bh(bh);
|
||||
|
||||
wnd->total_zeroes += op;
|
||||
bits -= op;
|
||||
wbit = 0;
|
||||
iw += 1;
|
||||
wnd_add_free_ext(wnd, bit, op, false);
|
||||
}
|
||||
|
||||
wnd_add_free_ext(wnd, bit, bits0, false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -760,20 +752,17 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
{
|
||||
int err = 0;
|
||||
struct super_block *sb = wnd->sb;
|
||||
size_t bits0 = bits;
|
||||
size_t iw = bit >> (sb->s_blocksize_bits + 3);
|
||||
u32 wbits = 8 * sb->s_blocksize;
|
||||
u32 wbit = bit & (wbits - 1);
|
||||
struct buffer_head *bh;
|
||||
u32 op;
|
||||
|
||||
while (iw < wnd->nwnd && bits) {
|
||||
u32 tail, op;
|
||||
|
||||
for (; iw < wnd->nwnd && bits; iw++, bit += op, bits -= op, wbit = 0) {
|
||||
if (unlikely(iw + 1 == wnd->nwnd))
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = min_t(u32, tail, bits);
|
||||
op = min_t(u32, wbits - wbit, bits);
|
||||
|
||||
bh = wnd_map(wnd, iw);
|
||||
if (IS_ERR(bh)) {
|
||||
@ -785,21 +774,16 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
|
||||
ntfs_bitmap_set_le(bh->b_data, wbit, op);
|
||||
wnd->free_bits[iw] -= op;
|
||||
wnd->total_zeroes -= op;
|
||||
|
||||
set_buffer_uptodate(bh);
|
||||
mark_buffer_dirty(bh);
|
||||
unlock_buffer(bh);
|
||||
put_bh(bh);
|
||||
|
||||
wnd->total_zeroes -= op;
|
||||
bits -= op;
|
||||
wbit = 0;
|
||||
iw += 1;
|
||||
if (!RB_EMPTY_ROOT(&wnd->start_tree))
|
||||
wnd_remove_free_ext(wnd, bit, op);
|
||||
}
|
||||
|
||||
if (!RB_EMPTY_ROOT(&wnd->start_tree))
|
||||
wnd_remove_free_ext(wnd, bit, bits0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -852,15 +836,13 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
size_t iw = bit >> (sb->s_blocksize_bits + 3);
|
||||
u32 wbits = 8 * sb->s_blocksize;
|
||||
u32 wbit = bit & (wbits - 1);
|
||||
u32 op;
|
||||
|
||||
while (iw < wnd->nwnd && bits) {
|
||||
u32 tail, op;
|
||||
|
||||
for (; iw < wnd->nwnd && bits; iw++, bits -= op, wbit = 0) {
|
||||
if (unlikely(iw + 1 == wnd->nwnd))
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = min_t(u32, tail, bits);
|
||||
op = min_t(u32, wbits - wbit, bits);
|
||||
|
||||
if (wbits != wnd->free_bits[iw]) {
|
||||
bool ret;
|
||||
@ -875,10 +857,6 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
if (!ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
bits -= op;
|
||||
wbit = 0;
|
||||
iw += 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -928,6 +906,7 @@ bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
size_t iw = bit >> (sb->s_blocksize_bits + 3);
|
||||
u32 wbits = 8 * sb->s_blocksize;
|
||||
u32 wbit = bit & (wbits - 1);
|
||||
u32 op;
|
||||
size_t end;
|
||||
struct rb_node *n;
|
||||
struct e_node *e;
|
||||
@ -945,14 +924,11 @@ bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
return false;
|
||||
|
||||
use_wnd:
|
||||
while (iw < wnd->nwnd && bits) {
|
||||
u32 tail, op;
|
||||
|
||||
for (; iw < wnd->nwnd && bits; iw++, bits -= op, wbit = 0) {
|
||||
if (unlikely(iw + 1 == wnd->nwnd))
|
||||
wbits = wnd->bits_last;
|
||||
|
||||
tail = wbits - wbit;
|
||||
op = min_t(u32, tail, bits);
|
||||
op = min_t(u32, wbits - wbit, bits);
|
||||
|
||||
if (wnd->free_bits[iw]) {
|
||||
bool ret;
|
||||
@ -966,10 +942,6 @@ bool wnd_is_used(struct wnd_bitmap *wnd, size_t bit, size_t bits)
|
||||
if (!ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
bits -= op;
|
||||
wbit = 0;
|
||||
iw += 1;
|
||||
}
|
||||
ret = true;
|
||||
|
||||
|
@ -182,13 +182,15 @@ static int ntfs_extend_initialized_size(struct file *file,
|
||||
loff_t pos = valid;
|
||||
int err;
|
||||
|
||||
if (valid >= new_valid)
|
||||
return 0;
|
||||
|
||||
if (is_resident(ni)) {
|
||||
ni->i_valid = new_valid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WARN_ON(is_compressed(ni));
|
||||
WARN_ON(valid >= new_valid);
|
||||
|
||||
for (;;) {
|
||||
u32 zerofrom, len;
|
||||
@ -222,7 +224,7 @@ static int ntfs_extend_initialized_size(struct file *file,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
folio_zero_range(folio, zerofrom, folio_size(folio));
|
||||
folio_zero_range(folio, zerofrom, folio_size(folio) - zerofrom);
|
||||
|
||||
err = ntfs_write_end(file, mapping, pos, len, len, folio, NULL);
|
||||
if (err < 0)
|
||||
@ -987,6 +989,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
u64 frame_vbo;
|
||||
pgoff_t index;
|
||||
bool frame_uptodate;
|
||||
struct folio *folio;
|
||||
|
||||
if (frame_size < PAGE_SIZE) {
|
||||
/*
|
||||
@ -1041,8 +1044,9 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
if (err) {
|
||||
for (ip = 0; ip < pages_per_frame; ip++) {
|
||||
page = pages[ip];
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
folio = page_folio(page);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@ -1052,9 +1056,10 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
off = offset_in_page(valid);
|
||||
for (; ip < pages_per_frame; ip++, off = 0) {
|
||||
page = pages[ip];
|
||||
folio = page_folio(page);
|
||||
zero_user_segment(page, off, PAGE_SIZE);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
folio_mark_uptodate(folio);
|
||||
}
|
||||
|
||||
ni_lock(ni);
|
||||
@ -1063,9 +1068,10 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
|
||||
for (ip = 0; ip < pages_per_frame; ip++) {
|
||||
page = pages[ip];
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
folio = page_folio(page);
|
||||
folio_mark_uptodate(folio);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
}
|
||||
|
||||
if (err)
|
||||
@ -1107,8 +1113,9 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
for (ip = 0; ip < pages_per_frame;
|
||||
ip++) {
|
||||
page = pages[ip];
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
folio = page_folio(page);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@ -1149,9 +1156,10 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
for (ip = 0; ip < pages_per_frame; ip++) {
|
||||
page = pages[ip];
|
||||
ClearPageDirty(page);
|
||||
SetPageUptodate(page);
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
folio = page_folio(page);
|
||||
folio_mark_uptodate(folio);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
}
|
||||
|
||||
if (err)
|
||||
|
@ -1900,46 +1900,6 @@ enum REPARSE_SIGN ni_parse_reparse(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
return REPARSE_LINK;
|
||||
}
|
||||
|
||||
/*
|
||||
* fiemap_fill_next_extent_k - a copy of fiemap_fill_next_extent
|
||||
* but it uses 'fe_k' instead of fieinfo->fi_extents_start
|
||||
*/
|
||||
static int fiemap_fill_next_extent_k(struct fiemap_extent_info *fieinfo,
|
||||
struct fiemap_extent *fe_k, u64 logical,
|
||||
u64 phys, u64 len, u32 flags)
|
||||
{
|
||||
struct fiemap_extent extent;
|
||||
|
||||
/* only count the extents */
|
||||
if (fieinfo->fi_extents_max == 0) {
|
||||
fieinfo->fi_extents_mapped++;
|
||||
return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
|
||||
return 1;
|
||||
|
||||
if (flags & FIEMAP_EXTENT_DELALLOC)
|
||||
flags |= FIEMAP_EXTENT_UNKNOWN;
|
||||
if (flags & FIEMAP_EXTENT_DATA_ENCRYPTED)
|
||||
flags |= FIEMAP_EXTENT_ENCODED;
|
||||
if (flags & (FIEMAP_EXTENT_DATA_TAIL | FIEMAP_EXTENT_DATA_INLINE))
|
||||
flags |= FIEMAP_EXTENT_NOT_ALIGNED;
|
||||
|
||||
memset(&extent, 0, sizeof(extent));
|
||||
extent.fe_logical = logical;
|
||||
extent.fe_physical = phys;
|
||||
extent.fe_length = len;
|
||||
extent.fe_flags = flags;
|
||||
|
||||
memcpy(fe_k + fieinfo->fi_extents_mapped, &extent, sizeof(extent));
|
||||
|
||||
fieinfo->fi_extents_mapped++;
|
||||
if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max)
|
||||
return 1;
|
||||
return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ni_fiemap - Helper for file_fiemap().
|
||||
*
|
||||
@ -1950,11 +1910,9 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
__u64 vbo, __u64 len)
|
||||
{
|
||||
int err = 0;
|
||||
struct fiemap_extent *fe_k = NULL;
|
||||
struct ntfs_sb_info *sbi = ni->mi.sbi;
|
||||
u8 cluster_bits = sbi->cluster_bits;
|
||||
struct runs_tree *run;
|
||||
struct rw_semaphore *run_lock;
|
||||
struct runs_tree run;
|
||||
struct ATTRIB *attr;
|
||||
CLST vcn = vbo >> cluster_bits;
|
||||
CLST lcn, clen;
|
||||
@ -1965,13 +1923,11 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
u32 flags;
|
||||
bool ok;
|
||||
|
||||
run_init(&run);
|
||||
if (S_ISDIR(ni->vfs_inode.i_mode)) {
|
||||
run = &ni->dir.alloc_run;
|
||||
attr = ni_find_attr(ni, NULL, NULL, ATTR_ALLOC, I30_NAME,
|
||||
ARRAY_SIZE(I30_NAME), NULL, NULL);
|
||||
run_lock = &ni->dir.run_lock;
|
||||
} else {
|
||||
run = &ni->file.run;
|
||||
attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
|
||||
NULL);
|
||||
if (!attr) {
|
||||
@ -1986,7 +1942,6 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
"fiemap is not supported for compressed file (cp -r)");
|
||||
goto out;
|
||||
}
|
||||
run_lock = &ni->file.run_lock;
|
||||
}
|
||||
|
||||
if (!attr || !attr->non_res) {
|
||||
@ -1998,51 +1953,32 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* To avoid lock problems replace pointer to user memory by pointer to kernel memory.
|
||||
*/
|
||||
fe_k = kmalloc_array(fieinfo->fi_extents_max,
|
||||
sizeof(struct fiemap_extent),
|
||||
GFP_NOFS | __GFP_ZERO);
|
||||
if (!fe_k) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
end = vbo + len;
|
||||
alloc_size = le64_to_cpu(attr->nres.alloc_size);
|
||||
if (end > alloc_size)
|
||||
end = alloc_size;
|
||||
|
||||
down_read(run_lock);
|
||||
|
||||
while (vbo < end) {
|
||||
if (idx == -1) {
|
||||
ok = run_lookup_entry(run, vcn, &lcn, &clen, &idx);
|
||||
ok = run_lookup_entry(&run, vcn, &lcn, &clen, &idx);
|
||||
} else {
|
||||
CLST vcn_next = vcn;
|
||||
|
||||
ok = run_get_entry(run, ++idx, &vcn, &lcn, &clen) &&
|
||||
ok = run_get_entry(&run, ++idx, &vcn, &lcn, &clen) &&
|
||||
vcn == vcn_next;
|
||||
if (!ok)
|
||||
vcn = vcn_next;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
up_read(run_lock);
|
||||
down_write(run_lock);
|
||||
|
||||
err = attr_load_runs_vcn(ni, attr->type,
|
||||
attr_name(attr),
|
||||
attr->name_len, run, vcn);
|
||||
|
||||
up_write(run_lock);
|
||||
down_read(run_lock);
|
||||
attr->name_len, &run, vcn);
|
||||
|
||||
if (err)
|
||||
break;
|
||||
|
||||
ok = run_lookup_entry(run, vcn, &lcn, &clen, &idx);
|
||||
ok = run_lookup_entry(&run, vcn, &lcn, &clen, &idx);
|
||||
|
||||
if (!ok) {
|
||||
err = -EINVAL;
|
||||
@ -2067,8 +2003,9 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
} else if (is_attr_compressed(attr)) {
|
||||
CLST clst_data;
|
||||
|
||||
err = attr_is_frame_compressed(
|
||||
ni, attr, vcn >> attr->nres.c_unit, &clst_data);
|
||||
err = attr_is_frame_compressed(ni, attr,
|
||||
vcn >> attr->nres.c_unit,
|
||||
&clst_data, &run);
|
||||
if (err)
|
||||
break;
|
||||
if (clst_data < NTFS_LZNT_CLUSTERS)
|
||||
@ -2097,8 +2034,8 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
if (vbo + dlen >= end)
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
|
||||
err = fiemap_fill_next_extent_k(fieinfo, fe_k, vbo, lbo,
|
||||
dlen, flags);
|
||||
err = fiemap_fill_next_extent(fieinfo, vbo, lbo, dlen,
|
||||
flags);
|
||||
|
||||
if (err < 0)
|
||||
break;
|
||||
@ -2119,8 +2056,7 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
if (vbo + bytes >= end)
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
|
||||
err = fiemap_fill_next_extent_k(fieinfo, fe_k, vbo, lbo, bytes,
|
||||
flags);
|
||||
err = fiemap_fill_next_extent(fieinfo, vbo, lbo, bytes, flags);
|
||||
if (err < 0)
|
||||
break;
|
||||
if (err == 1) {
|
||||
@ -2131,19 +2067,8 @@ int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
|
||||
vbo += bytes;
|
||||
}
|
||||
|
||||
up_read(run_lock);
|
||||
|
||||
/*
|
||||
* Copy to user memory out of lock
|
||||
*/
|
||||
if (copy_to_user(fieinfo->fi_extents_start, fe_k,
|
||||
fieinfo->fi_extents_max *
|
||||
sizeof(struct fiemap_extent))) {
|
||||
err = -EFAULT;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(fe_k);
|
||||
run_close(&run);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2672,7 +2597,8 @@ int ni_read_frame(struct ntfs_inode *ni, u64 frame_vbo, struct page **pages,
|
||||
down_write(&ni->file.run_lock);
|
||||
run_truncate_around(run, le64_to_cpu(attr->nres.svcn));
|
||||
frame = frame_vbo >> (cluster_bits + NTFS_LZNT_CUNIT);
|
||||
err = attr_is_frame_compressed(ni, attr, frame, &clst_data);
|
||||
err = attr_is_frame_compressed(ni, attr, frame, &clst_data,
|
||||
run);
|
||||
up_write(&ni->file.run_lock);
|
||||
if (err)
|
||||
goto out1;
|
||||
|
@ -2699,4 +2699,4 @@ int ntfs_set_label(struct ntfs_sb_info *sbi, u8 *label, int len)
|
||||
out:
|
||||
__putname(uni);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -446,7 +446,8 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
struct runs_tree *run, u64 frame, u64 frames,
|
||||
u8 frame_bits, u32 *ondisk_size, u64 *vbo_data);
|
||||
int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
|
||||
CLST frame, CLST *clst_data);
|
||||
CLST frame, CLST *clst_data,
|
||||
struct runs_tree *run);
|
||||
int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
|
||||
u64 new_valid);
|
||||
int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
|
||||
|
@ -212,7 +212,7 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
return NULL;
|
||||
|
||||
if (off >= used || off < MFTRECORD_FIXUP_OFFSET_1 ||
|
||||
!IS_ALIGNED(off, 4)) {
|
||||
!IS_ALIGNED(off, 8)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -236,8 +236,11 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
off += asize;
|
||||
}
|
||||
|
||||
/* Can we use the first field (attr->type). */
|
||||
/* NOTE: this code also checks attr->size availability. */
|
||||
/*
|
||||
* Can we use the first fields:
|
||||
* attr->type,
|
||||
* attr->size
|
||||
*/
|
||||
if (off + 8 > used) {
|
||||
static_assert(ALIGN(sizeof(enum ATTR_TYPE), 8) == 8);
|
||||
return NULL;
|
||||
@ -259,10 +262,17 @@ struct ATTRIB *mi_enum_attr(struct mft_inode *mi, struct ATTRIB *attr)
|
||||
|
||||
asize = le32_to_cpu(attr->size);
|
||||
|
||||
if (!IS_ALIGNED(asize, 8))
|
||||
return NULL;
|
||||
|
||||
/* Check overflow and boundary. */
|
||||
if (off + asize < off || off + asize > used)
|
||||
return NULL;
|
||||
|
||||
/* Can we use the field attr->non_res. */
|
||||
if (off + 9 > used)
|
||||
return NULL;
|
||||
|
||||
/* Check size of attribute. */
|
||||
if (!attr->non_res) {
|
||||
/* Check resident fields. */
|
||||
|
@ -1055,8 +1055,8 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
{
|
||||
int ret, err;
|
||||
CLST next_vcn, lcn, len;
|
||||
size_t index;
|
||||
bool ok;
|
||||
size_t index, done;
|
||||
bool ok, zone;
|
||||
struct wnd_bitmap *wnd;
|
||||
|
||||
ret = run_unpack(run, sbi, ino, svcn, evcn, vcn, run_buf, run_buf_size);
|
||||
@ -1087,8 +1087,9 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
continue;
|
||||
|
||||
down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
|
||||
zone = max(wnd->zone_bit, lcn) < min(wnd->zone_end, lcn + len);
|
||||
/* Check for free blocks. */
|
||||
ok = wnd_is_used(wnd, lcn, len);
|
||||
ok = !zone && wnd_is_used(wnd, lcn, len);
|
||||
up_read(&wnd->rw_lock);
|
||||
if (ok)
|
||||
continue;
|
||||
@ -1096,14 +1097,33 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
|
||||
/* Looks like volume is corrupted. */
|
||||
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
|
||||
|
||||
if (down_write_trylock(&wnd->rw_lock)) {
|
||||
/* Mark all zero bits as used in range [lcn, lcn+len). */
|
||||
size_t done;
|
||||
err = wnd_set_used_safe(wnd, lcn, len, &done);
|
||||
up_write(&wnd->rw_lock);
|
||||
if (err)
|
||||
return err;
|
||||
if (!down_write_trylock(&wnd->rw_lock))
|
||||
continue;
|
||||
|
||||
if (zone) {
|
||||
/*
|
||||
* Range [lcn, lcn + len) intersects with zone.
|
||||
* To avoid complex with zone just turn it off.
|
||||
*/
|
||||
wnd_zone_set(wnd, 0, 0);
|
||||
}
|
||||
|
||||
/* Mark all zero bits as used in range [lcn, lcn+len). */
|
||||
err = wnd_set_used_safe(wnd, lcn, len, &done);
|
||||
if (zone) {
|
||||
/* Restore zone. Lock mft run. */
|
||||
struct rw_semaphore *lock =
|
||||
is_mounted(sbi) ? &sbi->mft.ni->file.run_lock :
|
||||
NULL;
|
||||
if (lock)
|
||||
down_read(lock);
|
||||
ntfs_refresh_zone(sbi);
|
||||
if (lock)
|
||||
up_read(lock);
|
||||
}
|
||||
up_write(&wnd->rw_lock);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user