root/fs/ntfs3/attrib.c
// SPDX-License-Identifier: GPL-2.0
/*
 *
 * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved.
 *
 * TODO: Merge attr_set_size/attr_data_get_block/attr_allocate_frame?
 */

#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/kernel.h>

#include "debug.h"
#include "ntfs.h"
#include "ntfs_fs.h"

/*
 * You can set external NTFS_MIN_LOG2_OF_CLUMP/NTFS_MAX_LOG2_OF_CLUMP to manage
 * preallocate algorithm.
 */
#ifndef NTFS_MIN_LOG2_OF_CLUMP
#define NTFS_MIN_LOG2_OF_CLUMP 16
#endif

#ifndef NTFS_MAX_LOG2_OF_CLUMP
#define NTFS_MAX_LOG2_OF_CLUMP 26
#endif

// 16M
#define NTFS_CLUMP_MIN (1 << (NTFS_MIN_LOG2_OF_CLUMP + 8))
// 16G
#define NTFS_CLUMP_MAX (1ull << (NTFS_MAX_LOG2_OF_CLUMP + 8))

static inline u64 get_pre_allocated(u64 size)
{
        u32 clump;
        u8 align_shift;
        u64 ret;

        if (size <= NTFS_CLUMP_MIN) {
                clump = 1 << NTFS_MIN_LOG2_OF_CLUMP;
                align_shift = NTFS_MIN_LOG2_OF_CLUMP;
        } else if (size >= NTFS_CLUMP_MAX) {
                clump = 1 << NTFS_MAX_LOG2_OF_CLUMP;
                align_shift = NTFS_MAX_LOG2_OF_CLUMP;
        } else {
                align_shift = NTFS_MIN_LOG2_OF_CLUMP - 1 +
                              __ffs(size >> (8 + NTFS_MIN_LOG2_OF_CLUMP));
                clump = 1u << align_shift;
        }

        ret = (((size + clump - 1) >> align_shift)) << align_shift;

        return ret;
}

/*
 * attr_load_runs - Load all runs stored in @attr.
 */
static int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
                          struct runs_tree *run, const CLST *vcn)
{
        int err;
        CLST svcn = le64_to_cpu(attr->nres.svcn);
        CLST evcn = le64_to_cpu(attr->nres.evcn);
        u32 asize;
        u16 run_off;

        if (svcn >= evcn + 1 || run_is_mapped_full(run, svcn, evcn))
                return 0;

        if (vcn && (evcn < *vcn || *vcn < svcn))
                return -EINVAL;

        asize = le32_to_cpu(attr->size);
        run_off = le16_to_cpu(attr->nres.run_off);

        if (run_off > asize)
                return -EINVAL;

        err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn,
                            vcn ? *vcn : svcn, Add2Ptr(attr, run_off),
                            asize - run_off);
        if (err < 0)
                return err;

        return 0;
}

/*
 * run_deallocate_ex - Deallocate clusters.
 */
static int run_deallocate_ex(struct ntfs_sb_info *sbi, struct runs_tree *run,
                             CLST vcn, CLST len, CLST *done, bool trim,
                             struct runs_tree *run_da)
{
        int err = 0;
        CLST vcn_next, vcn0 = vcn, lcn, clen, dn = 0;
        size_t idx;

        if (!len)
                goto out;

        if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
failed:
                run_truncate(run, vcn0);
                err = -EINVAL;
                goto out;
        }

        for (;;) {
                if (clen > len)
                        clen = len;

                if (!clen) {
                        err = -EINVAL;
                        goto out;
                }

                if (lcn != SPARSE_LCN) {
                        if (sbi) {
                                /* mark bitmap range [lcn + clen) as free and trim clusters. */
                                mark_as_free_ex(sbi, lcn, clen, trim);

                                if (run_da) {
                                        CLST da_len;
                                        if (!run_remove_range(run_da, vcn, clen,
                                                              &da_len)) {
                                                err = -ENOMEM;
                                                goto failed;
                                        }
                                        ntfs_sub_da(sbi, da_len);
                                }
                        }
                        dn += clen;
                }

                len -= clen;
                if (!len)
                        break;

                vcn_next = vcn + clen;
                if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
                    vcn != vcn_next) {
                        /* Save memory - don't load entire run. */
                        goto failed;
                }
        }

out:
        if (done)
                *done += dn;

        return err;
}

/*
 * attr_allocate_clusters - Find free space, mark it as used and store in @run.
 */
int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
                           struct runs_tree *run_da, CLST vcn, CLST lcn,
                           CLST len, CLST *pre_alloc, enum ALLOCATE_OPT opt,
                           CLST *alen, const size_t fr, CLST *new_lcn,
                           CLST *new_len)
{
        int err;
        CLST flen, vcn0 = vcn, pre = pre_alloc ? *pre_alloc : 0;
        size_t cnt = run->count;

        for (;;) {
                err = ntfs_look_for_free_space(sbi, lcn, len + pre, &lcn, &flen,
                                               opt);

                if (err == -ENOSPC && pre) {
                        pre = 0;
                        if (*pre_alloc)
                                *pre_alloc = 0;
                        continue;
                }

                if (err == -ENOSPC && new_len && vcn - vcn0) {
                        /* Keep already allocated clusters. */
                        *alen = vcn - vcn0;
                        return 0;
                }

                if (err)
                        goto out;

                if (vcn == vcn0) {
                        /* Return the first fragment. */
                        if (new_lcn)
                                *new_lcn = lcn;
                        if (new_len)
                                *new_len = flen;
                }

                /* Add new fragment into run storage. */
                if (!run_add_entry(run, vcn, lcn, flen, opt & ALLOCATE_MFT)) {
undo_alloc:
                        /* Undo last 'ntfs_look_for_free_space' */
                        mark_as_free_ex(sbi, lcn, len, false);
                        err = -ENOMEM;
                        goto out;
                }

                if (run_da) {
                        CLST da_len;
                        if (!run_remove_range(run_da, vcn, flen, &da_len)) {
                                goto undo_alloc;
                        }
                        ntfs_sub_da(sbi, da_len);
                }

                if (opt & ALLOCATE_ZERO) {
                        u8 shift = sbi->cluster_bits - SECTOR_SHIFT;

                        err = blkdev_issue_zeroout(sbi->sb->s_bdev,
                                                   (sector_t)lcn << shift,
                                                   (sector_t)flen << shift,
                                                   GFP_NOFS, 0);
                        if (err)
                                goto out;
                }

                vcn += flen;

                if (flen >= len || (opt & ALLOCATE_MFT) ||
                    (opt & ALLOCATE_ONE_FR) || (fr && run->count - cnt >= fr)) {
                        *alen = vcn - vcn0;
                        return 0;
                }

                len -= flen;
        }

out:
        /* Undo 'ntfs_look_for_free_space' */
        if (vcn - vcn0) {
                run_deallocate_ex(sbi, run, vcn0, vcn - vcn0, NULL, false,
                                  run_da);
                run_truncate(run, vcn0);
        }

        return err;
}

/*
 * attr_make_nonresident
 *
 * If page is not NULL - it is already contains resident data
 * and locked (called from ni_write_frame()).
 */
int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
                          struct ATTR_LIST_ENTRY *le, struct mft_inode *mi,
                          u64 new_size, struct runs_tree *run,
                          struct ATTRIB **ins_attr, struct page *page)
{
        struct ntfs_sb_info *sbi;
        struct ATTRIB *attr_s;
        struct MFT_REC *rec;
        u32 used, asize, rsize, aoff;
        bool is_data;
        CLST len, alen;
        char *next;
        int err;

        if (attr->non_res) {
                *ins_attr = attr;
                return 0;
        }

        sbi = mi->sbi;
        rec = mi->mrec;
        attr_s = NULL;
        used = le32_to_cpu(rec->used);
        asize = le32_to_cpu(attr->size);
        next = Add2Ptr(attr, asize);
        aoff = PtrOffset(rec, attr);
        rsize = le32_to_cpu(attr->res.data_size);
        is_data = attr->type == ATTR_DATA && !attr->name_len;

        /* len - how many clusters required to store 'rsize' bytes */
        if (is_attr_compressed(attr)) {
                u8 shift = sbi->cluster_bits + NTFS_LZNT_CUNIT;
                len = ((rsize + (1u << shift) - 1) >> shift) << NTFS_LZNT_CUNIT;
        } else {
                len = bytes_to_cluster(sbi, rsize);
        }

        run_init(run);

        /* Make a copy of original attribute. */
        attr_s = kmemdup(attr, asize, GFP_NOFS);
        if (!attr_s) {
                err = -ENOMEM;
                goto out;
        }

        if (!len) {
                /* Empty resident -> Empty nonresident. */
                alen = 0;
        } else {
                const char *data = resident_data(attr);

                err = attr_allocate_clusters(sbi, run, NULL, 0, 0, len, NULL,
                                             ALLOCATE_DEF, &alen, 0, NULL,
                                             NULL);
                if (err)
                        goto out1;

                if (!rsize) {
                        /* Empty resident -> Non empty nonresident. */
                } else if (!is_data) {
                        err = ntfs_sb_write_run(sbi, run, 0, data, rsize, 0);
                        if (err)
                                goto out2;
                } else if (!page) {
                        struct address_space *mapping = ni->vfs_inode.i_mapping;
                        struct folio *folio;

                        folio = __filemap_get_folio(
                                mapping, 0, FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
                                mapping_gfp_mask(mapping));
                        if (IS_ERR(folio)) {
                                err = PTR_ERR(folio);
                                goto out2;
                        }
                        folio_fill_tail(folio, 0, data, rsize);
                        folio_mark_uptodate(folio);
                        folio_mark_dirty(folio);
                        folio_unlock(folio);
                        folio_put(folio);
                }
        }

