162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * TODO: Merge attr_set_size/attr_data_get_block/attr_allocate_frame?
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/fs.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "debug.h"
1462306a36Sopenharmony_ci#include "ntfs.h"
1562306a36Sopenharmony_ci#include "ntfs_fs.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * You can set external NTFS_MIN_LOG2_OF_CLUMP/NTFS_MAX_LOG2_OF_CLUMP to manage
1962306a36Sopenharmony_ci * preallocate algorithm.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci#ifndef NTFS_MIN_LOG2_OF_CLUMP
2262306a36Sopenharmony_ci#define NTFS_MIN_LOG2_OF_CLUMP 16
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#ifndef NTFS_MAX_LOG2_OF_CLUMP
2662306a36Sopenharmony_ci#define NTFS_MAX_LOG2_OF_CLUMP 26
2762306a36Sopenharmony_ci#endif
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci// 16M
3062306a36Sopenharmony_ci#define NTFS_CLUMP_MIN (1 << (NTFS_MIN_LOG2_OF_CLUMP + 8))
3162306a36Sopenharmony_ci// 16G
3262306a36Sopenharmony_ci#define NTFS_CLUMP_MAX (1ull << (NTFS_MAX_LOG2_OF_CLUMP + 8))
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic inline u64 get_pre_allocated(u64 size)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	u32 clump;
3762306a36Sopenharmony_ci	u8 align_shift;
3862306a36Sopenharmony_ci	u64 ret;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (size <= NTFS_CLUMP_MIN) {
4162306a36Sopenharmony_ci		clump = 1 << NTFS_MIN_LOG2_OF_CLUMP;
4262306a36Sopenharmony_ci		align_shift = NTFS_MIN_LOG2_OF_CLUMP;
4362306a36Sopenharmony_ci	} else if (size >= NTFS_CLUMP_MAX) {
4462306a36Sopenharmony_ci		clump = 1 << NTFS_MAX_LOG2_OF_CLUMP;
4562306a36Sopenharmony_ci		align_shift = NTFS_MAX_LOG2_OF_CLUMP;
4662306a36Sopenharmony_ci	} else {
4762306a36Sopenharmony_ci		align_shift = NTFS_MIN_LOG2_OF_CLUMP - 1 +
4862306a36Sopenharmony_ci			      __ffs(size >> (8 + NTFS_MIN_LOG2_OF_CLUMP));
4962306a36Sopenharmony_ci		clump = 1u << align_shift;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	ret = (((size + clump - 1) >> align_shift)) << align_shift;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return ret;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/*
5862306a36Sopenharmony_ci * attr_load_runs - Load all runs stored in @attr.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_cistatic int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
6162306a36Sopenharmony_ci			  struct runs_tree *run, const CLST *vcn)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	int err;
6462306a36Sopenharmony_ci	CLST svcn = le64_to_cpu(attr->nres.svcn);
6562306a36Sopenharmony_ci	CLST evcn = le64_to_cpu(attr->nres.evcn);
6662306a36Sopenharmony_ci	u32 asize;
6762306a36Sopenharmony_ci	u16 run_off;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (svcn >= evcn + 1 || run_is_mapped_full(run, svcn, evcn))
7062306a36Sopenharmony_ci		return 0;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (vcn && (evcn < *vcn || *vcn < svcn))
7362306a36Sopenharmony_ci		return -EINVAL;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	asize = le32_to_cpu(attr->size);
7662306a36Sopenharmony_ci	run_off = le16_to_cpu(attr->nres.run_off);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (run_off > asize)
7962306a36Sopenharmony_ci		return -EINVAL;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn,
8262306a36Sopenharmony_ci			    vcn ? *vcn : svcn, Add2Ptr(attr, run_off),
8362306a36Sopenharmony_ci			    asize - run_off);
8462306a36Sopenharmony_ci	if (err < 0)
8562306a36Sopenharmony_ci		return err;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return 0;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/*
9162306a36Sopenharmony_ci * run_deallocate_ex - Deallocate clusters.
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_cistatic int run_deallocate_ex(struct ntfs_sb_info *sbi, struct runs_tree *run,
9462306a36Sopenharmony_ci			     CLST vcn, CLST len, CLST *done, bool trim)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	int err = 0;
9762306a36Sopenharmony_ci	CLST vcn_next, vcn0 = vcn, lcn, clen, dn = 0;
9862306a36Sopenharmony_ci	size_t idx;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (!len)
10162306a36Sopenharmony_ci		goto out;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
10462306a36Sopenharmony_cifailed:
10562306a36Sopenharmony_ci		run_truncate(run, vcn0);
10662306a36Sopenharmony_ci		err = -EINVAL;
10762306a36Sopenharmony_ci		goto out;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	for (;;) {
11162306a36Sopenharmony_ci		if (clen > len)
11262306a36Sopenharmony_ci			clen = len;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		if (!clen) {
11562306a36Sopenharmony_ci			err = -EINVAL;
11662306a36Sopenharmony_ci			goto out;
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		if (lcn != SPARSE_LCN) {
12062306a36Sopenharmony_ci			if (sbi) {
12162306a36Sopenharmony_ci				/* mark bitmap range [lcn + clen) as free and trim clusters. */
12262306a36Sopenharmony_ci				mark_as_free_ex(sbi, lcn, clen, trim);
12362306a36Sopenharmony_ci			}
12462306a36Sopenharmony_ci			dn += clen;
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		len -= clen;
12862306a36Sopenharmony_ci		if (!len)
12962306a36Sopenharmony_ci			break;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		vcn_next = vcn + clen;
13262306a36Sopenharmony_ci		if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
13362306a36Sopenharmony_ci		    vcn != vcn_next) {
13462306a36Sopenharmony_ci			/* Save memory - don't load entire run. */
13562306a36Sopenharmony_ci			goto failed;
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ciout:
14062306a36Sopenharmony_ci	if (done)
14162306a36Sopenharmony_ci		*done += dn;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return err;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/*
14762306a36Sopenharmony_ci * attr_allocate_clusters - Find free space, mark it as used and store in @run.
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_ciint attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
15062306a36Sopenharmony_ci			   CLST vcn, CLST lcn, CLST len, CLST *pre_alloc,
15162306a36Sopenharmony_ci			   enum ALLOCATE_OPT opt, CLST *alen, const size_t fr,
15262306a36Sopenharmony_ci			   CLST *new_lcn, CLST *new_len)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	int err;
15562306a36Sopenharmony_ci	CLST flen, vcn0 = vcn, pre = pre_alloc ? *pre_alloc : 0;
15662306a36Sopenharmony_ci	size_t cnt = run->count;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	for (;;) {
15962306a36Sopenharmony_ci		err = ntfs_look_for_free_space(sbi, lcn, len + pre, &lcn, &flen,
16062306a36Sopenharmony_ci					       opt);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		if (err == -ENOSPC && pre) {
16362306a36Sopenharmony_ci			pre = 0;
16462306a36Sopenharmony_ci			if (*pre_alloc)
16562306a36Sopenharmony_ci				*pre_alloc = 0;
16662306a36Sopenharmony_ci			continue;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		if (err)
17062306a36Sopenharmony_ci			goto out;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci		if (vcn == vcn0) {
17362306a36Sopenharmony_ci			/* Return the first fragment. */
17462306a36Sopenharmony_ci			if (new_lcn)
17562306a36Sopenharmony_ci				*new_lcn = lcn;
17662306a36Sopenharmony_ci			if (new_len)
17762306a36Sopenharmony_ci				*new_len = flen;
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		/* Add new fragment into run storage. */
18162306a36Sopenharmony_ci		if (!run_add_entry(run, vcn, lcn, flen, opt & ALLOCATE_MFT)) {
18262306a36Sopenharmony_ci			/* Undo last 'ntfs_look_for_free_space' */
18362306a36Sopenharmony_ci			mark_as_free_ex(sbi, lcn, len, false);
18462306a36Sopenharmony_ci			err = -ENOMEM;
18562306a36Sopenharmony_ci			goto out;
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		if (opt & ALLOCATE_ZERO) {
18962306a36Sopenharmony_ci			u8 shift = sbi->cluster_bits - SECTOR_SHIFT;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci			err = blkdev_issue_zeroout(sbi->sb->s_bdev,
19262306a36Sopenharmony_ci						   (sector_t)lcn << shift,
19362306a36Sopenharmony_ci						   (sector_t)flen << shift,
19462306a36Sopenharmony_ci						   GFP_NOFS, 0);
19562306a36Sopenharmony_ci			if (err)
19662306a36Sopenharmony_ci				goto out;
19762306a36Sopenharmony_ci		}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		vcn += flen;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		if (flen >= len || (opt & ALLOCATE_MFT) ||
20262306a36Sopenharmony_ci		    (fr && run->count - cnt >= fr)) {
20362306a36Sopenharmony_ci			*alen = vcn - vcn0;
20462306a36Sopenharmony_ci			return 0;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		len -= flen;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ciout:
21162306a36Sopenharmony_ci	/* Undo 'ntfs_look_for_free_space' */
21262306a36Sopenharmony_ci	if (vcn - vcn0) {
21362306a36Sopenharmony_ci		run_deallocate_ex(sbi, run, vcn0, vcn - vcn0, NULL, false);
21462306a36Sopenharmony_ci		run_truncate(run, vcn0);
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return err;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/*
22162306a36Sopenharmony_ci * attr_make_nonresident
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * If page is not NULL - it is already contains resident data
22462306a36Sopenharmony_ci * and locked (called from ni_write_frame()).
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_ciint attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
22762306a36Sopenharmony_ci			  struct ATTR_LIST_ENTRY *le, struct mft_inode *mi,
22862306a36Sopenharmony_ci			  u64 new_size, struct runs_tree *run,
22962306a36Sopenharmony_ci			  struct ATTRIB **ins_attr, struct page *page)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	struct ntfs_sb_info *sbi;
23262306a36Sopenharmony_ci	struct ATTRIB *attr_s;
23362306a36Sopenharmony_ci	struct MFT_REC *rec;
23462306a36Sopenharmony_ci	u32 used, asize, rsize, aoff, align;
23562306a36Sopenharmony_ci	bool is_data;
23662306a36Sopenharmony_ci	CLST len, alen;
23762306a36Sopenharmony_ci	char *next;
23862306a36Sopenharmony_ci	int err;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (attr->non_res) {
24162306a36Sopenharmony_ci		*ins_attr = attr;
24262306a36Sopenharmony_ci		return 0;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	sbi = mi->sbi;
24662306a36Sopenharmony_ci	rec = mi->mrec;
24762306a36Sopenharmony_ci	attr_s = NULL;
24862306a36Sopenharmony_ci	used = le32_to_cpu(rec->used);
24962306a36Sopenharmony_ci	asize = le32_to_cpu(attr->size);
25062306a36Sopenharmony_ci	next = Add2Ptr(attr, asize);
25162306a36Sopenharmony_ci	aoff = PtrOffset(rec, attr);
25262306a36Sopenharmony_ci	rsize = le32_to_cpu(attr->res.data_size);
25362306a36Sopenharmony_ci	is_data = attr->type == ATTR_DATA && !attr->name_len;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	align = sbi->cluster_size;
25662306a36Sopenharmony_ci	if (is_attr_compressed(attr))
25762306a36Sopenharmony_ci		align <<= COMPRESSION_UNIT;
25862306a36Sopenharmony_ci	len = (rsize + align - 1) >> sbi->cluster_bits;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	run_init(run);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Make a copy of original attribute. */
26362306a36Sopenharmony_ci	attr_s = kmemdup(attr, asize, GFP_NOFS);
26462306a36Sopenharmony_ci	if (!attr_s) {
26562306a36Sopenharmony_ci		err = -ENOMEM;
26662306a36Sopenharmony_ci		goto out;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (!len) {
27062306a36Sopenharmony_ci		/* Empty resident -> Empty nonresident. */
27162306a36Sopenharmony_ci		alen = 0;
27262306a36Sopenharmony_ci	} else {
27362306a36Sopenharmony_ci		const char *data = resident_data(attr);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		err = attr_allocate_clusters(sbi, run, 0, 0, len, NULL,
27662306a36Sopenharmony_ci					     ALLOCATE_DEF, &alen, 0, NULL,
27762306a36Sopenharmony_ci					     NULL);
27862306a36Sopenharmony_ci		if (err)
27962306a36Sopenharmony_ci			goto out1;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		if (!rsize) {
28262306a36Sopenharmony_ci			/* Empty resident -> Non empty nonresident. */
28362306a36Sopenharmony_ci		} else if (!is_data) {
28462306a36Sopenharmony_ci			err = ntfs_sb_write_run(sbi, run, 0, data, rsize, 0);
28562306a36Sopenharmony_ci			if (err)
28662306a36Sopenharmony_ci				goto out2;
28762306a36Sopenharmony_ci		} else if (!page) {
28862306a36Sopenharmony_ci			char *kaddr;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci			page = grab_cache_page(ni->vfs_inode.i_mapping, 0);
29162306a36Sopenharmony_ci			if (!page) {
29262306a36Sopenharmony_ci				err = -ENOMEM;
29362306a36Sopenharmony_ci				goto out2;
29462306a36Sopenharmony_ci			}
29562306a36Sopenharmony_ci			kaddr = kmap_atomic(page);
29662306a36Sopenharmony_ci			memcpy(kaddr, data, rsize);
29762306a36Sopenharmony_ci			memset(kaddr + rsize, 0, PAGE_SIZE - rsize);
29862306a36Sopenharmony_ci			kunmap_atomic(kaddr);
29962306a36Sopenharmony_ci			flush_dcache_page(page);
30062306a36Sopenharmony_ci			SetPageUptodate(page);
30162306a36Sopenharmony_ci			set_page_dirty(page);
30262306a36Sopenharmony_ci			unlock_page(page);
30362306a36Sopenharmony_ci			put_page(page);
30462306a36Sopenharmony_ci		}
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* Remove original attribute. */
30862306a36Sopenharmony_ci	used -= asize;
30962306a36Sopenharmony_ci	memmove(attr, Add2Ptr(attr, asize), used - aoff);
31062306a36Sopenharmony_ci	rec->used = cpu_to_le32(used);
31162306a36Sopenharmony_ci	mi->dirty = true;
31262306a36Sopenharmony_ci	if (le)
31362306a36Sopenharmony_ci		al_remove_le(ni, le);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	err = ni_insert_nonresident(ni, attr_s->type, attr_name(attr_s),
31662306a36Sopenharmony_ci				    attr_s->name_len, run, 0, alen,
31762306a36Sopenharmony_ci				    attr_s->flags, &attr, NULL, NULL);
31862306a36Sopenharmony_ci	if (err)
31962306a36Sopenharmony_ci		goto out3;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	kfree(attr_s);
32262306a36Sopenharmony_ci	attr->nres.data_size = cpu_to_le64(rsize);
32362306a36Sopenharmony_ci	attr->nres.valid_size = attr->nres.data_size;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	*ins_attr = attr;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (is_data)
32862306a36Sopenharmony_ci		ni->ni_flags &= ~NI_FLAG_RESIDENT;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Resident attribute becomes non resident. */
33162306a36Sopenharmony_ci	return 0;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciout3:
33462306a36Sopenharmony_ci	attr = Add2Ptr(rec, aoff);
33562306a36Sopenharmony_ci	memmove(next, attr, used - aoff);
33662306a36Sopenharmony_ci	memcpy(attr, attr_s, asize);
33762306a36Sopenharmony_ci	rec->used = cpu_to_le32(used + asize);
33862306a36Sopenharmony_ci	mi->dirty = true;
33962306a36Sopenharmony_ciout2:
34062306a36Sopenharmony_ci	/* Undo: do not trim new allocated clusters. */
34162306a36Sopenharmony_ci	run_deallocate(sbi, run, false);
34262306a36Sopenharmony_ci	run_close(run);
34362306a36Sopenharmony_ciout1:
34462306a36Sopenharmony_ci	kfree(attr_s);
34562306a36Sopenharmony_ciout:
34662306a36Sopenharmony_ci	return err;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/*
35062306a36Sopenharmony_ci * attr_set_size_res - Helper for attr_set_size().
35162306a36Sopenharmony_ci */
35262306a36Sopenharmony_cistatic int attr_set_size_res(struct ntfs_inode *ni, struct ATTRIB *attr,
35362306a36Sopenharmony_ci			     struct ATTR_LIST_ENTRY *le, struct mft_inode *mi,
35462306a36Sopenharmony_ci			     u64 new_size, struct runs_tree *run,
35562306a36Sopenharmony_ci			     struct ATTRIB **ins_attr)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = mi->sbi;
35862306a36Sopenharmony_ci	struct MFT_REC *rec = mi->mrec;
35962306a36Sopenharmony_ci	u32 used = le32_to_cpu(rec->used);
36062306a36Sopenharmony_ci	u32 asize = le32_to_cpu(attr->size);
36162306a36Sopenharmony_ci	u32 aoff = PtrOffset(rec, attr);
36262306a36Sopenharmony_ci	u32 rsize = le32_to_cpu(attr->res.data_size);
36362306a36Sopenharmony_ci	u32 tail = used - aoff - asize;
36462306a36Sopenharmony_ci	char *next = Add2Ptr(attr, asize);
36562306a36Sopenharmony_ci	s64 dsize = ALIGN(new_size, 8) - ALIGN(rsize, 8);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (dsize < 0) {
36862306a36Sopenharmony_ci		memmove(next + dsize, next, tail);
36962306a36Sopenharmony_ci	} else if (dsize > 0) {
37062306a36Sopenharmony_ci		if (used + dsize > sbi->max_bytes_per_attr)
37162306a36Sopenharmony_ci			return attr_make_nonresident(ni, attr, le, mi, new_size,
37262306a36Sopenharmony_ci						     run, ins_attr, NULL);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		memmove(next + dsize, next, tail);
37562306a36Sopenharmony_ci		memset(next, 0, dsize);
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (new_size > rsize)
37962306a36Sopenharmony_ci		memset(Add2Ptr(resident_data(attr), rsize), 0,
38062306a36Sopenharmony_ci		       new_size - rsize);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	rec->used = cpu_to_le32(used + dsize);
38362306a36Sopenharmony_ci	attr->size = cpu_to_le32(asize + dsize);
38462306a36Sopenharmony_ci	attr->res.data_size = cpu_to_le32(new_size);
38562306a36Sopenharmony_ci	mi->dirty = true;
38662306a36Sopenharmony_ci	*ins_attr = attr;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return 0;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci/*
39262306a36Sopenharmony_ci * attr_set_size - Change the size of attribute.
39362306a36Sopenharmony_ci *
39462306a36Sopenharmony_ci * Extend:
39562306a36Sopenharmony_ci *   - Sparse/compressed: No allocated clusters.
39662306a36Sopenharmony_ci *   - Normal: Append allocated and preallocated new clusters.
39762306a36Sopenharmony_ci * Shrink:
39862306a36Sopenharmony_ci *   - No deallocate if @keep_prealloc is set.
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_ciint attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
40162306a36Sopenharmony_ci		  const __le16 *name, u8 name_len, struct runs_tree *run,
40262306a36Sopenharmony_ci		  u64 new_size, const u64 *new_valid, bool keep_prealloc,
40362306a36Sopenharmony_ci		  struct ATTRIB **ret)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	int err = 0;
40662306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = ni->mi.sbi;
40762306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
40862306a36Sopenharmony_ci	bool is_mft = ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA &&
40962306a36Sopenharmony_ci		      !name_len;
41062306a36Sopenharmony_ci	u64 old_valid, old_size, old_alloc, new_alloc, new_alloc_tmp;
41162306a36Sopenharmony_ci	struct ATTRIB *attr = NULL, *attr_b;
41262306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le, *le_b;
41362306a36Sopenharmony_ci	struct mft_inode *mi, *mi_b;
41462306a36Sopenharmony_ci	CLST alen, vcn, lcn, new_alen, old_alen, svcn, evcn;
41562306a36Sopenharmony_ci	CLST next_svcn, pre_alloc = -1, done = 0;
41662306a36Sopenharmony_ci	bool is_ext, is_bad = false;
41762306a36Sopenharmony_ci	bool dirty = false;
41862306a36Sopenharmony_ci	u32 align;
41962306a36Sopenharmony_ci	struct MFT_REC *rec;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ciagain:
42262306a36Sopenharmony_ci	alen = 0;
42362306a36Sopenharmony_ci	le_b = NULL;
42462306a36Sopenharmony_ci	attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len, NULL,
42562306a36Sopenharmony_ci			      &mi_b);
42662306a36Sopenharmony_ci	if (!attr_b) {
42762306a36Sopenharmony_ci		err = -ENOENT;
42862306a36Sopenharmony_ci		goto bad_inode;
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (!attr_b->non_res) {
43262306a36Sopenharmony_ci		err = attr_set_size_res(ni, attr_b, le_b, mi_b, new_size, run,
43362306a36Sopenharmony_ci					&attr_b);
43462306a36Sopenharmony_ci		if (err)
43562306a36Sopenharmony_ci			return err;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		/* Return if file is still resident. */
43862306a36Sopenharmony_ci		if (!attr_b->non_res) {
43962306a36Sopenharmony_ci			dirty = true;
44062306a36Sopenharmony_ci			goto ok1;
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		/* Layout of records may be changed, so do a full search. */
44462306a36Sopenharmony_ci		goto again;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	is_ext = is_attr_ext(attr_b);
44862306a36Sopenharmony_ci	align = sbi->cluster_size;
44962306a36Sopenharmony_ci	if (is_ext)
45062306a36Sopenharmony_ci		align <<= attr_b->nres.c_unit;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	old_valid = le64_to_cpu(attr_b->nres.valid_size);
45362306a36Sopenharmony_ci	old_size = le64_to_cpu(attr_b->nres.data_size);
45462306a36Sopenharmony_ci	old_alloc = le64_to_cpu(attr_b->nres.alloc_size);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ciagain_1:
45762306a36Sopenharmony_ci	old_alen = old_alloc >> cluster_bits;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	new_alloc = (new_size + align - 1) & ~(u64)(align - 1);
46062306a36Sopenharmony_ci	new_alen = new_alloc >> cluster_bits;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (keep_prealloc && new_size < old_size) {
46362306a36Sopenharmony_ci		attr_b->nres.data_size = cpu_to_le64(new_size);
46462306a36Sopenharmony_ci		mi_b->dirty = dirty = true;
46562306a36Sopenharmony_ci		goto ok;
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	vcn = old_alen - 1;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	svcn = le64_to_cpu(attr_b->nres.svcn);
47162306a36Sopenharmony_ci	evcn = le64_to_cpu(attr_b->nres.evcn);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (svcn <= vcn && vcn <= evcn) {
47462306a36Sopenharmony_ci		attr = attr_b;
47562306a36Sopenharmony_ci		le = le_b;
47662306a36Sopenharmony_ci		mi = mi_b;
47762306a36Sopenharmony_ci	} else if (!le_b) {
47862306a36Sopenharmony_ci		err = -EINVAL;
47962306a36Sopenharmony_ci		goto bad_inode;
48062306a36Sopenharmony_ci	} else {
48162306a36Sopenharmony_ci		le = le_b;
48262306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, type, name, name_len, &vcn,
48362306a36Sopenharmony_ci				    &mi);
48462306a36Sopenharmony_ci		if (!attr) {
48562306a36Sopenharmony_ci			err = -EINVAL;
48662306a36Sopenharmony_ci			goto bad_inode;
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cinext_le_1:
49062306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
49162306a36Sopenharmony_ci		evcn = le64_to_cpu(attr->nres.evcn);
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci	/*
49462306a36Sopenharmony_ci	 * Here we have:
49562306a36Sopenharmony_ci	 * attr,mi,le - last attribute segment (containing 'vcn').
49662306a36Sopenharmony_ci	 * attr_b,mi_b,le_b - base (primary) attribute segment.
49762306a36Sopenharmony_ci	 */
49862306a36Sopenharmony_cinext_le:
49962306a36Sopenharmony_ci	rec = mi->mrec;
50062306a36Sopenharmony_ci	err = attr_load_runs(attr, ni, run, NULL);
50162306a36Sopenharmony_ci	if (err)
50262306a36Sopenharmony_ci		goto out;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (new_size > old_size) {
50562306a36Sopenharmony_ci		CLST to_allocate;
50662306a36Sopenharmony_ci		size_t free;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		if (new_alloc <= old_alloc) {
50962306a36Sopenharmony_ci			attr_b->nres.data_size = cpu_to_le64(new_size);
51062306a36Sopenharmony_ci			mi_b->dirty = dirty = true;
51162306a36Sopenharmony_ci			goto ok;
51262306a36Sopenharmony_ci		}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		/*
51562306a36Sopenharmony_ci		 * Add clusters. In simple case we have to:
51662306a36Sopenharmony_ci		 *  - allocate space (vcn, lcn, len)
51762306a36Sopenharmony_ci		 *  - update packed run in 'mi'
51862306a36Sopenharmony_ci		 *  - update attr->nres.evcn
51962306a36Sopenharmony_ci		 *  - update attr_b->nres.data_size/attr_b->nres.alloc_size
52062306a36Sopenharmony_ci		 */
52162306a36Sopenharmony_ci		to_allocate = new_alen - old_alen;
52262306a36Sopenharmony_ciadd_alloc_in_same_attr_seg:
52362306a36Sopenharmony_ci		lcn = 0;
52462306a36Sopenharmony_ci		if (is_mft) {
52562306a36Sopenharmony_ci			/* MFT allocates clusters from MFT zone. */
52662306a36Sopenharmony_ci			pre_alloc = 0;
52762306a36Sopenharmony_ci		} else if (is_ext) {
52862306a36Sopenharmony_ci			/* No preallocate for sparse/compress. */
52962306a36Sopenharmony_ci			pre_alloc = 0;
53062306a36Sopenharmony_ci		} else if (pre_alloc == -1) {
53162306a36Sopenharmony_ci			pre_alloc = 0;
53262306a36Sopenharmony_ci			if (type == ATTR_DATA && !name_len &&
53362306a36Sopenharmony_ci			    sbi->options->prealloc) {
53462306a36Sopenharmony_ci				pre_alloc = bytes_to_cluster(
53562306a36Sopenharmony_ci						    sbi, get_pre_allocated(
53662306a36Sopenharmony_ci								 new_size)) -
53762306a36Sopenharmony_ci					    new_alen;
53862306a36Sopenharmony_ci			}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci			/* Get the last LCN to allocate from. */
54162306a36Sopenharmony_ci			if (old_alen &&
54262306a36Sopenharmony_ci			    !run_lookup_entry(run, vcn, &lcn, NULL, NULL)) {
54362306a36Sopenharmony_ci				lcn = SPARSE_LCN;
54462306a36Sopenharmony_ci			}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci			if (lcn == SPARSE_LCN)
54762306a36Sopenharmony_ci				lcn = 0;
54862306a36Sopenharmony_ci			else if (lcn)
54962306a36Sopenharmony_ci				lcn += 1;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci			free = wnd_zeroes(&sbi->used.bitmap);
55262306a36Sopenharmony_ci			if (to_allocate > free) {
55362306a36Sopenharmony_ci				err = -ENOSPC;
55462306a36Sopenharmony_ci				goto out;
55562306a36Sopenharmony_ci			}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci			if (pre_alloc && to_allocate + pre_alloc > free)
55862306a36Sopenharmony_ci				pre_alloc = 0;
55962306a36Sopenharmony_ci		}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		vcn = old_alen;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		if (is_ext) {
56462306a36Sopenharmony_ci			if (!run_add_entry(run, vcn, SPARSE_LCN, to_allocate,
56562306a36Sopenharmony_ci					   false)) {
56662306a36Sopenharmony_ci				err = -ENOMEM;
56762306a36Sopenharmony_ci				goto out;
56862306a36Sopenharmony_ci			}
56962306a36Sopenharmony_ci			alen = to_allocate;
57062306a36Sopenharmony_ci		} else {
57162306a36Sopenharmony_ci			/* ~3 bytes per fragment. */
57262306a36Sopenharmony_ci			err = attr_allocate_clusters(
57362306a36Sopenharmony_ci				sbi, run, vcn, lcn, to_allocate, &pre_alloc,
57462306a36Sopenharmony_ci				is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen,
57562306a36Sopenharmony_ci				is_mft ? 0 :
57662306a36Sopenharmony_ci					 (sbi->record_size -
57762306a36Sopenharmony_ci					  le32_to_cpu(rec->used) + 8) /
57862306a36Sopenharmony_ci							 3 +
57962306a36Sopenharmony_ci						 1,
58062306a36Sopenharmony_ci				NULL, NULL);
58162306a36Sopenharmony_ci			if (err)
58262306a36Sopenharmony_ci				goto out;
58362306a36Sopenharmony_ci		}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		done += alen;
58662306a36Sopenharmony_ci		vcn += alen;
58762306a36Sopenharmony_ci		if (to_allocate > alen)
58862306a36Sopenharmony_ci			to_allocate -= alen;
58962306a36Sopenharmony_ci		else
59062306a36Sopenharmony_ci			to_allocate = 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cipack_runs:
59362306a36Sopenharmony_ci		err = mi_pack_runs(mi, attr, run, vcn - svcn);
59462306a36Sopenharmony_ci		if (err)
59562306a36Sopenharmony_ci			goto undo_1;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
59862306a36Sopenharmony_ci		new_alloc_tmp = (u64)next_svcn << cluster_bits;
59962306a36Sopenharmony_ci		attr_b->nres.alloc_size = cpu_to_le64(new_alloc_tmp);
60062306a36Sopenharmony_ci		mi_b->dirty = dirty = true;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		if (next_svcn >= vcn && !to_allocate) {
60362306a36Sopenharmony_ci			/* Normal way. Update attribute and exit. */
60462306a36Sopenharmony_ci			attr_b->nres.data_size = cpu_to_le64(new_size);
60562306a36Sopenharmony_ci			goto ok;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		/* At least two MFT to avoid recursive loop. */
60962306a36Sopenharmony_ci		if (is_mft && next_svcn == vcn &&
61062306a36Sopenharmony_ci		    ((u64)done << sbi->cluster_bits) >= 2 * sbi->record_size) {
61162306a36Sopenharmony_ci			new_size = new_alloc_tmp;
61262306a36Sopenharmony_ci			attr_b->nres.data_size = attr_b->nres.alloc_size;
61362306a36Sopenharmony_ci			goto ok;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		if (le32_to_cpu(rec->used) < sbi->record_size) {
61762306a36Sopenharmony_ci			old_alen = next_svcn;
61862306a36Sopenharmony_ci			evcn = old_alen - 1;
61962306a36Sopenharmony_ci			goto add_alloc_in_same_attr_seg;
62062306a36Sopenharmony_ci		}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		attr_b->nres.data_size = attr_b->nres.alloc_size;
62362306a36Sopenharmony_ci		if (new_alloc_tmp < old_valid)
62462306a36Sopenharmony_ci			attr_b->nres.valid_size = attr_b->nres.data_size;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		if (type == ATTR_LIST) {
62762306a36Sopenharmony_ci			err = ni_expand_list(ni);
62862306a36Sopenharmony_ci			if (err)
62962306a36Sopenharmony_ci				goto undo_2;
63062306a36Sopenharmony_ci			if (next_svcn < vcn)
63162306a36Sopenharmony_ci				goto pack_runs;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci			/* Layout of records is changed. */
63462306a36Sopenharmony_ci			goto again;
63562306a36Sopenharmony_ci		}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		if (!ni->attr_list.size) {
63862306a36Sopenharmony_ci			err = ni_create_attr_list(ni);
63962306a36Sopenharmony_ci			/* In case of error layout of records is not changed. */
64062306a36Sopenharmony_ci			if (err)
64162306a36Sopenharmony_ci				goto undo_2;
64262306a36Sopenharmony_ci			/* Layout of records is changed. */
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		if (next_svcn >= vcn) {
64662306a36Sopenharmony_ci			/* This is MFT data, repeat. */
64762306a36Sopenharmony_ci			goto again;
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		/* Insert new attribute segment. */
65162306a36Sopenharmony_ci		err = ni_insert_nonresident(ni, type, name, name_len, run,
65262306a36Sopenharmony_ci					    next_svcn, vcn - next_svcn,
65362306a36Sopenharmony_ci					    attr_b->flags, &attr, &mi, NULL);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci		/*
65662306a36Sopenharmony_ci		 * Layout of records maybe changed.
65762306a36Sopenharmony_ci		 * Find base attribute to update.
65862306a36Sopenharmony_ci		 */
65962306a36Sopenharmony_ci		le_b = NULL;
66062306a36Sopenharmony_ci		attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len,
66162306a36Sopenharmony_ci				      NULL, &mi_b);
66262306a36Sopenharmony_ci		if (!attr_b) {
66362306a36Sopenharmony_ci			err = -EINVAL;
66462306a36Sopenharmony_ci			goto bad_inode;
66562306a36Sopenharmony_ci		}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		if (err) {
66862306a36Sopenharmony_ci			/* ni_insert_nonresident failed. */
66962306a36Sopenharmony_ci			attr = NULL;
67062306a36Sopenharmony_ci			goto undo_2;
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci		if (!is_mft)
67462306a36Sopenharmony_ci			run_truncate_head(run, evcn + 1);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
67762306a36Sopenharmony_ci		evcn = le64_to_cpu(attr->nres.evcn);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		/*
68062306a36Sopenharmony_ci		 * Attribute is in consistency state.
68162306a36Sopenharmony_ci		 * Save this point to restore to if next steps fail.
68262306a36Sopenharmony_ci		 */
68362306a36Sopenharmony_ci		old_valid = old_size = old_alloc = (u64)vcn << cluster_bits;
68462306a36Sopenharmony_ci		attr_b->nres.valid_size = attr_b->nres.data_size =
68562306a36Sopenharmony_ci			attr_b->nres.alloc_size = cpu_to_le64(old_size);
68662306a36Sopenharmony_ci		mi_b->dirty = dirty = true;
68762306a36Sopenharmony_ci		goto again_1;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	if (new_size != old_size ||
69162306a36Sopenharmony_ci	    (new_alloc != old_alloc && !keep_prealloc)) {
69262306a36Sopenharmony_ci		/*
69362306a36Sopenharmony_ci		 * Truncate clusters. In simple case we have to:
69462306a36Sopenharmony_ci		 *  - update packed run in 'mi'
69562306a36Sopenharmony_ci		 *  - update attr->nres.evcn
69662306a36Sopenharmony_ci		 *  - update attr_b->nres.data_size/attr_b->nres.alloc_size
69762306a36Sopenharmony_ci		 *  - mark and trim clusters as free (vcn, lcn, len)
69862306a36Sopenharmony_ci		 */
69962306a36Sopenharmony_ci		CLST dlen = 0;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		vcn = max(svcn, new_alen);
70262306a36Sopenharmony_ci		new_alloc_tmp = (u64)vcn << cluster_bits;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		if (vcn > svcn) {
70562306a36Sopenharmony_ci			err = mi_pack_runs(mi, attr, run, vcn - svcn);
70662306a36Sopenharmony_ci			if (err)
70762306a36Sopenharmony_ci				goto out;
70862306a36Sopenharmony_ci		} else if (le && le->vcn) {
70962306a36Sopenharmony_ci			u16 le_sz = le16_to_cpu(le->size);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci			/*
71262306a36Sopenharmony_ci			 * NOTE: List entries for one attribute are always
71362306a36Sopenharmony_ci			 * the same size. We deal with last entry (vcn==0)
71462306a36Sopenharmony_ci			 * and it is not first in entries array
71562306a36Sopenharmony_ci			 * (list entry for std attribute always first).
71662306a36Sopenharmony_ci			 * So it is safe to step back.
71762306a36Sopenharmony_ci			 */
71862306a36Sopenharmony_ci			mi_remove_attr(NULL, mi, attr);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci			if (!al_remove_le(ni, le)) {
72162306a36Sopenharmony_ci				err = -EINVAL;
72262306a36Sopenharmony_ci				goto bad_inode;
72362306a36Sopenharmony_ci			}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci			le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz);
72662306a36Sopenharmony_ci		} else {
72762306a36Sopenharmony_ci			attr->nres.evcn = cpu_to_le64((u64)vcn - 1);
72862306a36Sopenharmony_ci			mi->dirty = true;
72962306a36Sopenharmony_ci		}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		attr_b->nres.alloc_size = cpu_to_le64(new_alloc_tmp);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		if (vcn == new_alen) {
73462306a36Sopenharmony_ci			attr_b->nres.data_size = cpu_to_le64(new_size);
73562306a36Sopenharmony_ci			if (new_size < old_valid)
73662306a36Sopenharmony_ci				attr_b->nres.valid_size =
73762306a36Sopenharmony_ci					attr_b->nres.data_size;
73862306a36Sopenharmony_ci		} else {
73962306a36Sopenharmony_ci			if (new_alloc_tmp <=
74062306a36Sopenharmony_ci			    le64_to_cpu(attr_b->nres.data_size))
74162306a36Sopenharmony_ci				attr_b->nres.data_size =
74262306a36Sopenharmony_ci					attr_b->nres.alloc_size;
74362306a36Sopenharmony_ci			if (new_alloc_tmp <
74462306a36Sopenharmony_ci			    le64_to_cpu(attr_b->nres.valid_size))
74562306a36Sopenharmony_ci				attr_b->nres.valid_size =
74662306a36Sopenharmony_ci					attr_b->nres.alloc_size;
74762306a36Sopenharmony_ci		}
74862306a36Sopenharmony_ci		mi_b->dirty = dirty = true;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &dlen,
75162306a36Sopenharmony_ci					true);
75262306a36Sopenharmony_ci		if (err)
75362306a36Sopenharmony_ci			goto out;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci		if (is_ext) {
75662306a36Sopenharmony_ci			/* dlen - really deallocated clusters. */
75762306a36Sopenharmony_ci			le64_sub_cpu(&attr_b->nres.total_size,
75862306a36Sopenharmony_ci				     ((u64)dlen << cluster_bits));
75962306a36Sopenharmony_ci		}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		run_truncate(run, vcn);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		if (new_alloc_tmp <= new_alloc)
76462306a36Sopenharmony_ci			goto ok;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		old_size = new_alloc_tmp;
76762306a36Sopenharmony_ci		vcn = svcn - 1;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		if (le == le_b) {
77062306a36Sopenharmony_ci			attr = attr_b;
77162306a36Sopenharmony_ci			mi = mi_b;
77262306a36Sopenharmony_ci			evcn = svcn - 1;
77362306a36Sopenharmony_ci			svcn = 0;
77462306a36Sopenharmony_ci			goto next_le;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci		if (le->type != type || le->name_len != name_len ||
77862306a36Sopenharmony_ci		    memcmp(le_name(le), name, name_len * sizeof(short))) {
77962306a36Sopenharmony_ci			err = -EINVAL;
78062306a36Sopenharmony_ci			goto bad_inode;
78162306a36Sopenharmony_ci		}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		err = ni_load_mi(ni, le, &mi);
78462306a36Sopenharmony_ci		if (err)
78562306a36Sopenharmony_ci			goto out;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		attr = mi_find_attr(mi, NULL, type, name, name_len, &le->id);
78862306a36Sopenharmony_ci		if (!attr) {
78962306a36Sopenharmony_ci			err = -EINVAL;
79062306a36Sopenharmony_ci			goto bad_inode;
79162306a36Sopenharmony_ci		}
79262306a36Sopenharmony_ci		goto next_le_1;
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ciok:
79662306a36Sopenharmony_ci	if (new_valid) {
79762306a36Sopenharmony_ci		__le64 valid = cpu_to_le64(min(*new_valid, new_size));
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		if (attr_b->nres.valid_size != valid) {
80062306a36Sopenharmony_ci			attr_b->nres.valid_size = valid;
80162306a36Sopenharmony_ci			mi_b->dirty = true;
80262306a36Sopenharmony_ci		}
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ciok1:
80662306a36Sopenharmony_ci	if (ret)
80762306a36Sopenharmony_ci		*ret = attr_b;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (((type == ATTR_DATA && !name_len) ||
81062306a36Sopenharmony_ci	     (type == ATTR_ALLOC && name == I30_NAME))) {
81162306a36Sopenharmony_ci		/* Update inode_set_bytes. */
81262306a36Sopenharmony_ci		if (attr_b->non_res) {
81362306a36Sopenharmony_ci			new_alloc = le64_to_cpu(attr_b->nres.alloc_size);
81462306a36Sopenharmony_ci			if (inode_get_bytes(&ni->vfs_inode) != new_alloc) {
81562306a36Sopenharmony_ci				inode_set_bytes(&ni->vfs_inode, new_alloc);
81662306a36Sopenharmony_ci				dirty = true;
81762306a36Sopenharmony_ci			}
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci		/* Don't forget to update duplicate information in parent. */
82162306a36Sopenharmony_ci		if (dirty) {
82262306a36Sopenharmony_ci			ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
82362306a36Sopenharmony_ci			mark_inode_dirty(&ni->vfs_inode);
82462306a36Sopenharmony_ci		}
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	return 0;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ciundo_2:
83062306a36Sopenharmony_ci	vcn -= alen;
83162306a36Sopenharmony_ci	attr_b->nres.data_size = cpu_to_le64(old_size);
83262306a36Sopenharmony_ci	attr_b->nres.valid_size = cpu_to_le64(old_valid);
83362306a36Sopenharmony_ci	attr_b->nres.alloc_size = cpu_to_le64(old_alloc);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	/* Restore 'attr' and 'mi'. */
83662306a36Sopenharmony_ci	if (attr)
83762306a36Sopenharmony_ci		goto restore_run;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (le64_to_cpu(attr_b->nres.svcn) <= svcn &&
84062306a36Sopenharmony_ci	    svcn <= le64_to_cpu(attr_b->nres.evcn)) {
84162306a36Sopenharmony_ci		attr = attr_b;
84262306a36Sopenharmony_ci		le = le_b;
84362306a36Sopenharmony_ci		mi = mi_b;
84462306a36Sopenharmony_ci	} else if (!le_b) {
84562306a36Sopenharmony_ci		err = -EINVAL;
84662306a36Sopenharmony_ci		goto bad_inode;
84762306a36Sopenharmony_ci	} else {
84862306a36Sopenharmony_ci		le = le_b;
84962306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, type, name, name_len,
85062306a36Sopenharmony_ci				    &svcn, &mi);
85162306a36Sopenharmony_ci		if (!attr)
85262306a36Sopenharmony_ci			goto bad_inode;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cirestore_run:
85662306a36Sopenharmony_ci	if (mi_pack_runs(mi, attr, run, evcn - svcn + 1))
85762306a36Sopenharmony_ci		is_bad = true;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ciundo_1:
86062306a36Sopenharmony_ci	run_deallocate_ex(sbi, run, vcn, alen, NULL, false);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	run_truncate(run, vcn);
86362306a36Sopenharmony_ciout:
86462306a36Sopenharmony_ci	if (is_bad) {
86562306a36Sopenharmony_cibad_inode:
86662306a36Sopenharmony_ci		_ntfs_bad_inode(&ni->vfs_inode);
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci	return err;
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci/*
87262306a36Sopenharmony_ci * attr_data_get_block - Returns 'lcn' and 'len' for given 'vcn'.
87362306a36Sopenharmony_ci *
87462306a36Sopenharmony_ci * @new == NULL means just to get current mapping for 'vcn'
87562306a36Sopenharmony_ci * @new != NULL means allocate real cluster if 'vcn' maps to hole
87662306a36Sopenharmony_ci * @zero - zeroout new allocated clusters
87762306a36Sopenharmony_ci *
87862306a36Sopenharmony_ci *  NOTE:
87962306a36Sopenharmony_ci *  - @new != NULL is called only for sparsed or compressed attributes.
88062306a36Sopenharmony_ci *  - new allocated clusters are zeroed via blkdev_issue_zeroout.
88162306a36Sopenharmony_ci */
88262306a36Sopenharmony_ciint attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
88362306a36Sopenharmony_ci			CLST *len, bool *new, bool zero)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	int err = 0;
88662306a36Sopenharmony_ci	struct runs_tree *run = &ni->file.run;
88762306a36Sopenharmony_ci	struct ntfs_sb_info *sbi;
88862306a36Sopenharmony_ci	u8 cluster_bits;
88962306a36Sopenharmony_ci	struct ATTRIB *attr, *attr_b;
89062306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le, *le_b;
89162306a36Sopenharmony_ci	struct mft_inode *mi, *mi_b;
89262306a36Sopenharmony_ci	CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end, vcn0, alen;
89362306a36Sopenharmony_ci	CLST alloc, evcn;
89462306a36Sopenharmony_ci	unsigned fr;
89562306a36Sopenharmony_ci	u64 total_size, total_size0;
89662306a36Sopenharmony_ci	int step = 0;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (new)
89962306a36Sopenharmony_ci		*new = false;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	/* Try to find in cache. */
90262306a36Sopenharmony_ci	down_read(&ni->file.run_lock);
90362306a36Sopenharmony_ci	if (!run_lookup_entry(run, vcn, lcn, len, NULL))
90462306a36Sopenharmony_ci		*len = 0;
90562306a36Sopenharmony_ci	up_read(&ni->file.run_lock);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	if (*len && (*lcn != SPARSE_LCN || !new))
90862306a36Sopenharmony_ci		return 0; /* Fast normal way without allocation. */
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* No cluster in cache or we need to allocate cluster in hole. */
91162306a36Sopenharmony_ci	sbi = ni->mi.sbi;
91262306a36Sopenharmony_ci	cluster_bits = sbi->cluster_bits;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	ni_lock(ni);
91562306a36Sopenharmony_ci	down_write(&ni->file.run_lock);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	/* Repeat the code above (under write lock). */
91862306a36Sopenharmony_ci	if (!run_lookup_entry(run, vcn, lcn, len, NULL))
91962306a36Sopenharmony_ci		*len = 0;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	if (*len) {
92262306a36Sopenharmony_ci		if (*lcn != SPARSE_LCN || !new)
92362306a36Sopenharmony_ci			goto out; /* normal way without allocation. */
92462306a36Sopenharmony_ci		if (clen > *len)
92562306a36Sopenharmony_ci			clen = *len;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	le_b = NULL;
92962306a36Sopenharmony_ci	attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
93062306a36Sopenharmony_ci	if (!attr_b) {
93162306a36Sopenharmony_ci		err = -ENOENT;
93262306a36Sopenharmony_ci		goto out;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	if (!attr_b->non_res) {
93662306a36Sopenharmony_ci		*lcn = RESIDENT_LCN;
93762306a36Sopenharmony_ci		*len = 1;
93862306a36Sopenharmony_ci		goto out;
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	asize = le64_to_cpu(attr_b->nres.alloc_size) >> cluster_bits;
94262306a36Sopenharmony_ci	if (vcn >= asize) {
94362306a36Sopenharmony_ci		if (new) {
94462306a36Sopenharmony_ci			err = -EINVAL;
94562306a36Sopenharmony_ci		} else {
94662306a36Sopenharmony_ci			*len = 1;
94762306a36Sopenharmony_ci			*lcn = SPARSE_LCN;
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci		goto out;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	svcn = le64_to_cpu(attr_b->nres.svcn);
95362306a36Sopenharmony_ci	evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	attr = attr_b;
95662306a36Sopenharmony_ci	le = le_b;
95762306a36Sopenharmony_ci	mi = mi_b;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	if (le_b && (vcn < svcn || evcn1 <= vcn)) {
96062306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
96162306a36Sopenharmony_ci				    &mi);
96262306a36Sopenharmony_ci		if (!attr) {
96362306a36Sopenharmony_ci			err = -EINVAL;
96462306a36Sopenharmony_ci			goto out;
96562306a36Sopenharmony_ci		}
96662306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
96762306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
96862306a36Sopenharmony_ci	}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	/* Load in cache actual information. */
97162306a36Sopenharmony_ci	err = attr_load_runs(attr, ni, run, NULL);
97262306a36Sopenharmony_ci	if (err)
97362306a36Sopenharmony_ci		goto out;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (!*len) {
97662306a36Sopenharmony_ci		if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
97762306a36Sopenharmony_ci			if (*lcn != SPARSE_LCN || !new)
97862306a36Sopenharmony_ci				goto ok; /* Slow normal way without allocation. */
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci			if (clen > *len)
98162306a36Sopenharmony_ci				clen = *len;
98262306a36Sopenharmony_ci		} else if (!new) {
98362306a36Sopenharmony_ci			/* Here we may return -ENOENT.
98462306a36Sopenharmony_ci			 * In any case caller gets zero length. */
98562306a36Sopenharmony_ci			goto ok;
98662306a36Sopenharmony_ci		}
98762306a36Sopenharmony_ci	}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (!is_attr_ext(attr_b)) {
99062306a36Sopenharmony_ci		/* The code below only for sparsed or compressed attributes. */
99162306a36Sopenharmony_ci		err = -EINVAL;
99262306a36Sopenharmony_ci		goto out;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	vcn0 = vcn;
99662306a36Sopenharmony_ci	to_alloc = clen;
99762306a36Sopenharmony_ci	fr = (sbi->record_size - le32_to_cpu(mi->mrec->used) + 8) / 3 + 1;
99862306a36Sopenharmony_ci	/* Allocate frame aligned clusters.
99962306a36Sopenharmony_ci	 * ntfs.sys usually uses 16 clusters per frame for sparsed or compressed.
100062306a36Sopenharmony_ci	 * ntfs3 uses 1 cluster per frame for new created sparsed files. */
100162306a36Sopenharmony_ci	if (attr_b->nres.c_unit) {
100262306a36Sopenharmony_ci		CLST clst_per_frame = 1u << attr_b->nres.c_unit;
100362306a36Sopenharmony_ci		CLST cmask = ~(clst_per_frame - 1);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci		/* Get frame aligned vcn and to_alloc. */
100662306a36Sopenharmony_ci		vcn = vcn0 & cmask;
100762306a36Sopenharmony_ci		to_alloc = ((vcn0 + clen + clst_per_frame - 1) & cmask) - vcn;
100862306a36Sopenharmony_ci		if (fr < clst_per_frame)
100962306a36Sopenharmony_ci			fr = clst_per_frame;
101062306a36Sopenharmony_ci		zero = true;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci		/* Check if 'vcn' and 'vcn0' in different attribute segments. */
101362306a36Sopenharmony_ci		if (vcn < svcn || evcn1 <= vcn) {
101462306a36Sopenharmony_ci			/* Load attribute for truncated vcn. */
101562306a36Sopenharmony_ci			attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0,
101662306a36Sopenharmony_ci					    &vcn, &mi);
101762306a36Sopenharmony_ci			if (!attr) {
101862306a36Sopenharmony_ci				err = -EINVAL;
101962306a36Sopenharmony_ci				goto out;
102062306a36Sopenharmony_ci			}
102162306a36Sopenharmony_ci			svcn = le64_to_cpu(attr->nres.svcn);
102262306a36Sopenharmony_ci			evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
102362306a36Sopenharmony_ci			err = attr_load_runs(attr, ni, run, NULL);
102462306a36Sopenharmony_ci			if (err)
102562306a36Sopenharmony_ci				goto out;
102662306a36Sopenharmony_ci		}
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (vcn + to_alloc > asize)
103062306a36Sopenharmony_ci		to_alloc = asize - vcn;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	/* Get the last LCN to allocate from. */
103362306a36Sopenharmony_ci	hint = 0;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	if (vcn > evcn1) {
103662306a36Sopenharmony_ci		if (!run_add_entry(run, evcn1, SPARSE_LCN, vcn - evcn1,
103762306a36Sopenharmony_ci				   false)) {
103862306a36Sopenharmony_ci			err = -ENOMEM;
103962306a36Sopenharmony_ci			goto out;
104062306a36Sopenharmony_ci		}
104162306a36Sopenharmony_ci	} else if (vcn && !run_lookup_entry(run, vcn - 1, &hint, NULL, NULL)) {
104262306a36Sopenharmony_ci		hint = -1;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	/* Allocate and zeroout new clusters. */
104662306a36Sopenharmony_ci	err = attr_allocate_clusters(sbi, run, vcn, hint + 1, to_alloc, NULL,
104762306a36Sopenharmony_ci				     zero ? ALLOCATE_ZERO : ALLOCATE_DEF, &alen,
104862306a36Sopenharmony_ci				     fr, lcn, len);
104962306a36Sopenharmony_ci	if (err)
105062306a36Sopenharmony_ci		goto out;
105162306a36Sopenharmony_ci	*new = true;
105262306a36Sopenharmony_ci	step = 1;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	end = vcn + alen;
105562306a36Sopenharmony_ci	/* Save 'total_size0' to restore if error. */
105662306a36Sopenharmony_ci	total_size0 = le64_to_cpu(attr_b->nres.total_size);
105762306a36Sopenharmony_ci	total_size = total_size0 + ((u64)alen << cluster_bits);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	if (vcn != vcn0) {
106062306a36Sopenharmony_ci		if (!run_lookup_entry(run, vcn0, lcn, len, NULL)) {
106162306a36Sopenharmony_ci			err = -EINVAL;
106262306a36Sopenharmony_ci			goto out;
106362306a36Sopenharmony_ci		}
106462306a36Sopenharmony_ci		if (*lcn == SPARSE_LCN) {
106562306a36Sopenharmony_ci			/* Internal error. Should not happened. */
106662306a36Sopenharmony_ci			WARN_ON(1);
106762306a36Sopenharmony_ci			err = -EINVAL;
106862306a36Sopenharmony_ci			goto out;
106962306a36Sopenharmony_ci		}
107062306a36Sopenharmony_ci		/* Check case when vcn0 + len overlaps new allocated clusters. */
107162306a36Sopenharmony_ci		if (vcn0 + *len > end)
107262306a36Sopenharmony_ci			*len = end - vcn0;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cirepack:
107662306a36Sopenharmony_ci	err = mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn);
107762306a36Sopenharmony_ci	if (err)
107862306a36Sopenharmony_ci		goto out;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	attr_b->nres.total_size = cpu_to_le64(total_size);
108162306a36Sopenharmony_ci	inode_set_bytes(&ni->vfs_inode, total_size);
108262306a36Sopenharmony_ci	ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	mi_b->dirty = true;
108562306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	/* Stored [vcn : next_svcn) from [vcn : end). */
108862306a36Sopenharmony_ci	next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	if (end <= evcn1) {
109162306a36Sopenharmony_ci		if (next_svcn == evcn1) {
109262306a36Sopenharmony_ci			/* Normal way. Update attribute and exit. */
109362306a36Sopenharmony_ci			goto ok;
109462306a36Sopenharmony_ci		}
109562306a36Sopenharmony_ci		/* Add new segment [next_svcn : evcn1 - next_svcn). */
109662306a36Sopenharmony_ci		if (!ni->attr_list.size) {
109762306a36Sopenharmony_ci			err = ni_create_attr_list(ni);
109862306a36Sopenharmony_ci			if (err)
109962306a36Sopenharmony_ci				goto undo1;
110062306a36Sopenharmony_ci			/* Layout of records is changed. */
110162306a36Sopenharmony_ci			le_b = NULL;
110262306a36Sopenharmony_ci			attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
110362306a36Sopenharmony_ci					      0, NULL, &mi_b);
110462306a36Sopenharmony_ci			if (!attr_b) {
110562306a36Sopenharmony_ci				err = -ENOENT;
110662306a36Sopenharmony_ci				goto out;
110762306a36Sopenharmony_ci			}
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci			attr = attr_b;
111062306a36Sopenharmony_ci			le = le_b;
111162306a36Sopenharmony_ci			mi = mi_b;
111262306a36Sopenharmony_ci			goto repack;
111362306a36Sopenharmony_ci		}
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	/*
111762306a36Sopenharmony_ci	 * The code below may require additional cluster (to extend attribute list)
111862306a36Sopenharmony_ci	 * and / or one MFT record
111962306a36Sopenharmony_ci	 * It is too complex to undo operations if -ENOSPC occurs deep inside
112062306a36Sopenharmony_ci	 * in 'ni_insert_nonresident'.
112162306a36Sopenharmony_ci	 * Return in advance -ENOSPC here if there are no free cluster and no free MFT.
112262306a36Sopenharmony_ci	 */
112362306a36Sopenharmony_ci	if (!ntfs_check_for_free_space(sbi, 1, 1)) {
112462306a36Sopenharmony_ci		/* Undo step 1. */
112562306a36Sopenharmony_ci		err = -ENOSPC;
112662306a36Sopenharmony_ci		goto undo1;
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	step = 2;
113062306a36Sopenharmony_ci	svcn = evcn1;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	/* Estimate next attribute. */
113362306a36Sopenharmony_ci	attr = ni_find_attr(ni, attr, &le, ATTR_DATA, NULL, 0, &svcn, &mi);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	if (!attr) {
113662306a36Sopenharmony_ci		/* Insert new attribute segment. */
113762306a36Sopenharmony_ci		goto ins_ext;
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/* Try to update existed attribute segment. */
114162306a36Sopenharmony_ci	alloc = bytes_to_cluster(sbi, le64_to_cpu(attr_b->nres.alloc_size));
114262306a36Sopenharmony_ci	evcn = le64_to_cpu(attr->nres.evcn);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	if (end < next_svcn)
114562306a36Sopenharmony_ci		end = next_svcn;
114662306a36Sopenharmony_ci	while (end > evcn) {
114762306a36Sopenharmony_ci		/* Remove segment [svcn : evcn). */
114862306a36Sopenharmony_ci		mi_remove_attr(NULL, mi, attr);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci		if (!al_remove_le(ni, le)) {
115162306a36Sopenharmony_ci			err = -EINVAL;
115262306a36Sopenharmony_ci			goto out;
115362306a36Sopenharmony_ci		}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci		if (evcn + 1 >= alloc) {
115662306a36Sopenharmony_ci			/* Last attribute segment. */
115762306a36Sopenharmony_ci			evcn1 = evcn + 1;
115862306a36Sopenharmony_ci			goto ins_ext;
115962306a36Sopenharmony_ci		}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		if (ni_load_mi(ni, le, &mi)) {
116262306a36Sopenharmony_ci			attr = NULL;
116362306a36Sopenharmony_ci			goto out;
116462306a36Sopenharmony_ci		}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci		attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0, &le->id);
116762306a36Sopenharmony_ci		if (!attr) {
116862306a36Sopenharmony_ci			err = -EINVAL;
116962306a36Sopenharmony_ci			goto out;
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
117262306a36Sopenharmony_ci		evcn = le64_to_cpu(attr->nres.evcn);
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	if (end < svcn)
117662306a36Sopenharmony_ci		end = svcn;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	err = attr_load_runs(attr, ni, run, &end);
117962306a36Sopenharmony_ci	if (err)
118062306a36Sopenharmony_ci		goto out;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	evcn1 = evcn + 1;
118362306a36Sopenharmony_ci	attr->nres.svcn = cpu_to_le64(next_svcn);
118462306a36Sopenharmony_ci	err = mi_pack_runs(mi, attr, run, evcn1 - next_svcn);
118562306a36Sopenharmony_ci	if (err)
118662306a36Sopenharmony_ci		goto out;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	le->vcn = cpu_to_le64(next_svcn);
118962306a36Sopenharmony_ci	ni->attr_list.dirty = true;
119062306a36Sopenharmony_ci	mi->dirty = true;
119162306a36Sopenharmony_ci	next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ciins_ext:
119462306a36Sopenharmony_ci	if (evcn1 > next_svcn) {
119562306a36Sopenharmony_ci		err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
119662306a36Sopenharmony_ci					    next_svcn, evcn1 - next_svcn,
119762306a36Sopenharmony_ci					    attr_b->flags, &attr, &mi, NULL);
119862306a36Sopenharmony_ci		if (err)
119962306a36Sopenharmony_ci			goto out;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ciok:
120262306a36Sopenharmony_ci	run_truncate_around(run, vcn);
120362306a36Sopenharmony_ciout:
120462306a36Sopenharmony_ci	if (err && step > 1) {
120562306a36Sopenharmony_ci		/* Too complex to restore. */
120662306a36Sopenharmony_ci		_ntfs_bad_inode(&ni->vfs_inode);
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci	up_write(&ni->file.run_lock);
120962306a36Sopenharmony_ci	ni_unlock(ni);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	return err;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ciundo1:
121462306a36Sopenharmony_ci	/* Undo step1. */
121562306a36Sopenharmony_ci	attr_b->nres.total_size = cpu_to_le64(total_size0);
121662306a36Sopenharmony_ci	inode_set_bytes(&ni->vfs_inode, total_size0);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	if (run_deallocate_ex(sbi, run, vcn, alen, NULL, false) ||
121962306a36Sopenharmony_ci	    !run_add_entry(run, vcn, SPARSE_LCN, alen, false) ||
122062306a36Sopenharmony_ci	    mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn)) {
122162306a36Sopenharmony_ci		_ntfs_bad_inode(&ni->vfs_inode);
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci	goto out;
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ciint attr_data_read_resident(struct ntfs_inode *ni, struct page *page)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	u64 vbo;
122962306a36Sopenharmony_ci	struct ATTRIB *attr;
123062306a36Sopenharmony_ci	u32 data_size;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL, NULL);
123362306a36Sopenharmony_ci	if (!attr)
123462306a36Sopenharmony_ci		return -EINVAL;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	if (attr->non_res)
123762306a36Sopenharmony_ci		return E_NTFS_NONRESIDENT;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	vbo = page->index << PAGE_SHIFT;
124062306a36Sopenharmony_ci	data_size = le32_to_cpu(attr->res.data_size);
124162306a36Sopenharmony_ci	if (vbo < data_size) {
124262306a36Sopenharmony_ci		const char *data = resident_data(attr);
124362306a36Sopenharmony_ci		char *kaddr = kmap_atomic(page);
124462306a36Sopenharmony_ci		u32 use = data_size - vbo;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci		if (use > PAGE_SIZE)
124762306a36Sopenharmony_ci			use = PAGE_SIZE;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		memcpy(kaddr, data + vbo, use);
125062306a36Sopenharmony_ci		memset(kaddr + use, 0, PAGE_SIZE - use);
125162306a36Sopenharmony_ci		kunmap_atomic(kaddr);
125262306a36Sopenharmony_ci		flush_dcache_page(page);
125362306a36Sopenharmony_ci		SetPageUptodate(page);
125462306a36Sopenharmony_ci	} else if (!PageUptodate(page)) {
125562306a36Sopenharmony_ci		zero_user_segment(page, 0, PAGE_SIZE);
125662306a36Sopenharmony_ci		SetPageUptodate(page);
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	return 0;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ciint attr_data_write_resident(struct ntfs_inode *ni, struct page *page)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	u64 vbo;
126562306a36Sopenharmony_ci	struct mft_inode *mi;
126662306a36Sopenharmony_ci	struct ATTRIB *attr;
126762306a36Sopenharmony_ci	u32 data_size;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL, &mi);
127062306a36Sopenharmony_ci	if (!attr)
127162306a36Sopenharmony_ci		return -EINVAL;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	if (attr->non_res) {
127462306a36Sopenharmony_ci		/* Return special error code to check this case. */
127562306a36Sopenharmony_ci		return E_NTFS_NONRESIDENT;
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	vbo = page->index << PAGE_SHIFT;
127962306a36Sopenharmony_ci	data_size = le32_to_cpu(attr->res.data_size);
128062306a36Sopenharmony_ci	if (vbo < data_size) {
128162306a36Sopenharmony_ci		char *data = resident_data(attr);
128262306a36Sopenharmony_ci		char *kaddr = kmap_atomic(page);
128362306a36Sopenharmony_ci		u32 use = data_size - vbo;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		if (use > PAGE_SIZE)
128662306a36Sopenharmony_ci			use = PAGE_SIZE;
128762306a36Sopenharmony_ci		memcpy(data + vbo, kaddr, use);
128862306a36Sopenharmony_ci		kunmap_atomic(kaddr);
128962306a36Sopenharmony_ci		mi->dirty = true;
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci	ni->i_valid = data_size;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	return 0;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci/*
129762306a36Sopenharmony_ci * attr_load_runs_vcn - Load runs with VCN.
129862306a36Sopenharmony_ci */
129962306a36Sopenharmony_ciint attr_load_runs_vcn(struct ntfs_inode *ni, enum ATTR_TYPE type,
130062306a36Sopenharmony_ci		       const __le16 *name, u8 name_len, struct runs_tree *run,
130162306a36Sopenharmony_ci		       CLST vcn)
130262306a36Sopenharmony_ci{
130362306a36Sopenharmony_ci	struct ATTRIB *attr;
130462306a36Sopenharmony_ci	int err;
130562306a36Sopenharmony_ci	CLST svcn, evcn;
130662306a36Sopenharmony_ci	u16 ro;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (!ni) {
130962306a36Sopenharmony_ci		/* Is record corrupted? */
131062306a36Sopenharmony_ci		return -ENOENT;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	attr = ni_find_attr(ni, NULL, NULL, type, name, name_len, &vcn, NULL);
131462306a36Sopenharmony_ci	if (!attr) {
131562306a36Sopenharmony_ci		/* Is record corrupted? */
131662306a36Sopenharmony_ci		return -ENOENT;
131762306a36Sopenharmony_ci	}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	svcn = le64_to_cpu(attr->nres.svcn);
132062306a36Sopenharmony_ci	evcn = le64_to_cpu(attr->nres.evcn);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	if (evcn < vcn || vcn < svcn) {
132362306a36Sopenharmony_ci		/* Is record corrupted? */
132462306a36Sopenharmony_ci		return -EINVAL;
132562306a36Sopenharmony_ci	}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	ro = le16_to_cpu(attr->nres.run_off);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (ro > le32_to_cpu(attr->size))
133062306a36Sopenharmony_ci		return -EINVAL;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn, svcn,
133362306a36Sopenharmony_ci			    Add2Ptr(attr, ro), le32_to_cpu(attr->size) - ro);
133462306a36Sopenharmony_ci	if (err < 0)
133562306a36Sopenharmony_ci		return err;
133662306a36Sopenharmony_ci	return 0;
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci/*
134062306a36Sopenharmony_ci * attr_load_runs_range - Load runs for given range [from to).
134162306a36Sopenharmony_ci */
134262306a36Sopenharmony_ciint attr_load_runs_range(struct ntfs_inode *ni, enum ATTR_TYPE type,
134362306a36Sopenharmony_ci			 const __le16 *name, u8 name_len, struct runs_tree *run,
134462306a36Sopenharmony_ci			 u64 from, u64 to)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = ni->mi.sbi;
134762306a36Sopenharmony_ci	u8 cluster_bits = sbi->cluster_bits;
134862306a36Sopenharmony_ci	CLST vcn;
134962306a36Sopenharmony_ci	CLST vcn_last = (to - 1) >> cluster_bits;
135062306a36Sopenharmony_ci	CLST lcn, clen;
135162306a36Sopenharmony_ci	int err;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	for (vcn = from >> cluster_bits; vcn <= vcn_last; vcn += clen) {
135462306a36Sopenharmony_ci		if (!run_lookup_entry(run, vcn, &lcn, &clen, NULL)) {
135562306a36Sopenharmony_ci			err = attr_load_runs_vcn(ni, type, name, name_len, run,
135662306a36Sopenharmony_ci						 vcn);
135762306a36Sopenharmony_ci			if (err)
135862306a36Sopenharmony_ci				return err;
135962306a36Sopenharmony_ci			clen = 0; /* Next run_lookup_entry(vcn) must be success. */
136062306a36Sopenharmony_ci		}
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	return 0;
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci#ifdef CONFIG_NTFS3_LZX_XPRESS
136762306a36Sopenharmony_ci/*
136862306a36Sopenharmony_ci * attr_wof_frame_info
136962306a36Sopenharmony_ci *
137062306a36Sopenharmony_ci * Read header of Xpress/LZX file to get info about frame.
137162306a36Sopenharmony_ci */
137262306a36Sopenharmony_ciint attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
137362306a36Sopenharmony_ci			struct runs_tree *run, u64 frame, u64 frames,
137462306a36Sopenharmony_ci			u8 frame_bits, u32 *ondisk_size, u64 *vbo_data)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = ni->mi.sbi;
137762306a36Sopenharmony_ci	u64 vbo[2], off[2], wof_size;
137862306a36Sopenharmony_ci	u32 voff;
137962306a36Sopenharmony_ci	u8 bytes_per_off;
138062306a36Sopenharmony_ci	char *addr;
138162306a36Sopenharmony_ci	struct page *page;
138262306a36Sopenharmony_ci	int i, err;
138362306a36Sopenharmony_ci	__le32 *off32;
138462306a36Sopenharmony_ci	__le64 *off64;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (ni->vfs_inode.i_size < 0x100000000ull) {
138762306a36Sopenharmony_ci		/* File starts with array of 32 bit offsets. */
138862306a36Sopenharmony_ci		bytes_per_off = sizeof(__le32);
138962306a36Sopenharmony_ci		vbo[1] = frame << 2;
139062306a36Sopenharmony_ci		*vbo_data = frames << 2;
139162306a36Sopenharmony_ci	} else {
139262306a36Sopenharmony_ci		/* File starts with array of 64 bit offsets. */
139362306a36Sopenharmony_ci		bytes_per_off = sizeof(__le64);
139462306a36Sopenharmony_ci		vbo[1] = frame << 3;
139562306a36Sopenharmony_ci		*vbo_data = frames << 3;
139662306a36Sopenharmony_ci	}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	/*
139962306a36Sopenharmony_ci	 * Read 4/8 bytes at [vbo - 4(8)] == offset where compressed frame starts.
140062306a36Sopenharmony_ci	 * Read 4/8 bytes at [vbo] == offset where compressed frame ends.
140162306a36Sopenharmony_ci	 */
140262306a36Sopenharmony_ci	if (!attr->non_res) {
140362306a36Sopenharmony_ci		if (vbo[1] + bytes_per_off > le32_to_cpu(attr->res.data_size)) {
140462306a36Sopenharmony_ci			ntfs_inode_err(&ni->vfs_inode, "is corrupted");
140562306a36Sopenharmony_ci			return -EINVAL;
140662306a36Sopenharmony_ci		}
140762306a36Sopenharmony_ci		addr = resident_data(attr);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		if (bytes_per_off == sizeof(__le32)) {
141062306a36Sopenharmony_ci			off32 = Add2Ptr(addr, vbo[1]);
141162306a36Sopenharmony_ci			off[0] = vbo[1] ? le32_to_cpu(off32[-1]) : 0;
141262306a36Sopenharmony_ci			off[1] = le32_to_cpu(off32[0]);
141362306a36Sopenharmony_ci		} else {
141462306a36Sopenharmony_ci			off64 = Add2Ptr(addr, vbo[1]);
141562306a36Sopenharmony_ci			off[0] = vbo[1] ? le64_to_cpu(off64[-1]) : 0;
141662306a36Sopenharmony_ci			off[1] = le64_to_cpu(off64[0]);
141762306a36Sopenharmony_ci		}
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci		*vbo_data += off[0];
142062306a36Sopenharmony_ci		*ondisk_size = off[1] - off[0];
142162306a36Sopenharmony_ci		return 0;
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	wof_size = le64_to_cpu(attr->nres.data_size);
142562306a36Sopenharmony_ci	down_write(&ni->file.run_lock);
142662306a36Sopenharmony_ci	page = ni->file.offs_page;
142762306a36Sopenharmony_ci	if (!page) {
142862306a36Sopenharmony_ci		page = alloc_page(GFP_KERNEL);
142962306a36Sopenharmony_ci		if (!page) {
143062306a36Sopenharmony_ci			err = -ENOMEM;
143162306a36Sopenharmony_ci			goto out;
143262306a36Sopenharmony_ci		}
143362306a36Sopenharmony_ci		page->index = -1;
143462306a36Sopenharmony_ci		ni->file.offs_page = page;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci	lock_page(page);
143762306a36Sopenharmony_ci	addr = page_address(page);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	if (vbo[1]) {
144062306a36Sopenharmony_ci		voff = vbo[1] & (PAGE_SIZE - 1);
144162306a36Sopenharmony_ci		vbo[0] = vbo[1] - bytes_per_off;
144262306a36Sopenharmony_ci		i = 0;
144362306a36Sopenharmony_ci	} else {
144462306a36Sopenharmony_ci		voff = 0;
144562306a36Sopenharmony_ci		vbo[0] = 0;
144662306a36Sopenharmony_ci		off[0] = 0;
144762306a36Sopenharmony_ci		i = 1;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	do {
145162306a36Sopenharmony_ci		pgoff_t index = vbo[i] >> PAGE_SHIFT;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci		if (index != page->index) {
145462306a36Sopenharmony_ci			u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1);
145562306a36Sopenharmony_ci			u64 to = min(from + PAGE_SIZE, wof_size);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci			err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME,
145862306a36Sopenharmony_ci						   ARRAY_SIZE(WOF_NAME), run,
145962306a36Sopenharmony_ci						   from, to);
146062306a36Sopenharmony_ci			if (err)
146162306a36Sopenharmony_ci				goto out1;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci			err = ntfs_bio_pages(sbi, run, &page, 1, from,
146462306a36Sopenharmony_ci					     to - from, REQ_OP_READ);
146562306a36Sopenharmony_ci			if (err) {
146662306a36Sopenharmony_ci				page->index = -1;
146762306a36Sopenharmony_ci				goto out1;
146862306a36Sopenharmony_ci			}
146962306a36Sopenharmony_ci			page->index = index;
147062306a36Sopenharmony_ci		}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci		if (i) {
147362306a36Sopenharmony_ci			if (bytes_per_off == sizeof(__le32)) {
147462306a36Sopenharmony_ci				off32 = Add2Ptr(addr, voff);
147562306a36Sopenharmony_ci				off[1] = le32_to_cpu(*off32);
147662306a36Sopenharmony_ci			} else {
147762306a36Sopenharmony_ci				off64 = Add2Ptr(addr, voff);
147862306a36Sopenharmony_ci				off[1] = le64_to_cpu(*off64);
147962306a36Sopenharmony_ci			}
148062306a36Sopenharmony_ci		} else if (!voff) {
148162306a36Sopenharmony_ci			if (bytes_per_off == sizeof(__le32)) {
148262306a36Sopenharmony_ci				off32 = Add2Ptr(addr, PAGE_SIZE - sizeof(u32));
148362306a36Sopenharmony_ci				off[0] = le32_to_cpu(*off32);
148462306a36Sopenharmony_ci			} else {
148562306a36Sopenharmony_ci				off64 = Add2Ptr(addr, PAGE_SIZE - sizeof(u64));
148662306a36Sopenharmony_ci				off[0] = le64_to_cpu(*off64);
148762306a36Sopenharmony_ci			}
148862306a36Sopenharmony_ci		} else {
148962306a36Sopenharmony_ci			/* Two values in one page. */
149062306a36Sopenharmony_ci			if (bytes_per_off == sizeof(__le32)) {
149162306a36Sopenharmony_ci				off32 = Add2Ptr(addr, voff);
149262306a36Sopenharmony_ci				off[0] = le32_to_cpu(off32[-1]);
149362306a36Sopenharmony_ci				off[1] = le32_to_cpu(off32[0]);
149462306a36Sopenharmony_ci			} else {
149562306a36Sopenharmony_ci				off64 = Add2Ptr(addr, voff);
149662306a36Sopenharmony_ci				off[0] = le64_to_cpu(off64[-1]);
149762306a36Sopenharmony_ci				off[1] = le64_to_cpu(off64[0]);
149862306a36Sopenharmony_ci			}
149962306a36Sopenharmony_ci			break;
150062306a36Sopenharmony_ci		}
150162306a36Sopenharmony_ci	} while (++i < 2);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	*vbo_data += off[0];
150462306a36Sopenharmony_ci	*ondisk_size = off[1] - off[0];
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ciout1:
150762306a36Sopenharmony_ci	unlock_page(page);
150862306a36Sopenharmony_ciout:
150962306a36Sopenharmony_ci	up_write(&ni->file.run_lock);
151062306a36Sopenharmony_ci	return err;
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci#endif
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci/*
151562306a36Sopenharmony_ci * attr_is_frame_compressed - Used to detect compressed frame.
151662306a36Sopenharmony_ci */
151762306a36Sopenharmony_ciint attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
151862306a36Sopenharmony_ci			     CLST frame, CLST *clst_data)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	int err;
152162306a36Sopenharmony_ci	u32 clst_frame;
152262306a36Sopenharmony_ci	CLST clen, lcn, vcn, alen, slen, vcn_next;
152362306a36Sopenharmony_ci	size_t idx;
152462306a36Sopenharmony_ci	struct runs_tree *run;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	*clst_data = 0;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (!is_attr_compressed(attr))
152962306a36Sopenharmony_ci		return 0;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (!attr->non_res)
153262306a36Sopenharmony_ci		return 0;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	clst_frame = 1u << attr->nres.c_unit;
153562306a36Sopenharmony_ci	vcn = frame * clst_frame;
153662306a36Sopenharmony_ci	run = &ni->file.run;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
153962306a36Sopenharmony_ci		err = attr_load_runs_vcn(ni, attr->type, attr_name(attr),
154062306a36Sopenharmony_ci					 attr->name_len, run, vcn);
154162306a36Sopenharmony_ci		if (err)
154262306a36Sopenharmony_ci			return err;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx))
154562306a36Sopenharmony_ci			return -EINVAL;
154662306a36Sopenharmony_ci	}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	if (lcn == SPARSE_LCN) {
154962306a36Sopenharmony_ci		/* Sparsed frame. */
155062306a36Sopenharmony_ci		return 0;
155162306a36Sopenharmony_ci	}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	if (clen >= clst_frame) {
155462306a36Sopenharmony_ci		/*
155562306a36Sopenharmony_ci		 * The frame is not compressed 'cause
155662306a36Sopenharmony_ci		 * it does not contain any sparse clusters.
155762306a36Sopenharmony_ci		 */
155862306a36Sopenharmony_ci		*clst_data = clst_frame;
155962306a36Sopenharmony_ci		return 0;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	alen = bytes_to_cluster(ni->mi.sbi, le64_to_cpu(attr->nres.alloc_size));
156362306a36Sopenharmony_ci	slen = 0;
156462306a36Sopenharmony_ci	*clst_data = clen;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	/*
156762306a36Sopenharmony_ci	 * The frame is compressed if *clst_data + slen >= clst_frame.
156862306a36Sopenharmony_ci	 * Check next fragments.
156962306a36Sopenharmony_ci	 */
157062306a36Sopenharmony_ci	while ((vcn += clen) < alen) {
157162306a36Sopenharmony_ci		vcn_next = vcn;
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci		if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
157462306a36Sopenharmony_ci		    vcn_next != vcn) {
157562306a36Sopenharmony_ci			err = attr_load_runs_vcn(ni, attr->type,
157662306a36Sopenharmony_ci						 attr_name(attr),
157762306a36Sopenharmony_ci						 attr->name_len, run, vcn_next);
157862306a36Sopenharmony_ci			if (err)
157962306a36Sopenharmony_ci				return err;
158062306a36Sopenharmony_ci			vcn = vcn_next;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci			if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx))
158362306a36Sopenharmony_ci				return -EINVAL;
158462306a36Sopenharmony_ci		}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci		if (lcn == SPARSE_LCN) {
158762306a36Sopenharmony_ci			slen += clen;
158862306a36Sopenharmony_ci		} else {
158962306a36Sopenharmony_ci			if (slen) {
159062306a36Sopenharmony_ci				/*
159162306a36Sopenharmony_ci				 * Data_clusters + sparse_clusters =
159262306a36Sopenharmony_ci				 * not enough for frame.
159362306a36Sopenharmony_ci				 */
159462306a36Sopenharmony_ci				return -EINVAL;
159562306a36Sopenharmony_ci			}
159662306a36Sopenharmony_ci			*clst_data += clen;
159762306a36Sopenharmony_ci		}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci		if (*clst_data + slen >= clst_frame) {
160062306a36Sopenharmony_ci			if (!slen) {
160162306a36Sopenharmony_ci				/*
160262306a36Sopenharmony_ci				 * There is no sparsed clusters in this frame
160362306a36Sopenharmony_ci				 * so it is not compressed.
160462306a36Sopenharmony_ci				 */
160562306a36Sopenharmony_ci				*clst_data = clst_frame;
160662306a36Sopenharmony_ci			} else {
160762306a36Sopenharmony_ci				/* Frame is compressed. */
160862306a36Sopenharmony_ci			}
160962306a36Sopenharmony_ci			break;
161062306a36Sopenharmony_ci		}
161162306a36Sopenharmony_ci	}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	return 0;
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci/*
161762306a36Sopenharmony_ci * attr_allocate_frame - Allocate/free clusters for @frame.
161862306a36Sopenharmony_ci *
161962306a36Sopenharmony_ci * Assumed: down_write(&ni->file.run_lock);
162062306a36Sopenharmony_ci */
162162306a36Sopenharmony_ciint attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
162262306a36Sopenharmony_ci			u64 new_valid)
162362306a36Sopenharmony_ci{
162462306a36Sopenharmony_ci	int err = 0;
162562306a36Sopenharmony_ci	struct runs_tree *run = &ni->file.run;
162662306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = ni->mi.sbi;
162762306a36Sopenharmony_ci	struct ATTRIB *attr = NULL, *attr_b;
162862306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le, *le_b;
162962306a36Sopenharmony_ci	struct mft_inode *mi, *mi_b;
163062306a36Sopenharmony_ci	CLST svcn, evcn1, next_svcn, len;
163162306a36Sopenharmony_ci	CLST vcn, end, clst_data;
163262306a36Sopenharmony_ci	u64 total_size, valid_size, data_size;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	le_b = NULL;
163562306a36Sopenharmony_ci	attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
163662306a36Sopenharmony_ci	if (!attr_b)
163762306a36Sopenharmony_ci		return -ENOENT;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (!is_attr_ext(attr_b))
164062306a36Sopenharmony_ci		return -EINVAL;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	vcn = frame << NTFS_LZNT_CUNIT;
164362306a36Sopenharmony_ci	total_size = le64_to_cpu(attr_b->nres.total_size);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	svcn = le64_to_cpu(attr_b->nres.svcn);
164662306a36Sopenharmony_ci	evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
164762306a36Sopenharmony_ci	data_size = le64_to_cpu(attr_b->nres.data_size);
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	if (svcn <= vcn && vcn < evcn1) {
165062306a36Sopenharmony_ci		attr = attr_b;
165162306a36Sopenharmony_ci		le = le_b;
165262306a36Sopenharmony_ci		mi = mi_b;
165362306a36Sopenharmony_ci	} else if (!le_b) {
165462306a36Sopenharmony_ci		err = -EINVAL;
165562306a36Sopenharmony_ci		goto out;
165662306a36Sopenharmony_ci	} else {
165762306a36Sopenharmony_ci		le = le_b;
165862306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
165962306a36Sopenharmony_ci				    &mi);
166062306a36Sopenharmony_ci		if (!attr) {
166162306a36Sopenharmony_ci			err = -EINVAL;
166262306a36Sopenharmony_ci			goto out;
166362306a36Sopenharmony_ci		}
166462306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
166562306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
166662306a36Sopenharmony_ci	}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	err = attr_load_runs(attr, ni, run, NULL);
166962306a36Sopenharmony_ci	if (err)
167062306a36Sopenharmony_ci		goto out;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	err = attr_is_frame_compressed(ni, attr_b, frame, &clst_data);
167362306a36Sopenharmony_ci	if (err)
167462306a36Sopenharmony_ci		goto out;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	total_size -= (u64)clst_data << sbi->cluster_bits;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	len = bytes_to_cluster(sbi, compr_size);
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (len == clst_data)
168162306a36Sopenharmony_ci		goto out;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	if (len < clst_data) {
168462306a36Sopenharmony_ci		err = run_deallocate_ex(sbi, run, vcn + len, clst_data - len,
168562306a36Sopenharmony_ci					NULL, true);
168662306a36Sopenharmony_ci		if (err)
168762306a36Sopenharmony_ci			goto out;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci		if (!run_add_entry(run, vcn + len, SPARSE_LCN, clst_data - len,
169062306a36Sopenharmony_ci				   false)) {
169162306a36Sopenharmony_ci			err = -ENOMEM;
169262306a36Sopenharmony_ci			goto out;
169362306a36Sopenharmony_ci		}
169462306a36Sopenharmony_ci		end = vcn + clst_data;
169562306a36Sopenharmony_ci		/* Run contains updated range [vcn + len : end). */
169662306a36Sopenharmony_ci	} else {
169762306a36Sopenharmony_ci		CLST alen, hint = 0;
169862306a36Sopenharmony_ci		/* Get the last LCN to allocate from. */
169962306a36Sopenharmony_ci		if (vcn + clst_data &&
170062306a36Sopenharmony_ci		    !run_lookup_entry(run, vcn + clst_data - 1, &hint, NULL,
170162306a36Sopenharmony_ci				      NULL)) {
170262306a36Sopenharmony_ci			hint = -1;
170362306a36Sopenharmony_ci		}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci		err = attr_allocate_clusters(sbi, run, vcn + clst_data,
170662306a36Sopenharmony_ci					     hint + 1, len - clst_data, NULL,
170762306a36Sopenharmony_ci					     ALLOCATE_DEF, &alen, 0, NULL,
170862306a36Sopenharmony_ci					     NULL);
170962306a36Sopenharmony_ci		if (err)
171062306a36Sopenharmony_ci			goto out;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci		end = vcn + len;
171362306a36Sopenharmony_ci		/* Run contains updated range [vcn + clst_data : end). */
171462306a36Sopenharmony_ci	}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	total_size += (u64)len << sbi->cluster_bits;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_cirepack:
171962306a36Sopenharmony_ci	err = mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn);
172062306a36Sopenharmony_ci	if (err)
172162306a36Sopenharmony_ci		goto out;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	attr_b->nres.total_size = cpu_to_le64(total_size);
172462306a36Sopenharmony_ci	inode_set_bytes(&ni->vfs_inode, total_size);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	mi_b->dirty = true;
172762306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	/* Stored [vcn : next_svcn) from [vcn : end). */
173062306a36Sopenharmony_ci	next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (end <= evcn1) {
173362306a36Sopenharmony_ci		if (next_svcn == evcn1) {
173462306a36Sopenharmony_ci			/* Normal way. Update attribute and exit. */
173562306a36Sopenharmony_ci			goto ok;
173662306a36Sopenharmony_ci		}
173762306a36Sopenharmony_ci		/* Add new segment [next_svcn : evcn1 - next_svcn). */
173862306a36Sopenharmony_ci		if (!ni->attr_list.size) {
173962306a36Sopenharmony_ci			err = ni_create_attr_list(ni);
174062306a36Sopenharmony_ci			if (err)
174162306a36Sopenharmony_ci				goto out;
174262306a36Sopenharmony_ci			/* Layout of records is changed. */
174362306a36Sopenharmony_ci			le_b = NULL;
174462306a36Sopenharmony_ci			attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
174562306a36Sopenharmony_ci					      0, NULL, &mi_b);
174662306a36Sopenharmony_ci			if (!attr_b) {
174762306a36Sopenharmony_ci				err = -ENOENT;
174862306a36Sopenharmony_ci				goto out;
174962306a36Sopenharmony_ci			}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci			attr = attr_b;
175262306a36Sopenharmony_ci			le = le_b;
175362306a36Sopenharmony_ci			mi = mi_b;
175462306a36Sopenharmony_ci			goto repack;
175562306a36Sopenharmony_ci		}
175662306a36Sopenharmony_ci	}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	svcn = evcn1;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	/* Estimate next attribute. */
176162306a36Sopenharmony_ci	attr = ni_find_attr(ni, attr, &le, ATTR_DATA, NULL, 0, &svcn, &mi);
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	if (attr) {
176462306a36Sopenharmony_ci		CLST alloc = bytes_to_cluster(
176562306a36Sopenharmony_ci			sbi, le64_to_cpu(attr_b->nres.alloc_size));
176662306a36Sopenharmony_ci		CLST evcn = le64_to_cpu(attr->nres.evcn);
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci		if (end < next_svcn)
176962306a36Sopenharmony_ci			end = next_svcn;
177062306a36Sopenharmony_ci		while (end > evcn) {
177162306a36Sopenharmony_ci			/* Remove segment [svcn : evcn). */
177262306a36Sopenharmony_ci			mi_remove_attr(NULL, mi, attr);
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci			if (!al_remove_le(ni, le)) {
177562306a36Sopenharmony_ci				err = -EINVAL;
177662306a36Sopenharmony_ci				goto out;
177762306a36Sopenharmony_ci			}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci			if (evcn + 1 >= alloc) {
178062306a36Sopenharmony_ci				/* Last attribute segment. */
178162306a36Sopenharmony_ci				evcn1 = evcn + 1;
178262306a36Sopenharmony_ci				goto ins_ext;
178362306a36Sopenharmony_ci			}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci			if (ni_load_mi(ni, le, &mi)) {
178662306a36Sopenharmony_ci				attr = NULL;
178762306a36Sopenharmony_ci				goto out;
178862306a36Sopenharmony_ci			}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci			attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0,
179162306a36Sopenharmony_ci					    &le->id);
179262306a36Sopenharmony_ci			if (!attr) {
179362306a36Sopenharmony_ci				err = -EINVAL;
179462306a36Sopenharmony_ci				goto out;
179562306a36Sopenharmony_ci			}
179662306a36Sopenharmony_ci			svcn = le64_to_cpu(attr->nres.svcn);
179762306a36Sopenharmony_ci			evcn = le64_to_cpu(attr->nres.evcn);
179862306a36Sopenharmony_ci		}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci		if (end < svcn)
180162306a36Sopenharmony_ci			end = svcn;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci		err = attr_load_runs(attr, ni, run, &end);
180462306a36Sopenharmony_ci		if (err)
180562306a36Sopenharmony_ci			goto out;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci		evcn1 = evcn + 1;
180862306a36Sopenharmony_ci		attr->nres.svcn = cpu_to_le64(next_svcn);
180962306a36Sopenharmony_ci		err = mi_pack_runs(mi, attr, run, evcn1 - next_svcn);
181062306a36Sopenharmony_ci		if (err)
181162306a36Sopenharmony_ci			goto out;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci		le->vcn = cpu_to_le64(next_svcn);
181462306a36Sopenharmony_ci		ni->attr_list.dirty = true;
181562306a36Sopenharmony_ci		mi->dirty = true;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci		next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
181862306a36Sopenharmony_ci	}
181962306a36Sopenharmony_ciins_ext:
182062306a36Sopenharmony_ci	if (evcn1 > next_svcn) {
182162306a36Sopenharmony_ci		err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
182262306a36Sopenharmony_ci					    next_svcn, evcn1 - next_svcn,
182362306a36Sopenharmony_ci					    attr_b->flags, &attr, &mi, NULL);
182462306a36Sopenharmony_ci		if (err)
182562306a36Sopenharmony_ci			goto out;
182662306a36Sopenharmony_ci	}
182762306a36Sopenharmony_ciok:
182862306a36Sopenharmony_ci	run_truncate_around(run, vcn);
182962306a36Sopenharmony_ciout:
183062306a36Sopenharmony_ci	if (attr_b) {
183162306a36Sopenharmony_ci		if (new_valid > data_size)
183262306a36Sopenharmony_ci			new_valid = data_size;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci		valid_size = le64_to_cpu(attr_b->nres.valid_size);
183562306a36Sopenharmony_ci		if (new_valid != valid_size) {
183662306a36Sopenharmony_ci			attr_b->nres.valid_size = cpu_to_le64(valid_size);
183762306a36Sopenharmony_ci			mi_b->dirty = true;
183862306a36Sopenharmony_ci		}
183962306a36Sopenharmony_ci	}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	return err;
184262306a36Sopenharmony_ci}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci/*
184562306a36Sopenharmony_ci * attr_collapse_range - Collapse range in file.
184662306a36Sopenharmony_ci */
184762306a36Sopenharmony_ciint attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
184862306a36Sopenharmony_ci{
184962306a36Sopenharmony_ci	int err = 0;
185062306a36Sopenharmony_ci	struct runs_tree *run = &ni->file.run;
185162306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = ni->mi.sbi;
185262306a36Sopenharmony_ci	struct ATTRIB *attr = NULL, *attr_b;
185362306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le, *le_b;
185462306a36Sopenharmony_ci	struct mft_inode *mi, *mi_b;
185562306a36Sopenharmony_ci	CLST svcn, evcn1, len, dealloc, alen;
185662306a36Sopenharmony_ci	CLST vcn, end;
185762306a36Sopenharmony_ci	u64 valid_size, data_size, alloc_size, total_size;
185862306a36Sopenharmony_ci	u32 mask;
185962306a36Sopenharmony_ci	__le16 a_flags;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	if (!bytes)
186262306a36Sopenharmony_ci		return 0;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	le_b = NULL;
186562306a36Sopenharmony_ci	attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
186662306a36Sopenharmony_ci	if (!attr_b)
186762306a36Sopenharmony_ci		return -ENOENT;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	if (!attr_b->non_res) {
187062306a36Sopenharmony_ci		/* Attribute is resident. Nothing to do? */
187162306a36Sopenharmony_ci		return 0;
187262306a36Sopenharmony_ci	}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	data_size = le64_to_cpu(attr_b->nres.data_size);
187562306a36Sopenharmony_ci	alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
187662306a36Sopenharmony_ci	a_flags = attr_b->flags;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	if (is_attr_ext(attr_b)) {
187962306a36Sopenharmony_ci		total_size = le64_to_cpu(attr_b->nres.total_size);
188062306a36Sopenharmony_ci		mask = (sbi->cluster_size << attr_b->nres.c_unit) - 1;
188162306a36Sopenharmony_ci	} else {
188262306a36Sopenharmony_ci		total_size = alloc_size;
188362306a36Sopenharmony_ci		mask = sbi->cluster_mask;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	if ((vbo & mask) || (bytes & mask)) {
188762306a36Sopenharmony_ci		/* Allow to collapse only cluster aligned ranges. */
188862306a36Sopenharmony_ci		return -EINVAL;
188962306a36Sopenharmony_ci	}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	if (vbo > data_size)
189262306a36Sopenharmony_ci		return -EINVAL;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	down_write(&ni->file.run_lock);
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	if (vbo + bytes >= data_size) {
189762306a36Sopenharmony_ci		u64 new_valid = min(ni->i_valid, vbo);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci		/* Simple truncate file at 'vbo'. */
190062306a36Sopenharmony_ci		truncate_setsize(&ni->vfs_inode, vbo);
190162306a36Sopenharmony_ci		err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run, vbo,
190262306a36Sopenharmony_ci				    &new_valid, true, NULL);
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci		if (!err && new_valid < ni->i_valid)
190562306a36Sopenharmony_ci			ni->i_valid = new_valid;
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci		goto out;
190862306a36Sopenharmony_ci	}
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	/*
191162306a36Sopenharmony_ci	 * Enumerate all attribute segments and collapse.
191262306a36Sopenharmony_ci	 */
191362306a36Sopenharmony_ci	alen = alloc_size >> sbi->cluster_bits;
191462306a36Sopenharmony_ci	vcn = vbo >> sbi->cluster_bits;
191562306a36Sopenharmony_ci	len = bytes >> sbi->cluster_bits;
191662306a36Sopenharmony_ci	end = vcn + len;
191762306a36Sopenharmony_ci	dealloc = 0;
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	svcn = le64_to_cpu(attr_b->nres.svcn);
192062306a36Sopenharmony_ci	evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	if (svcn <= vcn && vcn < evcn1) {
192362306a36Sopenharmony_ci		attr = attr_b;
192462306a36Sopenharmony_ci		le = le_b;
192562306a36Sopenharmony_ci		mi = mi_b;
192662306a36Sopenharmony_ci	} else if (!le_b) {
192762306a36Sopenharmony_ci		err = -EINVAL;
192862306a36Sopenharmony_ci		goto out;
192962306a36Sopenharmony_ci	} else {
193062306a36Sopenharmony_ci		le = le_b;
193162306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
193262306a36Sopenharmony_ci				    &mi);
193362306a36Sopenharmony_ci		if (!attr) {
193462306a36Sopenharmony_ci			err = -EINVAL;
193562306a36Sopenharmony_ci			goto out;
193662306a36Sopenharmony_ci		}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
193962306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
194062306a36Sopenharmony_ci	}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	for (;;) {
194362306a36Sopenharmony_ci		if (svcn >= end) {
194462306a36Sopenharmony_ci			/* Shift VCN- */
194562306a36Sopenharmony_ci			attr->nres.svcn = cpu_to_le64(svcn - len);
194662306a36Sopenharmony_ci			attr->nres.evcn = cpu_to_le64(evcn1 - 1 - len);
194762306a36Sopenharmony_ci			if (le) {
194862306a36Sopenharmony_ci				le->vcn = attr->nres.svcn;
194962306a36Sopenharmony_ci				ni->attr_list.dirty = true;
195062306a36Sopenharmony_ci			}
195162306a36Sopenharmony_ci			mi->dirty = true;
195262306a36Sopenharmony_ci		} else if (svcn < vcn || end < evcn1) {
195362306a36Sopenharmony_ci			CLST vcn1, eat, next_svcn;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci			/* Collapse a part of this attribute segment. */
195662306a36Sopenharmony_ci			err = attr_load_runs(attr, ni, run, &svcn);
195762306a36Sopenharmony_ci			if (err)
195862306a36Sopenharmony_ci				goto out;
195962306a36Sopenharmony_ci			vcn1 = max(vcn, svcn);
196062306a36Sopenharmony_ci			eat = min(end, evcn1) - vcn1;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci			err = run_deallocate_ex(sbi, run, vcn1, eat, &dealloc,
196362306a36Sopenharmony_ci						true);
196462306a36Sopenharmony_ci			if (err)
196562306a36Sopenharmony_ci				goto out;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci			if (!run_collapse_range(run, vcn1, eat)) {
196862306a36Sopenharmony_ci				err = -ENOMEM;
196962306a36Sopenharmony_ci				goto out;
197062306a36Sopenharmony_ci			}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci			if (svcn >= vcn) {
197362306a36Sopenharmony_ci				/* Shift VCN */
197462306a36Sopenharmony_ci				attr->nres.svcn = cpu_to_le64(vcn);
197562306a36Sopenharmony_ci				if (le) {
197662306a36Sopenharmony_ci					le->vcn = attr->nres.svcn;
197762306a36Sopenharmony_ci					ni->attr_list.dirty = true;
197862306a36Sopenharmony_ci				}
197962306a36Sopenharmony_ci			}
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci			err = mi_pack_runs(mi, attr, run, evcn1 - svcn - eat);
198262306a36Sopenharmony_ci			if (err)
198362306a36Sopenharmony_ci				goto out;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci			next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
198662306a36Sopenharmony_ci			if (next_svcn + eat < evcn1) {
198762306a36Sopenharmony_ci				err = ni_insert_nonresident(
198862306a36Sopenharmony_ci					ni, ATTR_DATA, NULL, 0, run, next_svcn,
198962306a36Sopenharmony_ci					evcn1 - eat - next_svcn, a_flags, &attr,
199062306a36Sopenharmony_ci					&mi, &le);
199162306a36Sopenharmony_ci				if (err)
199262306a36Sopenharmony_ci					goto out;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci				/* Layout of records maybe changed. */
199562306a36Sopenharmony_ci				attr_b = NULL;
199662306a36Sopenharmony_ci			}
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci			/* Free all allocated memory. */
199962306a36Sopenharmony_ci			run_truncate(run, 0);
200062306a36Sopenharmony_ci		} else {
200162306a36Sopenharmony_ci			u16 le_sz;
200262306a36Sopenharmony_ci			u16 roff = le16_to_cpu(attr->nres.run_off);
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci			if (roff > le32_to_cpu(attr->size)) {
200562306a36Sopenharmony_ci				err = -EINVAL;
200662306a36Sopenharmony_ci				goto out;
200762306a36Sopenharmony_ci			}
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci			run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn,
201062306a36Sopenharmony_ci				      evcn1 - 1, svcn, Add2Ptr(attr, roff),
201162306a36Sopenharmony_ci				      le32_to_cpu(attr->size) - roff);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci			/* Delete this attribute segment. */
201462306a36Sopenharmony_ci			mi_remove_attr(NULL, mi, attr);
201562306a36Sopenharmony_ci			if (!le)
201662306a36Sopenharmony_ci				break;
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci			le_sz = le16_to_cpu(le->size);
201962306a36Sopenharmony_ci			if (!al_remove_le(ni, le)) {
202062306a36Sopenharmony_ci				err = -EINVAL;
202162306a36Sopenharmony_ci				goto out;
202262306a36Sopenharmony_ci			}
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci			if (evcn1 >= alen)
202562306a36Sopenharmony_ci				break;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci			if (!svcn) {
202862306a36Sopenharmony_ci				/* Load next record that contains this attribute. */
202962306a36Sopenharmony_ci				if (ni_load_mi(ni, le, &mi)) {
203062306a36Sopenharmony_ci					err = -EINVAL;
203162306a36Sopenharmony_ci					goto out;
203262306a36Sopenharmony_ci				}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci				/* Look for required attribute. */
203562306a36Sopenharmony_ci				attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL,
203662306a36Sopenharmony_ci						    0, &le->id);
203762306a36Sopenharmony_ci				if (!attr) {
203862306a36Sopenharmony_ci					err = -EINVAL;
203962306a36Sopenharmony_ci					goto out;
204062306a36Sopenharmony_ci				}
204162306a36Sopenharmony_ci				goto next_attr;
204262306a36Sopenharmony_ci			}
204362306a36Sopenharmony_ci			le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz);
204462306a36Sopenharmony_ci		}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci		if (evcn1 >= alen)
204762306a36Sopenharmony_ci			break;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci		attr = ni_enum_attr_ex(ni, attr, &le, &mi);
205062306a36Sopenharmony_ci		if (!attr) {
205162306a36Sopenharmony_ci			err = -EINVAL;
205262306a36Sopenharmony_ci			goto out;
205362306a36Sopenharmony_ci		}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_cinext_attr:
205662306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
205762306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
205862306a36Sopenharmony_ci	}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	if (!attr_b) {
206162306a36Sopenharmony_ci		le_b = NULL;
206262306a36Sopenharmony_ci		attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
206362306a36Sopenharmony_ci				      &mi_b);
206462306a36Sopenharmony_ci		if (!attr_b) {
206562306a36Sopenharmony_ci			err = -ENOENT;
206662306a36Sopenharmony_ci			goto out;
206762306a36Sopenharmony_ci		}
206862306a36Sopenharmony_ci	}
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	data_size -= bytes;
207162306a36Sopenharmony_ci	valid_size = ni->i_valid;
207262306a36Sopenharmony_ci	if (vbo + bytes <= valid_size)
207362306a36Sopenharmony_ci		valid_size -= bytes;
207462306a36Sopenharmony_ci	else if (vbo < valid_size)
207562306a36Sopenharmony_ci		valid_size = vbo;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	attr_b->nres.alloc_size = cpu_to_le64(alloc_size - bytes);
207862306a36Sopenharmony_ci	attr_b->nres.data_size = cpu_to_le64(data_size);
207962306a36Sopenharmony_ci	attr_b->nres.valid_size = cpu_to_le64(min(valid_size, data_size));
208062306a36Sopenharmony_ci	total_size -= (u64)dealloc << sbi->cluster_bits;
208162306a36Sopenharmony_ci	if (is_attr_ext(attr_b))
208262306a36Sopenharmony_ci		attr_b->nres.total_size = cpu_to_le64(total_size);
208362306a36Sopenharmony_ci	mi_b->dirty = true;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	/* Update inode size. */
208662306a36Sopenharmony_ci	ni->i_valid = valid_size;
208762306a36Sopenharmony_ci	i_size_write(&ni->vfs_inode, data_size);
208862306a36Sopenharmony_ci	inode_set_bytes(&ni->vfs_inode, total_size);
208962306a36Sopenharmony_ci	ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
209062306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ciout:
209362306a36Sopenharmony_ci	up_write(&ni->file.run_lock);
209462306a36Sopenharmony_ci	if (err)
209562306a36Sopenharmony_ci		_ntfs_bad_inode(&ni->vfs_inode);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	return err;
209862306a36Sopenharmony_ci}
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci/*
210162306a36Sopenharmony_ci * attr_punch_hole
210262306a36Sopenharmony_ci *
210362306a36Sopenharmony_ci * Not for normal files.
210462306a36Sopenharmony_ci */
210562306a36Sopenharmony_ciint attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
210662306a36Sopenharmony_ci{
210762306a36Sopenharmony_ci	int err = 0;
210862306a36Sopenharmony_ci	struct runs_tree *run = &ni->file.run;
210962306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = ni->mi.sbi;
211062306a36Sopenharmony_ci	struct ATTRIB *attr = NULL, *attr_b;
211162306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le, *le_b;
211262306a36Sopenharmony_ci	struct mft_inode *mi, *mi_b;
211362306a36Sopenharmony_ci	CLST svcn, evcn1, vcn, len, end, alen, hole, next_svcn;
211462306a36Sopenharmony_ci	u64 total_size, alloc_size;
211562306a36Sopenharmony_ci	u32 mask;
211662306a36Sopenharmony_ci	__le16 a_flags;
211762306a36Sopenharmony_ci	struct runs_tree run2;
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	if (!bytes)
212062306a36Sopenharmony_ci		return 0;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	le_b = NULL;
212362306a36Sopenharmony_ci	attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
212462306a36Sopenharmony_ci	if (!attr_b)
212562306a36Sopenharmony_ci		return -ENOENT;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	if (!attr_b->non_res) {
212862306a36Sopenharmony_ci		u32 data_size = le32_to_cpu(attr_b->res.data_size);
212962306a36Sopenharmony_ci		u32 from, to;
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci		if (vbo > data_size)
213262306a36Sopenharmony_ci			return 0;
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci		from = vbo;
213562306a36Sopenharmony_ci		to = min_t(u64, vbo + bytes, data_size);
213662306a36Sopenharmony_ci		memset(Add2Ptr(resident_data(attr_b), from), 0, to - from);
213762306a36Sopenharmony_ci		return 0;
213862306a36Sopenharmony_ci	}
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	if (!is_attr_ext(attr_b))
214162306a36Sopenharmony_ci		return -EOPNOTSUPP;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
214462306a36Sopenharmony_ci	total_size = le64_to_cpu(attr_b->nres.total_size);
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	if (vbo >= alloc_size) {
214762306a36Sopenharmony_ci		/* NOTE: It is allowed. */
214862306a36Sopenharmony_ci		return 0;
214962306a36Sopenharmony_ci	}
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	mask = (sbi->cluster_size << attr_b->nres.c_unit) - 1;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	bytes += vbo;
215462306a36Sopenharmony_ci	if (bytes > alloc_size)
215562306a36Sopenharmony_ci		bytes = alloc_size;
215662306a36Sopenharmony_ci	bytes -= vbo;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	if ((vbo & mask) || (bytes & mask)) {
215962306a36Sopenharmony_ci		/* We have to zero a range(s). */
216062306a36Sopenharmony_ci		if (frame_size == NULL) {
216162306a36Sopenharmony_ci			/* Caller insists range is aligned. */
216262306a36Sopenharmony_ci			return -EINVAL;
216362306a36Sopenharmony_ci		}
216462306a36Sopenharmony_ci		*frame_size = mask + 1;
216562306a36Sopenharmony_ci		return E_NTFS_NOTALIGNED;
216662306a36Sopenharmony_ci	}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	down_write(&ni->file.run_lock);
216962306a36Sopenharmony_ci	run_init(&run2);
217062306a36Sopenharmony_ci	run_truncate(run, 0);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	/*
217362306a36Sopenharmony_ci	 * Enumerate all attribute segments and punch hole where necessary.
217462306a36Sopenharmony_ci	 */
217562306a36Sopenharmony_ci	alen = alloc_size >> sbi->cluster_bits;
217662306a36Sopenharmony_ci	vcn = vbo >> sbi->cluster_bits;
217762306a36Sopenharmony_ci	len = bytes >> sbi->cluster_bits;
217862306a36Sopenharmony_ci	end = vcn + len;
217962306a36Sopenharmony_ci	hole = 0;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	svcn = le64_to_cpu(attr_b->nres.svcn);
218262306a36Sopenharmony_ci	evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
218362306a36Sopenharmony_ci	a_flags = attr_b->flags;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	if (svcn <= vcn && vcn < evcn1) {
218662306a36Sopenharmony_ci		attr = attr_b;
218762306a36Sopenharmony_ci		le = le_b;
218862306a36Sopenharmony_ci		mi = mi_b;
218962306a36Sopenharmony_ci	} else if (!le_b) {
219062306a36Sopenharmony_ci		err = -EINVAL;
219162306a36Sopenharmony_ci		goto bad_inode;
219262306a36Sopenharmony_ci	} else {
219362306a36Sopenharmony_ci		le = le_b;
219462306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
219562306a36Sopenharmony_ci				    &mi);
219662306a36Sopenharmony_ci		if (!attr) {
219762306a36Sopenharmony_ci			err = -EINVAL;
219862306a36Sopenharmony_ci			goto bad_inode;
219962306a36Sopenharmony_ci		}
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
220262306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
220362306a36Sopenharmony_ci	}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	while (svcn < end) {
220662306a36Sopenharmony_ci		CLST vcn1, zero, hole2 = hole;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci		err = attr_load_runs(attr, ni, run, &svcn);
220962306a36Sopenharmony_ci		if (err)
221062306a36Sopenharmony_ci			goto done;
221162306a36Sopenharmony_ci		vcn1 = max(vcn, svcn);
221262306a36Sopenharmony_ci		zero = min(end, evcn1) - vcn1;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci		/*
221562306a36Sopenharmony_ci		 * Check range [vcn1 + zero).
221662306a36Sopenharmony_ci		 * Calculate how many clusters there are.
221762306a36Sopenharmony_ci		 * Don't do any destructive actions.
221862306a36Sopenharmony_ci		 */
221962306a36Sopenharmony_ci		err = run_deallocate_ex(NULL, run, vcn1, zero, &hole2, false);
222062306a36Sopenharmony_ci		if (err)
222162306a36Sopenharmony_ci			goto done;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		/* Check if required range is already hole. */
222462306a36Sopenharmony_ci		if (hole2 == hole)
222562306a36Sopenharmony_ci			goto next_attr;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci		/* Make a clone of run to undo. */
222862306a36Sopenharmony_ci		err = run_clone(run, &run2);
222962306a36Sopenharmony_ci		if (err)
223062306a36Sopenharmony_ci			goto done;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci		/* Make a hole range (sparse) [vcn1 + zero). */
223362306a36Sopenharmony_ci		if (!run_add_entry(run, vcn1, SPARSE_LCN, zero, false)) {
223462306a36Sopenharmony_ci			err = -ENOMEM;
223562306a36Sopenharmony_ci			goto done;
223662306a36Sopenharmony_ci		}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci		/* Update run in attribute segment. */
223962306a36Sopenharmony_ci		err = mi_pack_runs(mi, attr, run, evcn1 - svcn);
224062306a36Sopenharmony_ci		if (err)
224162306a36Sopenharmony_ci			goto done;
224262306a36Sopenharmony_ci		next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
224362306a36Sopenharmony_ci		if (next_svcn < evcn1) {
224462306a36Sopenharmony_ci			/* Insert new attribute segment. */
224562306a36Sopenharmony_ci			err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
224662306a36Sopenharmony_ci						    next_svcn,
224762306a36Sopenharmony_ci						    evcn1 - next_svcn, a_flags,
224862306a36Sopenharmony_ci						    &attr, &mi, &le);
224962306a36Sopenharmony_ci			if (err)
225062306a36Sopenharmony_ci				goto undo_punch;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci			/* Layout of records maybe changed. */
225362306a36Sopenharmony_ci			attr_b = NULL;
225462306a36Sopenharmony_ci		}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci		/* Real deallocate. Should not fail. */
225762306a36Sopenharmony_ci		run_deallocate_ex(sbi, &run2, vcn1, zero, &hole, true);
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_cinext_attr:
226062306a36Sopenharmony_ci		/* Free all allocated memory. */
226162306a36Sopenharmony_ci		run_truncate(run, 0);
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci		if (evcn1 >= alen)
226462306a36Sopenharmony_ci			break;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci		/* Get next attribute segment. */
226762306a36Sopenharmony_ci		attr = ni_enum_attr_ex(ni, attr, &le, &mi);
226862306a36Sopenharmony_ci		if (!attr) {
226962306a36Sopenharmony_ci			err = -EINVAL;
227062306a36Sopenharmony_ci			goto bad_inode;
227162306a36Sopenharmony_ci		}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
227462306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
227562306a36Sopenharmony_ci	}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_cidone:
227862306a36Sopenharmony_ci	if (!hole)
227962306a36Sopenharmony_ci		goto out;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	if (!attr_b) {
228262306a36Sopenharmony_ci		attr_b = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
228362306a36Sopenharmony_ci				      &mi_b);
228462306a36Sopenharmony_ci		if (!attr_b) {
228562306a36Sopenharmony_ci			err = -EINVAL;
228662306a36Sopenharmony_ci			goto bad_inode;
228762306a36Sopenharmony_ci		}
228862306a36Sopenharmony_ci	}
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci	total_size -= (u64)hole << sbi->cluster_bits;
229162306a36Sopenharmony_ci	attr_b->nres.total_size = cpu_to_le64(total_size);
229262306a36Sopenharmony_ci	mi_b->dirty = true;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* Update inode size. */
229562306a36Sopenharmony_ci	inode_set_bytes(&ni->vfs_inode, total_size);
229662306a36Sopenharmony_ci	ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
229762306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ciout:
230062306a36Sopenharmony_ci	run_close(&run2);
230162306a36Sopenharmony_ci	up_write(&ni->file.run_lock);
230262306a36Sopenharmony_ci	return err;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_cibad_inode:
230562306a36Sopenharmony_ci	_ntfs_bad_inode(&ni->vfs_inode);
230662306a36Sopenharmony_ci	goto out;
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ciundo_punch:
230962306a36Sopenharmony_ci	/*
231062306a36Sopenharmony_ci	 * Restore packed runs.
231162306a36Sopenharmony_ci	 * 'mi_pack_runs' should not fail, cause we restore original.
231262306a36Sopenharmony_ci	 */
231362306a36Sopenharmony_ci	if (mi_pack_runs(mi, attr, &run2, evcn1 - svcn))
231462306a36Sopenharmony_ci		goto bad_inode;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	goto done;
231762306a36Sopenharmony_ci}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci/*
232062306a36Sopenharmony_ci * attr_insert_range - Insert range (hole) in file.
232162306a36Sopenharmony_ci * Not for normal files.
232262306a36Sopenharmony_ci */
232362306a36Sopenharmony_ciint attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
232462306a36Sopenharmony_ci{
232562306a36Sopenharmony_ci	int err = 0;
232662306a36Sopenharmony_ci	struct runs_tree *run = &ni->file.run;
232762306a36Sopenharmony_ci	struct ntfs_sb_info *sbi = ni->mi.sbi;
232862306a36Sopenharmony_ci	struct ATTRIB *attr = NULL, *attr_b;
232962306a36Sopenharmony_ci	struct ATTR_LIST_ENTRY *le, *le_b;
233062306a36Sopenharmony_ci	struct mft_inode *mi, *mi_b;
233162306a36Sopenharmony_ci	CLST vcn, svcn, evcn1, len, next_svcn;
233262306a36Sopenharmony_ci	u64 data_size, alloc_size;
233362306a36Sopenharmony_ci	u32 mask;
233462306a36Sopenharmony_ci	__le16 a_flags;
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	if (!bytes)
233762306a36Sopenharmony_ci		return 0;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	le_b = NULL;
234062306a36Sopenharmony_ci	attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
234162306a36Sopenharmony_ci	if (!attr_b)
234262306a36Sopenharmony_ci		return -ENOENT;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	if (!is_attr_ext(attr_b)) {
234562306a36Sopenharmony_ci		/* It was checked above. See fallocate. */
234662306a36Sopenharmony_ci		return -EOPNOTSUPP;
234762306a36Sopenharmony_ci	}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	if (!attr_b->non_res) {
235062306a36Sopenharmony_ci		data_size = le32_to_cpu(attr_b->res.data_size);
235162306a36Sopenharmony_ci		alloc_size = data_size;
235262306a36Sopenharmony_ci		mask = sbi->cluster_mask; /* cluster_size - 1 */
235362306a36Sopenharmony_ci	} else {
235462306a36Sopenharmony_ci		data_size = le64_to_cpu(attr_b->nres.data_size);
235562306a36Sopenharmony_ci		alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
235662306a36Sopenharmony_ci		mask = (sbi->cluster_size << attr_b->nres.c_unit) - 1;
235762306a36Sopenharmony_ci	}
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	if (vbo > data_size) {
236062306a36Sopenharmony_ci		/* Insert range after the file size is not allowed. */
236162306a36Sopenharmony_ci		return -EINVAL;
236262306a36Sopenharmony_ci	}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	if ((vbo & mask) || (bytes & mask)) {
236562306a36Sopenharmony_ci		/* Allow to insert only frame aligned ranges. */
236662306a36Sopenharmony_ci		return -EINVAL;
236762306a36Sopenharmony_ci	}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	/*
237062306a36Sopenharmony_ci	 * valid_size <= data_size <= alloc_size
237162306a36Sopenharmony_ci	 * Check alloc_size for maximum possible.
237262306a36Sopenharmony_ci	 */
237362306a36Sopenharmony_ci	if (bytes > sbi->maxbytes_sparse - alloc_size)
237462306a36Sopenharmony_ci		return -EFBIG;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	vcn = vbo >> sbi->cluster_bits;
237762306a36Sopenharmony_ci	len = bytes >> sbi->cluster_bits;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	down_write(&ni->file.run_lock);
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	if (!attr_b->non_res) {
238262306a36Sopenharmony_ci		err = attr_set_size(ni, ATTR_DATA, NULL, 0, run,
238362306a36Sopenharmony_ci				    data_size + bytes, NULL, false, NULL);
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci		le_b = NULL;
238662306a36Sopenharmony_ci		attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
238762306a36Sopenharmony_ci				      &mi_b);
238862306a36Sopenharmony_ci		if (!attr_b) {
238962306a36Sopenharmony_ci			err = -EINVAL;
239062306a36Sopenharmony_ci			goto bad_inode;
239162306a36Sopenharmony_ci		}
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci		if (err)
239462306a36Sopenharmony_ci			goto out;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci		if (!attr_b->non_res) {
239762306a36Sopenharmony_ci			/* Still resident. */
239862306a36Sopenharmony_ci			char *data = Add2Ptr(attr_b,
239962306a36Sopenharmony_ci					     le16_to_cpu(attr_b->res.data_off));
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci			memmove(data + bytes, data, bytes);
240262306a36Sopenharmony_ci			memset(data, 0, bytes);
240362306a36Sopenharmony_ci			goto done;
240462306a36Sopenharmony_ci		}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci		/* Resident files becomes nonresident. */
240762306a36Sopenharmony_ci		data_size = le64_to_cpu(attr_b->nres.data_size);
240862306a36Sopenharmony_ci		alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
240962306a36Sopenharmony_ci	}
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	/*
241262306a36Sopenharmony_ci	 * Enumerate all attribute segments and shift start vcn.
241362306a36Sopenharmony_ci	 */
241462306a36Sopenharmony_ci	a_flags = attr_b->flags;
241562306a36Sopenharmony_ci	svcn = le64_to_cpu(attr_b->nres.svcn);
241662306a36Sopenharmony_ci	evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	if (svcn <= vcn && vcn < evcn1) {
241962306a36Sopenharmony_ci		attr = attr_b;
242062306a36Sopenharmony_ci		le = le_b;
242162306a36Sopenharmony_ci		mi = mi_b;
242262306a36Sopenharmony_ci	} else if (!le_b) {
242362306a36Sopenharmony_ci		err = -EINVAL;
242462306a36Sopenharmony_ci		goto bad_inode;
242562306a36Sopenharmony_ci	} else {
242662306a36Sopenharmony_ci		le = le_b;
242762306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
242862306a36Sopenharmony_ci				    &mi);
242962306a36Sopenharmony_ci		if (!attr) {
243062306a36Sopenharmony_ci			err = -EINVAL;
243162306a36Sopenharmony_ci			goto bad_inode;
243262306a36Sopenharmony_ci		}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
243562306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
243662306a36Sopenharmony_ci	}
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	run_truncate(run, 0); /* clear cached values. */
243962306a36Sopenharmony_ci	err = attr_load_runs(attr, ni, run, NULL);
244062306a36Sopenharmony_ci	if (err)
244162306a36Sopenharmony_ci		goto out;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	if (!run_insert_range(run, vcn, len)) {
244462306a36Sopenharmony_ci		err = -ENOMEM;
244562306a36Sopenharmony_ci		goto out;
244662306a36Sopenharmony_ci	}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	/* Try to pack in current record as much as possible. */
244962306a36Sopenharmony_ci	err = mi_pack_runs(mi, attr, run, evcn1 + len - svcn);
245062306a36Sopenharmony_ci	if (err)
245162306a36Sopenharmony_ci		goto out;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
245462306a36Sopenharmony_ci
245562306a36Sopenharmony_ci	while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
245662306a36Sopenharmony_ci	       attr->type == ATTR_DATA && !attr->name_len) {
245762306a36Sopenharmony_ci		le64_add_cpu(&attr->nres.svcn, len);
245862306a36Sopenharmony_ci		le64_add_cpu(&attr->nres.evcn, len);
245962306a36Sopenharmony_ci		if (le) {
246062306a36Sopenharmony_ci			le->vcn = attr->nres.svcn;
246162306a36Sopenharmony_ci			ni->attr_list.dirty = true;
246262306a36Sopenharmony_ci		}
246362306a36Sopenharmony_ci		mi->dirty = true;
246462306a36Sopenharmony_ci	}
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci	if (next_svcn < evcn1 + len) {
246762306a36Sopenharmony_ci		err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
246862306a36Sopenharmony_ci					    next_svcn, evcn1 + len - next_svcn,
246962306a36Sopenharmony_ci					    a_flags, NULL, NULL, NULL);
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci		le_b = NULL;
247262306a36Sopenharmony_ci		attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
247362306a36Sopenharmony_ci				      &mi_b);
247462306a36Sopenharmony_ci		if (!attr_b) {
247562306a36Sopenharmony_ci			err = -EINVAL;
247662306a36Sopenharmony_ci			goto bad_inode;
247762306a36Sopenharmony_ci		}
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci		if (err) {
248062306a36Sopenharmony_ci			/* ni_insert_nonresident failed. Try to undo. */
248162306a36Sopenharmony_ci			goto undo_insert_range;
248262306a36Sopenharmony_ci		}
248362306a36Sopenharmony_ci	}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	/*
248662306a36Sopenharmony_ci	 * Update primary attribute segment.
248762306a36Sopenharmony_ci	 */
248862306a36Sopenharmony_ci	if (vbo <= ni->i_valid)
248962306a36Sopenharmony_ci		ni->i_valid += bytes;
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	attr_b->nres.data_size = cpu_to_le64(data_size + bytes);
249262306a36Sopenharmony_ci	attr_b->nres.alloc_size = cpu_to_le64(alloc_size + bytes);
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci	/* ni->valid may be not equal valid_size (temporary). */
249562306a36Sopenharmony_ci	if (ni->i_valid > data_size + bytes)
249662306a36Sopenharmony_ci		attr_b->nres.valid_size = attr_b->nres.data_size;
249762306a36Sopenharmony_ci	else
249862306a36Sopenharmony_ci		attr_b->nres.valid_size = cpu_to_le64(ni->i_valid);
249962306a36Sopenharmony_ci	mi_b->dirty = true;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_cidone:
250262306a36Sopenharmony_ci	i_size_write(&ni->vfs_inode, ni->vfs_inode.i_size + bytes);
250362306a36Sopenharmony_ci	ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
250462306a36Sopenharmony_ci	mark_inode_dirty(&ni->vfs_inode);
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_ciout:
250762306a36Sopenharmony_ci	run_truncate(run, 0); /* clear cached values. */
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	up_write(&ni->file.run_lock);
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	return err;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_cibad_inode:
251462306a36Sopenharmony_ci	_ntfs_bad_inode(&ni->vfs_inode);
251562306a36Sopenharmony_ci	goto out;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ciundo_insert_range:
251862306a36Sopenharmony_ci	svcn = le64_to_cpu(attr_b->nres.svcn);
251962306a36Sopenharmony_ci	evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	if (svcn <= vcn && vcn < evcn1) {
252262306a36Sopenharmony_ci		attr = attr_b;
252362306a36Sopenharmony_ci		le = le_b;
252462306a36Sopenharmony_ci		mi = mi_b;
252562306a36Sopenharmony_ci	} else if (!le_b) {
252662306a36Sopenharmony_ci		goto bad_inode;
252762306a36Sopenharmony_ci	} else {
252862306a36Sopenharmony_ci		le = le_b;
252962306a36Sopenharmony_ci		attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
253062306a36Sopenharmony_ci				    &mi);
253162306a36Sopenharmony_ci		if (!attr) {
253262306a36Sopenharmony_ci			goto bad_inode;
253362306a36Sopenharmony_ci		}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci		svcn = le64_to_cpu(attr->nres.svcn);
253662306a36Sopenharmony_ci		evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
253762306a36Sopenharmony_ci	}
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci	if (attr_load_runs(attr, ni, run, NULL))
254062306a36Sopenharmony_ci		goto bad_inode;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	if (!run_collapse_range(run, vcn, len))
254362306a36Sopenharmony_ci		goto bad_inode;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	if (mi_pack_runs(mi, attr, run, evcn1 + len - svcn))
254662306a36Sopenharmony_ci		goto bad_inode;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
254962306a36Sopenharmony_ci	       attr->type == ATTR_DATA && !attr->name_len) {
255062306a36Sopenharmony_ci		le64_sub_cpu(&attr->nres.svcn, len);
255162306a36Sopenharmony_ci		le64_sub_cpu(&attr->nres.evcn, len);
255262306a36Sopenharmony_ci		if (le) {
255362306a36Sopenharmony_ci			le->vcn = attr->nres.svcn;
255462306a36Sopenharmony_ci			ni->attr_list.dirty = true;
255562306a36Sopenharmony_ci		}
255662306a36Sopenharmony_ci		mi->dirty = true;
255762306a36Sopenharmony_ci	}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	goto out;
256062306a36Sopenharmony_ci}
2561