Unverified Commit 5fc982fe authored by Konstantin Komarov's avatar Konstantin Komarov
Browse files

fs/ntfs3: Fix case when unmarked clusters intersect with zone

parent e2705dd3
Loading
Loading
Loading
Loading
+30 −10
Original line number Diff line number Diff line
@@ -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,15 +1097,34 @@ 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)) {
		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). */
			size_t done;
		err = wnd_set_used_safe(wnd, lcn, len, &done);
		if (zone) {
			/* Restore zone. Lock mft run. */
			struct rw_semaphore *lock;
			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;
}