162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2001-2007 Anton Altaparmakov 662306a36Sopenharmony_ci * Copyright (c) 2002-2005 Richard Russon 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "debug.h" 1062306a36Sopenharmony_ci#include "dir.h" 1162306a36Sopenharmony_ci#include "endian.h" 1262306a36Sopenharmony_ci#include "malloc.h" 1362306a36Sopenharmony_ci#include "ntfs.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/** 1662306a36Sopenharmony_ci * ntfs_rl_mm - runlist memmove 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlist @base. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_cistatic inline void ntfs_rl_mm(runlist_element *base, int dst, int src, 2162306a36Sopenharmony_ci int size) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci if (likely((dst != src) && (size > 0))) 2462306a36Sopenharmony_ci memmove(base + dst, base + src, size * sizeof(*base)); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/** 2862306a36Sopenharmony_ci * ntfs_rl_mc - runlist memory copy 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dstbase and 3162306a36Sopenharmony_ci * @srcbase. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_cistatic inline void ntfs_rl_mc(runlist_element *dstbase, int dst, 3462306a36Sopenharmony_ci runlist_element *srcbase, int src, int size) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci if (likely(size > 0)) 3762306a36Sopenharmony_ci memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase)); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/** 4162306a36Sopenharmony_ci * ntfs_rl_realloc - Reallocate memory for runlists 4262306a36Sopenharmony_ci * @rl: original runlist 4362306a36Sopenharmony_ci * @old_size: number of runlist elements in the original runlist @rl 4462306a36Sopenharmony_ci * @new_size: number of runlist elements we need space for 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * As the runlists grow, more memory will be required. To prevent the 4762306a36Sopenharmony_ci * kernel having to allocate and reallocate large numbers of small bits of 4862306a36Sopenharmony_ci * memory, this function returns an entire page of memory. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlist @rl. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * N.B. If the new allocation doesn't require a different number of pages in 5362306a36Sopenharmony_ci * memory, the function will return the original pointer. 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * On success, return a pointer to the newly allocated, or recycled, memory. 5662306a36Sopenharmony_ci * On error, return -errno. The following error codes are defined: 5762306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 5862306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic inline runlist_element *ntfs_rl_realloc(runlist_element *rl, 6162306a36Sopenharmony_ci int old_size, int new_size) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci runlist_element *new_rl; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci old_size = PAGE_ALIGN(old_size * sizeof(*rl)); 6662306a36Sopenharmony_ci new_size = PAGE_ALIGN(new_size * sizeof(*rl)); 6762306a36Sopenharmony_ci if (old_size == new_size) 6862306a36Sopenharmony_ci return rl; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci new_rl = ntfs_malloc_nofs(new_size); 7162306a36Sopenharmony_ci if (unlikely(!new_rl)) 7262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (likely(rl != NULL)) { 7562306a36Sopenharmony_ci if (unlikely(old_size > new_size)) 7662306a36Sopenharmony_ci old_size = new_size; 7762306a36Sopenharmony_ci memcpy(new_rl, rl, old_size); 7862306a36Sopenharmony_ci ntfs_free(rl); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci return new_rl; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/** 8462306a36Sopenharmony_ci * ntfs_rl_realloc_nofail - Reallocate memory for runlists 8562306a36Sopenharmony_ci * @rl: original runlist 8662306a36Sopenharmony_ci * @old_size: number of runlist elements in the original runlist @rl 8762306a36Sopenharmony_ci * @new_size: number of runlist elements we need space for 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * As the runlists grow, more memory will be required. To prevent the 9062306a36Sopenharmony_ci * kernel having to allocate and reallocate large numbers of small bits of 9162306a36Sopenharmony_ci * memory, this function returns an entire page of memory. 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * This function guarantees that the allocation will succeed. It will sleep 9462306a36Sopenharmony_ci * for as long as it takes to complete the allocation. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlist @rl. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * N.B. If the new allocation doesn't require a different number of pages in 9962306a36Sopenharmony_ci * memory, the function will return the original pointer. 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * On success, return a pointer to the newly allocated, or recycled, memory. 10262306a36Sopenharmony_ci * On error, return -errno. The following error codes are defined: 10362306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 10462306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic inline runlist_element *ntfs_rl_realloc_nofail(runlist_element *rl, 10762306a36Sopenharmony_ci int old_size, int new_size) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci runlist_element *new_rl; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci old_size = PAGE_ALIGN(old_size * sizeof(*rl)); 11262306a36Sopenharmony_ci new_size = PAGE_ALIGN(new_size * sizeof(*rl)); 11362306a36Sopenharmony_ci if (old_size == new_size) 11462306a36Sopenharmony_ci return rl; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci new_rl = ntfs_malloc_nofs_nofail(new_size); 11762306a36Sopenharmony_ci BUG_ON(!new_rl); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (likely(rl != NULL)) { 12062306a36Sopenharmony_ci if (unlikely(old_size > new_size)) 12162306a36Sopenharmony_ci old_size = new_size; 12262306a36Sopenharmony_ci memcpy(new_rl, rl, old_size); 12362306a36Sopenharmony_ci ntfs_free(rl); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci return new_rl; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/** 12962306a36Sopenharmony_ci * ntfs_are_rl_mergeable - test if two runlists can be joined together 13062306a36Sopenharmony_ci * @dst: original runlist 13162306a36Sopenharmony_ci * @src: new runlist to test for mergeability with @dst 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * Test if two runlists can be joined together. For this, their VCNs and LCNs 13462306a36Sopenharmony_ci * must be adjacent. 13562306a36Sopenharmony_ci * 13662306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Return: true Success, the runlists can be merged. 13962306a36Sopenharmony_ci * false Failure, the runlists cannot be merged. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_cistatic inline bool ntfs_are_rl_mergeable(runlist_element *dst, 14262306a36Sopenharmony_ci runlist_element *src) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci BUG_ON(!dst); 14562306a36Sopenharmony_ci BUG_ON(!src); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* We can merge unmapped regions even if they are misaligned. */ 14862306a36Sopenharmony_ci if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED)) 14962306a36Sopenharmony_ci return true; 15062306a36Sopenharmony_ci /* If the runs are misaligned, we cannot merge them. */ 15162306a36Sopenharmony_ci if ((dst->vcn + dst->length) != src->vcn) 15262306a36Sopenharmony_ci return false; 15362306a36Sopenharmony_ci /* If both runs are non-sparse and contiguous, we can merge them. */ 15462306a36Sopenharmony_ci if ((dst->lcn >= 0) && (src->lcn >= 0) && 15562306a36Sopenharmony_ci ((dst->lcn + dst->length) == src->lcn)) 15662306a36Sopenharmony_ci return true; 15762306a36Sopenharmony_ci /* If we are merging two holes, we can merge them. */ 15862306a36Sopenharmony_ci if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE)) 15962306a36Sopenharmony_ci return true; 16062306a36Sopenharmony_ci /* Cannot merge. */ 16162306a36Sopenharmony_ci return false; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/** 16562306a36Sopenharmony_ci * __ntfs_rl_merge - merge two runlists without testing if they can be merged 16662306a36Sopenharmony_ci * @dst: original, destination runlist 16762306a36Sopenharmony_ci * @src: new runlist to merge with @dst 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * Merge the two runlists, writing into the destination runlist @dst. The 17062306a36Sopenharmony_ci * caller must make sure the runlists can be merged or this will corrupt the 17162306a36Sopenharmony_ci * destination runlist. 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistatic inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci dst->length += src->length; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/** 18162306a36Sopenharmony_ci * ntfs_rl_append - append a runlist after a given element 18262306a36Sopenharmony_ci * @dst: original runlist to be worked on 18362306a36Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 18462306a36Sopenharmony_ci * @src: runlist to be inserted into @dst 18562306a36Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 18662306a36Sopenharmony_ci * @loc: append the new runlist @src after this element in @dst 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * Append the runlist @src after element @loc in @dst. Merge the right end of 18962306a36Sopenharmony_ci * the new runlist, if necessary. Adjust the size of the hole before the 19062306a36Sopenharmony_ci * appended runlist. 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 19362306a36Sopenharmony_ci * 19462306a36Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 19562306a36Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 19662306a36Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 19762306a36Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 20062306a36Sopenharmony_ci * error codes are defined: 20162306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 20262306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_cistatic inline runlist_element *ntfs_rl_append(runlist_element *dst, 20562306a36Sopenharmony_ci int dsize, runlist_element *src, int ssize, int loc) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci bool right = false; /* Right end of @src needs merging. */ 20862306a36Sopenharmony_ci int marker; /* End of the inserted runs. */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci BUG_ON(!dst); 21162306a36Sopenharmony_ci BUG_ON(!src); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* First, check if the right hand end needs merging. */ 21462306a36Sopenharmony_ci if ((loc + 1) < dsize) 21562306a36Sopenharmony_ci right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci /* Space required: @dst size + @src size, less one if we merged. */ 21862306a36Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right); 21962306a36Sopenharmony_ci if (IS_ERR(dst)) 22062306a36Sopenharmony_ci return dst; 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 22362306a36Sopenharmony_ci * original runlists. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* First, merge the right hand end, if necessary. */ 22762306a36Sopenharmony_ci if (right) 22862306a36Sopenharmony_ci __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* First run after the @src runs that have been inserted. */ 23162306a36Sopenharmony_ci marker = loc + ssize + 1; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 23462306a36Sopenharmony_ci ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - (loc + 1 + right)); 23562306a36Sopenharmony_ci ntfs_rl_mc(dst, loc + 1, src, 0, ssize); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Adjust the size of the preceding hole. */ 23862306a36Sopenharmony_ci dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* We may have changed the length of the file, so fix the end marker */ 24162306a36Sopenharmony_ci if (dst[marker].lcn == LCN_ENOENT) 24262306a36Sopenharmony_ci dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return dst; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * ntfs_rl_insert - insert a runlist into another 24962306a36Sopenharmony_ci * @dst: original runlist to be worked on 25062306a36Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 25162306a36Sopenharmony_ci * @src: new runlist to be inserted 25262306a36Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 25362306a36Sopenharmony_ci * @loc: insert the new runlist @src before this element in @dst 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * Insert the runlist @src before element @loc in the runlist @dst. Merge the 25662306a36Sopenharmony_ci * left end of the new runlist, if necessary. Adjust the size of the hole 25762306a36Sopenharmony_ci * after the inserted runlist. 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 26262306a36Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 26362306a36Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 26462306a36Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 26762306a36Sopenharmony_ci * error codes are defined: 26862306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 26962306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_cistatic inline runlist_element *ntfs_rl_insert(runlist_element *dst, 27262306a36Sopenharmony_ci int dsize, runlist_element *src, int ssize, int loc) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci bool left = false; /* Left end of @src needs merging. */ 27562306a36Sopenharmony_ci bool disc = false; /* Discontinuity between @dst and @src. */ 27662306a36Sopenharmony_ci int marker; /* End of the inserted runs. */ 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci BUG_ON(!dst); 27962306a36Sopenharmony_ci BUG_ON(!src); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * disc => Discontinuity between the end of @dst and the start of @src. 28362306a36Sopenharmony_ci * This means we might need to insert a "not mapped" run. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci if (loc == 0) 28662306a36Sopenharmony_ci disc = (src[0].vcn > 0); 28762306a36Sopenharmony_ci else { 28862306a36Sopenharmony_ci s64 merged_length; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci left = ntfs_are_rl_mergeable(dst + loc - 1, src); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci merged_length = dst[loc - 1].length; 29362306a36Sopenharmony_ci if (left) 29462306a36Sopenharmony_ci merged_length += src->length; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci disc = (src[0].vcn > dst[loc - 1].vcn + merged_length); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci /* 29962306a36Sopenharmony_ci * Space required: @dst size + @src size, less one if we merged, plus 30062306a36Sopenharmony_ci * one if there was a discontinuity. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc); 30362306a36Sopenharmony_ci if (IS_ERR(dst)) 30462306a36Sopenharmony_ci return dst; 30562306a36Sopenharmony_ci /* 30662306a36Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 30762306a36Sopenharmony_ci * original runlist. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci if (left) 31062306a36Sopenharmony_ci __ntfs_rl_merge(dst + loc - 1, src); 31162306a36Sopenharmony_ci /* 31262306a36Sopenharmony_ci * First run after the @src runs that have been inserted. 31362306a36Sopenharmony_ci * Nominally, @marker equals @loc + @ssize, i.e. location + number of 31462306a36Sopenharmony_ci * runs in @src. However, if @left, then the first run in @src has 31562306a36Sopenharmony_ci * been merged with one in @dst. And if @disc, then @dst and @src do 31662306a36Sopenharmony_ci * not meet and we need an extra run to fill the gap. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci marker = loc + ssize - left + disc; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 32162306a36Sopenharmony_ci ntfs_rl_mm(dst, marker, loc, dsize - loc); 32262306a36Sopenharmony_ci ntfs_rl_mc(dst, loc + disc, src, left, ssize - left); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Adjust the VCN of the first run after the insertion... */ 32562306a36Sopenharmony_ci dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; 32662306a36Sopenharmony_ci /* ... and the length. */ 32762306a36Sopenharmony_ci if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED) 32862306a36Sopenharmony_ci dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Writing beyond the end of the file and there is a discontinuity. */ 33162306a36Sopenharmony_ci if (disc) { 33262306a36Sopenharmony_ci if (loc > 0) { 33362306a36Sopenharmony_ci dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length; 33462306a36Sopenharmony_ci dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; 33562306a36Sopenharmony_ci } else { 33662306a36Sopenharmony_ci dst[loc].vcn = 0; 33762306a36Sopenharmony_ci dst[loc].length = dst[loc + 1].vcn; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci dst[loc].lcn = LCN_RL_NOT_MAPPED; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci return dst; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/** 34562306a36Sopenharmony_ci * ntfs_rl_replace - overwrite a runlist element with another runlist 34662306a36Sopenharmony_ci * @dst: original runlist to be worked on 34762306a36Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 34862306a36Sopenharmony_ci * @src: new runlist to be inserted 34962306a36Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 35062306a36Sopenharmony_ci * @loc: index in runlist @dst to overwrite with @src 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * Replace the runlist element @dst at @loc with @src. Merge the left and 35362306a36Sopenharmony_ci * right ends of the inserted runlist, if necessary. 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 35862306a36Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 35962306a36Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 36062306a36Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 36162306a36Sopenharmony_ci * 36262306a36Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 36362306a36Sopenharmony_ci * error codes are defined: 36462306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 36562306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_cistatic inline runlist_element *ntfs_rl_replace(runlist_element *dst, 36862306a36Sopenharmony_ci int dsize, runlist_element *src, int ssize, int loc) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci signed delta; 37162306a36Sopenharmony_ci bool left = false; /* Left end of @src needs merging. */ 37262306a36Sopenharmony_ci bool right = false; /* Right end of @src needs merging. */ 37362306a36Sopenharmony_ci int tail; /* Start of tail of @dst. */ 37462306a36Sopenharmony_ci int marker; /* End of the inserted runs. */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci BUG_ON(!dst); 37762306a36Sopenharmony_ci BUG_ON(!src); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* First, see if the left and right ends need merging. */ 38062306a36Sopenharmony_ci if ((loc + 1) < dsize) 38162306a36Sopenharmony_ci right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); 38262306a36Sopenharmony_ci if (loc > 0) 38362306a36Sopenharmony_ci left = ntfs_are_rl_mergeable(dst + loc - 1, src); 38462306a36Sopenharmony_ci /* 38562306a36Sopenharmony_ci * Allocate some space. We will need less if the left, right, or both 38662306a36Sopenharmony_ci * ends get merged. The -1 accounts for the run being replaced. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ci delta = ssize - 1 - left - right; 38962306a36Sopenharmony_ci if (delta > 0) { 39062306a36Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + delta); 39162306a36Sopenharmony_ci if (IS_ERR(dst)) 39262306a36Sopenharmony_ci return dst; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci /* 39562306a36Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 39662306a36Sopenharmony_ci * original runlists. 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* First, merge the left and right ends, if necessary. */ 40062306a36Sopenharmony_ci if (right) 40162306a36Sopenharmony_ci __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); 40262306a36Sopenharmony_ci if (left) 40362306a36Sopenharmony_ci __ntfs_rl_merge(dst + loc - 1, src); 40462306a36Sopenharmony_ci /* 40562306a36Sopenharmony_ci * Offset of the tail of @dst. This needs to be moved out of the way 40662306a36Sopenharmony_ci * to make space for the runs to be copied from @src, i.e. the first 40762306a36Sopenharmony_ci * run of the tail of @dst. 40862306a36Sopenharmony_ci * Nominally, @tail equals @loc + 1, i.e. location, skipping the 40962306a36Sopenharmony_ci * replaced run. However, if @right, then one of @dst's runs is 41062306a36Sopenharmony_ci * already merged into @src. 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci tail = loc + right + 1; 41362306a36Sopenharmony_ci /* 41462306a36Sopenharmony_ci * First run after the @src runs that have been inserted, i.e. where 41562306a36Sopenharmony_ci * the tail of @dst needs to be moved to. 41662306a36Sopenharmony_ci * Nominally, @marker equals @loc + @ssize, i.e. location + number of 41762306a36Sopenharmony_ci * runs in @src. However, if @left, then the first run in @src has 41862306a36Sopenharmony_ci * been merged with one in @dst. 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci marker = loc + ssize - left; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 42362306a36Sopenharmony_ci ntfs_rl_mm(dst, marker, tail, dsize - tail); 42462306a36Sopenharmony_ci ntfs_rl_mc(dst, loc, src, left, ssize - left); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* We may have changed the length of the file, so fix the end marker. */ 42762306a36Sopenharmony_ci if (dsize - tail > 0 && dst[marker].lcn == LCN_ENOENT) 42862306a36Sopenharmony_ci dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; 42962306a36Sopenharmony_ci return dst; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci/** 43362306a36Sopenharmony_ci * ntfs_rl_split - insert a runlist into the centre of a hole 43462306a36Sopenharmony_ci * @dst: original runlist to be worked on 43562306a36Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 43662306a36Sopenharmony_ci * @src: new runlist to be inserted 43762306a36Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 43862306a36Sopenharmony_ci * @loc: index in runlist @dst at which to split and insert @src 43962306a36Sopenharmony_ci * 44062306a36Sopenharmony_ci * Split the runlist @dst at @loc into two and insert @new in between the two 44162306a36Sopenharmony_ci * fragments. No merging of runlists is necessary. Adjust the size of the 44262306a36Sopenharmony_ci * holes either side. 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 44762306a36Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 44862306a36Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 44962306a36Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 45262306a36Sopenharmony_ci * error codes are defined: 45362306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 45462306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_cistatic inline runlist_element *ntfs_rl_split(runlist_element *dst, int dsize, 45762306a36Sopenharmony_ci runlist_element *src, int ssize, int loc) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci BUG_ON(!dst); 46062306a36Sopenharmony_ci BUG_ON(!src); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Space required: @dst size + @src size + one new hole. */ 46362306a36Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1); 46462306a36Sopenharmony_ci if (IS_ERR(dst)) 46562306a36Sopenharmony_ci return dst; 46662306a36Sopenharmony_ci /* 46762306a36Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 46862306a36Sopenharmony_ci * original runlists. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 47262306a36Sopenharmony_ci ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc); 47362306a36Sopenharmony_ci ntfs_rl_mc(dst, loc + 1, src, 0, ssize); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Adjust the size of the holes either size of @src. */ 47662306a36Sopenharmony_ci dst[loc].length = dst[loc+1].vcn - dst[loc].vcn; 47762306a36Sopenharmony_ci dst[loc+ssize+1].vcn = dst[loc+ssize].vcn + dst[loc+ssize].length; 47862306a36Sopenharmony_ci dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci return dst; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci/** 48462306a36Sopenharmony_ci * ntfs_runlists_merge - merge two runlists into one 48562306a36Sopenharmony_ci * @drl: original runlist to be worked on 48662306a36Sopenharmony_ci * @srl: new runlist to be merged into @drl 48762306a36Sopenharmony_ci * 48862306a36Sopenharmony_ci * First we sanity check the two runlists @srl and @drl to make sure that they 48962306a36Sopenharmony_ci * are sensible and can be merged. The runlist @srl must be either after the 49062306a36Sopenharmony_ci * runlist @drl or completely within a hole (or unmapped region) in @drl. 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlists @drl and @srl. 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * Merging of runlists is necessary in two cases: 49562306a36Sopenharmony_ci * 1. When attribute lists are used and a further extent is being mapped. 49662306a36Sopenharmony_ci * 2. When new clusters are allocated to fill a hole or extend a file. 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * There are four possible ways @srl can be merged. It can: 49962306a36Sopenharmony_ci * - be inserted at the beginning of a hole, 50062306a36Sopenharmony_ci * - split the hole in two and be inserted between the two fragments, 50162306a36Sopenharmony_ci * - be appended at the end of a hole, or it can 50262306a36Sopenharmony_ci * - replace the whole hole. 50362306a36Sopenharmony_ci * It can also be appended to the end of the runlist, which is just a variant 50462306a36Sopenharmony_ci * of the insert case. 50562306a36Sopenharmony_ci * 50662306a36Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 50762306a36Sopenharmony_ci * runlists @drl and @srl are deallocated before returning so you cannot use 50862306a36Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 50962306a36Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 51262306a36Sopenharmony_ci * error codes are defined: 51362306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 51462306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 51562306a36Sopenharmony_ci * -ERANGE - The runlists overlap and cannot be merged. 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_cirunlist_element *ntfs_runlists_merge(runlist_element *drl, 51862306a36Sopenharmony_ci runlist_element *srl) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci int di, si; /* Current index into @[ds]rl. */ 52162306a36Sopenharmony_ci int sstart; /* First index with lcn > LCN_RL_NOT_MAPPED. */ 52262306a36Sopenharmony_ci int dins; /* Index into @drl at which to insert @srl. */ 52362306a36Sopenharmony_ci int dend, send; /* Last index into @[ds]rl. */ 52462306a36Sopenharmony_ci int dfinal, sfinal; /* The last index into @[ds]rl with 52562306a36Sopenharmony_ci lcn >= LCN_HOLE. */ 52662306a36Sopenharmony_ci int marker = 0; 52762306a36Sopenharmony_ci VCN marker_vcn = 0; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci#ifdef DEBUG 53062306a36Sopenharmony_ci ntfs_debug("dst:"); 53162306a36Sopenharmony_ci ntfs_debug_dump_runlist(drl); 53262306a36Sopenharmony_ci ntfs_debug("src:"); 53362306a36Sopenharmony_ci ntfs_debug_dump_runlist(srl); 53462306a36Sopenharmony_ci#endif 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Check for silly calling... */ 53762306a36Sopenharmony_ci if (unlikely(!srl)) 53862306a36Sopenharmony_ci return drl; 53962306a36Sopenharmony_ci if (IS_ERR(srl) || IS_ERR(drl)) 54062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* Check for the case where the first mapping is being done now. */ 54362306a36Sopenharmony_ci if (unlikely(!drl)) { 54462306a36Sopenharmony_ci drl = srl; 54562306a36Sopenharmony_ci /* Complete the source runlist if necessary. */ 54662306a36Sopenharmony_ci if (unlikely(drl[0].vcn)) { 54762306a36Sopenharmony_ci /* Scan to the end of the source runlist. */ 54862306a36Sopenharmony_ci for (dend = 0; likely(drl[dend].length); dend++) 54962306a36Sopenharmony_ci ; 55062306a36Sopenharmony_ci dend++; 55162306a36Sopenharmony_ci drl = ntfs_rl_realloc(drl, dend, dend + 1); 55262306a36Sopenharmony_ci if (IS_ERR(drl)) 55362306a36Sopenharmony_ci return drl; 55462306a36Sopenharmony_ci /* Insert start element at the front of the runlist. */ 55562306a36Sopenharmony_ci ntfs_rl_mm(drl, 1, 0, dend); 55662306a36Sopenharmony_ci drl[0].vcn = 0; 55762306a36Sopenharmony_ci drl[0].lcn = LCN_RL_NOT_MAPPED; 55862306a36Sopenharmony_ci drl[0].length = drl[1].vcn; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci goto finished; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci si = di = 0; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Skip any unmapped start element(s) in the source runlist. */ 56662306a36Sopenharmony_ci while (srl[si].length && srl[si].lcn < LCN_HOLE) 56762306a36Sopenharmony_ci si++; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Can't have an entirely unmapped source runlist. */ 57062306a36Sopenharmony_ci BUG_ON(!srl[si].length); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Record the starting points. */ 57362306a36Sopenharmony_ci sstart = si; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* 57662306a36Sopenharmony_ci * Skip forward in @drl until we reach the position where @srl needs to 57762306a36Sopenharmony_ci * be inserted. If we reach the end of @drl, @srl just needs to be 57862306a36Sopenharmony_ci * appended to @drl. 57962306a36Sopenharmony_ci */ 58062306a36Sopenharmony_ci for (; drl[di].length; di++) { 58162306a36Sopenharmony_ci if (drl[di].vcn + drl[di].length > srl[sstart].vcn) 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci dins = di; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* Sanity check for illegal overlaps. */ 58762306a36Sopenharmony_ci if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) && 58862306a36Sopenharmony_ci (srl[si].lcn >= 0)) { 58962306a36Sopenharmony_ci ntfs_error(NULL, "Run lists overlap. Cannot merge!"); 59062306a36Sopenharmony_ci return ERR_PTR(-ERANGE); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Scan to the end of both runlists in order to know their sizes. */ 59462306a36Sopenharmony_ci for (send = si; srl[send].length; send++) 59562306a36Sopenharmony_ci ; 59662306a36Sopenharmony_ci for (dend = di; drl[dend].length; dend++) 59762306a36Sopenharmony_ci ; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if (srl[send].lcn == LCN_ENOENT) 60062306a36Sopenharmony_ci marker_vcn = srl[marker = send].vcn; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Scan to the last element with lcn >= LCN_HOLE. */ 60362306a36Sopenharmony_ci for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--) 60462306a36Sopenharmony_ci ; 60562306a36Sopenharmony_ci for (dfinal = dend; dfinal >= 0 && drl[dfinal].lcn < LCN_HOLE; dfinal--) 60662306a36Sopenharmony_ci ; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci { 60962306a36Sopenharmony_ci bool start; 61062306a36Sopenharmony_ci bool finish; 61162306a36Sopenharmony_ci int ds = dend + 1; /* Number of elements in drl & srl */ 61262306a36Sopenharmony_ci int ss = sfinal - sstart + 1; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci start = ((drl[dins].lcn < LCN_RL_NOT_MAPPED) || /* End of file */ 61562306a36Sopenharmony_ci (drl[dins].vcn == srl[sstart].vcn)); /* Start of hole */ 61662306a36Sopenharmony_ci finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) && /* End of file */ 61762306a36Sopenharmony_ci ((drl[dins].vcn + drl[dins].length) <= /* End of hole */ 61862306a36Sopenharmony_ci (srl[send - 1].vcn + srl[send - 1].length))); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* Or we will lose an end marker. */ 62162306a36Sopenharmony_ci if (finish && !drl[dins].length) 62262306a36Sopenharmony_ci ss++; 62362306a36Sopenharmony_ci if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn)) 62462306a36Sopenharmony_ci finish = false; 62562306a36Sopenharmony_ci#if 0 62662306a36Sopenharmony_ci ntfs_debug("dfinal = %i, dend = %i", dfinal, dend); 62762306a36Sopenharmony_ci ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send); 62862306a36Sopenharmony_ci ntfs_debug("start = %i, finish = %i", start, finish); 62962306a36Sopenharmony_ci ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins); 63062306a36Sopenharmony_ci#endif 63162306a36Sopenharmony_ci if (start) { 63262306a36Sopenharmony_ci if (finish) 63362306a36Sopenharmony_ci drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins); 63462306a36Sopenharmony_ci else 63562306a36Sopenharmony_ci drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins); 63662306a36Sopenharmony_ci } else { 63762306a36Sopenharmony_ci if (finish) 63862306a36Sopenharmony_ci drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins); 63962306a36Sopenharmony_ci else 64062306a36Sopenharmony_ci drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci if (IS_ERR(drl)) { 64362306a36Sopenharmony_ci ntfs_error(NULL, "Merge failed."); 64462306a36Sopenharmony_ci return drl; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci ntfs_free(srl); 64762306a36Sopenharmony_ci if (marker) { 64862306a36Sopenharmony_ci ntfs_debug("Triggering marker code."); 64962306a36Sopenharmony_ci for (ds = dend; drl[ds].length; ds++) 65062306a36Sopenharmony_ci ; 65162306a36Sopenharmony_ci /* We only need to care if @srl ended after @drl. */ 65262306a36Sopenharmony_ci if (drl[ds].vcn <= marker_vcn) { 65362306a36Sopenharmony_ci int slots = 0; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (drl[ds].vcn == marker_vcn) { 65662306a36Sopenharmony_ci ntfs_debug("Old marker = 0x%llx, replacing " 65762306a36Sopenharmony_ci "with LCN_ENOENT.", 65862306a36Sopenharmony_ci (unsigned long long) 65962306a36Sopenharmony_ci drl[ds].lcn); 66062306a36Sopenharmony_ci drl[ds].lcn = LCN_ENOENT; 66162306a36Sopenharmony_ci goto finished; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci /* 66462306a36Sopenharmony_ci * We need to create an unmapped runlist element in 66562306a36Sopenharmony_ci * @drl or extend an existing one before adding the 66662306a36Sopenharmony_ci * ENOENT terminator. 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ci if (drl[ds].lcn == LCN_ENOENT) { 66962306a36Sopenharmony_ci ds--; 67062306a36Sopenharmony_ci slots = 1; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci if (drl[ds].lcn != LCN_RL_NOT_MAPPED) { 67362306a36Sopenharmony_ci /* Add an unmapped runlist element. */ 67462306a36Sopenharmony_ci if (!slots) { 67562306a36Sopenharmony_ci drl = ntfs_rl_realloc_nofail(drl, ds, 67662306a36Sopenharmony_ci ds + 2); 67762306a36Sopenharmony_ci slots = 2; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci ds++; 68062306a36Sopenharmony_ci /* Need to set vcn if it isn't set already. */ 68162306a36Sopenharmony_ci if (slots != 1) 68262306a36Sopenharmony_ci drl[ds].vcn = drl[ds - 1].vcn + 68362306a36Sopenharmony_ci drl[ds - 1].length; 68462306a36Sopenharmony_ci drl[ds].lcn = LCN_RL_NOT_MAPPED; 68562306a36Sopenharmony_ci /* We now used up a slot. */ 68662306a36Sopenharmony_ci slots--; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci drl[ds].length = marker_vcn - drl[ds].vcn; 68962306a36Sopenharmony_ci /* Finally add the ENOENT terminator. */ 69062306a36Sopenharmony_ci ds++; 69162306a36Sopenharmony_ci if (!slots) 69262306a36Sopenharmony_ci drl = ntfs_rl_realloc_nofail(drl, ds, ds + 1); 69362306a36Sopenharmony_ci drl[ds].vcn = marker_vcn; 69462306a36Sopenharmony_ci drl[ds].lcn = LCN_ENOENT; 69562306a36Sopenharmony_ci drl[ds].length = (s64)0; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cifinished: 70162306a36Sopenharmony_ci /* The merge was completed successfully. */ 70262306a36Sopenharmony_ci ntfs_debug("Merged runlist:"); 70362306a36Sopenharmony_ci ntfs_debug_dump_runlist(drl); 70462306a36Sopenharmony_ci return drl; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci/** 70862306a36Sopenharmony_ci * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist 70962306a36Sopenharmony_ci * @vol: ntfs volume on which the attribute resides 71062306a36Sopenharmony_ci * @attr: attribute record whose mapping pairs array to decompress 71162306a36Sopenharmony_ci * @old_rl: optional runlist in which to insert @attr's runlist 71262306a36Sopenharmony_ci * 71362306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlist @old_rl. 71462306a36Sopenharmony_ci * 71562306a36Sopenharmony_ci * Decompress the attribute @attr's mapping pairs array into a runlist. On 71662306a36Sopenharmony_ci * success, return the decompressed runlist. 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * If @old_rl is not NULL, decompressed runlist is inserted into the 71962306a36Sopenharmony_ci * appropriate place in @old_rl and the resultant, combined runlist is 72062306a36Sopenharmony_ci * returned. The original @old_rl is deallocated. 72162306a36Sopenharmony_ci * 72262306a36Sopenharmony_ci * On error, return -errno. @old_rl is left unmodified in that case. 72362306a36Sopenharmony_ci * 72462306a36Sopenharmony_ci * The following error codes are defined: 72562306a36Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 72662306a36Sopenharmony_ci * -EIO - Corrupt runlist. 72762306a36Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 72862306a36Sopenharmony_ci * -ERANGE - The two runlists overlap. 72962306a36Sopenharmony_ci * 73062306a36Sopenharmony_ci * FIXME: For now we take the conceptionally simplest approach of creating the 73162306a36Sopenharmony_ci * new runlist disregarding the already existing one and then splicing the 73262306a36Sopenharmony_ci * two into one, if that is possible (we check for overlap and discard the new 73362306a36Sopenharmony_ci * runlist if overlap present before returning ERR_PTR(-ERANGE)). 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_cirunlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, 73662306a36Sopenharmony_ci const ATTR_RECORD *attr, runlist_element *old_rl) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci VCN vcn; /* Current vcn. */ 73962306a36Sopenharmony_ci LCN lcn; /* Current lcn. */ 74062306a36Sopenharmony_ci s64 deltaxcn; /* Change in [vl]cn. */ 74162306a36Sopenharmony_ci runlist_element *rl; /* The output runlist. */ 74262306a36Sopenharmony_ci u8 *buf; /* Current position in mapping pairs array. */ 74362306a36Sopenharmony_ci u8 *attr_end; /* End of attribute. */ 74462306a36Sopenharmony_ci int rlsize; /* Size of runlist buffer. */ 74562306a36Sopenharmony_ci u16 rlpos; /* Current runlist position in units of 74662306a36Sopenharmony_ci runlist_elements. */ 74762306a36Sopenharmony_ci u8 b; /* Current byte offset in buf. */ 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci#ifdef DEBUG 75062306a36Sopenharmony_ci /* Make sure attr exists and is non-resident. */ 75162306a36Sopenharmony_ci if (!attr || !attr->non_resident || sle64_to_cpu( 75262306a36Sopenharmony_ci attr->data.non_resident.lowest_vcn) < (VCN)0) { 75362306a36Sopenharmony_ci ntfs_error(vol->sb, "Invalid arguments."); 75462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci#endif 75762306a36Sopenharmony_ci /* Start at vcn = lowest_vcn and lcn 0. */ 75862306a36Sopenharmony_ci vcn = sle64_to_cpu(attr->data.non_resident.lowest_vcn); 75962306a36Sopenharmony_ci lcn = 0; 76062306a36Sopenharmony_ci /* Get start of the mapping pairs array. */ 76162306a36Sopenharmony_ci buf = (u8*)attr + le16_to_cpu( 76262306a36Sopenharmony_ci attr->data.non_resident.mapping_pairs_offset); 76362306a36Sopenharmony_ci attr_end = (u8*)attr + le32_to_cpu(attr->length); 76462306a36Sopenharmony_ci if (unlikely(buf < (u8*)attr || buf > attr_end)) { 76562306a36Sopenharmony_ci ntfs_error(vol->sb, "Corrupt attribute."); 76662306a36Sopenharmony_ci return ERR_PTR(-EIO); 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci /* If the mapping pairs array is valid but empty, nothing to do. */ 76962306a36Sopenharmony_ci if (!vcn && !*buf) 77062306a36Sopenharmony_ci return old_rl; 77162306a36Sopenharmony_ci /* Current position in runlist array. */ 77262306a36Sopenharmony_ci rlpos = 0; 77362306a36Sopenharmony_ci /* Allocate first page and set current runlist size to one page. */ 77462306a36Sopenharmony_ci rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE); 77562306a36Sopenharmony_ci if (unlikely(!rl)) 77662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 77762306a36Sopenharmony_ci /* Insert unmapped starting element if necessary. */ 77862306a36Sopenharmony_ci if (vcn) { 77962306a36Sopenharmony_ci rl->vcn = 0; 78062306a36Sopenharmony_ci rl->lcn = LCN_RL_NOT_MAPPED; 78162306a36Sopenharmony_ci rl->length = vcn; 78262306a36Sopenharmony_ci rlpos++; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci while (buf < attr_end && *buf) { 78562306a36Sopenharmony_ci /* 78662306a36Sopenharmony_ci * Allocate more memory if needed, including space for the 78762306a36Sopenharmony_ci * not-mapped and terminator elements. ntfs_malloc_nofs() 78862306a36Sopenharmony_ci * operates on whole pages only. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) { 79162306a36Sopenharmony_ci runlist_element *rl2; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE); 79462306a36Sopenharmony_ci if (unlikely(!rl2)) { 79562306a36Sopenharmony_ci ntfs_free(rl); 79662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci memcpy(rl2, rl, rlsize); 79962306a36Sopenharmony_ci ntfs_free(rl); 80062306a36Sopenharmony_ci rl = rl2; 80162306a36Sopenharmony_ci rlsize += PAGE_SIZE; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci /* Enter the current vcn into the current runlist element. */ 80462306a36Sopenharmony_ci rl[rlpos].vcn = vcn; 80562306a36Sopenharmony_ci /* 80662306a36Sopenharmony_ci * Get the change in vcn, i.e. the run length in clusters. 80762306a36Sopenharmony_ci * Doing it this way ensures that we signextend negative values. 80862306a36Sopenharmony_ci * A negative run length doesn't make any sense, but hey, I 80962306a36Sopenharmony_ci * didn't make up the NTFS specs and Windows NT4 treats the run 81062306a36Sopenharmony_ci * length as a signed value so that's how it is... 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_ci b = *buf & 0xf; 81362306a36Sopenharmony_ci if (b) { 81462306a36Sopenharmony_ci if (unlikely(buf + b > attr_end)) 81562306a36Sopenharmony_ci goto io_error; 81662306a36Sopenharmony_ci for (deltaxcn = (s8)buf[b--]; b; b--) 81762306a36Sopenharmony_ci deltaxcn = (deltaxcn << 8) + buf[b]; 81862306a36Sopenharmony_ci } else { /* The length entry is compulsory. */ 81962306a36Sopenharmony_ci ntfs_error(vol->sb, "Missing length entry in mapping " 82062306a36Sopenharmony_ci "pairs array."); 82162306a36Sopenharmony_ci deltaxcn = (s64)-1; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci /* 82462306a36Sopenharmony_ci * Assume a negative length to indicate data corruption and 82562306a36Sopenharmony_ci * hence clean-up and return NULL. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci if (unlikely(deltaxcn < 0)) { 82862306a36Sopenharmony_ci ntfs_error(vol->sb, "Invalid length in mapping pairs " 82962306a36Sopenharmony_ci "array."); 83062306a36Sopenharmony_ci goto err_out; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci /* 83362306a36Sopenharmony_ci * Enter the current run length into the current runlist 83462306a36Sopenharmony_ci * element. 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_ci rl[rlpos].length = deltaxcn; 83762306a36Sopenharmony_ci /* Increment the current vcn by the current run length. */ 83862306a36Sopenharmony_ci vcn += deltaxcn; 83962306a36Sopenharmony_ci /* 84062306a36Sopenharmony_ci * There might be no lcn change at all, as is the case for 84162306a36Sopenharmony_ci * sparse clusters on NTFS 3.0+, in which case we set the lcn 84262306a36Sopenharmony_ci * to LCN_HOLE. 84362306a36Sopenharmony_ci */ 84462306a36Sopenharmony_ci if (!(*buf & 0xf0)) 84562306a36Sopenharmony_ci rl[rlpos].lcn = LCN_HOLE; 84662306a36Sopenharmony_ci else { 84762306a36Sopenharmony_ci /* Get the lcn change which really can be negative. */ 84862306a36Sopenharmony_ci u8 b2 = *buf & 0xf; 84962306a36Sopenharmony_ci b = b2 + ((*buf >> 4) & 0xf); 85062306a36Sopenharmony_ci if (buf + b > attr_end) 85162306a36Sopenharmony_ci goto io_error; 85262306a36Sopenharmony_ci for (deltaxcn = (s8)buf[b--]; b > b2; b--) 85362306a36Sopenharmony_ci deltaxcn = (deltaxcn << 8) + buf[b]; 85462306a36Sopenharmony_ci /* Change the current lcn to its new value. */ 85562306a36Sopenharmony_ci lcn += deltaxcn; 85662306a36Sopenharmony_ci#ifdef DEBUG 85762306a36Sopenharmony_ci /* 85862306a36Sopenharmony_ci * On NTFS 1.2-, apparently can have lcn == -1 to 85962306a36Sopenharmony_ci * indicate a hole. But we haven't verified ourselves 86062306a36Sopenharmony_ci * whether it is really the lcn or the deltaxcn that is 86162306a36Sopenharmony_ci * -1. So if either is found give us a message so we 86262306a36Sopenharmony_ci * can investigate it further! 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_ci if (vol->major_ver < 3) { 86562306a36Sopenharmony_ci if (unlikely(deltaxcn == (LCN)-1)) 86662306a36Sopenharmony_ci ntfs_error(vol->sb, "lcn delta == -1"); 86762306a36Sopenharmony_ci if (unlikely(lcn == (LCN)-1)) 86862306a36Sopenharmony_ci ntfs_error(vol->sb, "lcn == -1"); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci#endif 87162306a36Sopenharmony_ci /* Check lcn is not below -1. */ 87262306a36Sopenharmony_ci if (unlikely(lcn < (LCN)-1)) { 87362306a36Sopenharmony_ci ntfs_error(vol->sb, "Invalid LCN < -1 in " 87462306a36Sopenharmony_ci "mapping pairs array."); 87562306a36Sopenharmony_ci goto err_out; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci /* Enter the current lcn into the runlist element. */ 87862306a36Sopenharmony_ci rl[rlpos].lcn = lcn; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci /* Get to the next runlist element. */ 88162306a36Sopenharmony_ci rlpos++; 88262306a36Sopenharmony_ci /* Increment the buffer position to the next mapping pair. */ 88362306a36Sopenharmony_ci buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci if (unlikely(buf >= attr_end)) 88662306a36Sopenharmony_ci goto io_error; 88762306a36Sopenharmony_ci /* 88862306a36Sopenharmony_ci * If there is a highest_vcn specified, it must be equal to the final 88962306a36Sopenharmony_ci * vcn in the runlist - 1, or something has gone badly wrong. 89062306a36Sopenharmony_ci */ 89162306a36Sopenharmony_ci deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn); 89262306a36Sopenharmony_ci if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) { 89362306a36Sopenharmony_cimpa_err: 89462306a36Sopenharmony_ci ntfs_error(vol->sb, "Corrupt mapping pairs array in " 89562306a36Sopenharmony_ci "non-resident attribute."); 89662306a36Sopenharmony_ci goto err_out; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci /* Setup not mapped runlist element if this is the base extent. */ 89962306a36Sopenharmony_ci if (!attr->data.non_resident.lowest_vcn) { 90062306a36Sopenharmony_ci VCN max_cluster; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci max_cluster = ((sle64_to_cpu( 90362306a36Sopenharmony_ci attr->data.non_resident.allocated_size) + 90462306a36Sopenharmony_ci vol->cluster_size - 1) >> 90562306a36Sopenharmony_ci vol->cluster_size_bits) - 1; 90662306a36Sopenharmony_ci /* 90762306a36Sopenharmony_ci * A highest_vcn of zero means this is a single extent 90862306a36Sopenharmony_ci * attribute so simply terminate the runlist with LCN_ENOENT). 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci if (deltaxcn) { 91162306a36Sopenharmony_ci /* 91262306a36Sopenharmony_ci * If there is a difference between the highest_vcn and 91362306a36Sopenharmony_ci * the highest cluster, the runlist is either corrupt 91462306a36Sopenharmony_ci * or, more likely, there are more extents following 91562306a36Sopenharmony_ci * this one. 91662306a36Sopenharmony_ci */ 91762306a36Sopenharmony_ci if (deltaxcn < max_cluster) { 91862306a36Sopenharmony_ci ntfs_debug("More extents to follow; deltaxcn " 91962306a36Sopenharmony_ci "= 0x%llx, max_cluster = " 92062306a36Sopenharmony_ci "0x%llx", 92162306a36Sopenharmony_ci (unsigned long long)deltaxcn, 92262306a36Sopenharmony_ci (unsigned long long) 92362306a36Sopenharmony_ci max_cluster); 92462306a36Sopenharmony_ci rl[rlpos].vcn = vcn; 92562306a36Sopenharmony_ci vcn += rl[rlpos].length = max_cluster - 92662306a36Sopenharmony_ci deltaxcn; 92762306a36Sopenharmony_ci rl[rlpos].lcn = LCN_RL_NOT_MAPPED; 92862306a36Sopenharmony_ci rlpos++; 92962306a36Sopenharmony_ci } else if (unlikely(deltaxcn > max_cluster)) { 93062306a36Sopenharmony_ci ntfs_error(vol->sb, "Corrupt attribute. " 93162306a36Sopenharmony_ci "deltaxcn = 0x%llx, " 93262306a36Sopenharmony_ci "max_cluster = 0x%llx", 93362306a36Sopenharmony_ci (unsigned long long)deltaxcn, 93462306a36Sopenharmony_ci (unsigned long long) 93562306a36Sopenharmony_ci max_cluster); 93662306a36Sopenharmony_ci goto mpa_err; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci } 93962306a36Sopenharmony_ci rl[rlpos].lcn = LCN_ENOENT; 94062306a36Sopenharmony_ci } else /* Not the base extent. There may be more extents to follow. */ 94162306a36Sopenharmony_ci rl[rlpos].lcn = LCN_RL_NOT_MAPPED; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* Setup terminating runlist element. */ 94462306a36Sopenharmony_ci rl[rlpos].vcn = vcn; 94562306a36Sopenharmony_ci rl[rlpos].length = (s64)0; 94662306a36Sopenharmony_ci /* If no existing runlist was specified, we are done. */ 94762306a36Sopenharmony_ci if (!old_rl) { 94862306a36Sopenharmony_ci ntfs_debug("Mapping pairs array successfully decompressed:"); 94962306a36Sopenharmony_ci ntfs_debug_dump_runlist(rl); 95062306a36Sopenharmony_ci return rl; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci /* Now combine the new and old runlists checking for overlaps. */ 95362306a36Sopenharmony_ci old_rl = ntfs_runlists_merge(old_rl, rl); 95462306a36Sopenharmony_ci if (!IS_ERR(old_rl)) 95562306a36Sopenharmony_ci return old_rl; 95662306a36Sopenharmony_ci ntfs_free(rl); 95762306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to merge runlists."); 95862306a36Sopenharmony_ci return old_rl; 95962306a36Sopenharmony_ciio_error: 96062306a36Sopenharmony_ci ntfs_error(vol->sb, "Corrupt attribute."); 96162306a36Sopenharmony_cierr_out: 96262306a36Sopenharmony_ci ntfs_free(rl); 96362306a36Sopenharmony_ci return ERR_PTR(-EIO); 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci/** 96762306a36Sopenharmony_ci * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist 96862306a36Sopenharmony_ci * @rl: runlist to use for conversion 96962306a36Sopenharmony_ci * @vcn: vcn to convert 97062306a36Sopenharmony_ci * 97162306a36Sopenharmony_ci * Convert the virtual cluster number @vcn of an attribute into a logical 97262306a36Sopenharmony_ci * cluster number (lcn) of a device using the runlist @rl to map vcns to their 97362306a36Sopenharmony_ci * corresponding lcns. 97462306a36Sopenharmony_ci * 97562306a36Sopenharmony_ci * It is up to the caller to serialize access to the runlist @rl. 97662306a36Sopenharmony_ci * 97762306a36Sopenharmony_ci * Since lcns must be >= 0, we use negative return codes with special meaning: 97862306a36Sopenharmony_ci * 97962306a36Sopenharmony_ci * Return code Meaning / Description 98062306a36Sopenharmony_ci * ================================================== 98162306a36Sopenharmony_ci * LCN_HOLE Hole / not allocated on disk. 98262306a36Sopenharmony_ci * LCN_RL_NOT_MAPPED This is part of the runlist which has not been 98362306a36Sopenharmony_ci * inserted into the runlist yet. 98462306a36Sopenharmony_ci * LCN_ENOENT There is no such vcn in the attribute. 98562306a36Sopenharmony_ci * 98662306a36Sopenharmony_ci * Locking: - The caller must have locked the runlist (for reading or writing). 98762306a36Sopenharmony_ci * - This function does not touch the lock, nor does it modify the 98862306a36Sopenharmony_ci * runlist. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_ciLCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci int i; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci BUG_ON(vcn < 0); 99562306a36Sopenharmony_ci /* 99662306a36Sopenharmony_ci * If rl is NULL, assume that we have found an unmapped runlist. The 99762306a36Sopenharmony_ci * caller can then attempt to map it and fail appropriately if 99862306a36Sopenharmony_ci * necessary. 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ci if (unlikely(!rl)) 100162306a36Sopenharmony_ci return LCN_RL_NOT_MAPPED; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* Catch out of lower bounds vcn. */ 100462306a36Sopenharmony_ci if (unlikely(vcn < rl[0].vcn)) 100562306a36Sopenharmony_ci return LCN_ENOENT; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci for (i = 0; likely(rl[i].length); i++) { 100862306a36Sopenharmony_ci if (unlikely(vcn < rl[i+1].vcn)) { 100962306a36Sopenharmony_ci if (likely(rl[i].lcn >= (LCN)0)) 101062306a36Sopenharmony_ci return rl[i].lcn + (vcn - rl[i].vcn); 101162306a36Sopenharmony_ci return rl[i].lcn; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci /* 101562306a36Sopenharmony_ci * The terminator element is setup to the correct value, i.e. one of 101662306a36Sopenharmony_ci * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci if (likely(rl[i].lcn < (LCN)0)) 101962306a36Sopenharmony_ci return rl[i].lcn; 102062306a36Sopenharmony_ci /* Just in case... We could replace this with BUG() some day. */ 102162306a36Sopenharmony_ci return LCN_ENOENT; 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci#ifdef NTFS_RW 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci/** 102762306a36Sopenharmony_ci * ntfs_rl_find_vcn_nolock - find a vcn in a runlist 102862306a36Sopenharmony_ci * @rl: runlist to search 102962306a36Sopenharmony_ci * @vcn: vcn to find 103062306a36Sopenharmony_ci * 103162306a36Sopenharmony_ci * Find the virtual cluster number @vcn in the runlist @rl and return the 103262306a36Sopenharmony_ci * address of the runlist element containing the @vcn on success. 103362306a36Sopenharmony_ci * 103462306a36Sopenharmony_ci * Return NULL if @rl is NULL or @vcn is in an unmapped part/out of bounds of 103562306a36Sopenharmony_ci * the runlist. 103662306a36Sopenharmony_ci * 103762306a36Sopenharmony_ci * Locking: The runlist must be locked on entry. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_cirunlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl, const VCN vcn) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci BUG_ON(vcn < 0); 104262306a36Sopenharmony_ci if (unlikely(!rl || vcn < rl[0].vcn)) 104362306a36Sopenharmony_ci return NULL; 104462306a36Sopenharmony_ci while (likely(rl->length)) { 104562306a36Sopenharmony_ci if (unlikely(vcn < rl[1].vcn)) { 104662306a36Sopenharmony_ci if (likely(rl->lcn >= LCN_HOLE)) 104762306a36Sopenharmony_ci return rl; 104862306a36Sopenharmony_ci return NULL; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci rl++; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci if (likely(rl->lcn == LCN_ENOENT)) 105362306a36Sopenharmony_ci return rl; 105462306a36Sopenharmony_ci return NULL; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci/** 105862306a36Sopenharmony_ci * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number 105962306a36Sopenharmony_ci * @n: number for which to get the number of bytes for 106062306a36Sopenharmony_ci * 106162306a36Sopenharmony_ci * Return the number of bytes required to store @n unambiguously as 106262306a36Sopenharmony_ci * a signed number. 106362306a36Sopenharmony_ci * 106462306a36Sopenharmony_ci * This is used in the context of the mapping pairs array to determine how 106562306a36Sopenharmony_ci * many bytes will be needed in the array to store a given logical cluster 106662306a36Sopenharmony_ci * number (lcn) or a specific run length. 106762306a36Sopenharmony_ci * 106862306a36Sopenharmony_ci * Return the number of bytes written. This function cannot fail. 106962306a36Sopenharmony_ci */ 107062306a36Sopenharmony_cistatic inline int ntfs_get_nr_significant_bytes(const s64 n) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci s64 l = n; 107362306a36Sopenharmony_ci int i; 107462306a36Sopenharmony_ci s8 j; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci i = 0; 107762306a36Sopenharmony_ci do { 107862306a36Sopenharmony_ci l >>= 8; 107962306a36Sopenharmony_ci i++; 108062306a36Sopenharmony_ci } while (l != 0 && l != -1); 108162306a36Sopenharmony_ci j = (n >> 8 * (i - 1)) & 0xff; 108262306a36Sopenharmony_ci /* If the sign bit is wrong, we need an extra byte. */ 108362306a36Sopenharmony_ci if ((n < 0 && j >= 0) || (n > 0 && j < 0)) 108462306a36Sopenharmony_ci i++; 108562306a36Sopenharmony_ci return i; 108662306a36Sopenharmony_ci} 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci/** 108962306a36Sopenharmony_ci * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array 109062306a36Sopenharmony_ci * @vol: ntfs volume (needed for the ntfs version) 109162306a36Sopenharmony_ci * @rl: locked runlist to determine the size of the mapping pairs of 109262306a36Sopenharmony_ci * @first_vcn: first vcn which to include in the mapping pairs array 109362306a36Sopenharmony_ci * @last_vcn: last vcn which to include in the mapping pairs array 109462306a36Sopenharmony_ci * 109562306a36Sopenharmony_ci * Walk the locked runlist @rl and calculate the size in bytes of the mapping 109662306a36Sopenharmony_ci * pairs array corresponding to the runlist @rl, starting at vcn @first_vcn and 109762306a36Sopenharmony_ci * finishing with vcn @last_vcn. 109862306a36Sopenharmony_ci * 109962306a36Sopenharmony_ci * A @last_vcn of -1 means end of runlist and in that case the size of the 110062306a36Sopenharmony_ci * mapping pairs array corresponding to the runlist starting at vcn @first_vcn 110162306a36Sopenharmony_ci * and finishing at the end of the runlist is determined. 110262306a36Sopenharmony_ci * 110362306a36Sopenharmony_ci * This for example allows us to allocate a buffer of the right size when 110462306a36Sopenharmony_ci * building the mapping pairs array. 110562306a36Sopenharmony_ci * 110662306a36Sopenharmony_ci * If @rl is NULL, just return 1 (for the single terminator byte). 110762306a36Sopenharmony_ci * 110862306a36Sopenharmony_ci * Return the calculated size in bytes on success. On error, return -errno. 110962306a36Sopenharmony_ci * The following error codes are defined: 111062306a36Sopenharmony_ci * -EINVAL - Run list contains unmapped elements. Make sure to only pass 111162306a36Sopenharmony_ci * fully mapped runlists to this function. 111262306a36Sopenharmony_ci * -EIO - The runlist is corrupt. 111362306a36Sopenharmony_ci * 111462306a36Sopenharmony_ci * Locking: @rl must be locked on entry (either for reading or writing), it 111562306a36Sopenharmony_ci * remains locked throughout, and is left locked upon return. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ciint ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, 111862306a36Sopenharmony_ci const runlist_element *rl, const VCN first_vcn, 111962306a36Sopenharmony_ci const VCN last_vcn) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci LCN prev_lcn; 112262306a36Sopenharmony_ci int rls; 112362306a36Sopenharmony_ci bool the_end = false; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci BUG_ON(first_vcn < 0); 112662306a36Sopenharmony_ci BUG_ON(last_vcn < -1); 112762306a36Sopenharmony_ci BUG_ON(last_vcn >= 0 && first_vcn > last_vcn); 112862306a36Sopenharmony_ci if (!rl) { 112962306a36Sopenharmony_ci BUG_ON(first_vcn); 113062306a36Sopenharmony_ci BUG_ON(last_vcn > 0); 113162306a36Sopenharmony_ci return 1; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci /* Skip to runlist element containing @first_vcn. */ 113462306a36Sopenharmony_ci while (rl->length && first_vcn >= rl[1].vcn) 113562306a36Sopenharmony_ci rl++; 113662306a36Sopenharmony_ci if (unlikely((!rl->length && first_vcn > rl->vcn) || 113762306a36Sopenharmony_ci first_vcn < rl->vcn)) 113862306a36Sopenharmony_ci return -EINVAL; 113962306a36Sopenharmony_ci prev_lcn = 0; 114062306a36Sopenharmony_ci /* Always need the termining zero byte. */ 114162306a36Sopenharmony_ci rls = 1; 114262306a36Sopenharmony_ci /* Do the first partial run if present. */ 114362306a36Sopenharmony_ci if (first_vcn > rl->vcn) { 114462306a36Sopenharmony_ci s64 delta, length = rl->length; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* We know rl->length != 0 already. */ 114762306a36Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 114862306a36Sopenharmony_ci goto err_out; 114962306a36Sopenharmony_ci /* 115062306a36Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 115162306a36Sopenharmony_ci * run length. 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 115462306a36Sopenharmony_ci s64 s1 = last_vcn + 1; 115562306a36Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 115662306a36Sopenharmony_ci length = s1 - rl->vcn; 115762306a36Sopenharmony_ci the_end = true; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci delta = first_vcn - rl->vcn; 116062306a36Sopenharmony_ci /* Header byte + length. */ 116162306a36Sopenharmony_ci rls += 1 + ntfs_get_nr_significant_bytes(length - delta); 116262306a36Sopenharmony_ci /* 116362306a36Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 116462306a36Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 116562306a36Sopenharmony_ci * zero space. On earlier NTFS versions we just store the lcn. 116662306a36Sopenharmony_ci * Note: this assumes that on NTFS 1.2-, holes are stored with 116762306a36Sopenharmony_ci * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). 116862306a36Sopenharmony_ci */ 116962306a36Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 117062306a36Sopenharmony_ci prev_lcn = rl->lcn; 117162306a36Sopenharmony_ci if (likely(rl->lcn >= 0)) 117262306a36Sopenharmony_ci prev_lcn += delta; 117362306a36Sopenharmony_ci /* Change in lcn. */ 117462306a36Sopenharmony_ci rls += ntfs_get_nr_significant_bytes(prev_lcn); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci /* Go to next runlist element. */ 117762306a36Sopenharmony_ci rl++; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci /* Do the full runs. */ 118062306a36Sopenharmony_ci for (; rl->length && !the_end; rl++) { 118162306a36Sopenharmony_ci s64 length = rl->length; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 118462306a36Sopenharmony_ci goto err_out; 118562306a36Sopenharmony_ci /* 118662306a36Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 118762306a36Sopenharmony_ci * run length. 118862306a36Sopenharmony_ci */ 118962306a36Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 119062306a36Sopenharmony_ci s64 s1 = last_vcn + 1; 119162306a36Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 119262306a36Sopenharmony_ci length = s1 - rl->vcn; 119362306a36Sopenharmony_ci the_end = true; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci /* Header byte + length. */ 119662306a36Sopenharmony_ci rls += 1 + ntfs_get_nr_significant_bytes(length); 119762306a36Sopenharmony_ci /* 119862306a36Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 119962306a36Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 120062306a36Sopenharmony_ci * zero space. On earlier NTFS versions we just store the lcn. 120162306a36Sopenharmony_ci * Note: this assumes that on NTFS 1.2-, holes are stored with 120262306a36Sopenharmony_ci * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). 120362306a36Sopenharmony_ci */ 120462306a36Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 120562306a36Sopenharmony_ci /* Change in lcn. */ 120662306a36Sopenharmony_ci rls += ntfs_get_nr_significant_bytes(rl->lcn - 120762306a36Sopenharmony_ci prev_lcn); 120862306a36Sopenharmony_ci prev_lcn = rl->lcn; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci return rls; 121262306a36Sopenharmony_cierr_out: 121362306a36Sopenharmony_ci if (rl->lcn == LCN_RL_NOT_MAPPED) 121462306a36Sopenharmony_ci rls = -EINVAL; 121562306a36Sopenharmony_ci else 121662306a36Sopenharmony_ci rls = -EIO; 121762306a36Sopenharmony_ci return rls; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci/** 122162306a36Sopenharmony_ci * ntfs_write_significant_bytes - write the significant bytes of a number 122262306a36Sopenharmony_ci * @dst: destination buffer to write to 122362306a36Sopenharmony_ci * @dst_max: pointer to last byte of destination buffer for bounds checking 122462306a36Sopenharmony_ci * @n: number whose significant bytes to write 122562306a36Sopenharmony_ci * 122662306a36Sopenharmony_ci * Store in @dst, the minimum bytes of the number @n which are required to 122762306a36Sopenharmony_ci * identify @n unambiguously as a signed number, taking care not to exceed 122862306a36Sopenharmony_ci * @dest_max, the maximum position within @dst to which we are allowed to 122962306a36Sopenharmony_ci * write. 123062306a36Sopenharmony_ci * 123162306a36Sopenharmony_ci * This is used when building the mapping pairs array of a runlist to compress 123262306a36Sopenharmony_ci * a given logical cluster number (lcn) or a specific run length to the minimum 123362306a36Sopenharmony_ci * size possible. 123462306a36Sopenharmony_ci * 123562306a36Sopenharmony_ci * Return the number of bytes written on success. On error, i.e. the 123662306a36Sopenharmony_ci * destination buffer @dst is too small, return -ENOSPC. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_cistatic inline int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max, 123962306a36Sopenharmony_ci const s64 n) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci s64 l = n; 124262306a36Sopenharmony_ci int i; 124362306a36Sopenharmony_ci s8 j; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci i = 0; 124662306a36Sopenharmony_ci do { 124762306a36Sopenharmony_ci if (unlikely(dst > dst_max)) 124862306a36Sopenharmony_ci goto err_out; 124962306a36Sopenharmony_ci *dst++ = l & 0xffll; 125062306a36Sopenharmony_ci l >>= 8; 125162306a36Sopenharmony_ci i++; 125262306a36Sopenharmony_ci } while (l != 0 && l != -1); 125362306a36Sopenharmony_ci j = (n >> 8 * (i - 1)) & 0xff; 125462306a36Sopenharmony_ci /* If the sign bit is wrong, we need an extra byte. */ 125562306a36Sopenharmony_ci if (n < 0 && j >= 0) { 125662306a36Sopenharmony_ci if (unlikely(dst > dst_max)) 125762306a36Sopenharmony_ci goto err_out; 125862306a36Sopenharmony_ci i++; 125962306a36Sopenharmony_ci *dst = (s8)-1; 126062306a36Sopenharmony_ci } else if (n > 0 && j < 0) { 126162306a36Sopenharmony_ci if (unlikely(dst > dst_max)) 126262306a36Sopenharmony_ci goto err_out; 126362306a36Sopenharmony_ci i++; 126462306a36Sopenharmony_ci *dst = (s8)0; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci return i; 126762306a36Sopenharmony_cierr_out: 126862306a36Sopenharmony_ci return -ENOSPC; 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci/** 127262306a36Sopenharmony_ci * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist 127362306a36Sopenharmony_ci * @vol: ntfs volume (needed for the ntfs version) 127462306a36Sopenharmony_ci * @dst: destination buffer to which to write the mapping pairs array 127562306a36Sopenharmony_ci * @dst_len: size of destination buffer @dst in bytes 127662306a36Sopenharmony_ci * @rl: locked runlist for which to build the mapping pairs array 127762306a36Sopenharmony_ci * @first_vcn: first vcn which to include in the mapping pairs array 127862306a36Sopenharmony_ci * @last_vcn: last vcn which to include in the mapping pairs array 127962306a36Sopenharmony_ci * @stop_vcn: first vcn outside destination buffer on success or -ENOSPC 128062306a36Sopenharmony_ci * 128162306a36Sopenharmony_ci * Create the mapping pairs array from the locked runlist @rl, starting at vcn 128262306a36Sopenharmony_ci * @first_vcn and finishing with vcn @last_vcn and save the array in @dst. 128362306a36Sopenharmony_ci * @dst_len is the size of @dst in bytes and it should be at least equal to the 128462306a36Sopenharmony_ci * value obtained by calling ntfs_get_size_for_mapping_pairs(). 128562306a36Sopenharmony_ci * 128662306a36Sopenharmony_ci * A @last_vcn of -1 means end of runlist and in that case the mapping pairs 128762306a36Sopenharmony_ci * array corresponding to the runlist starting at vcn @first_vcn and finishing 128862306a36Sopenharmony_ci * at the end of the runlist is created. 128962306a36Sopenharmony_ci * 129062306a36Sopenharmony_ci * If @rl is NULL, just write a single terminator byte to @dst. 129162306a36Sopenharmony_ci * 129262306a36Sopenharmony_ci * On success or -ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to 129362306a36Sopenharmony_ci * the first vcn outside the destination buffer. Note that on error, @dst has 129462306a36Sopenharmony_ci * been filled with all the mapping pairs that will fit, thus it can be treated 129562306a36Sopenharmony_ci * as partial success, in that a new attribute extent needs to be created or 129662306a36Sopenharmony_ci * the next extent has to be used and the mapping pairs build has to be 129762306a36Sopenharmony_ci * continued with @first_vcn set to *@stop_vcn. 129862306a36Sopenharmony_ci * 129962306a36Sopenharmony_ci * Return 0 on success and -errno on error. The following error codes are 130062306a36Sopenharmony_ci * defined: 130162306a36Sopenharmony_ci * -EINVAL - Run list contains unmapped elements. Make sure to only pass 130262306a36Sopenharmony_ci * fully mapped runlists to this function. 130362306a36Sopenharmony_ci * -EIO - The runlist is corrupt. 130462306a36Sopenharmony_ci * -ENOSPC - The destination buffer is too small. 130562306a36Sopenharmony_ci * 130662306a36Sopenharmony_ci * Locking: @rl must be locked on entry (either for reading or writing), it 130762306a36Sopenharmony_ci * remains locked throughout, and is left locked upon return. 130862306a36Sopenharmony_ci */ 130962306a36Sopenharmony_ciint ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, 131062306a36Sopenharmony_ci const int dst_len, const runlist_element *rl, 131162306a36Sopenharmony_ci const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci LCN prev_lcn; 131462306a36Sopenharmony_ci s8 *dst_max, *dst_next; 131562306a36Sopenharmony_ci int err = -ENOSPC; 131662306a36Sopenharmony_ci bool the_end = false; 131762306a36Sopenharmony_ci s8 len_len, lcn_len; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci BUG_ON(first_vcn < 0); 132062306a36Sopenharmony_ci BUG_ON(last_vcn < -1); 132162306a36Sopenharmony_ci BUG_ON(last_vcn >= 0 && first_vcn > last_vcn); 132262306a36Sopenharmony_ci BUG_ON(dst_len < 1); 132362306a36Sopenharmony_ci if (!rl) { 132462306a36Sopenharmony_ci BUG_ON(first_vcn); 132562306a36Sopenharmony_ci BUG_ON(last_vcn > 0); 132662306a36Sopenharmony_ci if (stop_vcn) 132762306a36Sopenharmony_ci *stop_vcn = 0; 132862306a36Sopenharmony_ci /* Terminator byte. */ 132962306a36Sopenharmony_ci *dst = 0; 133062306a36Sopenharmony_ci return 0; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci /* Skip to runlist element containing @first_vcn. */ 133362306a36Sopenharmony_ci while (rl->length && first_vcn >= rl[1].vcn) 133462306a36Sopenharmony_ci rl++; 133562306a36Sopenharmony_ci if (unlikely((!rl->length && first_vcn > rl->vcn) || 133662306a36Sopenharmony_ci first_vcn < rl->vcn)) 133762306a36Sopenharmony_ci return -EINVAL; 133862306a36Sopenharmony_ci /* 133962306a36Sopenharmony_ci * @dst_max is used for bounds checking in 134062306a36Sopenharmony_ci * ntfs_write_significant_bytes(). 134162306a36Sopenharmony_ci */ 134262306a36Sopenharmony_ci dst_max = dst + dst_len - 1; 134362306a36Sopenharmony_ci prev_lcn = 0; 134462306a36Sopenharmony_ci /* Do the first partial run if present. */ 134562306a36Sopenharmony_ci if (first_vcn > rl->vcn) { 134662306a36Sopenharmony_ci s64 delta, length = rl->length; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci /* We know rl->length != 0 already. */ 134962306a36Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 135062306a36Sopenharmony_ci goto err_out; 135162306a36Sopenharmony_ci /* 135262306a36Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 135362306a36Sopenharmony_ci * run length. 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 135662306a36Sopenharmony_ci s64 s1 = last_vcn + 1; 135762306a36Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 135862306a36Sopenharmony_ci length = s1 - rl->vcn; 135962306a36Sopenharmony_ci the_end = true; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci delta = first_vcn - rl->vcn; 136262306a36Sopenharmony_ci /* Write length. */ 136362306a36Sopenharmony_ci len_len = ntfs_write_significant_bytes(dst + 1, dst_max, 136462306a36Sopenharmony_ci length - delta); 136562306a36Sopenharmony_ci if (unlikely(len_len < 0)) 136662306a36Sopenharmony_ci goto size_err; 136762306a36Sopenharmony_ci /* 136862306a36Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 136962306a36Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 137062306a36Sopenharmony_ci * zero space. On earlier NTFS versions we just write the lcn 137162306a36Sopenharmony_ci * change. FIXME: Do we need to write the lcn change or just 137262306a36Sopenharmony_ci * the lcn in that case? Not sure as I have never seen this 137362306a36Sopenharmony_ci * case on NT4. - We assume that we just need to write the lcn 137462306a36Sopenharmony_ci * change until someone tells us otherwise... (AIA) 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 137762306a36Sopenharmony_ci prev_lcn = rl->lcn; 137862306a36Sopenharmony_ci if (likely(rl->lcn >= 0)) 137962306a36Sopenharmony_ci prev_lcn += delta; 138062306a36Sopenharmony_ci /* Write change in lcn. */ 138162306a36Sopenharmony_ci lcn_len = ntfs_write_significant_bytes(dst + 1 + 138262306a36Sopenharmony_ci len_len, dst_max, prev_lcn); 138362306a36Sopenharmony_ci if (unlikely(lcn_len < 0)) 138462306a36Sopenharmony_ci goto size_err; 138562306a36Sopenharmony_ci } else 138662306a36Sopenharmony_ci lcn_len = 0; 138762306a36Sopenharmony_ci dst_next = dst + len_len + lcn_len + 1; 138862306a36Sopenharmony_ci if (unlikely(dst_next > dst_max)) 138962306a36Sopenharmony_ci goto size_err; 139062306a36Sopenharmony_ci /* Update header byte. */ 139162306a36Sopenharmony_ci *dst = lcn_len << 4 | len_len; 139262306a36Sopenharmony_ci /* Position at next mapping pairs array element. */ 139362306a36Sopenharmony_ci dst = dst_next; 139462306a36Sopenharmony_ci /* Go to next runlist element. */ 139562306a36Sopenharmony_ci rl++; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci /* Do the full runs. */ 139862306a36Sopenharmony_ci for (; rl->length && !the_end; rl++) { 139962306a36Sopenharmony_ci s64 length = rl->length; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 140262306a36Sopenharmony_ci goto err_out; 140362306a36Sopenharmony_ci /* 140462306a36Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 140562306a36Sopenharmony_ci * run length. 140662306a36Sopenharmony_ci */ 140762306a36Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 140862306a36Sopenharmony_ci s64 s1 = last_vcn + 1; 140962306a36Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 141062306a36Sopenharmony_ci length = s1 - rl->vcn; 141162306a36Sopenharmony_ci the_end = true; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci /* Write length. */ 141462306a36Sopenharmony_ci len_len = ntfs_write_significant_bytes(dst + 1, dst_max, 141562306a36Sopenharmony_ci length); 141662306a36Sopenharmony_ci if (unlikely(len_len < 0)) 141762306a36Sopenharmony_ci goto size_err; 141862306a36Sopenharmony_ci /* 141962306a36Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 142062306a36Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 142162306a36Sopenharmony_ci * zero space. On earlier NTFS versions we just write the lcn 142262306a36Sopenharmony_ci * change. FIXME: Do we need to write the lcn change or just 142362306a36Sopenharmony_ci * the lcn in that case? Not sure as I have never seen this 142462306a36Sopenharmony_ci * case on NT4. - We assume that we just need to write the lcn 142562306a36Sopenharmony_ci * change until someone tells us otherwise... (AIA) 142662306a36Sopenharmony_ci */ 142762306a36Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 142862306a36Sopenharmony_ci /* Write change in lcn. */ 142962306a36Sopenharmony_ci lcn_len = ntfs_write_significant_bytes(dst + 1 + 143062306a36Sopenharmony_ci len_len, dst_max, rl->lcn - prev_lcn); 143162306a36Sopenharmony_ci if (unlikely(lcn_len < 0)) 143262306a36Sopenharmony_ci goto size_err; 143362306a36Sopenharmony_ci prev_lcn = rl->lcn; 143462306a36Sopenharmony_ci } else 143562306a36Sopenharmony_ci lcn_len = 0; 143662306a36Sopenharmony_ci dst_next = dst + len_len + lcn_len + 1; 143762306a36Sopenharmony_ci if (unlikely(dst_next > dst_max)) 143862306a36Sopenharmony_ci goto size_err; 143962306a36Sopenharmony_ci /* Update header byte. */ 144062306a36Sopenharmony_ci *dst = lcn_len << 4 | len_len; 144162306a36Sopenharmony_ci /* Position at next mapping pairs array element. */ 144262306a36Sopenharmony_ci dst = dst_next; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci /* Success. */ 144562306a36Sopenharmony_ci err = 0; 144662306a36Sopenharmony_cisize_err: 144762306a36Sopenharmony_ci /* Set stop vcn. */ 144862306a36Sopenharmony_ci if (stop_vcn) 144962306a36Sopenharmony_ci *stop_vcn = rl->vcn; 145062306a36Sopenharmony_ci /* Add terminator byte. */ 145162306a36Sopenharmony_ci *dst = 0; 145262306a36Sopenharmony_ci return err; 145362306a36Sopenharmony_cierr_out: 145462306a36Sopenharmony_ci if (rl->lcn == LCN_RL_NOT_MAPPED) 145562306a36Sopenharmony_ci err = -EINVAL; 145662306a36Sopenharmony_ci else 145762306a36Sopenharmony_ci err = -EIO; 145862306a36Sopenharmony_ci return err; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci/** 146262306a36Sopenharmony_ci * ntfs_rl_truncate_nolock - truncate a runlist starting at a specified vcn 146362306a36Sopenharmony_ci * @vol: ntfs volume (needed for error output) 146462306a36Sopenharmony_ci * @runlist: runlist to truncate 146562306a36Sopenharmony_ci * @new_length: the new length of the runlist in VCNs 146662306a36Sopenharmony_ci * 146762306a36Sopenharmony_ci * Truncate the runlist described by @runlist as well as the memory buffer 146862306a36Sopenharmony_ci * holding the runlist elements to a length of @new_length VCNs. 146962306a36Sopenharmony_ci * 147062306a36Sopenharmony_ci * If @new_length lies within the runlist, the runlist elements with VCNs of 147162306a36Sopenharmony_ci * @new_length and above are discarded. As a special case if @new_length is 147262306a36Sopenharmony_ci * zero, the runlist is discarded and set to NULL. 147362306a36Sopenharmony_ci * 147462306a36Sopenharmony_ci * If @new_length lies beyond the runlist, a sparse runlist element is added to 147562306a36Sopenharmony_ci * the end of the runlist @runlist or if the last runlist element is a sparse 147662306a36Sopenharmony_ci * one already, this is extended. 147762306a36Sopenharmony_ci * 147862306a36Sopenharmony_ci * Note, no checking is done for unmapped runlist elements. It is assumed that 147962306a36Sopenharmony_ci * the caller has mapped any elements that need to be mapped already. 148062306a36Sopenharmony_ci * 148162306a36Sopenharmony_ci * Return 0 on success and -errno on error. 148262306a36Sopenharmony_ci * 148362306a36Sopenharmony_ci * Locking: The caller must hold @runlist->lock for writing. 148462306a36Sopenharmony_ci */ 148562306a36Sopenharmony_ciint ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist, 148662306a36Sopenharmony_ci const s64 new_length) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci runlist_element *rl; 148962306a36Sopenharmony_ci int old_size; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci ntfs_debug("Entering for new_length 0x%llx.", (long long)new_length); 149262306a36Sopenharmony_ci BUG_ON(!runlist); 149362306a36Sopenharmony_ci BUG_ON(new_length < 0); 149462306a36Sopenharmony_ci rl = runlist->rl; 149562306a36Sopenharmony_ci if (!new_length) { 149662306a36Sopenharmony_ci ntfs_debug("Freeing runlist."); 149762306a36Sopenharmony_ci runlist->rl = NULL; 149862306a36Sopenharmony_ci if (rl) 149962306a36Sopenharmony_ci ntfs_free(rl); 150062306a36Sopenharmony_ci return 0; 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci if (unlikely(!rl)) { 150362306a36Sopenharmony_ci /* 150462306a36Sopenharmony_ci * Create a runlist consisting of a sparse runlist element of 150562306a36Sopenharmony_ci * length @new_length followed by a terminator runlist element. 150662306a36Sopenharmony_ci */ 150762306a36Sopenharmony_ci rl = ntfs_malloc_nofs(PAGE_SIZE); 150862306a36Sopenharmony_ci if (unlikely(!rl)) { 150962306a36Sopenharmony_ci ntfs_error(vol->sb, "Not enough memory to allocate " 151062306a36Sopenharmony_ci "runlist element buffer."); 151162306a36Sopenharmony_ci return -ENOMEM; 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci runlist->rl = rl; 151462306a36Sopenharmony_ci rl[1].length = rl->vcn = 0; 151562306a36Sopenharmony_ci rl->lcn = LCN_HOLE; 151662306a36Sopenharmony_ci rl[1].vcn = rl->length = new_length; 151762306a36Sopenharmony_ci rl[1].lcn = LCN_ENOENT; 151862306a36Sopenharmony_ci return 0; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci BUG_ON(new_length < rl->vcn); 152162306a36Sopenharmony_ci /* Find @new_length in the runlist. */ 152262306a36Sopenharmony_ci while (likely(rl->length && new_length >= rl[1].vcn)) 152362306a36Sopenharmony_ci rl++; 152462306a36Sopenharmony_ci /* 152562306a36Sopenharmony_ci * If not at the end of the runlist we need to shrink it. 152662306a36Sopenharmony_ci * If at the end of the runlist we need to expand it. 152762306a36Sopenharmony_ci */ 152862306a36Sopenharmony_ci if (rl->length) { 152962306a36Sopenharmony_ci runlist_element *trl; 153062306a36Sopenharmony_ci bool is_end; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci ntfs_debug("Shrinking runlist."); 153362306a36Sopenharmony_ci /* Determine the runlist size. */ 153462306a36Sopenharmony_ci trl = rl + 1; 153562306a36Sopenharmony_ci while (likely(trl->length)) 153662306a36Sopenharmony_ci trl++; 153762306a36Sopenharmony_ci old_size = trl - runlist->rl + 1; 153862306a36Sopenharmony_ci /* Truncate the run. */ 153962306a36Sopenharmony_ci rl->length = new_length - rl->vcn; 154062306a36Sopenharmony_ci /* 154162306a36Sopenharmony_ci * If a run was partially truncated, make the following runlist 154262306a36Sopenharmony_ci * element a terminator. 154362306a36Sopenharmony_ci */ 154462306a36Sopenharmony_ci is_end = false; 154562306a36Sopenharmony_ci if (rl->length) { 154662306a36Sopenharmony_ci rl++; 154762306a36Sopenharmony_ci if (!rl->length) 154862306a36Sopenharmony_ci is_end = true; 154962306a36Sopenharmony_ci rl->vcn = new_length; 155062306a36Sopenharmony_ci rl->length = 0; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci rl->lcn = LCN_ENOENT; 155362306a36Sopenharmony_ci /* Reallocate memory if necessary. */ 155462306a36Sopenharmony_ci if (!is_end) { 155562306a36Sopenharmony_ci int new_size = rl - runlist->rl + 1; 155662306a36Sopenharmony_ci rl = ntfs_rl_realloc(runlist->rl, old_size, new_size); 155762306a36Sopenharmony_ci if (IS_ERR(rl)) 155862306a36Sopenharmony_ci ntfs_warning(vol->sb, "Failed to shrink " 155962306a36Sopenharmony_ci "runlist buffer. This just " 156062306a36Sopenharmony_ci "wastes a bit of memory " 156162306a36Sopenharmony_ci "temporarily so we ignore it " 156262306a36Sopenharmony_ci "and return success."); 156362306a36Sopenharmony_ci else 156462306a36Sopenharmony_ci runlist->rl = rl; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci } else if (likely(/* !rl->length && */ new_length > rl->vcn)) { 156762306a36Sopenharmony_ci ntfs_debug("Expanding runlist."); 156862306a36Sopenharmony_ci /* 156962306a36Sopenharmony_ci * If there is a previous runlist element and it is a sparse 157062306a36Sopenharmony_ci * one, extend it. Otherwise need to add a new, sparse runlist 157162306a36Sopenharmony_ci * element. 157262306a36Sopenharmony_ci */ 157362306a36Sopenharmony_ci if ((rl > runlist->rl) && ((rl - 1)->lcn == LCN_HOLE)) 157462306a36Sopenharmony_ci (rl - 1)->length = new_length - (rl - 1)->vcn; 157562306a36Sopenharmony_ci else { 157662306a36Sopenharmony_ci /* Determine the runlist size. */ 157762306a36Sopenharmony_ci old_size = rl - runlist->rl + 1; 157862306a36Sopenharmony_ci /* Reallocate memory if necessary. */ 157962306a36Sopenharmony_ci rl = ntfs_rl_realloc(runlist->rl, old_size, 158062306a36Sopenharmony_ci old_size + 1); 158162306a36Sopenharmony_ci if (IS_ERR(rl)) { 158262306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to expand runlist " 158362306a36Sopenharmony_ci "buffer, aborting."); 158462306a36Sopenharmony_ci return PTR_ERR(rl); 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci runlist->rl = rl; 158762306a36Sopenharmony_ci /* 158862306a36Sopenharmony_ci * Set @rl to the same runlist element in the new 158962306a36Sopenharmony_ci * runlist as before in the old runlist. 159062306a36Sopenharmony_ci */ 159162306a36Sopenharmony_ci rl += old_size - 1; 159262306a36Sopenharmony_ci /* Add a new, sparse runlist element. */ 159362306a36Sopenharmony_ci rl->lcn = LCN_HOLE; 159462306a36Sopenharmony_ci rl->length = new_length - rl->vcn; 159562306a36Sopenharmony_ci /* Add a new terminator runlist element. */ 159662306a36Sopenharmony_ci rl++; 159762306a36Sopenharmony_ci rl->length = 0; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci rl->vcn = new_length; 160062306a36Sopenharmony_ci rl->lcn = LCN_ENOENT; 160162306a36Sopenharmony_ci } else /* if (unlikely(!rl->length && new_length == rl->vcn)) */ { 160262306a36Sopenharmony_ci /* Runlist already has same size as requested. */ 160362306a36Sopenharmony_ci rl->lcn = LCN_ENOENT; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci ntfs_debug("Done."); 160662306a36Sopenharmony_ci return 0; 160762306a36Sopenharmony_ci} 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci/** 161062306a36Sopenharmony_ci * ntfs_rl_punch_nolock - punch a hole into a runlist 161162306a36Sopenharmony_ci * @vol: ntfs volume (needed for error output) 161262306a36Sopenharmony_ci * @runlist: runlist to punch a hole into 161362306a36Sopenharmony_ci * @start: starting VCN of the hole to be created 161462306a36Sopenharmony_ci * @length: size of the hole to be created in units of clusters 161562306a36Sopenharmony_ci * 161662306a36Sopenharmony_ci * Punch a hole into the runlist @runlist starting at VCN @start and of size 161762306a36Sopenharmony_ci * @length clusters. 161862306a36Sopenharmony_ci * 161962306a36Sopenharmony_ci * Return 0 on success and -errno on error, in which case @runlist has not been 162062306a36Sopenharmony_ci * modified. 162162306a36Sopenharmony_ci * 162262306a36Sopenharmony_ci * If @start and/or @start + @length are outside the runlist return error code 162362306a36Sopenharmony_ci * -ENOENT. 162462306a36Sopenharmony_ci * 162562306a36Sopenharmony_ci * If the runlist contains unmapped or error elements between @start and @start 162662306a36Sopenharmony_ci * + @length return error code -EINVAL. 162762306a36Sopenharmony_ci * 162862306a36Sopenharmony_ci * Locking: The caller must hold @runlist->lock for writing. 162962306a36Sopenharmony_ci */ 163062306a36Sopenharmony_ciint ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist, 163162306a36Sopenharmony_ci const VCN start, const s64 length) 163262306a36Sopenharmony_ci{ 163362306a36Sopenharmony_ci const VCN end = start + length; 163462306a36Sopenharmony_ci s64 delta; 163562306a36Sopenharmony_ci runlist_element *rl, *rl_end, *rl_real_end, *trl; 163662306a36Sopenharmony_ci int old_size; 163762306a36Sopenharmony_ci bool lcn_fixup = false; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci ntfs_debug("Entering for start 0x%llx, length 0x%llx.", 164062306a36Sopenharmony_ci (long long)start, (long long)length); 164162306a36Sopenharmony_ci BUG_ON(!runlist); 164262306a36Sopenharmony_ci BUG_ON(start < 0); 164362306a36Sopenharmony_ci BUG_ON(length < 0); 164462306a36Sopenharmony_ci BUG_ON(end < 0); 164562306a36Sopenharmony_ci rl = runlist->rl; 164662306a36Sopenharmony_ci if (unlikely(!rl)) { 164762306a36Sopenharmony_ci if (likely(!start && !length)) 164862306a36Sopenharmony_ci return 0; 164962306a36Sopenharmony_ci return -ENOENT; 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci /* Find @start in the runlist. */ 165262306a36Sopenharmony_ci while (likely(rl->length && start >= rl[1].vcn)) 165362306a36Sopenharmony_ci rl++; 165462306a36Sopenharmony_ci rl_end = rl; 165562306a36Sopenharmony_ci /* Find @end in the runlist. */ 165662306a36Sopenharmony_ci while (likely(rl_end->length && end >= rl_end[1].vcn)) { 165762306a36Sopenharmony_ci /* Verify there are no unmapped or error elements. */ 165862306a36Sopenharmony_ci if (unlikely(rl_end->lcn < LCN_HOLE)) 165962306a36Sopenharmony_ci return -EINVAL; 166062306a36Sopenharmony_ci rl_end++; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci /* Check the last element. */ 166362306a36Sopenharmony_ci if (unlikely(rl_end->length && rl_end->lcn < LCN_HOLE)) 166462306a36Sopenharmony_ci return -EINVAL; 166562306a36Sopenharmony_ci /* This covers @start being out of bounds, too. */ 166662306a36Sopenharmony_ci if (!rl_end->length && end > rl_end->vcn) 166762306a36Sopenharmony_ci return -ENOENT; 166862306a36Sopenharmony_ci if (!length) 166962306a36Sopenharmony_ci return 0; 167062306a36Sopenharmony_ci if (!rl->length) 167162306a36Sopenharmony_ci return -ENOENT; 167262306a36Sopenharmony_ci rl_real_end = rl_end; 167362306a36Sopenharmony_ci /* Determine the runlist size. */ 167462306a36Sopenharmony_ci while (likely(rl_real_end->length)) 167562306a36Sopenharmony_ci rl_real_end++; 167662306a36Sopenharmony_ci old_size = rl_real_end - runlist->rl + 1; 167762306a36Sopenharmony_ci /* If @start is in a hole simply extend the hole. */ 167862306a36Sopenharmony_ci if (rl->lcn == LCN_HOLE) { 167962306a36Sopenharmony_ci /* 168062306a36Sopenharmony_ci * If both @start and @end are in the same sparse run, we are 168162306a36Sopenharmony_ci * done. 168262306a36Sopenharmony_ci */ 168362306a36Sopenharmony_ci if (end <= rl[1].vcn) { 168462306a36Sopenharmony_ci ntfs_debug("Done (requested hole is already sparse)."); 168562306a36Sopenharmony_ci return 0; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ciextend_hole: 168862306a36Sopenharmony_ci /* Extend the hole. */ 168962306a36Sopenharmony_ci rl->length = end - rl->vcn; 169062306a36Sopenharmony_ci /* If @end is in a hole, merge it with the current one. */ 169162306a36Sopenharmony_ci if (rl_end->lcn == LCN_HOLE) { 169262306a36Sopenharmony_ci rl_end++; 169362306a36Sopenharmony_ci rl->length = rl_end->vcn - rl->vcn; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci /* We have done the hole. Now deal with the remaining tail. */ 169662306a36Sopenharmony_ci rl++; 169762306a36Sopenharmony_ci /* Cut out all runlist elements up to @end. */ 169862306a36Sopenharmony_ci if (rl < rl_end) 169962306a36Sopenharmony_ci memmove(rl, rl_end, (rl_real_end - rl_end + 1) * 170062306a36Sopenharmony_ci sizeof(*rl)); 170162306a36Sopenharmony_ci /* Adjust the beginning of the tail if necessary. */ 170262306a36Sopenharmony_ci if (end > rl->vcn) { 170362306a36Sopenharmony_ci delta = end - rl->vcn; 170462306a36Sopenharmony_ci rl->vcn = end; 170562306a36Sopenharmony_ci rl->length -= delta; 170662306a36Sopenharmony_ci /* Only adjust the lcn if it is real. */ 170762306a36Sopenharmony_ci if (rl->lcn >= 0) 170862306a36Sopenharmony_ci rl->lcn += delta; 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_cishrink_allocation: 171162306a36Sopenharmony_ci /* Reallocate memory if the allocation changed. */ 171262306a36Sopenharmony_ci if (rl < rl_end) { 171362306a36Sopenharmony_ci rl = ntfs_rl_realloc(runlist->rl, old_size, 171462306a36Sopenharmony_ci old_size - (rl_end - rl)); 171562306a36Sopenharmony_ci if (IS_ERR(rl)) 171662306a36Sopenharmony_ci ntfs_warning(vol->sb, "Failed to shrink " 171762306a36Sopenharmony_ci "runlist buffer. This just " 171862306a36Sopenharmony_ci "wastes a bit of memory " 171962306a36Sopenharmony_ci "temporarily so we ignore it " 172062306a36Sopenharmony_ci "and return success."); 172162306a36Sopenharmony_ci else 172262306a36Sopenharmony_ci runlist->rl = rl; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci ntfs_debug("Done (extend hole)."); 172562306a36Sopenharmony_ci return 0; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci /* 172862306a36Sopenharmony_ci * If @start is at the beginning of a run things are easier as there is 172962306a36Sopenharmony_ci * no need to split the first run. 173062306a36Sopenharmony_ci */ 173162306a36Sopenharmony_ci if (start == rl->vcn) { 173262306a36Sopenharmony_ci /* 173362306a36Sopenharmony_ci * @start is at the beginning of a run. 173462306a36Sopenharmony_ci * 173562306a36Sopenharmony_ci * If the previous run is sparse, extend its hole. 173662306a36Sopenharmony_ci * 173762306a36Sopenharmony_ci * If @end is not in the same run, switch the run to be sparse 173862306a36Sopenharmony_ci * and extend the newly created hole. 173962306a36Sopenharmony_ci * 174062306a36Sopenharmony_ci * Thus both of these cases reduce the problem to the above 174162306a36Sopenharmony_ci * case of "@start is in a hole". 174262306a36Sopenharmony_ci */ 174362306a36Sopenharmony_ci if (rl > runlist->rl && (rl - 1)->lcn == LCN_HOLE) { 174462306a36Sopenharmony_ci rl--; 174562306a36Sopenharmony_ci goto extend_hole; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci if (end >= rl[1].vcn) { 174862306a36Sopenharmony_ci rl->lcn = LCN_HOLE; 174962306a36Sopenharmony_ci goto extend_hole; 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci /* 175262306a36Sopenharmony_ci * The final case is when @end is in the same run as @start. 175362306a36Sopenharmony_ci * For this need to split the run into two. One run for the 175462306a36Sopenharmony_ci * sparse region between the beginning of the old run, i.e. 175562306a36Sopenharmony_ci * @start, and @end and one for the remaining non-sparse 175662306a36Sopenharmony_ci * region, i.e. between @end and the end of the old run. 175762306a36Sopenharmony_ci */ 175862306a36Sopenharmony_ci trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1); 175962306a36Sopenharmony_ci if (IS_ERR(trl)) 176062306a36Sopenharmony_ci goto enomem_out; 176162306a36Sopenharmony_ci old_size++; 176262306a36Sopenharmony_ci if (runlist->rl != trl) { 176362306a36Sopenharmony_ci rl = trl + (rl - runlist->rl); 176462306a36Sopenharmony_ci rl_end = trl + (rl_end - runlist->rl); 176562306a36Sopenharmony_ci rl_real_end = trl + (rl_real_end - runlist->rl); 176662306a36Sopenharmony_ci runlist->rl = trl; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_cisplit_end: 176962306a36Sopenharmony_ci /* Shift all the runs up by one. */ 177062306a36Sopenharmony_ci memmove(rl + 1, rl, (rl_real_end - rl + 1) * sizeof(*rl)); 177162306a36Sopenharmony_ci /* Finally, setup the two split runs. */ 177262306a36Sopenharmony_ci rl->lcn = LCN_HOLE; 177362306a36Sopenharmony_ci rl->length = length; 177462306a36Sopenharmony_ci rl++; 177562306a36Sopenharmony_ci rl->vcn += length; 177662306a36Sopenharmony_ci /* Only adjust the lcn if it is real. */ 177762306a36Sopenharmony_ci if (rl->lcn >= 0 || lcn_fixup) 177862306a36Sopenharmony_ci rl->lcn += length; 177962306a36Sopenharmony_ci rl->length -= length; 178062306a36Sopenharmony_ci ntfs_debug("Done (split one)."); 178162306a36Sopenharmony_ci return 0; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci /* 178462306a36Sopenharmony_ci * @start is neither in a hole nor at the beginning of a run. 178562306a36Sopenharmony_ci * 178662306a36Sopenharmony_ci * If @end is in a hole, things are easier as simply truncating the run 178762306a36Sopenharmony_ci * @start is in to end at @start - 1, deleting all runs after that up 178862306a36Sopenharmony_ci * to @end, and finally extending the beginning of the run @end is in 178962306a36Sopenharmony_ci * to be @start is all that is needed. 179062306a36Sopenharmony_ci */ 179162306a36Sopenharmony_ci if (rl_end->lcn == LCN_HOLE) { 179262306a36Sopenharmony_ci /* Truncate the run containing @start. */ 179362306a36Sopenharmony_ci rl->length = start - rl->vcn; 179462306a36Sopenharmony_ci rl++; 179562306a36Sopenharmony_ci /* Cut out all runlist elements up to @end. */ 179662306a36Sopenharmony_ci if (rl < rl_end) 179762306a36Sopenharmony_ci memmove(rl, rl_end, (rl_real_end - rl_end + 1) * 179862306a36Sopenharmony_ci sizeof(*rl)); 179962306a36Sopenharmony_ci /* Extend the beginning of the run @end is in to be @start. */ 180062306a36Sopenharmony_ci rl->vcn = start; 180162306a36Sopenharmony_ci rl->length = rl[1].vcn - start; 180262306a36Sopenharmony_ci goto shrink_allocation; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci /* 180562306a36Sopenharmony_ci * If @end is not in a hole there are still two cases to distinguish. 180662306a36Sopenharmony_ci * Either @end is or is not in the same run as @start. 180762306a36Sopenharmony_ci * 180862306a36Sopenharmony_ci * The second case is easier as it can be reduced to an already solved 180962306a36Sopenharmony_ci * problem by truncating the run @start is in to end at @start - 1. 181062306a36Sopenharmony_ci * Then, if @end is in the next run need to split the run into a sparse 181162306a36Sopenharmony_ci * run followed by a non-sparse run (already covered above) and if @end 181262306a36Sopenharmony_ci * is not in the next run switching it to be sparse, again reduces the 181362306a36Sopenharmony_ci * problem to the already covered case of "@start is in a hole". 181462306a36Sopenharmony_ci */ 181562306a36Sopenharmony_ci if (end >= rl[1].vcn) { 181662306a36Sopenharmony_ci /* 181762306a36Sopenharmony_ci * If @end is not in the next run, reduce the problem to the 181862306a36Sopenharmony_ci * case of "@start is in a hole". 181962306a36Sopenharmony_ci */ 182062306a36Sopenharmony_ci if (rl[1].length && end >= rl[2].vcn) { 182162306a36Sopenharmony_ci /* Truncate the run containing @start. */ 182262306a36Sopenharmony_ci rl->length = start - rl->vcn; 182362306a36Sopenharmony_ci rl++; 182462306a36Sopenharmony_ci rl->vcn = start; 182562306a36Sopenharmony_ci rl->lcn = LCN_HOLE; 182662306a36Sopenharmony_ci goto extend_hole; 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1); 182962306a36Sopenharmony_ci if (IS_ERR(trl)) 183062306a36Sopenharmony_ci goto enomem_out; 183162306a36Sopenharmony_ci old_size++; 183262306a36Sopenharmony_ci if (runlist->rl != trl) { 183362306a36Sopenharmony_ci rl = trl + (rl - runlist->rl); 183462306a36Sopenharmony_ci rl_end = trl + (rl_end - runlist->rl); 183562306a36Sopenharmony_ci rl_real_end = trl + (rl_real_end - runlist->rl); 183662306a36Sopenharmony_ci runlist->rl = trl; 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci /* Truncate the run containing @start. */ 183962306a36Sopenharmony_ci rl->length = start - rl->vcn; 184062306a36Sopenharmony_ci rl++; 184162306a36Sopenharmony_ci /* 184262306a36Sopenharmony_ci * @end is in the next run, reduce the problem to the case 184362306a36Sopenharmony_ci * where "@start is at the beginning of a run and @end is in 184462306a36Sopenharmony_ci * the same run as @start". 184562306a36Sopenharmony_ci */ 184662306a36Sopenharmony_ci delta = rl->vcn - start; 184762306a36Sopenharmony_ci rl->vcn = start; 184862306a36Sopenharmony_ci if (rl->lcn >= 0) { 184962306a36Sopenharmony_ci rl->lcn -= delta; 185062306a36Sopenharmony_ci /* Need this in case the lcn just became negative. */ 185162306a36Sopenharmony_ci lcn_fixup = true; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci rl->length += delta; 185462306a36Sopenharmony_ci goto split_end; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci /* 185762306a36Sopenharmony_ci * The first case from above, i.e. @end is in the same run as @start. 185862306a36Sopenharmony_ci * We need to split the run into three. One run for the non-sparse 185962306a36Sopenharmony_ci * region between the beginning of the old run and @start, one for the 186062306a36Sopenharmony_ci * sparse region between @start and @end, and one for the remaining 186162306a36Sopenharmony_ci * non-sparse region, i.e. between @end and the end of the old run. 186262306a36Sopenharmony_ci */ 186362306a36Sopenharmony_ci trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 2); 186462306a36Sopenharmony_ci if (IS_ERR(trl)) 186562306a36Sopenharmony_ci goto enomem_out; 186662306a36Sopenharmony_ci old_size += 2; 186762306a36Sopenharmony_ci if (runlist->rl != trl) { 186862306a36Sopenharmony_ci rl = trl + (rl - runlist->rl); 186962306a36Sopenharmony_ci rl_end = trl + (rl_end - runlist->rl); 187062306a36Sopenharmony_ci rl_real_end = trl + (rl_real_end - runlist->rl); 187162306a36Sopenharmony_ci runlist->rl = trl; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci /* Shift all the runs up by two. */ 187462306a36Sopenharmony_ci memmove(rl + 2, rl, (rl_real_end - rl + 1) * sizeof(*rl)); 187562306a36Sopenharmony_ci /* Finally, setup the three split runs. */ 187662306a36Sopenharmony_ci rl->length = start - rl->vcn; 187762306a36Sopenharmony_ci rl++; 187862306a36Sopenharmony_ci rl->vcn = start; 187962306a36Sopenharmony_ci rl->lcn = LCN_HOLE; 188062306a36Sopenharmony_ci rl->length = length; 188162306a36Sopenharmony_ci rl++; 188262306a36Sopenharmony_ci delta = end - rl->vcn; 188362306a36Sopenharmony_ci rl->vcn = end; 188462306a36Sopenharmony_ci rl->lcn += delta; 188562306a36Sopenharmony_ci rl->length -= delta; 188662306a36Sopenharmony_ci ntfs_debug("Done (split both)."); 188762306a36Sopenharmony_ci return 0; 188862306a36Sopenharmony_cienomem_out: 188962306a36Sopenharmony_ci ntfs_error(vol->sb, "Not enough memory to extend runlist buffer."); 189062306a36Sopenharmony_ci return -ENOMEM; 189162306a36Sopenharmony_ci} 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci#endif /* NTFS_RW */ 1894