        /* Remove original attribute. */
        used -= asize;
        memmove(attr, Add2Ptr(attr, asize), used - aoff);
        rec->used = cpu_to_le32(used);
        mi->dirty = true;
        if (le)
                al_remove_le(ni, le);

        err = ni_insert_nonresident(ni, attr_s->type, attr_name(attr_s),
                                    attr_s->name_len, run, 0, alen,
                                    attr_s->flags, &attr, NULL, NULL);
        if (err)
                goto out3;

        kfree(attr_s);
        attr->nres.data_size = cpu_to_le64(rsize);
        attr->nres.valid_size = attr->nres.data_size;

        *ins_attr = attr;

        if (is_data)
                ni->ni_flags &= ~NI_FLAG_RESIDENT;

        /* Resident attribute becomes non resident. */
        return 0;

out3:
        attr = Add2Ptr(rec, aoff);
        memmove(next, attr, used - aoff);
        memcpy(attr, attr_s, asize);
        rec->used = cpu_to_le32(used + asize);
        mi->dirty = true;
out2:
        /* Undo: do not trim new allocated clusters. */
        run_deallocate(sbi, run, false);
        run_close(run);
out1:
        kfree(attr_s);
out:
        return err;
}

/*
 * attr_set_size_res - Helper for attr_set_size().
 */
static int attr_set_size_res(struct ntfs_inode *ni, struct ATTRIB *attr,
                             struct ATTR_LIST_ENTRY *le, struct mft_inode *mi,
                             u64 new_size, struct runs_tree *run,
                             struct ATTRIB **ins_attr)
{
        struct ntfs_sb_info *sbi = mi->sbi;
        struct MFT_REC *rec = mi->mrec;
        u32 used = le32_to_cpu(rec->used);
        u32 asize = le32_to_cpu(attr->size);
        u32 aoff = PtrOffset(rec, attr);
        u32 rsize = le32_to_cpu(attr->res.data_size);
        u32 tail = used - aoff - asize;
        char *next = Add2Ptr(attr, asize);
        s64 dsize = ALIGN(new_size, 8) - ALIGN(rsize, 8);

        if (dsize < 0) {
                memmove(next + dsize, next, tail);
        } else if (dsize > 0) {
                if (used + dsize > sbi->max_bytes_per_attr)
                        return attr_make_nonresident(ni, attr, le, mi, new_size,
                                                     run, ins_attr, NULL);

                memmove(next + dsize, next, tail);
                memset(next, 0, dsize);
        }

        if (new_size > rsize)
                memset(Add2Ptr(resident_data(attr), rsize), 0,
                       new_size - rsize);

        rec->used = cpu_to_le32(used + dsize);
        attr->size = cpu_to_le32(asize + dsize);
        attr->res.data_size = cpu_to_le32(new_size);
        mi->dirty = true;
        *ins_attr = attr;

        return 0;
}

/*
 * attr_set_size_ex - Change the size of attribute.
 *
 * Extend:
 *   - Sparse/compressed: No allocated clusters.
 *   - Normal: Append allocated and preallocated new clusters.
 * Shrink:
 *   - No deallocate if @keep_prealloc is set.
 */
int attr_set_size_ex(struct ntfs_inode *ni, enum ATTR_TYPE type,
                     const __le16 *name, u8 name_len, struct runs_tree *run,
                     u64 new_size, const u64 *new_valid, bool keep_prealloc,
                     struct ATTRIB **ret, bool no_da)
{
        int err = 0;
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        u8 cluster_bits = sbi->cluster_bits;
        bool is_mft = ni->mi.rno == MFT_REC_MFT && type == ATTR_DATA &&
                      !name_len;
        u64 old_valid, old_size, old_alloc, new_alloc_tmp;
        u64 new_alloc = 0;
        struct ATTRIB *attr = NULL, *attr_b;
        struct ATTR_LIST_ENTRY *le, *le_b;
        struct mft_inode *mi, *mi_b;
        CLST alen, vcn, lcn, new_alen, old_alen, svcn, evcn;
        CLST next_svcn, pre_alloc = -1, done = 0;
        bool is_ext = false, is_bad = false;
        bool dirty = false;
        struct runs_tree *run_da = run == &ni->file.run ? &ni->file.run_da :
                                                          NULL;
        bool da = !is_mft && sbi->options->delalloc && run_da && !no_da;
        u32 align;
        struct MFT_REC *rec;

again:
        alen = 0;
        le_b = NULL;
        attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len, NULL,
                              &mi_b);
        if (!attr_b) {
                err = -ENOENT;
                goto bad_inode;
        }

        if (!attr_b->non_res) {
                err = attr_set_size_res(ni, attr_b, le_b, mi_b, new_size, run,
                                        &attr_b);
                if (err)
                        return err;

                /* Return if file is still resident. */
                if (!attr_b->non_res) {
                        dirty = true;
                        goto ok1;
                }

                /* Layout of records may be changed, so do a full search. */
                goto again;
        }

        is_ext = is_attr_ext(attr_b);
        align = sbi->cluster_size;
        if (is_ext) {
                align <<= attr_b->nres.c_unit;
                keep_prealloc = false;
                da = false;
        }

        old_valid = le64_to_cpu(attr_b->nres.valid_size);
        old_size = le64_to_cpu(attr_b->nres.data_size);
        old_alloc = le64_to_cpu(attr_b->nres.alloc_size);

again_1:
        old_alen = old_alloc >> cluster_bits;

        new_alloc = (new_size + align - 1) & ~(u64)(align - 1);
        new_alen = new_alloc >> cluster_bits;

        if (keep_prealloc && new_size < old_size) {
                attr_b->nres.data_size = cpu_to_le64(new_size);
                mi_b->dirty = dirty = true;
                goto ok;
        }

        if (da &&
            (vcn = old_alen + run_len(&ni->file.run_da), new_alen > vcn)) {
                /* Resize up normal file. Delay new clusters allocation. */
                alen = new_alen - vcn;

                if (ntfs_check_free_space(sbi, alen, 0, true)) {
                        if (!run_add_entry(&ni->file.run_da, vcn, SPARSE_LCN,
                                           alen, false)) {
                                err = -ENOMEM;
                                goto out;
                        }

                        ntfs_add_da(sbi, alen);
                        goto ok1;
                }
        }

        if (!keep_prealloc && run_da && run_da->count &&
            (vcn = run_get_max_vcn(run_da), new_alen < vcn)) {
                /* Shrink delayed clusters. */

                /* Try to remove fragment from delay allocated run. */
                if (!run_remove_range(run_da, new_alen, vcn - new_alen,
                                      &alen)) {
                        err = -ENOMEM;
                        goto out;
                }

                ntfs_sub_da(sbi, alen);
        }

        vcn = old_alen - 1;

        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn = le64_to_cpu(attr_b->nres.evcn);

        if (svcn <= vcn && vcn <= evcn) {
                attr = attr_b;
                le = le_b;
                mi = mi_b;
        } else if (!le_b) {
                err = -EINVAL;
                goto bad_inode;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, type, name, name_len, &vcn,
                                    &mi);
                if (!attr) {
                        err = -EINVAL;
                        goto bad_inode;
                }

next_le_1:
                svcn = le64_to_cpu(attr->nres.svcn);
                evcn = le64_to_cpu(attr->nres.evcn);
        }
        /*
         * Here we have:
         * attr,mi,le - last attribute segment (containing 'vcn').
         * attr_b,mi_b,le_b - base (primary) attribute segment.
         */
