162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * TODO: try to use extents tree (instead of array) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/blkdev.h> 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/log2.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "debug.h" 1462306a36Sopenharmony_ci#include "ntfs.h" 1562306a36Sopenharmony_ci#include "ntfs_fs.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* runs_tree is a continues memory. Try to avoid big size. */ 1862306a36Sopenharmony_ci#define NTFS3_RUN_MAX_BYTES 0x10000 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct ntfs_run { 2162306a36Sopenharmony_ci CLST vcn; /* Virtual cluster number. */ 2262306a36Sopenharmony_ci CLST len; /* Length in clusters. */ 2362306a36Sopenharmony_ci CLST lcn; /* Logical cluster number. */ 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * run_lookup - Lookup the index of a MCB entry that is first <= vcn. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Case of success it will return non-zero value and set 3062306a36Sopenharmony_ci * @index parameter to index of entry been found. 3162306a36Sopenharmony_ci * Case of entry missing from list 'index' will be set to 3262306a36Sopenharmony_ci * point to insertion position for the entry question. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic bool run_lookup(const struct runs_tree *run, CLST vcn, size_t *index) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci size_t min_idx, max_idx, mid_idx; 3762306a36Sopenharmony_ci struct ntfs_run *r; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (!run->count) { 4062306a36Sopenharmony_ci *index = 0; 4162306a36Sopenharmony_ci return false; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci min_idx = 0; 4562306a36Sopenharmony_ci max_idx = run->count - 1; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* Check boundary cases specially, 'cause they cover the often requests. */ 4862306a36Sopenharmony_ci r = run->runs; 4962306a36Sopenharmony_ci if (vcn < r->vcn) { 5062306a36Sopenharmony_ci *index = 0; 5162306a36Sopenharmony_ci return false; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (vcn < r->vcn + r->len) { 5562306a36Sopenharmony_ci *index = 0; 5662306a36Sopenharmony_ci return true; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci r += max_idx; 6062306a36Sopenharmony_ci if (vcn >= r->vcn + r->len) { 6162306a36Sopenharmony_ci *index = run->count; 6262306a36Sopenharmony_ci return false; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (vcn >= r->vcn) { 6662306a36Sopenharmony_ci *index = max_idx; 6762306a36Sopenharmony_ci return true; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci do { 7162306a36Sopenharmony_ci mid_idx = min_idx + ((max_idx - min_idx) >> 1); 7262306a36Sopenharmony_ci r = run->runs + mid_idx; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (vcn < r->vcn) { 7562306a36Sopenharmony_ci max_idx = mid_idx - 1; 7662306a36Sopenharmony_ci if (!mid_idx) 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci } else if (vcn >= r->vcn + r->len) { 7962306a36Sopenharmony_ci min_idx = mid_idx + 1; 8062306a36Sopenharmony_ci } else { 8162306a36Sopenharmony_ci *index = mid_idx; 8262306a36Sopenharmony_ci return true; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci } while (min_idx <= max_idx); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci *index = max_idx + 1; 8762306a36Sopenharmony_ci return false; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * run_consolidate - Consolidate runs starting from a given one. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic void run_consolidate(struct runs_tree *run, size_t index) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci size_t i; 9662306a36Sopenharmony_ci struct ntfs_run *r = run->runs + index; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci while (index + 1 < run->count) { 9962306a36Sopenharmony_ci /* 10062306a36Sopenharmony_ci * I should merge current run with next 10162306a36Sopenharmony_ci * if start of the next run lies inside one being tested. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci struct ntfs_run *n = r + 1; 10462306a36Sopenharmony_ci CLST end = r->vcn + r->len; 10562306a36Sopenharmony_ci CLST dl; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Stop if runs are not aligned one to another. */ 10862306a36Sopenharmony_ci if (n->vcn > end) 10962306a36Sopenharmony_ci break; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci dl = end - n->vcn; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * If range at index overlaps with next one 11562306a36Sopenharmony_ci * then I will either adjust it's start position 11662306a36Sopenharmony_ci * or (if completely matches) dust remove one from the list. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci if (dl > 0) { 11962306a36Sopenharmony_ci if (n->len <= dl) 12062306a36Sopenharmony_ci goto remove_next_range; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci n->len -= dl; 12362306a36Sopenharmony_ci n->vcn += dl; 12462306a36Sopenharmony_ci if (n->lcn != SPARSE_LCN) 12562306a36Sopenharmony_ci n->lcn += dl; 12662306a36Sopenharmony_ci dl = 0; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * Stop if sparse mode does not match 13162306a36Sopenharmony_ci * both current and next runs. 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci if ((n->lcn == SPARSE_LCN) != (r->lcn == SPARSE_LCN)) { 13462306a36Sopenharmony_ci index += 1; 13562306a36Sopenharmony_ci r = n; 13662306a36Sopenharmony_ci continue; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * Check if volume block 14162306a36Sopenharmony_ci * of a next run lcn does not match 14262306a36Sopenharmony_ci * last volume block of the current run. 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ci if (n->lcn != SPARSE_LCN && n->lcn != r->lcn + r->len) 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * Next and current are siblings. 14962306a36Sopenharmony_ci * Eat/join. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci r->len += n->len - dl; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciremove_next_range: 15462306a36Sopenharmony_ci i = run->count - (index + 1); 15562306a36Sopenharmony_ci if (i > 1) 15662306a36Sopenharmony_ci memmove(n, n + 1, sizeof(*n) * (i - 1)); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci run->count -= 1; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * run_is_mapped_full 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * Return: True if range [svcn - evcn] is mapped. 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_cibool run_is_mapped_full(const struct runs_tree *run, CLST svcn, CLST evcn) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci size_t i; 17062306a36Sopenharmony_ci const struct ntfs_run *r, *end; 17162306a36Sopenharmony_ci CLST next_vcn; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!run_lookup(run, svcn, &i)) 17462306a36Sopenharmony_ci return false; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci end = run->runs + run->count; 17762306a36Sopenharmony_ci r = run->runs + i; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci for (;;) { 18062306a36Sopenharmony_ci next_vcn = r->vcn + r->len; 18162306a36Sopenharmony_ci if (next_vcn > evcn) 18262306a36Sopenharmony_ci return true; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (++r >= end) 18562306a36Sopenharmony_ci return false; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (r->vcn != next_vcn) 18862306a36Sopenharmony_ci return false; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cibool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn, 19362306a36Sopenharmony_ci CLST *len, size_t *index) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci size_t idx; 19662306a36Sopenharmony_ci CLST gap; 19762306a36Sopenharmony_ci struct ntfs_run *r; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Fail immediately if nrun was not touched yet. */ 20062306a36Sopenharmony_ci if (!run->runs) 20162306a36Sopenharmony_ci return false; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (!run_lookup(run, vcn, &idx)) 20462306a36Sopenharmony_ci return false; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci r = run->runs + idx; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (vcn >= r->vcn + r->len) 20962306a36Sopenharmony_ci return false; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci gap = vcn - r->vcn; 21262306a36Sopenharmony_ci if (r->len <= gap) 21362306a36Sopenharmony_ci return false; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci *lcn = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + gap); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (len) 21862306a36Sopenharmony_ci *len = r->len - gap; 21962306a36Sopenharmony_ci if (index) 22062306a36Sopenharmony_ci *index = idx; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return true; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* 22662306a36Sopenharmony_ci * run_truncate_head - Decommit the range before vcn. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_civoid run_truncate_head(struct runs_tree *run, CLST vcn) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci size_t index; 23162306a36Sopenharmony_ci struct ntfs_run *r; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (run_lookup(run, vcn, &index)) { 23462306a36Sopenharmony_ci r = run->runs + index; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (vcn > r->vcn) { 23762306a36Sopenharmony_ci CLST dlen = vcn - r->vcn; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci r->vcn = vcn; 24062306a36Sopenharmony_ci r->len -= dlen; 24162306a36Sopenharmony_ci if (r->lcn != SPARSE_LCN) 24262306a36Sopenharmony_ci r->lcn += dlen; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (!index) 24662306a36Sopenharmony_ci return; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci r = run->runs; 24962306a36Sopenharmony_ci memmove(r, r + index, sizeof(*r) * (run->count - index)); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci run->count -= index; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (!run->count) { 25462306a36Sopenharmony_ci kvfree(run->runs); 25562306a36Sopenharmony_ci run->runs = NULL; 25662306a36Sopenharmony_ci run->allocated = 0; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* 26162306a36Sopenharmony_ci * run_truncate - Decommit the range after vcn. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_civoid run_truncate(struct runs_tree *run, CLST vcn) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci size_t index; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* 26862306a36Sopenharmony_ci * If I hit the range then 26962306a36Sopenharmony_ci * I have to truncate one. 27062306a36Sopenharmony_ci * If range to be truncated is becoming empty 27162306a36Sopenharmony_ci * then it will entirely be removed. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci if (run_lookup(run, vcn, &index)) { 27462306a36Sopenharmony_ci struct ntfs_run *r = run->runs + index; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci r->len = vcn - r->vcn; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (r->len > 0) 27962306a36Sopenharmony_ci index += 1; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * At this point 'index' is set to position that 28462306a36Sopenharmony_ci * should be thrown away (including index itself) 28562306a36Sopenharmony_ci * Simple one - just set the limit. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ci run->count = index; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* Do not reallocate array 'runs'. Only free if possible. */ 29062306a36Sopenharmony_ci if (!index) { 29162306a36Sopenharmony_ci kvfree(run->runs); 29262306a36Sopenharmony_ci run->runs = NULL; 29362306a36Sopenharmony_ci run->allocated = 0; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* 29862306a36Sopenharmony_ci * run_truncate_around - Trim head and tail if necessary. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_civoid run_truncate_around(struct runs_tree *run, CLST vcn) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci run_truncate_head(run, vcn); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (run->count >= NTFS3_RUN_MAX_BYTES / sizeof(struct ntfs_run) / 2) 30562306a36Sopenharmony_ci run_truncate(run, (run->runs + (run->count >> 1))->vcn); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* 30962306a36Sopenharmony_ci * run_add_entry 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * Sets location to known state. 31262306a36Sopenharmony_ci * Run to be added may overlap with existing location. 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * Return: false if of memory. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_cibool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len, 31762306a36Sopenharmony_ci bool is_mft) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci size_t used, index; 32062306a36Sopenharmony_ci struct ntfs_run *r; 32162306a36Sopenharmony_ci bool inrange; 32262306a36Sopenharmony_ci CLST tail_vcn = 0, tail_len = 0, tail_lcn = 0; 32362306a36Sopenharmony_ci bool should_add_tail = false; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * Lookup the insertion point. 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci * Execute bsearch for the entry containing 32962306a36Sopenharmony_ci * start position question. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_ci inrange = run_lookup(run, vcn, &index); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* 33462306a36Sopenharmony_ci * Shortcut here would be case of 33562306a36Sopenharmony_ci * range not been found but one been added 33662306a36Sopenharmony_ci * continues previous run. 33762306a36Sopenharmony_ci * This case I can directly make use of 33862306a36Sopenharmony_ci * existing range as my start point. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci if (!inrange && index > 0) { 34162306a36Sopenharmony_ci struct ntfs_run *t = run->runs + index - 1; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (t->vcn + t->len == vcn && 34462306a36Sopenharmony_ci (t->lcn == SPARSE_LCN) == (lcn == SPARSE_LCN) && 34562306a36Sopenharmony_ci (lcn == SPARSE_LCN || lcn == t->lcn + t->len)) { 34662306a36Sopenharmony_ci inrange = true; 34762306a36Sopenharmony_ci index -= 1; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* 35262306a36Sopenharmony_ci * At this point 'index' either points to the range 35362306a36Sopenharmony_ci * containing start position or to the insertion position 35462306a36Sopenharmony_ci * for a new range. 35562306a36Sopenharmony_ci * So first let's check if range I'm probing is here already. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci if (!inrange) { 35862306a36Sopenharmony_cirequires_new_range: 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * Range was not found. 36162306a36Sopenharmony_ci * Insert at position 'index' 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci used = run->count * sizeof(struct ntfs_run); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * Check allocated space. 36762306a36Sopenharmony_ci * If one is not enough to get one more entry 36862306a36Sopenharmony_ci * then it will be reallocated. 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_ci if (run->allocated < used + sizeof(struct ntfs_run)) { 37162306a36Sopenharmony_ci size_t bytes; 37262306a36Sopenharmony_ci struct ntfs_run *new_ptr; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Use power of 2 for 'bytes'. */ 37562306a36Sopenharmony_ci if (!used) { 37662306a36Sopenharmony_ci bytes = 64; 37762306a36Sopenharmony_ci } else if (used <= 16 * PAGE_SIZE) { 37862306a36Sopenharmony_ci if (is_power_of_2(run->allocated)) 37962306a36Sopenharmony_ci bytes = run->allocated << 1; 38062306a36Sopenharmony_ci else 38162306a36Sopenharmony_ci bytes = (size_t)1 38262306a36Sopenharmony_ci << (2 + blksize_bits(used)); 38362306a36Sopenharmony_ci } else { 38462306a36Sopenharmony_ci bytes = run->allocated + (16 * PAGE_SIZE); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci WARN_ON(!is_mft && bytes > NTFS3_RUN_MAX_BYTES); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci new_ptr = kvmalloc(bytes, GFP_KERNEL); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (!new_ptr) 39262306a36Sopenharmony_ci return false; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci r = new_ptr + index; 39562306a36Sopenharmony_ci memcpy(new_ptr, run->runs, 39662306a36Sopenharmony_ci index * sizeof(struct ntfs_run)); 39762306a36Sopenharmony_ci memcpy(r + 1, run->runs + index, 39862306a36Sopenharmony_ci sizeof(struct ntfs_run) * (run->count - index)); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci kvfree(run->runs); 40162306a36Sopenharmony_ci run->runs = new_ptr; 40262306a36Sopenharmony_ci run->allocated = bytes; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci } else { 40562306a36Sopenharmony_ci size_t i = run->count - index; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci r = run->runs + index; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* memmove appears to be a bottle neck here... */ 41062306a36Sopenharmony_ci if (i > 0) 41162306a36Sopenharmony_ci memmove(r + 1, r, sizeof(struct ntfs_run) * i); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci r->vcn = vcn; 41562306a36Sopenharmony_ci r->lcn = lcn; 41662306a36Sopenharmony_ci r->len = len; 41762306a36Sopenharmony_ci run->count += 1; 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci r = run->runs + index; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* 42262306a36Sopenharmony_ci * If one of ranges was not allocated then we 42362306a36Sopenharmony_ci * have to split location we just matched and 42462306a36Sopenharmony_ci * insert current one. 42562306a36Sopenharmony_ci * A common case this requires tail to be reinserted 42662306a36Sopenharmony_ci * a recursive call. 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci if (((lcn == SPARSE_LCN) != (r->lcn == SPARSE_LCN)) || 42962306a36Sopenharmony_ci (lcn != SPARSE_LCN && lcn != r->lcn + (vcn - r->vcn))) { 43062306a36Sopenharmony_ci CLST to_eat = vcn - r->vcn; 43162306a36Sopenharmony_ci CLST Tovcn = to_eat + len; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci should_add_tail = Tovcn < r->len; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (should_add_tail) { 43662306a36Sopenharmony_ci tail_lcn = r->lcn == SPARSE_LCN ? 43762306a36Sopenharmony_ci SPARSE_LCN : 43862306a36Sopenharmony_ci (r->lcn + Tovcn); 43962306a36Sopenharmony_ci tail_vcn = r->vcn + Tovcn; 44062306a36Sopenharmony_ci tail_len = r->len - Tovcn; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (to_eat > 0) { 44462306a36Sopenharmony_ci r->len = to_eat; 44562306a36Sopenharmony_ci inrange = false; 44662306a36Sopenharmony_ci index += 1; 44762306a36Sopenharmony_ci goto requires_new_range; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* lcn should match one were going to add. */ 45162306a36Sopenharmony_ci r->lcn = lcn; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* 45562306a36Sopenharmony_ci * If existing range fits then were done. 45662306a36Sopenharmony_ci * Otherwise extend found one and fall back to range jocode. 45762306a36Sopenharmony_ci */ 45862306a36Sopenharmony_ci if (r->vcn + r->len < vcn + len) 45962306a36Sopenharmony_ci r->len += len - ((r->vcn + r->len) - vcn); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * And normalize it starting from insertion point. 46462306a36Sopenharmony_ci * It's possible that no insertion needed case if 46562306a36Sopenharmony_ci * start point lies within the range of an entry 46662306a36Sopenharmony_ci * that 'index' points to. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci if (inrange && index > 0) 46962306a36Sopenharmony_ci index -= 1; 47062306a36Sopenharmony_ci run_consolidate(run, index); 47162306a36Sopenharmony_ci run_consolidate(run, index + 1); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * A special case. 47562306a36Sopenharmony_ci * We have to add extra range a tail. 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci if (should_add_tail && 47862306a36Sopenharmony_ci !run_add_entry(run, tail_vcn, tail_lcn, tail_len, is_mft)) 47962306a36Sopenharmony_ci return false; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return true; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci/* run_collapse_range 48562306a36Sopenharmony_ci * 48662306a36Sopenharmony_ci * Helper for attr_collapse_range(), 48762306a36Sopenharmony_ci * which is helper for fallocate(collapse_range). 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_cibool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci size_t index, eat; 49262306a36Sopenharmony_ci struct ntfs_run *r, *e, *eat_start, *eat_end; 49362306a36Sopenharmony_ci CLST end; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (WARN_ON(!run_lookup(run, vcn, &index))) 49662306a36Sopenharmony_ci return true; /* Should never be here. */ 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci e = run->runs + run->count; 49962306a36Sopenharmony_ci r = run->runs + index; 50062306a36Sopenharmony_ci end = vcn + len; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (vcn > r->vcn) { 50362306a36Sopenharmony_ci if (r->vcn + r->len <= end) { 50462306a36Sopenharmony_ci /* Collapse tail of run .*/ 50562306a36Sopenharmony_ci r->len = vcn - r->vcn; 50662306a36Sopenharmony_ci } else if (r->lcn == SPARSE_LCN) { 50762306a36Sopenharmony_ci /* Collapse a middle part of sparsed run. */ 50862306a36Sopenharmony_ci r->len -= len; 50962306a36Sopenharmony_ci } else { 51062306a36Sopenharmony_ci /* Collapse a middle part of normal run, split. */ 51162306a36Sopenharmony_ci if (!run_add_entry(run, vcn, SPARSE_LCN, len, false)) 51262306a36Sopenharmony_ci return false; 51362306a36Sopenharmony_ci return run_collapse_range(run, vcn, len); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci r += 1; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci eat_start = r; 52062306a36Sopenharmony_ci eat_end = r; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci for (; r < e; r++) { 52362306a36Sopenharmony_ci CLST d; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (r->vcn >= end) { 52662306a36Sopenharmony_ci r->vcn -= len; 52762306a36Sopenharmony_ci continue; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (r->vcn + r->len <= end) { 53162306a36Sopenharmony_ci /* Eat this run. */ 53262306a36Sopenharmony_ci eat_end = r + 1; 53362306a36Sopenharmony_ci continue; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci d = end - r->vcn; 53762306a36Sopenharmony_ci if (r->lcn != SPARSE_LCN) 53862306a36Sopenharmony_ci r->lcn += d; 53962306a36Sopenharmony_ci r->len -= d; 54062306a36Sopenharmony_ci r->vcn -= len - d; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci eat = eat_end - eat_start; 54462306a36Sopenharmony_ci memmove(eat_start, eat_end, (e - eat_end) * sizeof(*r)); 54562306a36Sopenharmony_ci run->count -= eat; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return true; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci/* run_insert_range 55162306a36Sopenharmony_ci * 55262306a36Sopenharmony_ci * Helper for attr_insert_range(), 55362306a36Sopenharmony_ci * which is helper for fallocate(insert_range). 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_cibool run_insert_range(struct runs_tree *run, CLST vcn, CLST len) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci size_t index; 55862306a36Sopenharmony_ci struct ntfs_run *r, *e; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (WARN_ON(!run_lookup(run, vcn, &index))) 56162306a36Sopenharmony_ci return false; /* Should never be here. */ 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci e = run->runs + run->count; 56462306a36Sopenharmony_ci r = run->runs + index; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (vcn > r->vcn) 56762306a36Sopenharmony_ci r += 1; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci for (; r < e; r++) 57062306a36Sopenharmony_ci r->vcn += len; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci r = run->runs + index; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (vcn > r->vcn) { 57562306a36Sopenharmony_ci /* split fragment. */ 57662306a36Sopenharmony_ci CLST len1 = vcn - r->vcn; 57762306a36Sopenharmony_ci CLST len2 = r->len - len1; 57862306a36Sopenharmony_ci CLST lcn2 = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len1); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci r->len = len1; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!run_add_entry(run, vcn + len, lcn2, len2, false)) 58362306a36Sopenharmony_ci return false; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (!run_add_entry(run, vcn, SPARSE_LCN, len, false)) 58762306a36Sopenharmony_ci return false; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci return true; 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci/* 59362306a36Sopenharmony_ci * run_get_entry - Return index-th mapped region. 59462306a36Sopenharmony_ci */ 59562306a36Sopenharmony_cibool run_get_entry(const struct runs_tree *run, size_t index, CLST *vcn, 59662306a36Sopenharmony_ci CLST *lcn, CLST *len) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci const struct ntfs_run *r; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (index >= run->count) 60162306a36Sopenharmony_ci return false; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci r = run->runs + index; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (!r->len) 60662306a36Sopenharmony_ci return false; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (vcn) 60962306a36Sopenharmony_ci *vcn = r->vcn; 61062306a36Sopenharmony_ci if (lcn) 61162306a36Sopenharmony_ci *lcn = r->lcn; 61262306a36Sopenharmony_ci if (len) 61362306a36Sopenharmony_ci *len = r->len; 61462306a36Sopenharmony_ci return true; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci/* 61862306a36Sopenharmony_ci * run_packed_size - Calculate the size of packed int64. 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 62162306a36Sopenharmony_cistatic inline int run_packed_size(const s64 n) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci const u8 *p = (const u8 *)&n + sizeof(n) - 1; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (n >= 0) { 62662306a36Sopenharmony_ci if (p[-7] || p[-6] || p[-5] || p[-4]) 62762306a36Sopenharmony_ci p -= 4; 62862306a36Sopenharmony_ci if (p[-3] || p[-2]) 62962306a36Sopenharmony_ci p -= 2; 63062306a36Sopenharmony_ci if (p[-1]) 63162306a36Sopenharmony_ci p -= 1; 63262306a36Sopenharmony_ci if (p[0] & 0x80) 63362306a36Sopenharmony_ci p -= 1; 63462306a36Sopenharmony_ci } else { 63562306a36Sopenharmony_ci if (p[-7] != 0xff || p[-6] != 0xff || p[-5] != 0xff || 63662306a36Sopenharmony_ci p[-4] != 0xff) 63762306a36Sopenharmony_ci p -= 4; 63862306a36Sopenharmony_ci if (p[-3] != 0xff || p[-2] != 0xff) 63962306a36Sopenharmony_ci p -= 2; 64062306a36Sopenharmony_ci if (p[-1] != 0xff) 64162306a36Sopenharmony_ci p -= 1; 64262306a36Sopenharmony_ci if (!(p[0] & 0x80)) 64362306a36Sopenharmony_ci p -= 1; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci return (const u8 *)&n + sizeof(n) - p; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci/* Full trusted function. It does not check 'size' for errors. */ 64962306a36Sopenharmony_cistatic inline void run_pack_s64(u8 *run_buf, u8 size, s64 v) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci const u8 *p = (u8 *)&v; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci switch (size) { 65462306a36Sopenharmony_ci case 8: 65562306a36Sopenharmony_ci run_buf[7] = p[0]; 65662306a36Sopenharmony_ci fallthrough; 65762306a36Sopenharmony_ci case 7: 65862306a36Sopenharmony_ci run_buf[6] = p[1]; 65962306a36Sopenharmony_ci fallthrough; 66062306a36Sopenharmony_ci case 6: 66162306a36Sopenharmony_ci run_buf[5] = p[2]; 66262306a36Sopenharmony_ci fallthrough; 66362306a36Sopenharmony_ci case 5: 66462306a36Sopenharmony_ci run_buf[4] = p[3]; 66562306a36Sopenharmony_ci fallthrough; 66662306a36Sopenharmony_ci case 4: 66762306a36Sopenharmony_ci run_buf[3] = p[4]; 66862306a36Sopenharmony_ci fallthrough; 66962306a36Sopenharmony_ci case 3: 67062306a36Sopenharmony_ci run_buf[2] = p[5]; 67162306a36Sopenharmony_ci fallthrough; 67262306a36Sopenharmony_ci case 2: 67362306a36Sopenharmony_ci run_buf[1] = p[6]; 67462306a36Sopenharmony_ci fallthrough; 67562306a36Sopenharmony_ci case 1: 67662306a36Sopenharmony_ci run_buf[0] = p[7]; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci/* Full trusted function. It does not check 'size' for errors. */ 68162306a36Sopenharmony_cistatic inline s64 run_unpack_s64(const u8 *run_buf, u8 size, s64 v) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci u8 *p = (u8 *)&v; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci switch (size) { 68662306a36Sopenharmony_ci case 8: 68762306a36Sopenharmony_ci p[0] = run_buf[7]; 68862306a36Sopenharmony_ci fallthrough; 68962306a36Sopenharmony_ci case 7: 69062306a36Sopenharmony_ci p[1] = run_buf[6]; 69162306a36Sopenharmony_ci fallthrough; 69262306a36Sopenharmony_ci case 6: 69362306a36Sopenharmony_ci p[2] = run_buf[5]; 69462306a36Sopenharmony_ci fallthrough; 69562306a36Sopenharmony_ci case 5: 69662306a36Sopenharmony_ci p[3] = run_buf[4]; 69762306a36Sopenharmony_ci fallthrough; 69862306a36Sopenharmony_ci case 4: 69962306a36Sopenharmony_ci p[4] = run_buf[3]; 70062306a36Sopenharmony_ci fallthrough; 70162306a36Sopenharmony_ci case 3: 70262306a36Sopenharmony_ci p[5] = run_buf[2]; 70362306a36Sopenharmony_ci fallthrough; 70462306a36Sopenharmony_ci case 2: 70562306a36Sopenharmony_ci p[6] = run_buf[1]; 70662306a36Sopenharmony_ci fallthrough; 70762306a36Sopenharmony_ci case 1: 70862306a36Sopenharmony_ci p[7] = run_buf[0]; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci return v; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci#else 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic inline int run_packed_size(const s64 n) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci const u8 *p = (const u8 *)&n; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci if (n >= 0) { 72062306a36Sopenharmony_ci if (p[7] || p[6] || p[5] || p[4]) 72162306a36Sopenharmony_ci p += 4; 72262306a36Sopenharmony_ci if (p[3] || p[2]) 72362306a36Sopenharmony_ci p += 2; 72462306a36Sopenharmony_ci if (p[1]) 72562306a36Sopenharmony_ci p += 1; 72662306a36Sopenharmony_ci if (p[0] & 0x80) 72762306a36Sopenharmony_ci p += 1; 72862306a36Sopenharmony_ci } else { 72962306a36Sopenharmony_ci if (p[7] != 0xff || p[6] != 0xff || p[5] != 0xff || 73062306a36Sopenharmony_ci p[4] != 0xff) 73162306a36Sopenharmony_ci p += 4; 73262306a36Sopenharmony_ci if (p[3] != 0xff || p[2] != 0xff) 73362306a36Sopenharmony_ci p += 2; 73462306a36Sopenharmony_ci if (p[1] != 0xff) 73562306a36Sopenharmony_ci p += 1; 73662306a36Sopenharmony_ci if (!(p[0] & 0x80)) 73762306a36Sopenharmony_ci p += 1; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return 1 + p - (const u8 *)&n; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci/* Full trusted function. It does not check 'size' for errors. */ 74462306a36Sopenharmony_cistatic inline void run_pack_s64(u8 *run_buf, u8 size, s64 v) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci const u8 *p = (u8 *)&v; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* memcpy( run_buf, &v, size); Is it faster? */ 74962306a36Sopenharmony_ci switch (size) { 75062306a36Sopenharmony_ci case 8: 75162306a36Sopenharmony_ci run_buf[7] = p[7]; 75262306a36Sopenharmony_ci fallthrough; 75362306a36Sopenharmony_ci case 7: 75462306a36Sopenharmony_ci run_buf[6] = p[6]; 75562306a36Sopenharmony_ci fallthrough; 75662306a36Sopenharmony_ci case 6: 75762306a36Sopenharmony_ci run_buf[5] = p[5]; 75862306a36Sopenharmony_ci fallthrough; 75962306a36Sopenharmony_ci case 5: 76062306a36Sopenharmony_ci run_buf[4] = p[4]; 76162306a36Sopenharmony_ci fallthrough; 76262306a36Sopenharmony_ci case 4: 76362306a36Sopenharmony_ci run_buf[3] = p[3]; 76462306a36Sopenharmony_ci fallthrough; 76562306a36Sopenharmony_ci case 3: 76662306a36Sopenharmony_ci run_buf[2] = p[2]; 76762306a36Sopenharmony_ci fallthrough; 76862306a36Sopenharmony_ci case 2: 76962306a36Sopenharmony_ci run_buf[1] = p[1]; 77062306a36Sopenharmony_ci fallthrough; 77162306a36Sopenharmony_ci case 1: 77262306a36Sopenharmony_ci run_buf[0] = p[0]; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/* full trusted function. It does not check 'size' for errors */ 77762306a36Sopenharmony_cistatic inline s64 run_unpack_s64(const u8 *run_buf, u8 size, s64 v) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci u8 *p = (u8 *)&v; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci /* memcpy( &v, run_buf, size); Is it faster? */ 78262306a36Sopenharmony_ci switch (size) { 78362306a36Sopenharmony_ci case 8: 78462306a36Sopenharmony_ci p[7] = run_buf[7]; 78562306a36Sopenharmony_ci fallthrough; 78662306a36Sopenharmony_ci case 7: 78762306a36Sopenharmony_ci p[6] = run_buf[6]; 78862306a36Sopenharmony_ci fallthrough; 78962306a36Sopenharmony_ci case 6: 79062306a36Sopenharmony_ci p[5] = run_buf[5]; 79162306a36Sopenharmony_ci fallthrough; 79262306a36Sopenharmony_ci case 5: 79362306a36Sopenharmony_ci p[4] = run_buf[4]; 79462306a36Sopenharmony_ci fallthrough; 79562306a36Sopenharmony_ci case 4: 79662306a36Sopenharmony_ci p[3] = run_buf[3]; 79762306a36Sopenharmony_ci fallthrough; 79862306a36Sopenharmony_ci case 3: 79962306a36Sopenharmony_ci p[2] = run_buf[2]; 80062306a36Sopenharmony_ci fallthrough; 80162306a36Sopenharmony_ci case 2: 80262306a36Sopenharmony_ci p[1] = run_buf[1]; 80362306a36Sopenharmony_ci fallthrough; 80462306a36Sopenharmony_ci case 1: 80562306a36Sopenharmony_ci p[0] = run_buf[0]; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci return v; 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci#endif 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci/* 81262306a36Sopenharmony_ci * run_pack - Pack runs into buffer. 81362306a36Sopenharmony_ci * 81462306a36Sopenharmony_ci * packed_vcns - How much runs we have packed. 81562306a36Sopenharmony_ci * packed_size - How much bytes we have used run_buf. 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ciint run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf, 81862306a36Sopenharmony_ci u32 run_buf_size, CLST *packed_vcns) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci CLST next_vcn, vcn, lcn; 82162306a36Sopenharmony_ci CLST prev_lcn = 0; 82262306a36Sopenharmony_ci CLST evcn1 = svcn + len; 82362306a36Sopenharmony_ci const struct ntfs_run *r, *r_end; 82462306a36Sopenharmony_ci int packed_size = 0; 82562306a36Sopenharmony_ci size_t i; 82662306a36Sopenharmony_ci s64 dlcn; 82762306a36Sopenharmony_ci int offset_size, size_size, tmp; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci *packed_vcns = 0; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (!len) 83262306a36Sopenharmony_ci goto out; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* Check all required entries [svcn, encv1) available. */ 83562306a36Sopenharmony_ci if (!run_lookup(run, svcn, &i)) 83662306a36Sopenharmony_ci return -ENOENT; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci r_end = run->runs + run->count; 83962306a36Sopenharmony_ci r = run->runs + i; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci for (next_vcn = r->vcn + r->len; next_vcn < evcn1; 84262306a36Sopenharmony_ci next_vcn = r->vcn + r->len) { 84362306a36Sopenharmony_ci if (++r >= r_end || r->vcn != next_vcn) 84462306a36Sopenharmony_ci return -ENOENT; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* Repeat cycle above and pack runs. Assume no errors. */ 84862306a36Sopenharmony_ci r = run->runs + i; 84962306a36Sopenharmony_ci len = svcn - r->vcn; 85062306a36Sopenharmony_ci vcn = svcn; 85162306a36Sopenharmony_ci lcn = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len); 85262306a36Sopenharmony_ci len = r->len - len; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci for (;;) { 85562306a36Sopenharmony_ci next_vcn = vcn + len; 85662306a36Sopenharmony_ci if (next_vcn > evcn1) 85762306a36Sopenharmony_ci len = evcn1 - vcn; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* How much bytes required to pack len. */ 86062306a36Sopenharmony_ci size_size = run_packed_size(len); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* offset_size - How much bytes is packed dlcn. */ 86362306a36Sopenharmony_ci if (lcn == SPARSE_LCN) { 86462306a36Sopenharmony_ci offset_size = 0; 86562306a36Sopenharmony_ci dlcn = 0; 86662306a36Sopenharmony_ci } else { 86762306a36Sopenharmony_ci /* NOTE: lcn can be less than prev_lcn! */ 86862306a36Sopenharmony_ci dlcn = (s64)lcn - prev_lcn; 86962306a36Sopenharmony_ci offset_size = run_packed_size(dlcn); 87062306a36Sopenharmony_ci prev_lcn = lcn; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci tmp = run_buf_size - packed_size - 2 - offset_size; 87462306a36Sopenharmony_ci if (tmp <= 0) 87562306a36Sopenharmony_ci goto out; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci /* Can we store this entire run. */ 87862306a36Sopenharmony_ci if (tmp < size_size) 87962306a36Sopenharmony_ci goto out; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci if (run_buf) { 88262306a36Sopenharmony_ci /* Pack run header. */ 88362306a36Sopenharmony_ci run_buf[0] = ((u8)(size_size | (offset_size << 4))); 88462306a36Sopenharmony_ci run_buf += 1; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* Pack the length of run. */ 88762306a36Sopenharmony_ci run_pack_s64(run_buf, size_size, len); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci run_buf += size_size; 89062306a36Sopenharmony_ci /* Pack the offset from previous LCN. */ 89162306a36Sopenharmony_ci run_pack_s64(run_buf, offset_size, dlcn); 89262306a36Sopenharmony_ci run_buf += offset_size; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci packed_size += 1 + offset_size + size_size; 89662306a36Sopenharmony_ci *packed_vcns += len; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (packed_size + 1 >= run_buf_size || next_vcn >= evcn1) 89962306a36Sopenharmony_ci goto out; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci r += 1; 90262306a36Sopenharmony_ci vcn = r->vcn; 90362306a36Sopenharmony_ci lcn = r->lcn; 90462306a36Sopenharmony_ci len = r->len; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ciout: 90862306a36Sopenharmony_ci /* Store last zero. */ 90962306a36Sopenharmony_ci if (run_buf) 91062306a36Sopenharmony_ci run_buf[0] = 0; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci return packed_size + 1; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci/* 91662306a36Sopenharmony_ci * run_unpack - Unpack packed runs from @run_buf. 91762306a36Sopenharmony_ci * 91862306a36Sopenharmony_ci * Return: Error if negative, or real used bytes. 91962306a36Sopenharmony_ci */ 92062306a36Sopenharmony_ciint run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino, 92162306a36Sopenharmony_ci CLST svcn, CLST evcn, CLST vcn, const u8 *run_buf, 92262306a36Sopenharmony_ci int run_buf_size) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci u64 prev_lcn, vcn64, lcn, next_vcn; 92562306a36Sopenharmony_ci const u8 *run_last, *run_0; 92662306a36Sopenharmony_ci bool is_mft = ino == MFT_REC_MFT; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (run_buf_size < 0) 92962306a36Sopenharmony_ci return -EINVAL; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* Check for empty. */ 93262306a36Sopenharmony_ci if (evcn + 1 == svcn) 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (evcn < svcn) 93662306a36Sopenharmony_ci return -EINVAL; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci run_0 = run_buf; 93962306a36Sopenharmony_ci run_last = run_buf + run_buf_size; 94062306a36Sopenharmony_ci prev_lcn = 0; 94162306a36Sopenharmony_ci vcn64 = svcn; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* Read all runs the chain. */ 94462306a36Sopenharmony_ci /* size_size - How much bytes is packed len. */ 94562306a36Sopenharmony_ci while (run_buf < run_last) { 94662306a36Sopenharmony_ci /* size_size - How much bytes is packed len. */ 94762306a36Sopenharmony_ci u8 size_size = *run_buf & 0xF; 94862306a36Sopenharmony_ci /* offset_size - How much bytes is packed dlcn. */ 94962306a36Sopenharmony_ci u8 offset_size = *run_buf++ >> 4; 95062306a36Sopenharmony_ci u64 len; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (!size_size) 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* 95662306a36Sopenharmony_ci * Unpack runs. 95762306a36Sopenharmony_ci * NOTE: Runs are stored little endian order 95862306a36Sopenharmony_ci * "len" is unsigned value, "dlcn" is signed. 95962306a36Sopenharmony_ci * Large positive number requires to store 5 bytes 96062306a36Sopenharmony_ci * e.g.: 05 FF 7E FF FF 00 00 00 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci if (size_size > 8) 96362306a36Sopenharmony_ci return -EINVAL; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci len = run_unpack_s64(run_buf, size_size, 0); 96662306a36Sopenharmony_ci /* Skip size_size. */ 96762306a36Sopenharmony_ci run_buf += size_size; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (!len) 97062306a36Sopenharmony_ci return -EINVAL; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (!offset_size) 97362306a36Sopenharmony_ci lcn = SPARSE_LCN64; 97462306a36Sopenharmony_ci else if (offset_size <= 8) { 97562306a36Sopenharmony_ci s64 dlcn; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* Initial value of dlcn is -1 or 0. */ 97862306a36Sopenharmony_ci dlcn = (run_buf[offset_size - 1] & 0x80) ? (s64)-1 : 0; 97962306a36Sopenharmony_ci dlcn = run_unpack_s64(run_buf, offset_size, dlcn); 98062306a36Sopenharmony_ci /* Skip offset_size. */ 98162306a36Sopenharmony_ci run_buf += offset_size; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (!dlcn) 98462306a36Sopenharmony_ci return -EINVAL; 98562306a36Sopenharmony_ci lcn = prev_lcn + dlcn; 98662306a36Sopenharmony_ci prev_lcn = lcn; 98762306a36Sopenharmony_ci } else 98862306a36Sopenharmony_ci return -EINVAL; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci next_vcn = vcn64 + len; 99162306a36Sopenharmony_ci /* Check boundary. */ 99262306a36Sopenharmony_ci if (next_vcn > evcn + 1) 99362306a36Sopenharmony_ci return -EINVAL; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci#ifndef CONFIG_NTFS3_64BIT_CLUSTER 99662306a36Sopenharmony_ci if (next_vcn > 0x100000000ull || (lcn + len) > 0x100000000ull) { 99762306a36Sopenharmony_ci ntfs_err( 99862306a36Sopenharmony_ci sbi->sb, 99962306a36Sopenharmony_ci "This driver is compiled without CONFIG_NTFS3_64BIT_CLUSTER (like windows driver).\n" 100062306a36Sopenharmony_ci "Volume contains 64 bits run: vcn %llx, lcn %llx, len %llx.\n" 100162306a36Sopenharmony_ci "Activate CONFIG_NTFS3_64BIT_CLUSTER to process this case", 100262306a36Sopenharmony_ci vcn64, lcn, len); 100362306a36Sopenharmony_ci return -EOPNOTSUPP; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci#endif 100662306a36Sopenharmony_ci if (lcn != SPARSE_LCN64 && lcn + len > sbi->used.bitmap.nbits) { 100762306a36Sopenharmony_ci /* LCN range is out of volume. */ 100862306a36Sopenharmony_ci return -EINVAL; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (!run) 101262306a36Sopenharmony_ci ; /* Called from check_attr(fslog.c) to check run. */ 101362306a36Sopenharmony_ci else if (run == RUN_DEALLOCATE) { 101462306a36Sopenharmony_ci /* 101562306a36Sopenharmony_ci * Called from ni_delete_all to free clusters 101662306a36Sopenharmony_ci * without storing in run. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci if (lcn != SPARSE_LCN64) 101962306a36Sopenharmony_ci mark_as_free_ex(sbi, lcn, len, true); 102062306a36Sopenharmony_ci } else if (vcn64 >= vcn) { 102162306a36Sopenharmony_ci if (!run_add_entry(run, vcn64, lcn, len, is_mft)) 102262306a36Sopenharmony_ci return -ENOMEM; 102362306a36Sopenharmony_ci } else if (next_vcn > vcn) { 102462306a36Sopenharmony_ci u64 dlen = vcn - vcn64; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (!run_add_entry(run, vcn, lcn + dlen, len - dlen, 102762306a36Sopenharmony_ci is_mft)) 102862306a36Sopenharmony_ci return -ENOMEM; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci vcn64 = next_vcn; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if (vcn64 != evcn + 1) { 103562306a36Sopenharmony_ci /* Not expected length of unpacked runs. */ 103662306a36Sopenharmony_ci return -EINVAL; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return run_buf - run_0; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci#ifdef NTFS3_CHECK_FREE_CLST 104362306a36Sopenharmony_ci/* 104462306a36Sopenharmony_ci * run_unpack_ex - Unpack packed runs from "run_buf". 104562306a36Sopenharmony_ci * 104662306a36Sopenharmony_ci * Checks unpacked runs to be used in bitmap. 104762306a36Sopenharmony_ci * 104862306a36Sopenharmony_ci * Return: Error if negative, or real used bytes. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ciint run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino, 105162306a36Sopenharmony_ci CLST svcn, CLST evcn, CLST vcn, const u8 *run_buf, 105262306a36Sopenharmony_ci int run_buf_size) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci int ret, err; 105562306a36Sopenharmony_ci CLST next_vcn, lcn, len; 105662306a36Sopenharmony_ci size_t index; 105762306a36Sopenharmony_ci bool ok; 105862306a36Sopenharmony_ci struct wnd_bitmap *wnd; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci ret = run_unpack(run, sbi, ino, svcn, evcn, vcn, run_buf, run_buf_size); 106162306a36Sopenharmony_ci if (ret <= 0) 106262306a36Sopenharmony_ci return ret; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (!sbi->used.bitmap.sb || !run || run == RUN_DEALLOCATE) 106562306a36Sopenharmony_ci return ret; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (ino == MFT_REC_BADCLUST) 106862306a36Sopenharmony_ci return ret; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci next_vcn = vcn = svcn; 107162306a36Sopenharmony_ci wnd = &sbi->used.bitmap; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci for (ok = run_lookup_entry(run, vcn, &lcn, &len, &index); 107462306a36Sopenharmony_ci next_vcn <= evcn; 107562306a36Sopenharmony_ci ok = run_get_entry(run, ++index, &vcn, &lcn, &len)) { 107662306a36Sopenharmony_ci if (!ok || next_vcn != vcn) 107762306a36Sopenharmony_ci return -EINVAL; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci next_vcn = vcn + len; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if (lcn == SPARSE_LCN) 108262306a36Sopenharmony_ci continue; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci if (sbi->flags & NTFS_FLAGS_NEED_REPLAY) 108562306a36Sopenharmony_ci continue; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci down_read_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS); 108862306a36Sopenharmony_ci /* Check for free blocks. */ 108962306a36Sopenharmony_ci ok = wnd_is_used(wnd, lcn, len); 109062306a36Sopenharmony_ci up_read(&wnd->rw_lock); 109162306a36Sopenharmony_ci if (ok) 109262306a36Sopenharmony_ci continue; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* Looks like volume is corrupted. */ 109562306a36Sopenharmony_ci ntfs_set_state(sbi, NTFS_DIRTY_ERROR); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (down_write_trylock(&wnd->rw_lock)) { 109862306a36Sopenharmony_ci /* Mark all zero bits as used in range [lcn, lcn+len). */ 109962306a36Sopenharmony_ci size_t done; 110062306a36Sopenharmony_ci err = wnd_set_used_safe(wnd, lcn, len, &done); 110162306a36Sopenharmony_ci up_write(&wnd->rw_lock); 110262306a36Sopenharmony_ci if (err) 110362306a36Sopenharmony_ci return err; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci return ret; 110862306a36Sopenharmony_ci} 110962306a36Sopenharmony_ci#endif 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci/* 111262306a36Sopenharmony_ci * run_get_highest_vcn 111362306a36Sopenharmony_ci * 111462306a36Sopenharmony_ci * Return the highest vcn from a mapping pairs array 111562306a36Sopenharmony_ci * it used while replaying log file. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ciint run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci u64 vcn64 = vcn; 112062306a36Sopenharmony_ci u8 size_size; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci while ((size_size = *run_buf & 0xF)) { 112362306a36Sopenharmony_ci u8 offset_size = *run_buf++ >> 4; 112462306a36Sopenharmony_ci u64 len; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci if (size_size > 8 || offset_size > 8) 112762306a36Sopenharmony_ci return -EINVAL; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci len = run_unpack_s64(run_buf, size_size, 0); 113062306a36Sopenharmony_ci if (!len) 113162306a36Sopenharmony_ci return -EINVAL; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci run_buf += size_size + offset_size; 113462306a36Sopenharmony_ci vcn64 += len; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci#ifndef CONFIG_NTFS3_64BIT_CLUSTER 113762306a36Sopenharmony_ci if (vcn64 > 0x100000000ull) 113862306a36Sopenharmony_ci return -EINVAL; 113962306a36Sopenharmony_ci#endif 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci *highest_vcn = vcn64 - 1; 114362306a36Sopenharmony_ci return 0; 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci/* 114762306a36Sopenharmony_ci * run_clone 114862306a36Sopenharmony_ci * 114962306a36Sopenharmony_ci * Make a copy of run 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_ciint run_clone(const struct runs_tree *run, struct runs_tree *new_run) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci size_t bytes = run->count * sizeof(struct ntfs_run); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (bytes > new_run->allocated) { 115662306a36Sopenharmony_ci struct ntfs_run *new_ptr = kvmalloc(bytes, GFP_KERNEL); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci if (!new_ptr) 115962306a36Sopenharmony_ci return -ENOMEM; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci kvfree(new_run->runs); 116262306a36Sopenharmony_ci new_run->runs = new_ptr; 116362306a36Sopenharmony_ci new_run->allocated = bytes; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci memcpy(new_run->runs, run->runs, bytes); 116762306a36Sopenharmony_ci new_run->count = run->count; 116862306a36Sopenharmony_ci return 0; 116962306a36Sopenharmony_ci} 1170