Commit 1fdae000 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 8170a99c bac89bb3
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -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;

+17 −45
Original line number Diff line number Diff line
@@ -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, bits0);

			wnd_remove_free_ext(wnd, bit, op);
	}
	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;

+21 −13
Original line number Diff line number Diff line
@@ -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)
+15 −89
Original line number Diff line number Diff line
@@ -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;
+2 −1
Original line number Diff line number Diff line
@@ -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);
Loading