next_le:
        rec = mi->mrec;
        err = attr_load_runs(attr, ni, run, NULL);
        if (err)
                goto out;

        if (new_size > old_size) {
                CLST to_allocate;
                size_t free;

                if (new_alloc <= old_alloc) {
                        attr_b->nres.data_size = cpu_to_le64(new_size);
                        mi_b->dirty = dirty = true;
                        goto ok;
                }

                /*
                 * Add clusters. In simple case we have to:
                 *  - allocate space (vcn, lcn, len)
                 *  - update packed run in 'mi'
                 *  - update attr->nres.evcn
                 *  - update attr_b->nres.data_size/attr_b->nres.alloc_size
                 */
                to_allocate = new_alen - old_alen;
add_alloc_in_same_attr_seg:
                lcn = 0;
                if (is_mft) {
                        /* MFT allocates clusters from MFT zone. */
                        pre_alloc = 0;
                } else if (is_ext) {
                        /* No preallocate for sparse/compress. */
                        pre_alloc = 0;
                } else if (pre_alloc == -1) {
                        pre_alloc = 0;
                        if (type == ATTR_DATA && !name_len &&
                            sbi->options->prealloc) {
                                pre_alloc = bytes_to_cluster(
                                                    sbi, get_pre_allocated(
                                                                 new_size)) -
                                            new_alen;
                        }

                        /* Get the last LCN to allocate from. */
                        if (old_alen &&
                            !run_lookup_entry(run, vcn, &lcn, NULL, NULL)) {
                                lcn = SPARSE_LCN;
                        }

                        if (lcn == SPARSE_LCN)
                                lcn = 0;
                        else if (lcn)
                                lcn += 1;

                        free = wnd_zeroes(&sbi->used.bitmap);
                        if (to_allocate > free) {
                                err = -ENOSPC;
                                goto out;
                        }

                        if (pre_alloc && to_allocate + pre_alloc > free)
                                pre_alloc = 0;
                }

                vcn = old_alen;

                if (is_ext) {
                        if (!run_add_entry(run, vcn, SPARSE_LCN, to_allocate,
                                           false)) {
                                err = -ENOMEM;
                                goto out;
                        }
                        alen = to_allocate;
                } else {
                        /* ~3 bytes per fragment. */
                        err = attr_allocate_clusters(
                                sbi, run, run_da, vcn, lcn, to_allocate,
                                &pre_alloc,
                                is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen,
                                is_mft ? 0 :
                                         (sbi->record_size -
                                          le32_to_cpu(rec->used) + 8) /
                                                         3 +
                                                 1,
                                NULL, NULL);
                        if (err)
                                goto out;
                }

                done += alen;
                vcn += alen;
                if (to_allocate > alen)
                        to_allocate -= alen;
                else
                        to_allocate = 0;

pack_runs:
                err = mi_pack_runs(mi, attr, run, vcn - svcn);
                if (err)
                        goto undo_1;

                next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
                new_alloc_tmp = (u64)next_svcn << cluster_bits;
                attr_b->nres.alloc_size = cpu_to_le64(new_alloc_tmp);
                mi_b->dirty = dirty = true;

                if (next_svcn >= vcn && !to_allocate) {
                        /* Normal way. Update attribute and exit. */
                        attr_b->nres.data_size = cpu_to_le64(new_size);
                        goto ok;
                }

                /* At least two MFT to avoid recursive loop. */
                if (is_mft && next_svcn == vcn &&
                    ((u64)done << sbi->cluster_bits) >= 2 * sbi->record_size) {
                        new_size = new_alloc_tmp;
                        attr_b->nres.data_size = attr_b->nres.alloc_size;
                        goto ok;
                }

                if (le32_to_cpu(rec->used) < sbi->record_size) {
                        old_alen = next_svcn;
                        evcn = old_alen - 1;
                        goto add_alloc_in_same_attr_seg;
                }

                attr_b->nres.data_size = attr_b->nres.alloc_size;
                if (new_alloc_tmp < old_valid)
                        attr_b->nres.valid_size = attr_b->nres.data_size;

                if (type == ATTR_LIST) {
                        err = ni_expand_list(ni);
                        if (err)
                                goto undo_2;
                        if (next_svcn < vcn)
                                goto pack_runs;

                        /* Layout of records is changed. */
                        goto again;
                }

                if (!ni->attr_list.size) {
                        err = ni_create_attr_list(ni);
                        /* In case of error layout of records is not changed. */
                        if (err)
                                goto undo_2;
                        /* Layout of records is changed. */
                }

                if (next_svcn >= vcn) {
                        /* This is MFT data, repeat. */
                        goto again;
                }

                /* Insert new attribute segment. */
                err = ni_insert_nonresident(ni, type, name, name_len, run,
                                            next_svcn, vcn - next_svcn,
                                            attr_b->flags, &attr, &mi, NULL);

                /*
                 * Layout of records maybe changed.
                 * Find base attribute to update.
                 */
                le_b = NULL;
                attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len,
                                      NULL, &mi_b);
                if (!attr_b) {
                        err = -EINVAL;
                        goto bad_inode;
                }

                if (err) {
                        /* ni_insert_nonresident failed. */
                        attr = NULL;
                        goto undo_2;
                }

                /* keep runs for $MFT::$ATTR_DATA and $MFT::$ATTR_BITMAP. */
                if (ni->mi.rno != MFT_REC_MFT)
                        run_truncate_head(run, evcn + 1);

                svcn = le64_to_cpu(attr->nres.svcn);
                evcn = le64_to_cpu(attr->nres.evcn);

                /*
                 * Attribute is in consistency state.
                 * Save this point to restore to if next steps fail.
                 */
                old_valid = old_size = old_alloc = (u64)vcn << cluster_bits;
                attr_b->nres.valid_size = attr_b->nres.data_size =
                        attr_b->nres.alloc_size = cpu_to_le64(old_size);
                mi_b->dirty = dirty = true;
                goto again_1;
        }

        if (new_size != old_size ||
            (new_alloc != old_alloc && !keep_prealloc)) {
                /*
                 * Truncate clusters. In simple case we have to:
                 *  - update packed run in 'mi'
                 *  - update attr->nres.evcn
                 *  - update attr_b->nres.data_size/attr_b->nres.alloc_size
                 *  - mark and trim clusters as free (vcn, lcn, len)
                 */
                CLST dlen = 0;

                vcn = max(svcn, new_alen);
                new_alloc_tmp = (u64)vcn << cluster_bits;

                if (vcn > svcn) {
                        err = mi_pack_runs(mi, attr, run, vcn - svcn);
                        if (err)
                                goto out;
                } else if (le && le->vcn) {
                        u16 le_sz = le16_to_cpu(le->size);

                        /*
                         * NOTE: List entries for one attribute are always
                         * the same size. We deal with last entry (vcn==0)
                         * and it is not first in entries array
                         * (list entry for std attribute always first).
                         * So it is safe to step back.
                         */
                        mi_remove_attr(NULL, mi, attr);

                        if (!al_remove_le(ni, le)) {
                                err = -EINVAL;
                                goto bad_inode;
                        }

                        le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz);
                } else {
                        attr->nres.evcn = cpu_to_le64((u64)vcn - 1);
                        mi->dirty = true;
                }

                attr_b->nres.alloc_size = cpu_to_le64(new_alloc_tmp);

                if (vcn == new_alen) {
                        attr_b->nres.data_size = cpu_to_le64(new_size);
                        if (new_size < old_valid)
                                attr_b->nres.valid_size =
                                        attr_b->nres.data_size;
                } else {
                        if (new_alloc_tmp <=
                            le64_to_cpu(attr_b->nres.data_size))
                                attr_b->nres.data_size =
                                        attr_b->nres.alloc_size;
                        if (new_alloc_tmp <
                            le64_to_cpu(attr_b->nres.valid_size))
                                attr_b->nres.valid_size =
                                        attr_b->nres.alloc_size;
                }
                mi_b->dirty = dirty = true;

                err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &dlen,
                                        true, run_da);
                if (err)
                        goto out;

                if (is_ext) {
                        /* dlen - really deallocated clusters. */
                        le64_sub_cpu(&attr_b->nres.total_size,
                                     (u64)dlen << cluster_bits);
                }

                run_truncate(run, vcn);

                if (new_alloc_tmp <= new_alloc)
                        goto ok;

                old_size = new_alloc_tmp;
                vcn = svcn - 1;

                if (le == le_b) {
                        attr = attr_b;
                        mi = mi_b;
                        evcn = svcn - 1;
                        svcn = 0;
                        goto next_le;
                }

                if (le->type != type || le->name_len != name_len ||
                    memcmp(le_name(le), name, name_len * sizeof(short))) {
                        err = -EINVAL;
                        goto bad_inode;
                }

                err = ni_load_mi(ni, le, &mi);
                if (err)
                        goto out;

                attr = mi_find_attr(ni, mi, NULL, type, name, name_len,
                                    &le->id);
                if (!attr) {
                        err = -EINVAL;
                        goto bad_inode;
                }
                goto next_le_1;
        }

ok:
        if (new_valid) {
                __le64 valid = cpu_to_le64(min(*new_valid, new_size));

                if (attr_b->nres.valid_size != valid) {
                        attr_b->nres.valid_size = valid;
                        mi_b->dirty = true;
                }
        }

ok1:
        if (ret)
                *ret = attr_b;

        if (((type == ATTR_DATA && !name_len) ||
             (type == ATTR_ALLOC && name == I30_NAME))) {
                /* Update inode_set_bytes. */
                if (attr_b->non_res &&
                    inode_get_bytes(&ni->vfs_inode) != new_alloc) {
                        inode_set_bytes(&ni->vfs_inode, new_alloc);
                        dirty = true;
                }

                i_size_write(&ni->vfs_inode, new_size);

                /* Don't forget to update duplicate information in parent. */
                if (dirty) {
                        ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
                        mark_inode_dirty(&ni->vfs_inode);
                }
        }

        return 0;

undo_2:
        vcn -= alen;
        attr_b->nres.data_size = cpu_to_le64(old_size);
        attr_b->nres.valid_size = cpu_to_le64(old_valid);
        attr_b->nres.alloc_size = cpu_to_le64(old_alloc);

        /* Restore 'attr' and 'mi'. */
        if (attr)
                goto restore_run;

        if (le64_to_cpu(attr_b->nres.svcn) <= svcn &&
            svcn <= le64_to_cpu(attr_b->nres.evcn)) {
                attr = attr_b;
                le = le_b;
                mi = mi_b;
        } else if (!le_b) {
                err = -EINVAL;
                goto bad_inode;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, type, name, name_len,
                                    &svcn, &mi);
                if (!attr)
                        goto bad_inode;
        }

restore_run:
        if (mi_pack_runs(mi, attr, run, evcn - svcn + 1))
                is_bad = true;

undo_1:
        run_deallocate_ex(sbi, run, vcn, alen, NULL, false, run_da);

        run_truncate(run, vcn);
out:
        if (is_bad) {
bad_inode:
                _ntfs_bad_inode(&ni->vfs_inode);
        }
        return err;
}

/*
 * attr_data_get_block - Returns 'lcn' and 'len' for given 'vcn'.
 *
 * @new == NULL means just to get current mapping for 'vcn'
 * @new != NULL means allocate real cluster if 'vcn' maps to hole
 * @zero - zeroout new allocated clusters
 *
 *  NOTE:
 *  - @new != NULL is called only for sparsed or compressed attributes.
 *  - new allocated clusters are zeroed via blkdev_issue_zeroout.
 */
int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
                        CLST *len, bool *new, bool zero, void **res, bool no_da)
{
        int err;

        if (new)
                *new = false;
        if (res)
                *res = NULL;

        /* Try to find in cache. */
        down_read(&ni->file.run_lock);
        if (!no_da && run_lookup_entry(&ni->file.run_da, vcn, lcn, len, NULL)) {
                /* The requested vcn is delay allocated. */
                *lcn = DELALLOC_LCN;
        } else if (run_lookup_entry(&ni->file.run, vcn, lcn, len, NULL)) {
                /* The requested vcn is known in current run. */
        } else {
                *len = 0;
        }
        up_read(&ni->file.run_lock);

        if (*len && (*lcn != SPARSE_LCN || !new))
                return 0; /* Fast normal way without allocation. */

        /* No cluster in cache or we need to allocate cluster in hole. */
        ni_lock(ni);
        down_write(&ni->file.run_lock);

        err = attr_data_get_block_locked(ni, vcn, clen, lcn, len, new, zero,
                                         res, no_da);

        up_write(&ni->file.run_lock);
        ni_unlock(ni);

        return err;
}

/*
 * attr_data_get_block_locked - Helper for attr_data_get_block.
 */
int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
                               CLST *lcn, CLST *len, bool *new, bool zero,
                               void **res, bool no_da)
{
        int err = 0;
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        struct runs_tree *run = &ni->file.run;
        struct runs_tree *run_da = &ni->file.run_da;
        bool da = sbi->options->delalloc && !no_da;
        u8 cluster_bits;
        struct ATTRIB *attr, *attr_b;
        struct ATTR_LIST_ENTRY *le, *le_b;
        struct mft_inode *mi, *mi_b;
        CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end, vcn0;
        CLST alloc, evcn;
        unsigned fr;
        u64 total_size, total_size0;
        int step;

again:
        if (da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) {
                /* The requested vcn is delay allocated. */
                *lcn = DELALLOC_LCN;
        } else if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
                /* The requested vcn is known in current run. */
        } else {
                *len = 0;
        }

        if (*len) {
                if (*lcn != SPARSE_LCN || !new)
                        goto out; /* normal way without allocation. */
                if (clen > *len)
                        clen = *len;
        }

        cluster_bits = sbi->cluster_bits;
        step = 0;

        le_b = NULL;
        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
        if (!attr_b) {
                err = -ENOENT;
                goto out;
        }

        if (!attr_b->non_res) {
                u32 data_size = le32_to_cpu(attr_b->res.data_size);
                *lcn = RESIDENT_LCN;
                *len = data_size;
                if (res && data_size) {
                        *res = kmemdup(resident_data(attr_b), data_size,
                                       GFP_KERNEL);
                        if (!*res)
                                err = -ENOMEM;
                }
                goto out;
        }

        asize = le64_to_cpu(attr_b->nres.alloc_size) >> cluster_bits;
        if (vcn >= asize) {
                if (new) {
                        err = -EINVAL;
                } else {
                        *len = 1;
                        *lcn = EOF_LCN;
                }
                goto out;
        }

        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;

        attr = attr_b;
        le = le_b;
        mi = mi_b;

        if (le_b && (vcn < svcn || evcn1 <= vcn)) {
                attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
                                    &mi);
                if (!attr) {
                        err = -EINVAL;
                        goto out;
                }
                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
        }

        /* Load in cache actual information. */
        err = attr_load_runs(attr, ni, run, NULL);
        if (err)
                goto out;

        /* Check for compressed frame. */
        err = attr_is_frame_compressed(ni, attr_b, vcn >> NTFS_LZNT_CUNIT,
                                       &hint, run);
        if (err)
                goto out;

        if (hint) {
                /* if frame is compressed - don't touch it. */
                *lcn = COMPRESSED_LCN;
                /* length to the end of frame. */
                *len = NTFS_LZNT_CLUSTERS - (vcn & (NTFS_LZNT_CLUSTERS - 1));
                err = 0;
                goto out;
        }

        if (!*len) {
                if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
                        if (*lcn != SPARSE_LCN || !new)
                                goto ok; /* Slow normal way without allocation. */

                        if (clen > *len)
                                clen = *len;
                } else if (!new) {
                        /* Here we may return -ENOENT.
                         * In any case caller gets zero length. */
                        goto ok;
                }
        }

        if (!is_attr_ext(attr_b)) {
                /* The code below only for sparsed or compressed attributes. */
                err = -EINVAL;
                goto out;
        }

        vcn0 = vcn;
        to_alloc = clen;
        fr = (sbi->record_size - le32_to_cpu(mi->mrec->used) + 8) / 3 + 1;
        /* Allocate frame aligned clusters.
         * ntfs.sys usually uses 16 clusters per frame for sparsed or compressed.
         * ntfs3 uses 1 cluster per frame for new created sparsed files. */
        if (attr_b->nres.c_unit) {
                CLST clst_per_frame = 1u << attr_b->nres.c_unit;
                CLST cmask = ~(clst_per_frame - 1);

                /* Get frame aligned vcn and to_alloc. */
                vcn = vcn0 & cmask;
                to_alloc = ((vcn0 + clen + clst_per_frame - 1) & cmask) - vcn;
                if (fr < clst_per_frame)
                        fr = clst_per_frame;
                if (vcn != vcn0)
                        zero = true;

                /* Check if 'vcn' and 'vcn0' in different attribute segments. */
                if (vcn < svcn || evcn1 <= vcn) {
                        struct ATTRIB *attr2;
                        /* Load runs for truncated vcn. */
                        attr2 = ni_find_attr(ni, attr_b, &le_b, ATTR_DATA, NULL,
                                             0, &vcn, &mi);
                        if (!attr2) {
                                err = -EINVAL;
                                goto out;
                        }
                        evcn1 = le64_to_cpu(attr2->nres.evcn) + 1;
                        err = attr_load_runs(attr2, ni, run, NULL);
                        if (err)
                                goto out;
                }
                da = false; /* no delalloc for compressed file. */
        }

        if (vcn + to_alloc > asize)
                to_alloc = asize - vcn;

        if (da) {
                CLST rlen1, rlen2;
                if (!ntfs_check_free_space(sbi, to_alloc, 0, true)) {
                        err = ni_allocate_da_blocks_locked(ni);
                        if (err)
                                goto out;
                        /* Layout of records may be changed. Start again without 'da'. */
                        da = false;
                        goto again;
                }

                /* run_add_entry consolidates existed ranges. */
                rlen1 = run_len(run_da);
                if (!run_add_entry(run_da, vcn, SPARSE_LCN, to_alloc, false)) {
                        err = -ENOMEM;
                        goto out;
                }
                rlen2 = run_len(run_da);

                /* new added delay clusters = rlen2 - rlen1. */
                ntfs_add_da(sbi, rlen2 - rlen1);
                *len = to_alloc;
                *lcn = DELALLOC_LCN;
                goto ok;
        }

        /* Get the last LCN to allocate from. */
        hint = 0;

        if (vcn > evcn1) {
                if (!run_add_entry(run, evcn1, SPARSE_LCN, vcn - evcn1,
                                   false)) {
                        err = -ENOMEM;
                        goto out;
                }
        } else if (vcn && !run_lookup_entry(run, vcn - 1, &hint, NULL, NULL)) {
                hint = -1;
        }

        /* Allocate and zeroout new clusters. */
        err = attr_allocate_clusters(sbi, run, run_da, vcn, hint + 1, to_alloc,
                                     NULL,
                                     zero ? ALLOCATE_ZERO : ALLOCATE_ONE_FR,
                                     len, fr, lcn, len);
        if (err)
                goto out;
        *new = true;
        step = 1;

        end = vcn + *len;
        /* Save 'total_size0' to restore if error. */
        total_size0 = le64_to_cpu(attr_b->nres.total_size);
        total_size = total_size0 + ((u64)*len << cluster_bits);

        if (vcn != vcn0) {
                if (!run_lookup_entry(run, vcn0, lcn, len, NULL)) {
                        err = -EINVAL;
                        goto out;
                }
                if (*lcn == SPARSE_LCN) {
                        /* Internal error. Should not happened. */
                        WARN_ON(1);
                        err = -EINVAL;
                        goto out;
                }
                /* Check case when vcn0 + len overlaps new allocated clusters. */
                if (vcn0 + *len > end)
                        *len = end - vcn0;
        }

repack:
        err = mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn);
        if (err)
                goto out;

        attr_b->nres.total_size = cpu_to_le64(total_size);
        inode_set_bytes(&ni->vfs_inode, total_size);
        ni->ni_flags |= NI_FLAG_UPDATE_PARENT;

        mi_b->dirty = true;
        mark_inode_dirty(&ni->vfs_inode);

        /* Stored [vcn : next_svcn) from [vcn : end). */
        next_svcn = le64_to_cpu(attr->nres.evcn) + 1;

        if (end <= evcn1) {
                if (next_svcn == evcn1) {
                        /* Normal way. Update attribute and exit. */
                        goto ok;
                }
                /* Add new segment [next_svcn : evcn1 - next_svcn). */
                if (!ni->attr_list.size) {
                        err = ni_create_attr_list(ni);
                        if (err)
                                goto undo1;
                        /* Layout of records is changed. */
                        le_b = NULL;
                        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
                                              0, NULL, &mi_b);
                        if (!attr_b) {
                                err = -ENOENT;
                                goto out;
                        }

                        attr = attr_b;
                        le = le_b;
                        mi = mi_b;
                        goto repack;
                }
        }

        /*
         * The code below may require additional cluster (to extend attribute list)
         * and / or one MFT record
         * It is too complex to undo operations if -ENOSPC occurs deep inside
         * in 'ni_insert_nonresident'.
         * Return in advance -ENOSPC here if there are no free cluster and no free MFT.
         */
        if (!ntfs_check_free_space(sbi, 1, 1, false)) {
                /* Undo step 1. */
                err = -ENOSPC;
                goto undo1;
        }

        step = 2;
        svcn = evcn1;

        /* Estimate next attribute. */
        attr = ni_find_attr(ni, attr, &le, ATTR_DATA, NULL, 0, &svcn, &mi);

        if (!attr) {
                /* Insert new attribute segment. */
                goto ins_ext;
        }

        /* Try to update existed attribute segment. */
        alloc = bytes_to_cluster(sbi, le64_to_cpu(attr_b->nres.alloc_size));
        evcn = le64_to_cpu(attr->nres.evcn);

        if (end < next_svcn)
                end = next_svcn;
        while (end > evcn) {
                /* Remove segment [svcn : evcn). */
                mi_remove_attr(NULL, mi, attr);

                if (!al_remove_le(ni, le)) {
                        err = -EINVAL;
                        goto out;
                }

                if (evcn + 1 >= alloc) {
                        /* Last attribute segment. */
                        evcn1 = evcn + 1;
                        goto ins_ext;
                }

                if (ni_load_mi(ni, le, &mi)) {
                        attr = NULL;
                        goto out;
                }

                attr = mi_find_attr(ni, mi, NULL, ATTR_DATA, NULL, 0, &le->id);
                if (!attr) {
                        err = -EINVAL;
                        goto out;
                }
                svcn = le64_to_cpu(attr->nres.svcn);
                evcn = le64_to_cpu(attr->nres.evcn);
        }

        if (end < svcn)
                end = svcn;

        err = attr_load_runs(attr, ni, run, &end);
        if (err)
                goto out;

        evcn1 = evcn + 1;
        attr->nres.svcn = cpu_to_le64(next_svcn);
        err = mi_pack_runs(mi, attr, run, evcn1 - next_svcn);
        if (err)
                goto out;

        le->vcn = cpu_to_le64(next_svcn);
        ni->attr_list.dirty = true;
        mi->dirty = true;
        next_svcn = le64_to_cpu(attr->nres.evcn) + 1;

ins_ext:
        if (evcn1 > next_svcn) {
                err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
                                            next_svcn, evcn1 - next_svcn,
                                            attr_b->flags, &attr, &mi, NULL);
                if (err)
                        goto out;
        }
ok:
        run_truncate_around(run, vcn);
out:
        if (err && step > 1) {
                /* Too complex to restore. */
                _ntfs_bad_inode(&ni->vfs_inode);
        }

        return err;

undo1:
        /* Undo step1. */
        attr_b->nres.total_size = cpu_to_le64(total_size0);
        inode_set_bytes(&ni->vfs_inode, total_size0);

        if (run_deallocate_ex(sbi, run, vcn, *len, NULL, false, run_da) ||
            !run_add_entry(run, vcn, SPARSE_LCN, *len, false) ||
            mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn)) {
                _ntfs_bad_inode(&ni->vfs_inode);
        }
        goto out;
}

int attr_data_write_resident(struct ntfs_inode *ni, struct folio *folio)
{
        u64 vbo;
        struct mft_inode *mi;
        struct ATTRIB *attr;
        u32 data_size;

        attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL, &mi);
        if (!attr)
                return -EINVAL;

        if (attr->non_res) {
                /* Return special error code to check this case. */
                return E_NTFS_NONRESIDENT;
        }

        vbo = folio_pos(folio);
        data_size = le32_to_cpu(attr->res.data_size);
        if (vbo < data_size) {
                char *data = resident_data(attr);
                size_t len = min(data_size - vbo, folio_size(folio));

                memcpy_from_folio(data + vbo, folio, 0, len);
                mi->dirty = true;
        }
        ni->i_valid = data_size;

        return 0;
}

/*
 * attr_load_runs_vcn - Load runs with VCN.
 */
int attr_load_runs_vcn(struct ntfs_inode *ni, enum ATTR_TYPE type,
                       const __le16 *name, u8 name_len, struct runs_tree *run,
                       CLST vcn)
{
        struct ATTRIB *attr;
        int err;
        CLST svcn, evcn;
        u16 ro;

        if (!ni) {
                /* Is record corrupted? */
                return -ENOENT;
        }

        attr = ni_find_attr(ni, NULL, NULL, type, name, name_len, &vcn, NULL);
        if (!attr) {
                /* Is record corrupted? */
                return -ENOENT;
        }

        svcn = le64_to_cpu(attr->nres.svcn);
        evcn = le64_to_cpu(attr->nres.evcn);

        if (evcn < vcn || vcn < svcn) {
                /* Is record corrupted? */
                return -EINVAL;
        }

        ro = le16_to_cpu(attr->nres.run_off);

        if (ro > le32_to_cpu(attr->size))
                return -EINVAL;

        err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn, svcn,
                            Add2Ptr(attr, ro), le32_to_cpu(attr->size) - ro);
        if (err < 0)
                return err;
        return 0;
}

/*
 * attr_load_runs_range - Load runs for given range [from to).
 */
int attr_load_runs_range(struct ntfs_inode *ni, enum ATTR_TYPE type,
                         const __le16 *name, u8 name_len, struct runs_tree *run,
                         u64 from, u64 to)
{
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        u8 cluster_bits = sbi->cluster_bits;
        CLST vcn;
        CLST vcn_last = (to - 1) >> cluster_bits;
        CLST lcn, clen;
        int err = 0;
        int retry = 0;

        for (vcn = from >> cluster_bits; vcn <= vcn_last; vcn += clen) {
                if (run_lookup_entry(run, vcn, &lcn, &clen, NULL)) {
                        retry = 0;
                        continue;
                }
                if (retry) {
                        err = -EINVAL;
                        break;
                }
                err = attr_load_runs_vcn(ni, type, name, name_len, run, vcn);
                if (err)
                        break;

                clen = 0; /* Next run_lookup_entry(vcn) must be success. */
                retry++;
        }

        return err;
}

#ifdef CONFIG_NTFS3_LZX_XPRESS
/*
 * attr_wof_frame_info
 *
 * Read header of Xpress/LZX file to get info about frame.
 */
int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
                        struct runs_tree *run, u64 frame, u64 frames,
                        u8 frame_bits, u32 *ondisk_size, u64 *vbo_data)
{
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        u64 vbo[2], off[2], wof_size;
        u32 voff;
        u8 bytes_per_off;
        char *addr;
        struct folio *folio;
        int i, err;
        __le32 *off32;
        __le64 *off64;

        if (ni->vfs_inode.i_size < 0x100000000ull) {
                /* File starts with array of 32 bit offsets. */
                bytes_per_off = sizeof(__le32);
                vbo[1] = frame << 2;
                *vbo_data = frames << 2;
        } else {
                /* File starts with array of 64 bit offsets. */
                bytes_per_off = sizeof(__le64);
                vbo[1] = frame << 3;
                *vbo_data = frames << 3;
        }

        /*
         * Read 4/8 bytes at [vbo - 4(8)] == offset where compressed frame starts.
         * Read 4/8 bytes at [vbo] == offset where compressed frame ends.
         */
        if (!attr->non_res) {
                if (vbo[1] + bytes_per_off > le32_to_cpu(attr->res.data_size)) {
                        _ntfs_bad_inode(&ni->vfs_inode);
                        return -EINVAL;
                }
                addr = resident_data(attr);

                if (bytes_per_off == sizeof(__le32)) {
                        off32 = Add2Ptr(addr, vbo[1]);
                        off[0] = vbo[1] ? le32_to_cpu(off32[-1]) : 0;
                        off[1] = le32_to_cpu(off32[0]);
                } else {
                        off64 = Add2Ptr(addr, vbo[1]);
                        off[0] = vbo[1] ? le64_to_cpu(off64[-1]) : 0;
                        off[1] = le64_to_cpu(off64[0]);
                }

                *vbo_data += off[0];
                *ondisk_size = off[1] - off[0];
                return 0;
        }

        wof_size = le64_to_cpu(attr->nres.data_size);
        down_write(&ni->file.run_lock);
        folio = ni->file.offs_folio;
        if (!folio) {
                folio = folio_alloc(GFP_KERNEL, 0);
                if (!folio) {
                        err = -ENOMEM;
                        goto out;
                }
                folio->index = -1;
                ni->file.offs_folio = folio;
        }
        folio_lock(folio);
        addr = folio_address(folio);

        if (vbo[1]) {
                voff = vbo[1] & (PAGE_SIZE - 1);
                vbo[0] = vbo[1] - bytes_per_off;
                i = 0;
        } else {
                voff = 0;
                vbo[0] = 0;
                off[0] = 0;
                i = 1;
        }

        do {
                pgoff_t index = vbo[i] >> PAGE_SHIFT;

                if (index != folio->index) {
                        u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1);
                        u64 to = min(from + PAGE_SIZE, wof_size);

                        err = attr_load_runs_range(ni, ATTR_DATA, WOF_NAME,
                                                   ARRAY_SIZE(WOF_NAME), run,
                                                   from, to);
                        if (err)
                                goto out1;

                        err = ntfs_read_run(sbi, run, addr, from, to - from);
                        if (err) {
                                folio->index = -1;
                                goto out1;
                        }
                        folio->index = index;
                }

                if (i) {
                        if (bytes_per_off == sizeof(__le32)) {
                                off32 = Add2Ptr(addr, voff);
                                off[1] = le32_to_cpu(*off32);
                        } else {
                                off64 = Add2Ptr(addr, voff);
                                off[1] = le64_to_cpu(*off64);
                        }
                } else if (!voff) {
                        if (bytes_per_off == sizeof(__le32)) {
                                off32 = Add2Ptr(addr, PAGE_SIZE - sizeof(u32));
                                off[0] = le32_to_cpu(*off32);
                        } else {
                                off64 = Add2Ptr(addr, PAGE_SIZE - sizeof(u64));
                                off[0] = le64_to_cpu(*off64);
                        }
                } else {
                        /* Two values in one page. */
                        if (bytes_per_off == sizeof(__le32)) {
                                off32 = Add2Ptr(addr, voff);
                                off[0] = le32_to_cpu(off32[-1]);
                                off[1] = le32_to_cpu(off32[0]);
                        } else {
                                off64 = Add2Ptr(addr, voff);
                                off[0] = le64_to_cpu(off64[-1]);
                                off[1] = le64_to_cpu(off64[0]);
                        }
                        break;
                }
        } while (++i < 2);

        *vbo_data += off[0];
        *ondisk_size = off[1] - off[0];

out1:
        folio_unlock(folio);
out:
        up_write(&ni->file.run_lock);
        return err;
}
#endif

/*
 * attr_is_frame_compressed - Used to detect compressed frame.
 *
 * attr - base (primary) attribute segment.
 * run  - run to use, usually == &ni->file.run.
 * Only base segments contains valid 'attr->nres.c_unit'
 */
int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
                             CLST frame, CLST *clst_data, struct runs_tree *run)
{
        int err;
        u32 clst_frame;
        CLST clen, lcn, vcn, alen, slen, vcn_next;
        size_t idx;

        *clst_data = 0;

        if (!is_attr_compressed(attr))
                return 0;

        if (!attr->non_res)
                return 0;

        clst_frame = 1u << attr->nres.c_unit;
        vcn = frame * clst_frame;

        if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx)) {
                err = attr_load_runs_vcn(ni, attr->type, attr_name(attr),
                                         attr->name_len, run, vcn);
                if (err)
                        return err;

                if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx))
                        return -EINVAL;
        }

        if (lcn == SPARSE_LCN) {
                /* Sparsed frame. */
                return 0;
        }

        if (clen >= clst_frame) {
                /*
                 * The frame is not compressed 'cause
                 * it does not contain any sparse clusters.
                 */
                *clst_data = clst_frame;
                return 0;
        }

        alen = bytes_to_cluster(ni->mi.sbi, le64_to_cpu(attr->nres.alloc_size));
        slen = 0;
        *clst_data = clen;

        /*
         * The frame is compressed if *clst_data + slen >= clst_frame.
         * Check next fragments.
         */
        while ((vcn += clen) < alen) {
                vcn_next = vcn;

                if (!run_get_entry(run, ++idx, &vcn, &lcn, &clen) ||
                    vcn_next != vcn) {
                        err = attr_load_runs_vcn(ni, attr->type,
                                                 attr_name(attr),
                                                 attr->name_len, run, vcn_next);
                        if (err)
                                return err;
                        vcn = vcn_next;

                        if (!run_lookup_entry(run, vcn, &lcn, &clen, &idx))
                                return -EINVAL;
                }

                if (lcn == SPARSE_LCN) {
                        slen += clen;
                } else {
                        if (slen) {
                                /*
                                 * Data_clusters + sparse_clusters =
                                 * not enough for frame.
                                 */
                                return -EINVAL;
                        }
                        *clst_data += clen;
                }

                if (*clst_data + slen >= clst_frame) {
                        if (!slen) {
                                /*
                                 * There is no sparsed clusters in this frame
                                 * so it is not compressed.
                                 */
                                *clst_data = clst_frame;
                        } else {
                                /* Frame is compressed. */
                        }
                        break;
                }
        }

        return 0;
}

/*
 * attr_allocate_frame - Allocate/free clusters for @frame.
 *
 * Assumed: down_write(&ni->file.run_lock);
 */
int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
                        u64 new_valid)
{
        int err = 0;
        struct runs_tree *run = &ni->file.run;
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        struct ATTRIB *attr = NULL, *attr_b;
        struct ATTR_LIST_ENTRY *le, *le_b;
        struct mft_inode *mi, *mi_b;
        CLST svcn, evcn1, next_svcn, len;
        CLST vcn, end, clst_data;
        u64 total_size, valid_size, data_size;

        le_b = NULL;
        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
        if (!attr_b)
                return -ENOENT;

        if (!is_attr_ext(attr_b))
                return -EINVAL;

        vcn = frame << NTFS_LZNT_CUNIT;
        total_size = le64_to_cpu(attr_b->nres.total_size);

        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
        data_size = le64_to_cpu(attr_b->nres.data_size);

        if (svcn <= vcn && vcn < evcn1) {
                attr = attr_b;
                le = le_b;
                mi = mi_b;
        } else if (!le_b) {
                err = -EINVAL;
                goto out;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
                                    &mi);
                if (!attr) {
                        err = -EINVAL;
                        goto out;
                }
                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
        }

        err = attr_load_runs(attr, ni, run, NULL);
        if (err)
                goto out;

        err = attr_is_frame_compressed(ni, attr_b, frame, &clst_data, run);
        if (err)
                goto out;

        total_size -= (u64)clst_data << sbi->cluster_bits;

        len = bytes_to_cluster(sbi, compr_size);

        if (len == clst_data)
                goto out;

        if (len < clst_data) {
                err = run_deallocate_ex(sbi, run, vcn + len, clst_data - len,
                                        NULL, true, NULL);
                if (err)
                        goto out;

                if (!run_add_entry(run, vcn + len, SPARSE_LCN, clst_data - len,
                                   false)) {
                        err = -ENOMEM;
                        goto out;
                }
                end = vcn + clst_data;
                /* Run contains updated range [vcn + len : end). */
        } else {
                CLST alen, hint = 0;
                /* Get the last LCN to allocate from. */
                if (vcn + clst_data &&
                    !run_lookup_entry(run, vcn + clst_data - 1, &hint, NULL,
                                      NULL)) {
                        hint = -1;
                }

                err = attr_allocate_clusters(sbi, run, NULL, vcn + clst_data,
                                             hint + 1, len - clst_data, NULL,
                                             ALLOCATE_DEF, &alen, 0, NULL,
                                             NULL);
                if (err)
                        goto out;

                end = vcn + len;
                /* Run contains updated range [vcn + clst_data : end). */
        }

        total_size += (u64)len << sbi->cluster_bits;

repack:
        err = mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn);
        if (err)
                goto out;

        attr_b->nres.total_size = cpu_to_le64(total_size);
        inode_set_bytes(&ni->vfs_inode, total_size);
        ni->ni_flags |= NI_FLAG_UPDATE_PARENT;

        mi_b->dirty = true;
        mark_inode_dirty(&ni->vfs_inode);

        /* Stored [vcn : next_svcn) from [vcn : end). */
        next_svcn = le64_to_cpu(attr->nres.evcn) + 1;

        if (end <= evcn1) {
                if (next_svcn == evcn1) {
                        /* Normal way. Update attribute and exit. */
                        goto ok;
                }
                /* Add new segment [next_svcn : evcn1 - next_svcn). */
                if (!ni->attr_list.size) {
                        err = ni_create_attr_list(ni);
                        if (err)
                                goto out;
                        /* Layout of records is changed. */
                        le_b = NULL;
                        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL,
                                              0, NULL, &mi_b);
                        if (!attr_b) {
                                err = -ENOENT;
                                goto out;
                        }

                        attr = attr_b;
                        le = le_b;
                        mi = mi_b;
                        goto repack;
                }
        }

        svcn = evcn1;

        /* Estimate next attribute. */
        attr = ni_find_attr(ni, attr, &le, ATTR_DATA, NULL, 0, &svcn, &mi);

        if (attr) {
                CLST alloc = bytes_to_cluster(
                        sbi, le64_to_cpu(attr_b->nres.alloc_size));
                CLST evcn = le64_to_cpu(attr->nres.evcn);

                if (end < next_svcn)
                        end = next_svcn;
                while (end > evcn) {
                        /* Remove segment [svcn : evcn). */
                        mi_remove_attr(NULL, mi, attr);

                        if (!al_remove_le(ni, le)) {
                                err = -EINVAL;
                                goto out;
                        }

                        if (evcn + 1 >= alloc) {
                                /* Last attribute segment. */
                                evcn1 = evcn + 1;
                                goto ins_ext;
                        }

                        if (ni_load_mi(ni, le, &mi)) {
                                attr = NULL;
                                goto out;
                        }

                        attr = mi_find_attr(ni, mi, NULL, ATTR_DATA, NULL, 0,
                                            &le->id);
                        if (!attr) {
                                err = -EINVAL;
                                goto out;
                        }
                        svcn = le64_to_cpu(attr->nres.svcn);
                        evcn = le64_to_cpu(attr->nres.evcn);
                }

                if (end < svcn)
                        end = svcn;

                err = attr_load_runs(attr, ni, run, &end);
                if (err)
                        goto out;

                evcn1 = evcn + 1;
                attr->nres.svcn = cpu_to_le64(next_svcn);
                err = mi_pack_runs(mi, attr, run, evcn1 - next_svcn);
                if (err)
                        goto out;

                le->vcn = cpu_to_le64(next_svcn);
                ni->attr_list.dirty = true;
                mi->dirty = true;

                next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
        }
ins_ext:
        if (evcn1 > next_svcn) {
                err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
                                            next_svcn, evcn1 - next_svcn,
                                            attr_b->flags, &attr, &mi, NULL);
                if (err)
                        goto out;
        }
ok:
        run_truncate_around(run, vcn);
out:
        if (attr_b) {
                if (new_valid > data_size)
                        new_valid = data_size;

                valid_size = le64_to_cpu(attr_b->nres.valid_size);
                if (new_valid != valid_size) {
                        attr_b->nres.valid_size = cpu_to_le64(valid_size);
                        mi_b->dirty = true;
                }
        }

        return err;
}

/*
 * attr_collapse_range - Collapse range in file.
 */
int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
{
        int err = 0;
        struct runs_tree *run = &ni->file.run;
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        struct ATTRIB *attr = NULL, *attr_b;
        struct ATTR_LIST_ENTRY *le, *le_b;
        struct mft_inode *mi, *mi_b;
        CLST svcn, evcn1, len, dealloc, alen, done;
        CLST vcn, end;
        u64 valid_size, data_size, alloc_size, total_size;
        u32 mask;
        u64 i_size;
        __le16 a_flags;

        if (!bytes)
                return 0;

        le_b = NULL;
        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
        if (!attr_b)
                return -ENOENT;

        if (!attr_b->non_res) {
                /* Attribute is resident. Nothing to do? */
                return 0;
        }

        mask = is_attr_ext(attr_b) ?
                       ((sbi->cluster_size << attr_b->nres.c_unit) - 1) :
                       sbi->cluster_mask;
        if ((vbo | bytes) & mask) {
                /* Allow to collapse only cluster aligned ranges. */
                return -EINVAL;
        }

        /* i_size - size of file with delay allocated clusters. */
        i_size = ni->vfs_inode.i_size;

        if (vbo > i_size)
                return -EINVAL;

        down_write(&ni->file.run_lock);

        if (vbo + bytes >= i_size) {
                valid_size = min(ni->i_valid, vbo);

                /* Simple truncate file at 'vbo'. */
                truncate_setsize(&ni->vfs_inode, vbo);
                err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run, vbo,
                                    &valid_size, true);

                if (!err && valid_size < ni->i_valid)
                        ni->i_valid = valid_size;

                goto out;
        }

        vcn = vbo >> sbi->cluster_bits;
        len = bytes >> sbi->cluster_bits;
        end = vcn + len;
        dealloc = 0;
        done = 0;

        /*
         * Check delayed clusters.
         */
        if (ni->file.run_da.count) {
                struct runs_tree *run_da = &ni->file.run_da;
                if (run_is_mapped_full(run_da, vcn, end - 1)) {
                        /*
                         * The requested range is full in delayed clusters.
                         */
                        err = attr_set_size_ex(ni, ATTR_DATA, NULL, 0, run,
                                               i_size - bytes, NULL, false,
                                               NULL, true);
                        goto out;
                }

                /* Collapse request crosses real and delayed clusters. */
                err = ni_allocate_da_blocks_locked(ni);
                if (err)
                        goto out;

                /* Layout of records maybe changed. */
                le_b = NULL;
                attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
                                      &mi_b);
                if (!attr_b || !attr_b->non_res) {
                        err = -ENOENT;
                        goto out;
                }
        }

        data_size = le64_to_cpu(attr_b->nres.data_size);
        alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
        total_size = is_attr_ext(attr_b) ?
                             le64_to_cpu(attr_b->nres.total_size) :
                             alloc_size;
        alen = alloc_size >> sbi->cluster_bits;
        a_flags = attr_b->flags;
        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;

        if (svcn <= vcn && vcn < evcn1) {
                attr = attr_b;
                le = le_b;
                mi = mi_b;
                goto check_seg;
        }

        if (!le_b) {
                err = -EINVAL;
                goto out;
        }

        le = le_b;
        attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn, &mi);
        if (!attr) {
                err = -EINVAL;
                goto out;
        }

        /*
         * Enumerate all attribute segments and collapse.
         */
        for (;;) {
                CLST vcn1, eat, next_svcn;

                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;

check_seg:
                if (svcn >= end) {
                        /* Shift VCN- */
                        attr->nres.svcn = cpu_to_le64(svcn - len);
                        attr->nres.evcn = cpu_to_le64(evcn1 - 1 - len);
                        if (le) {
                                le->vcn = attr->nres.svcn;
                                ni->attr_list.dirty = true;
                        }
                        mi->dirty = true;
                        goto next_attr;
                }

                run_truncate(run, 0);
                err = attr_load_runs(attr, ni, run, &svcn);
                if (err)
                        goto out;

                vcn1 = vcn + done; /* original vcn in attr/run. */
                eat = min(end, evcn1) - vcn1;

                err = run_deallocate_ex(sbi, run, vcn1, eat, &dealloc, true,
                                        NULL);
                if (err)
                        goto out;

                if (svcn + eat < evcn1) {
                        /* Collapse a part of this attribute segment. */
                        if (!run_collapse_range(run, vcn1, eat, done)) {
                                err = -ENOMEM;
                                goto out;
                        }

                        if (svcn >= vcn) {
                                /* Shift VCN */
                                attr->nres.svcn = cpu_to_le64(vcn);
                                if (le && attr->nres.svcn != le->vcn) {
                                        le->vcn = attr->nres.svcn;
                                        ni->attr_list.dirty = true;
                                }
                        }

                        err = mi_pack_runs(mi, attr, run, evcn1 - svcn - eat);
                        if (err)
                                goto out;

                        next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
                        if (next_svcn + eat + done < evcn1) {
                                err = ni_insert_nonresident(
                                        ni, ATTR_DATA, NULL, 0, run, next_svcn,
                                        evcn1 - eat - next_svcn, a_flags, &attr,
                                        &mi, &le);
                                if (err)
                                        goto out;

                                /* Layout of records maybe changed. */
                                attr_b = NULL;
                        }

                        /* Free all allocated memory. */
                        run_truncate(run, 0);
                        done += eat;
                } else {
                        u16 le_sz;

                        /* Delete this attribute segment. */
                        mi_remove_attr(NULL, mi, attr);
                        if (!le)
                                break;

                        le_sz = le16_to_cpu(le->size);
                        if (!al_remove_le(ni, le)) {
                                err = -EINVAL;
                                goto out;
                        }

                        done += evcn1 - svcn;
                        if (evcn1 >= alen)
                                break;

                        if (!svcn) {
                                /* Load next record that contains this attribute. */
                                if (ni_load_mi(ni, le, &mi)) {
                                        err = -EINVAL;
                                        goto out;
                                }

                                /* Look for required attribute. */
                                attr = mi_find_attr(ni, mi, NULL, ATTR_DATA,
                                                    NULL, 0, &le->id);
                                if (!attr) {
                                        err = -EINVAL;
                                        goto out;
                                }
                                continue;
                        }
                        le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz);
                }

next_attr:
                if (evcn1 >= alen)
                        break;

                attr = ni_enum_attr_ex(ni, attr, &le, &mi);
                if (!attr) {
                        err = -EINVAL;
                        goto out;
                }
        }

        if (!attr_b) {
                le_b = NULL;
                attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
                                      &mi_b);
                if (!attr_b) {
                        err = -ENOENT;
                        goto out;
                }
        }

        data_size -= bytes;
        valid_size = ni->i_valid;
        if (vbo + bytes <= valid_size)
                valid_size -= bytes;
        else if (vbo < valid_size)
                valid_size = vbo;

        attr_b->nres.alloc_size = cpu_to_le64(alloc_size - bytes);
        attr_b->nres.data_size = cpu_to_le64(data_size);
        attr_b->nres.valid_size = cpu_to_le64(min(valid_size, data_size));
        total_size -= (u64)dealloc << sbi->cluster_bits;
        if (is_attr_ext(attr_b))
                attr_b->nres.total_size = cpu_to_le64(total_size);
        mi_b->dirty = true;

        /* Update inode size. */
        ni->i_valid = valid_size;
        i_size_write(&ni->vfs_inode, data_size);
        inode_set_bytes(&ni->vfs_inode, total_size);
        ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
        mark_inode_dirty(&ni->vfs_inode);

out:
        up_write(&ni->file.run_lock);
        if (err)
                _ntfs_bad_inode(&ni->vfs_inode);

        return err;
}

/*
 * attr_punch_hole
 *
 * Not for normal files.
 */
int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
{
        int err = 0;
        struct runs_tree *run = &ni->file.run;
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        struct ATTRIB *attr = NULL, *attr_b;
        struct ATTR_LIST_ENTRY *le, *le_b;
        struct mft_inode *mi, *mi_b;
        CLST svcn, evcn1, vcn, len, end, alen, hole, next_svcn;
        u64 total_size, alloc_size;
        u32 mask;
        __le16 a_flags;
        struct runs_tree run2;

        if (!bytes)
                return 0;

        le_b = NULL;
        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
        if (!attr_b)
                return -ENOENT;

        if (!attr_b->non_res) {
                u32 data_size = le32_to_cpu(attr_b->res.data_size);
                u32 from, to;

                if (vbo > data_size)
                        return 0;

                from = vbo;
                to = min_t(u64, vbo + bytes, data_size);
                memset(Add2Ptr(resident_data(attr_b), from), 0, to - from);
                return 0;
        }

        if (!is_attr_ext(attr_b))
                return -EOPNOTSUPP;

        alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
        total_size = le64_to_cpu(attr_b->nres.total_size);

        if (vbo >= alloc_size) {
                /* NOTE: It is allowed. */
                return 0;
        }

        mask = (sbi->cluster_size << attr_b->nres.c_unit) - 1;

        bytes += vbo;
        if (bytes > alloc_size)
                bytes = alloc_size;
        bytes -= vbo;

        if ((vbo | bytes) & mask) {
                /* We have to zero a range(s). */
                if (!frame_size) {
                        /* Caller insists range is aligned. */
                        return -EINVAL;
                }
                *frame_size = mask + 1;
                return E_NTFS_NOTALIGNED;
        }

        down_write(&ni->file.run_lock);
        run_init(&run2);
        run_truncate(run, 0);

        /*
         * Enumerate all attribute segments and punch hole where necessary.
         */
        alen = alloc_size >> sbi->cluster_bits;
        vcn = vbo >> sbi->cluster_bits;
        len = bytes >> sbi->cluster_bits;
        end = vcn + len;
        hole = 0;

        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
        a_flags = attr_b->flags;

        if (svcn <= vcn && vcn < evcn1) {
                attr = attr_b;
                le = le_b;
                mi = mi_b;
        } else if (!le_b) {
                err = -EINVAL;
                goto bad_inode;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
                                    &mi);
                if (!attr) {
                        err = -EINVAL;
                        goto bad_inode;
                }

                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
        }

        while (svcn < end) {
                CLST vcn1, zero, hole2 = hole;

                err = attr_load_runs(attr, ni, run, &svcn);
                if (err)
                        goto done;
                vcn1 = max(vcn, svcn);
                zero = min(end, evcn1) - vcn1;

                /*
                 * Check range [vcn1 + zero).
                 * Calculate how many clusters there are.
                 * Don't do any destructive actions.
                 */
                err = run_deallocate_ex(NULL, run, vcn1, zero, &hole2, false,
                                        NULL);
                if (err)
                        goto done;

                /* Check if required range is already hole. */
                if (hole2 == hole)
                        goto next_attr;

                /* Make a clone of run to undo. */
                err = run_clone(run, &run2);
                if (err)
                        goto done;

                /* Make a hole range (sparse) [vcn1 + zero). */
                if (!run_add_entry(run, vcn1, SPARSE_LCN, zero, false)) {
                        err = -ENOMEM;
                        goto done;
                }

                /* Update run in attribute segment. */
                err = mi_pack_runs(mi, attr, run, evcn1 - svcn);
                if (err)
                        goto done;
                next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
                if (next_svcn < evcn1) {
                        /* Insert new attribute segment. */
                        err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
                                                    next_svcn,
                                                    evcn1 - next_svcn, a_flags,
                                                    &attr, &mi, &le);
                        if (err)
                                goto undo_punch;

                        /* Layout of records maybe changed. */
                        attr_b = NULL;
                }

                /* Real deallocate. Should not fail. */
                run_deallocate_ex(sbi, &run2, vcn1, zero, &hole, true,
                                  &ni->file.run_da);

next_attr:
                /* Free all allocated memory. */
                run_truncate(run, 0);

                if (evcn1 >= alen)
                        break;

                /* Get next attribute segment. */
                attr = ni_enum_attr_ex(ni, attr, &le, &mi);
                if (!attr) {
                        err = -EINVAL;
                        goto bad_inode;
                }

                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
        }

done:
        if (!hole)
                goto out;

        if (!attr_b) {
                attr_b = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
                                      &mi_b);
                if (!attr_b) {
                        err = -EINVAL;
                        goto bad_inode;
                }
        }

        total_size -= (u64)hole << sbi->cluster_bits;
        attr_b->nres.total_size = cpu_to_le64(total_size);
        mi_b->dirty = true;

        /* Update inode size. */
        inode_set_bytes(&ni->vfs_inode, total_size);
        ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
        mark_inode_dirty(&ni->vfs_inode);

out:
        run_close(&run2);
        up_write(&ni->file.run_lock);
        return err;

bad_inode:
        _ntfs_bad_inode(&ni->vfs_inode);
        goto out;

undo_punch:
        /*
         * Restore packed runs.
         * 'mi_pack_runs' should not fail, cause we restore original.
         */
        if (mi_pack_runs(mi, attr, &run2, evcn1 - svcn))
                goto bad_inode;

        goto done;
}

/*
 * attr_insert_range - Insert range (hole) in file.
 * Not for normal files.
 */
int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
{
        int err = 0;
        struct runs_tree *run = &ni->file.run;
        struct ntfs_sb_info *sbi = ni->mi.sbi;
        struct ATTRIB *attr = NULL, *attr_b;
        struct ATTR_LIST_ENTRY *le, *le_b;
        struct mft_inode *mi, *mi_b;
        CLST vcn, svcn, evcn1, len, next_svcn;
        u64 data_size, alloc_size;
        u32 mask;
        __le16 a_flags;

        if (!bytes)
                return 0;

        le_b = NULL;
        attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
        if (!attr_b)
                return -ENOENT;

        if (!is_attr_ext(attr_b)) {
                /* It was checked above. See fallocate. */
                return -EOPNOTSUPP;
        }

        if (!attr_b->non_res) {
                data_size = le32_to_cpu(attr_b->res.data_size);
                alloc_size = data_size;
                mask = sbi->cluster_mask; /* cluster_size - 1 */
        } else {
                data_size = le64_to_cpu(attr_b->nres.data_size);
                alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
                mask = (sbi->cluster_size << attr_b->nres.c_unit) - 1;
        }

        if (vbo >= data_size) {
                /*
                 * Insert range after the file size is not allowed.
                 * If the offset is equal to or greater than the end of
                 * file, an error is returned.  For such operations (i.e., inserting
                 * a hole at the end of file), ftruncate(2) should be used.
                 */
                return -EINVAL;
        }

        if ((vbo | bytes) & mask) {
                /* Allow to insert only frame aligned ranges. */
                return -EINVAL;
        }

        /*
         * valid_size <= data_size <= alloc_size
         * Check alloc_size for maximum possible.
         */
        if (bytes > sbi->maxbytes_sparse - alloc_size)
                return -EFBIG;

        vcn = vbo >> sbi->cluster_bits;
        len = bytes >> sbi->cluster_bits;

        down_write(&ni->file.run_lock);

        if (!attr_b->non_res) {
                err = attr_set_size(ni, ATTR_DATA, NULL, 0, run,
                                    data_size + bytes, NULL, false);

                le_b = NULL;
                attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
                                      &mi_b);
                if (!attr_b) {
                        err = -EINVAL;
                        goto bad_inode;
                }

                if (err)
                        goto out;

                if (!attr_b->non_res) {
                        /* Still resident. */
                        char *data = Add2Ptr(attr_b,
                                             le16_to_cpu(attr_b->res.data_off));

                        memmove(data + bytes, data, bytes);
                        memset(data, 0, bytes);
                        goto done;
                }

                /* Resident file becomes nonresident. */
                data_size = le64_to_cpu(attr_b->nres.data_size);
                alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
        }

        /*
         * Enumerate all attribute segments and shift start vcn.
         */
        a_flags = attr_b->flags;
        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;

        if (svcn <= vcn && vcn < evcn1) {
                attr = attr_b;
                le = le_b;
                mi = mi_b;
        } else if (!le_b) {
                err = -EINVAL;
                goto bad_inode;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
                                    &mi);
                if (!attr) {
                        err = -EINVAL;
                        goto bad_inode;
                }

                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
        }

        run_truncate(run, 0); /* clear cached values. */
        err = attr_load_runs(attr, ni, run, NULL);
        if (err)
                goto out;

        err = run_insert_range(run, vcn, len);
        if (err)
                goto out;

        err = run_insert_range_da(&ni->file.run_da, vcn, len);
        if (err)
                goto out;

        /* Try to pack in current record as much as possible. */
        err = mi_pack_runs(mi, attr, run, evcn1 + len - svcn);
        if (err)
                goto out;

        next_svcn = le64_to_cpu(attr->nres.evcn) + 1;

        while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
               attr->type == ATTR_DATA && !attr->name_len) {
                le64_add_cpu(&attr->nres.svcn, len);
                le64_add_cpu(&attr->nres.evcn, len);
                if (le) {
                        le->vcn = attr->nres.svcn;
                        ni->attr_list.dirty = true;
                }
                mi->dirty = true;
        }

        if (next_svcn < evcn1 + len) {
                err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
                                            next_svcn, evcn1 + len - next_svcn,
                                            a_flags, NULL, NULL, NULL);

                le_b = NULL;
                attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
                                      &mi_b);
                if (!attr_b) {
                        err = -EINVAL;
                        goto bad_inode;
                }

                if (err) {
                        /* ni_insert_nonresident failed. Try to undo. */
                        goto undo_insert_range;
                }
        }

        /*
         * Update primary attribute segment.
         */
        if (vbo <= ni->i_valid)
                ni->i_valid += bytes;

        attr_b->nres.data_size = cpu_to_le64(data_size + bytes);
        attr_b->nres.alloc_size = cpu_to_le64(alloc_size + bytes);

        /* ni->valid may be not equal valid_size (temporary). */
        if (ni->i_valid > data_size + bytes)
                attr_b->nres.valid_size = attr_b->nres.data_size;
        else
                attr_b->nres.valid_size = cpu_to_le64(ni->i_valid);
        mi_b->dirty = true;

done:
        i_size_write(&ni->vfs_inode, ni->vfs_inode.i_size + bytes);
        ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
        mark_inode_dirty(&ni->vfs_inode);

out:
        run_truncate(run, 0); /* clear cached values. */

        up_write(&ni->file.run_lock);

        return err;

bad_inode:
        _ntfs_bad_inode(&ni->vfs_inode);
        goto out;

undo_insert_range:
        svcn = le64_to_cpu(attr_b->nres.svcn);
        evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;

        if (svcn <= vcn && vcn < evcn1) {
                attr = attr_b;
                le = le_b;
                mi = mi_b;
        } else if (!le_b) {
                goto bad_inode;
        } else {
                le = le_b;
                attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
                                    &mi);
                if (!attr) {
                        goto bad_inode;
                }

                svcn = le64_to_cpu(attr->nres.svcn);
                evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
        }

        if (attr_load_runs(attr, ni, run, NULL))
                goto bad_inode;

        if (!run_collapse_range(run, vcn, len, 0))
                goto bad_inode;

        if (mi_pack_runs(mi, attr, run, evcn1 + len - svcn))
                goto bad_inode;

        while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
               attr->type == ATTR_DATA && !attr->name_len) {
                le64_sub_cpu(&attr->nres.svcn, len);
                le64_sub_cpu(&attr->nres.evcn, len);
                if (le) {
                        le->vcn = attr->nres.svcn;
                        ni->attr_list.dirty = true;
                }
                mi->dirty = true;
        }

        goto out;
}

/*
 * attr_force_nonresident
 *
 * Convert default data attribute into non resident form.
 */
int attr_force_nonresident(struct ntfs_inode *ni)
{
        int err;
        struct ATTRIB *attr;
        struct ATTR_LIST_ENTRY *le = NULL;
        struct mft_inode *mi;

        attr = ni_find_attr(ni, NULL, &le, ATTR_DATA, NULL, 0, NULL, &mi);
        if (!attr) {
                _ntfs_bad_inode(&ni->vfs_inode);
                return -ENOENT;
        }

        if (attr->non_res) {
                /* Already non resident. */
                return 0;
        }

        down_write(&ni->file.run_lock);
        err = attr_make_nonresident(ni, attr, le, mi,
                                    le32_to_cpu(attr->res.data_size),
                                    &ni->file.run, &attr, NULL);
        up_write(&ni->file.run_lock);

        return err;
}