18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2001-2007 Anton Altaparmakov 68c2ecf20Sopenharmony_ci * Copyright (c) 2002-2005 Richard Russon 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "debug.h" 108c2ecf20Sopenharmony_ci#include "dir.h" 118c2ecf20Sopenharmony_ci#include "endian.h" 128c2ecf20Sopenharmony_ci#include "malloc.h" 138c2ecf20Sopenharmony_ci#include "ntfs.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/** 168c2ecf20Sopenharmony_ci * ntfs_rl_mm - runlist memmove 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlist @base. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_cistatic inline void ntfs_rl_mm(runlist_element *base, int dst, int src, 218c2ecf20Sopenharmony_ci int size) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci if (likely((dst != src) && (size > 0))) 248c2ecf20Sopenharmony_ci memmove(base + dst, base + src, size * sizeof(*base)); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/** 288c2ecf20Sopenharmony_ci * ntfs_rl_mc - runlist memory copy 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dstbase and 318c2ecf20Sopenharmony_ci * @srcbase. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_cistatic inline void ntfs_rl_mc(runlist_element *dstbase, int dst, 348c2ecf20Sopenharmony_ci runlist_element *srcbase, int src, int size) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci if (likely(size > 0)) 378c2ecf20Sopenharmony_ci memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase)); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/** 418c2ecf20Sopenharmony_ci * ntfs_rl_realloc - Reallocate memory for runlists 428c2ecf20Sopenharmony_ci * @rl: original runlist 438c2ecf20Sopenharmony_ci * @old_size: number of runlist elements in the original runlist @rl 448c2ecf20Sopenharmony_ci * @new_size: number of runlist elements we need space for 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * As the runlists grow, more memory will be required. To prevent the 478c2ecf20Sopenharmony_ci * kernel having to allocate and reallocate large numbers of small bits of 488c2ecf20Sopenharmony_ci * memory, this function returns an entire page of memory. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlist @rl. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * N.B. If the new allocation doesn't require a different number of pages in 538c2ecf20Sopenharmony_ci * memory, the function will return the original pointer. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * On success, return a pointer to the newly allocated, or recycled, memory. 568c2ecf20Sopenharmony_ci * On error, return -errno. The following error codes are defined: 578c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 588c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_cistatic inline runlist_element *ntfs_rl_realloc(runlist_element *rl, 618c2ecf20Sopenharmony_ci int old_size, int new_size) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci runlist_element *new_rl; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci old_size = PAGE_ALIGN(old_size * sizeof(*rl)); 668c2ecf20Sopenharmony_ci new_size = PAGE_ALIGN(new_size * sizeof(*rl)); 678c2ecf20Sopenharmony_ci if (old_size == new_size) 688c2ecf20Sopenharmony_ci return rl; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci new_rl = ntfs_malloc_nofs(new_size); 718c2ecf20Sopenharmony_ci if (unlikely(!new_rl)) 728c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (likely(rl != NULL)) { 758c2ecf20Sopenharmony_ci if (unlikely(old_size > new_size)) 768c2ecf20Sopenharmony_ci old_size = new_size; 778c2ecf20Sopenharmony_ci memcpy(new_rl, rl, old_size); 788c2ecf20Sopenharmony_ci ntfs_free(rl); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci return new_rl; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** 848c2ecf20Sopenharmony_ci * ntfs_rl_realloc_nofail - Reallocate memory for runlists 858c2ecf20Sopenharmony_ci * @rl: original runlist 868c2ecf20Sopenharmony_ci * @old_size: number of runlist elements in the original runlist @rl 878c2ecf20Sopenharmony_ci * @new_size: number of runlist elements we need space for 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * As the runlists grow, more memory will be required. To prevent the 908c2ecf20Sopenharmony_ci * kernel having to allocate and reallocate large numbers of small bits of 918c2ecf20Sopenharmony_ci * memory, this function returns an entire page of memory. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * This function guarantees that the allocation will succeed. It will sleep 948c2ecf20Sopenharmony_ci * for as long as it takes to complete the allocation. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlist @rl. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * N.B. If the new allocation doesn't require a different number of pages in 998c2ecf20Sopenharmony_ci * memory, the function will return the original pointer. 1008c2ecf20Sopenharmony_ci * 1018c2ecf20Sopenharmony_ci * On success, return a pointer to the newly allocated, or recycled, memory. 1028c2ecf20Sopenharmony_ci * On error, return -errno. The following error codes are defined: 1038c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 1048c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_cistatic inline runlist_element *ntfs_rl_realloc_nofail(runlist_element *rl, 1078c2ecf20Sopenharmony_ci int old_size, int new_size) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci runlist_element *new_rl; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci old_size = PAGE_ALIGN(old_size * sizeof(*rl)); 1128c2ecf20Sopenharmony_ci new_size = PAGE_ALIGN(new_size * sizeof(*rl)); 1138c2ecf20Sopenharmony_ci if (old_size == new_size) 1148c2ecf20Sopenharmony_ci return rl; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci new_rl = ntfs_malloc_nofs_nofail(new_size); 1178c2ecf20Sopenharmony_ci BUG_ON(!new_rl); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (likely(rl != NULL)) { 1208c2ecf20Sopenharmony_ci if (unlikely(old_size > new_size)) 1218c2ecf20Sopenharmony_ci old_size = new_size; 1228c2ecf20Sopenharmony_ci memcpy(new_rl, rl, old_size); 1238c2ecf20Sopenharmony_ci ntfs_free(rl); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci return new_rl; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/** 1298c2ecf20Sopenharmony_ci * ntfs_are_rl_mergeable - test if two runlists can be joined together 1308c2ecf20Sopenharmony_ci * @dst: original runlist 1318c2ecf20Sopenharmony_ci * @src: new runlist to test for mergeability with @dst 1328c2ecf20Sopenharmony_ci * 1338c2ecf20Sopenharmony_ci * Test if two runlists can be joined together. For this, their VCNs and LCNs 1348c2ecf20Sopenharmony_ci * must be adjacent. 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * Return: true Success, the runlists can be merged. 1398c2ecf20Sopenharmony_ci * false Failure, the runlists cannot be merged. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic inline bool ntfs_are_rl_mergeable(runlist_element *dst, 1428c2ecf20Sopenharmony_ci runlist_element *src) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci BUG_ON(!dst); 1458c2ecf20Sopenharmony_ci BUG_ON(!src); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* We can merge unmapped regions even if they are misaligned. */ 1488c2ecf20Sopenharmony_ci if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED)) 1498c2ecf20Sopenharmony_ci return true; 1508c2ecf20Sopenharmony_ci /* If the runs are misaligned, we cannot merge them. */ 1518c2ecf20Sopenharmony_ci if ((dst->vcn + dst->length) != src->vcn) 1528c2ecf20Sopenharmony_ci return false; 1538c2ecf20Sopenharmony_ci /* If both runs are non-sparse and contiguous, we can merge them. */ 1548c2ecf20Sopenharmony_ci if ((dst->lcn >= 0) && (src->lcn >= 0) && 1558c2ecf20Sopenharmony_ci ((dst->lcn + dst->length) == src->lcn)) 1568c2ecf20Sopenharmony_ci return true; 1578c2ecf20Sopenharmony_ci /* If we are merging two holes, we can merge them. */ 1588c2ecf20Sopenharmony_ci if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE)) 1598c2ecf20Sopenharmony_ci return true; 1608c2ecf20Sopenharmony_ci /* Cannot merge. */ 1618c2ecf20Sopenharmony_ci return false; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/** 1658c2ecf20Sopenharmony_ci * __ntfs_rl_merge - merge two runlists without testing if they can be merged 1668c2ecf20Sopenharmony_ci * @dst: original, destination runlist 1678c2ecf20Sopenharmony_ci * @src: new runlist to merge with @dst 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * Merge the two runlists, writing into the destination runlist @dst. The 1708c2ecf20Sopenharmony_ci * caller must make sure the runlists can be merged or this will corrupt the 1718c2ecf20Sopenharmony_ci * destination runlist. 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_cistatic inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci dst->length += src->length; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/** 1818c2ecf20Sopenharmony_ci * ntfs_rl_append - append a runlist after a given element 1828c2ecf20Sopenharmony_ci * @dst: original runlist to be worked on 1838c2ecf20Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 1848c2ecf20Sopenharmony_ci * @src: runlist to be inserted into @dst 1858c2ecf20Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 1868c2ecf20Sopenharmony_ci * @loc: append the new runlist @src after this element in @dst 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * Append the runlist @src after element @loc in @dst. Merge the right end of 1898c2ecf20Sopenharmony_ci * the new runlist, if necessary. Adjust the size of the hole before the 1908c2ecf20Sopenharmony_ci * appended runlist. 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 1958c2ecf20Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 1968c2ecf20Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 1978c2ecf20Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 2008c2ecf20Sopenharmony_ci * error codes are defined: 2018c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 2028c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_cistatic inline runlist_element *ntfs_rl_append(runlist_element *dst, 2058c2ecf20Sopenharmony_ci int dsize, runlist_element *src, int ssize, int loc) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci bool right = false; /* Right end of @src needs merging. */ 2088c2ecf20Sopenharmony_ci int marker; /* End of the inserted runs. */ 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci BUG_ON(!dst); 2118c2ecf20Sopenharmony_ci BUG_ON(!src); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* First, check if the right hand end needs merging. */ 2148c2ecf20Sopenharmony_ci if ((loc + 1) < dsize) 2158c2ecf20Sopenharmony_ci right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Space required: @dst size + @src size, less one if we merged. */ 2188c2ecf20Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right); 2198c2ecf20Sopenharmony_ci if (IS_ERR(dst)) 2208c2ecf20Sopenharmony_ci return dst; 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 2238c2ecf20Sopenharmony_ci * original runlists. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* First, merge the right hand end, if necessary. */ 2278c2ecf20Sopenharmony_ci if (right) 2288c2ecf20Sopenharmony_ci __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* First run after the @src runs that have been inserted. */ 2318c2ecf20Sopenharmony_ci marker = loc + ssize + 1; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 2348c2ecf20Sopenharmony_ci ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - (loc + 1 + right)); 2358c2ecf20Sopenharmony_ci ntfs_rl_mc(dst, loc + 1, src, 0, ssize); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* Adjust the size of the preceding hole. */ 2388c2ecf20Sopenharmony_ci dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* We may have changed the length of the file, so fix the end marker */ 2418c2ecf20Sopenharmony_ci if (dst[marker].lcn == LCN_ENOENT) 2428c2ecf20Sopenharmony_ci dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return dst; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/** 2488c2ecf20Sopenharmony_ci * ntfs_rl_insert - insert a runlist into another 2498c2ecf20Sopenharmony_ci * @dst: original runlist to be worked on 2508c2ecf20Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 2518c2ecf20Sopenharmony_ci * @src: new runlist to be inserted 2528c2ecf20Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 2538c2ecf20Sopenharmony_ci * @loc: insert the new runlist @src before this element in @dst 2548c2ecf20Sopenharmony_ci * 2558c2ecf20Sopenharmony_ci * Insert the runlist @src before element @loc in the runlist @dst. Merge the 2568c2ecf20Sopenharmony_ci * left end of the new runlist, if necessary. Adjust the size of the hole 2578c2ecf20Sopenharmony_ci * after the inserted runlist. 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 2628c2ecf20Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 2638c2ecf20Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 2648c2ecf20Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 2678c2ecf20Sopenharmony_ci * error codes are defined: 2688c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 2698c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_cistatic inline runlist_element *ntfs_rl_insert(runlist_element *dst, 2728c2ecf20Sopenharmony_ci int dsize, runlist_element *src, int ssize, int loc) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci bool left = false; /* Left end of @src needs merging. */ 2758c2ecf20Sopenharmony_ci bool disc = false; /* Discontinuity between @dst and @src. */ 2768c2ecf20Sopenharmony_ci int marker; /* End of the inserted runs. */ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci BUG_ON(!dst); 2798c2ecf20Sopenharmony_ci BUG_ON(!src); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* 2828c2ecf20Sopenharmony_ci * disc => Discontinuity between the end of @dst and the start of @src. 2838c2ecf20Sopenharmony_ci * This means we might need to insert a "not mapped" run. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci if (loc == 0) 2868c2ecf20Sopenharmony_ci disc = (src[0].vcn > 0); 2878c2ecf20Sopenharmony_ci else { 2888c2ecf20Sopenharmony_ci s64 merged_length; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci left = ntfs_are_rl_mergeable(dst + loc - 1, src); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci merged_length = dst[loc - 1].length; 2938c2ecf20Sopenharmony_ci if (left) 2948c2ecf20Sopenharmony_ci merged_length += src->length; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci disc = (src[0].vcn > dst[loc - 1].vcn + merged_length); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci /* 2998c2ecf20Sopenharmony_ci * Space required: @dst size + @src size, less one if we merged, plus 3008c2ecf20Sopenharmony_ci * one if there was a discontinuity. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc); 3038c2ecf20Sopenharmony_ci if (IS_ERR(dst)) 3048c2ecf20Sopenharmony_ci return dst; 3058c2ecf20Sopenharmony_ci /* 3068c2ecf20Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 3078c2ecf20Sopenharmony_ci * original runlist. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci if (left) 3108c2ecf20Sopenharmony_ci __ntfs_rl_merge(dst + loc - 1, src); 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * First run after the @src runs that have been inserted. 3138c2ecf20Sopenharmony_ci * Nominally, @marker equals @loc + @ssize, i.e. location + number of 3148c2ecf20Sopenharmony_ci * runs in @src. However, if @left, then the first run in @src has 3158c2ecf20Sopenharmony_ci * been merged with one in @dst. And if @disc, then @dst and @src do 3168c2ecf20Sopenharmony_ci * not meet and we need an extra run to fill the gap. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci marker = loc + ssize - left + disc; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 3218c2ecf20Sopenharmony_ci ntfs_rl_mm(dst, marker, loc, dsize - loc); 3228c2ecf20Sopenharmony_ci ntfs_rl_mc(dst, loc + disc, src, left, ssize - left); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci /* Adjust the VCN of the first run after the insertion... */ 3258c2ecf20Sopenharmony_ci dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; 3268c2ecf20Sopenharmony_ci /* ... and the length. */ 3278c2ecf20Sopenharmony_ci if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED) 3288c2ecf20Sopenharmony_ci dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Writing beyond the end of the file and there is a discontinuity. */ 3318c2ecf20Sopenharmony_ci if (disc) { 3328c2ecf20Sopenharmony_ci if (loc > 0) { 3338c2ecf20Sopenharmony_ci dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length; 3348c2ecf20Sopenharmony_ci dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci dst[loc].vcn = 0; 3378c2ecf20Sopenharmony_ci dst[loc].length = dst[loc + 1].vcn; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci dst[loc].lcn = LCN_RL_NOT_MAPPED; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci return dst; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/** 3458c2ecf20Sopenharmony_ci * ntfs_rl_replace - overwrite a runlist element with another runlist 3468c2ecf20Sopenharmony_ci * @dst: original runlist to be worked on 3478c2ecf20Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 3488c2ecf20Sopenharmony_ci * @src: new runlist to be inserted 3498c2ecf20Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 3508c2ecf20Sopenharmony_ci * @loc: index in runlist @dst to overwrite with @src 3518c2ecf20Sopenharmony_ci * 3528c2ecf20Sopenharmony_ci * Replace the runlist element @dst at @loc with @src. Merge the left and 3538c2ecf20Sopenharmony_ci * right ends of the inserted runlist, if necessary. 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 3588c2ecf20Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 3598c2ecf20Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 3608c2ecf20Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 3638c2ecf20Sopenharmony_ci * error codes are defined: 3648c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 3658c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_cistatic inline runlist_element *ntfs_rl_replace(runlist_element *dst, 3688c2ecf20Sopenharmony_ci int dsize, runlist_element *src, int ssize, int loc) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci signed delta; 3718c2ecf20Sopenharmony_ci bool left = false; /* Left end of @src needs merging. */ 3728c2ecf20Sopenharmony_ci bool right = false; /* Right end of @src needs merging. */ 3738c2ecf20Sopenharmony_ci int tail; /* Start of tail of @dst. */ 3748c2ecf20Sopenharmony_ci int marker; /* End of the inserted runs. */ 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci BUG_ON(!dst); 3778c2ecf20Sopenharmony_ci BUG_ON(!src); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* First, see if the left and right ends need merging. */ 3808c2ecf20Sopenharmony_ci if ((loc + 1) < dsize) 3818c2ecf20Sopenharmony_ci right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); 3828c2ecf20Sopenharmony_ci if (loc > 0) 3838c2ecf20Sopenharmony_ci left = ntfs_are_rl_mergeable(dst + loc - 1, src); 3848c2ecf20Sopenharmony_ci /* 3858c2ecf20Sopenharmony_ci * Allocate some space. We will need less if the left, right, or both 3868c2ecf20Sopenharmony_ci * ends get merged. The -1 accounts for the run being replaced. 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci delta = ssize - 1 - left - right; 3898c2ecf20Sopenharmony_ci if (delta > 0) { 3908c2ecf20Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + delta); 3918c2ecf20Sopenharmony_ci if (IS_ERR(dst)) 3928c2ecf20Sopenharmony_ci return dst; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci /* 3958c2ecf20Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 3968c2ecf20Sopenharmony_ci * original runlists. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* First, merge the left and right ends, if necessary. */ 4008c2ecf20Sopenharmony_ci if (right) 4018c2ecf20Sopenharmony_ci __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); 4028c2ecf20Sopenharmony_ci if (left) 4038c2ecf20Sopenharmony_ci __ntfs_rl_merge(dst + loc - 1, src); 4048c2ecf20Sopenharmony_ci /* 4058c2ecf20Sopenharmony_ci * Offset of the tail of @dst. This needs to be moved out of the way 4068c2ecf20Sopenharmony_ci * to make space for the runs to be copied from @src, i.e. the first 4078c2ecf20Sopenharmony_ci * run of the tail of @dst. 4088c2ecf20Sopenharmony_ci * Nominally, @tail equals @loc + 1, i.e. location, skipping the 4098c2ecf20Sopenharmony_ci * replaced run. However, if @right, then one of @dst's runs is 4108c2ecf20Sopenharmony_ci * already merged into @src. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci tail = loc + right + 1; 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * First run after the @src runs that have been inserted, i.e. where 4158c2ecf20Sopenharmony_ci * the tail of @dst needs to be moved to. 4168c2ecf20Sopenharmony_ci * Nominally, @marker equals @loc + @ssize, i.e. location + number of 4178c2ecf20Sopenharmony_ci * runs in @src. However, if @left, then the first run in @src has 4188c2ecf20Sopenharmony_ci * been merged with one in @dst. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci marker = loc + ssize - left; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 4238c2ecf20Sopenharmony_ci ntfs_rl_mm(dst, marker, tail, dsize - tail); 4248c2ecf20Sopenharmony_ci ntfs_rl_mc(dst, loc, src, left, ssize - left); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* We may have changed the length of the file, so fix the end marker. */ 4278c2ecf20Sopenharmony_ci if (dsize - tail > 0 && dst[marker].lcn == LCN_ENOENT) 4288c2ecf20Sopenharmony_ci dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; 4298c2ecf20Sopenharmony_ci return dst; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci/** 4338c2ecf20Sopenharmony_ci * ntfs_rl_split - insert a runlist into the centre of a hole 4348c2ecf20Sopenharmony_ci * @dst: original runlist to be worked on 4358c2ecf20Sopenharmony_ci * @dsize: number of elements in @dst (including end marker) 4368c2ecf20Sopenharmony_ci * @src: new runlist to be inserted 4378c2ecf20Sopenharmony_ci * @ssize: number of elements in @src (excluding end marker) 4388c2ecf20Sopenharmony_ci * @loc: index in runlist @dst at which to split and insert @src 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * Split the runlist @dst at @loc into two and insert @new in between the two 4418c2ecf20Sopenharmony_ci * fragments. No merging of runlists is necessary. Adjust the size of the 4428c2ecf20Sopenharmony_ci * holes either side. 4438c2ecf20Sopenharmony_ci * 4448c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @dst and @src. 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 4478c2ecf20Sopenharmony_ci * runlists @dst and @src are deallocated before returning so you cannot use 4488c2ecf20Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 4498c2ecf20Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 4508c2ecf20Sopenharmony_ci * 4518c2ecf20Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 4528c2ecf20Sopenharmony_ci * error codes are defined: 4538c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 4548c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_cistatic inline runlist_element *ntfs_rl_split(runlist_element *dst, int dsize, 4578c2ecf20Sopenharmony_ci runlist_element *src, int ssize, int loc) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci BUG_ON(!dst); 4608c2ecf20Sopenharmony_ci BUG_ON(!src); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* Space required: @dst size + @src size + one new hole. */ 4638c2ecf20Sopenharmony_ci dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1); 4648c2ecf20Sopenharmony_ci if (IS_ERR(dst)) 4658c2ecf20Sopenharmony_ci return dst; 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * We are guaranteed to succeed from here so can start modifying the 4688c2ecf20Sopenharmony_ci * original runlists. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Move the tail of @dst out of the way, then copy in @src. */ 4728c2ecf20Sopenharmony_ci ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc); 4738c2ecf20Sopenharmony_ci ntfs_rl_mc(dst, loc + 1, src, 0, ssize); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Adjust the size of the holes either size of @src. */ 4768c2ecf20Sopenharmony_ci dst[loc].length = dst[loc+1].vcn - dst[loc].vcn; 4778c2ecf20Sopenharmony_ci dst[loc+ssize+1].vcn = dst[loc+ssize].vcn + dst[loc+ssize].length; 4788c2ecf20Sopenharmony_ci dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return dst; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci/** 4848c2ecf20Sopenharmony_ci * ntfs_runlists_merge - merge two runlists into one 4858c2ecf20Sopenharmony_ci * @drl: original runlist to be worked on 4868c2ecf20Sopenharmony_ci * @srl: new runlist to be merged into @drl 4878c2ecf20Sopenharmony_ci * 4888c2ecf20Sopenharmony_ci * First we sanity check the two runlists @srl and @drl to make sure that they 4898c2ecf20Sopenharmony_ci * are sensible and can be merged. The runlist @srl must be either after the 4908c2ecf20Sopenharmony_ci * runlist @drl or completely within a hole (or unmapped region) in @drl. 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlists @drl and @srl. 4938c2ecf20Sopenharmony_ci * 4948c2ecf20Sopenharmony_ci * Merging of runlists is necessary in two cases: 4958c2ecf20Sopenharmony_ci * 1. When attribute lists are used and a further extent is being mapped. 4968c2ecf20Sopenharmony_ci * 2. When new clusters are allocated to fill a hole or extend a file. 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * There are four possible ways @srl can be merged. It can: 4998c2ecf20Sopenharmony_ci * - be inserted at the beginning of a hole, 5008c2ecf20Sopenharmony_ci * - split the hole in two and be inserted between the two fragments, 5018c2ecf20Sopenharmony_ci * - be appended at the end of a hole, or it can 5028c2ecf20Sopenharmony_ci * - replace the whole hole. 5038c2ecf20Sopenharmony_ci * It can also be appended to the end of the runlist, which is just a variant 5048c2ecf20Sopenharmony_ci * of the insert case. 5058c2ecf20Sopenharmony_ci * 5068c2ecf20Sopenharmony_ci * On success, return a pointer to the new, combined, runlist. Note, both 5078c2ecf20Sopenharmony_ci * runlists @drl and @srl are deallocated before returning so you cannot use 5088c2ecf20Sopenharmony_ci * the pointers for anything any more. (Strictly speaking the returned runlist 5098c2ecf20Sopenharmony_ci * may be the same as @dst but this is irrelevant.) 5108c2ecf20Sopenharmony_ci * 5118c2ecf20Sopenharmony_ci * On error, return -errno. Both runlists are left unmodified. The following 5128c2ecf20Sopenharmony_ci * error codes are defined: 5138c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 5148c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 5158c2ecf20Sopenharmony_ci * -ERANGE - The runlists overlap and cannot be merged. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_cirunlist_element *ntfs_runlists_merge(runlist_element *drl, 5188c2ecf20Sopenharmony_ci runlist_element *srl) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci int di, si; /* Current index into @[ds]rl. */ 5218c2ecf20Sopenharmony_ci int sstart; /* First index with lcn > LCN_RL_NOT_MAPPED. */ 5228c2ecf20Sopenharmony_ci int dins; /* Index into @drl at which to insert @srl. */ 5238c2ecf20Sopenharmony_ci int dend, send; /* Last index into @[ds]rl. */ 5248c2ecf20Sopenharmony_ci int dfinal, sfinal; /* The last index into @[ds]rl with 5258c2ecf20Sopenharmony_ci lcn >= LCN_HOLE. */ 5268c2ecf20Sopenharmony_ci int marker = 0; 5278c2ecf20Sopenharmony_ci VCN marker_vcn = 0; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci#ifdef DEBUG 5308c2ecf20Sopenharmony_ci ntfs_debug("dst:"); 5318c2ecf20Sopenharmony_ci ntfs_debug_dump_runlist(drl); 5328c2ecf20Sopenharmony_ci ntfs_debug("src:"); 5338c2ecf20Sopenharmony_ci ntfs_debug_dump_runlist(srl); 5348c2ecf20Sopenharmony_ci#endif 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* Check for silly calling... */ 5378c2ecf20Sopenharmony_ci if (unlikely(!srl)) 5388c2ecf20Sopenharmony_ci return drl; 5398c2ecf20Sopenharmony_ci if (IS_ERR(srl) || IS_ERR(drl)) 5408c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* Check for the case where the first mapping is being done now. */ 5438c2ecf20Sopenharmony_ci if (unlikely(!drl)) { 5448c2ecf20Sopenharmony_ci drl = srl; 5458c2ecf20Sopenharmony_ci /* Complete the source runlist if necessary. */ 5468c2ecf20Sopenharmony_ci if (unlikely(drl[0].vcn)) { 5478c2ecf20Sopenharmony_ci /* Scan to the end of the source runlist. */ 5488c2ecf20Sopenharmony_ci for (dend = 0; likely(drl[dend].length); dend++) 5498c2ecf20Sopenharmony_ci ; 5508c2ecf20Sopenharmony_ci dend++; 5518c2ecf20Sopenharmony_ci drl = ntfs_rl_realloc(drl, dend, dend + 1); 5528c2ecf20Sopenharmony_ci if (IS_ERR(drl)) 5538c2ecf20Sopenharmony_ci return drl; 5548c2ecf20Sopenharmony_ci /* Insert start element at the front of the runlist. */ 5558c2ecf20Sopenharmony_ci ntfs_rl_mm(drl, 1, 0, dend); 5568c2ecf20Sopenharmony_ci drl[0].vcn = 0; 5578c2ecf20Sopenharmony_ci drl[0].lcn = LCN_RL_NOT_MAPPED; 5588c2ecf20Sopenharmony_ci drl[0].length = drl[1].vcn; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci goto finished; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci si = di = 0; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Skip any unmapped start element(s) in the source runlist. */ 5668c2ecf20Sopenharmony_ci while (srl[si].length && srl[si].lcn < LCN_HOLE) 5678c2ecf20Sopenharmony_ci si++; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* Can't have an entirely unmapped source runlist. */ 5708c2ecf20Sopenharmony_ci BUG_ON(!srl[si].length); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* Record the starting points. */ 5738c2ecf20Sopenharmony_ci sstart = si; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * Skip forward in @drl until we reach the position where @srl needs to 5778c2ecf20Sopenharmony_ci * be inserted. If we reach the end of @drl, @srl just needs to be 5788c2ecf20Sopenharmony_ci * appended to @drl. 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci for (; drl[di].length; di++) { 5818c2ecf20Sopenharmony_ci if (drl[di].vcn + drl[di].length > srl[sstart].vcn) 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci dins = di; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* Sanity check for illegal overlaps. */ 5878c2ecf20Sopenharmony_ci if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) && 5888c2ecf20Sopenharmony_ci (srl[si].lcn >= 0)) { 5898c2ecf20Sopenharmony_ci ntfs_error(NULL, "Run lists overlap. Cannot merge!"); 5908c2ecf20Sopenharmony_ci return ERR_PTR(-ERANGE); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* Scan to the end of both runlists in order to know their sizes. */ 5948c2ecf20Sopenharmony_ci for (send = si; srl[send].length; send++) 5958c2ecf20Sopenharmony_ci ; 5968c2ecf20Sopenharmony_ci for (dend = di; drl[dend].length; dend++) 5978c2ecf20Sopenharmony_ci ; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (srl[send].lcn == LCN_ENOENT) 6008c2ecf20Sopenharmony_ci marker_vcn = srl[marker = send].vcn; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* Scan to the last element with lcn >= LCN_HOLE. */ 6038c2ecf20Sopenharmony_ci for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--) 6048c2ecf20Sopenharmony_ci ; 6058c2ecf20Sopenharmony_ci for (dfinal = dend; dfinal >= 0 && drl[dfinal].lcn < LCN_HOLE; dfinal--) 6068c2ecf20Sopenharmony_ci ; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci { 6098c2ecf20Sopenharmony_ci bool start; 6108c2ecf20Sopenharmony_ci bool finish; 6118c2ecf20Sopenharmony_ci int ds = dend + 1; /* Number of elements in drl & srl */ 6128c2ecf20Sopenharmony_ci int ss = sfinal - sstart + 1; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci start = ((drl[dins].lcn < LCN_RL_NOT_MAPPED) || /* End of file */ 6158c2ecf20Sopenharmony_ci (drl[dins].vcn == srl[sstart].vcn)); /* Start of hole */ 6168c2ecf20Sopenharmony_ci finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) && /* End of file */ 6178c2ecf20Sopenharmony_ci ((drl[dins].vcn + drl[dins].length) <= /* End of hole */ 6188c2ecf20Sopenharmony_ci (srl[send - 1].vcn + srl[send - 1].length))); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* Or we will lose an end marker. */ 6218c2ecf20Sopenharmony_ci if (finish && !drl[dins].length) 6228c2ecf20Sopenharmony_ci ss++; 6238c2ecf20Sopenharmony_ci if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn)) 6248c2ecf20Sopenharmony_ci finish = false; 6258c2ecf20Sopenharmony_ci#if 0 6268c2ecf20Sopenharmony_ci ntfs_debug("dfinal = %i, dend = %i", dfinal, dend); 6278c2ecf20Sopenharmony_ci ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send); 6288c2ecf20Sopenharmony_ci ntfs_debug("start = %i, finish = %i", start, finish); 6298c2ecf20Sopenharmony_ci ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins); 6308c2ecf20Sopenharmony_ci#endif 6318c2ecf20Sopenharmony_ci if (start) { 6328c2ecf20Sopenharmony_ci if (finish) 6338c2ecf20Sopenharmony_ci drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins); 6348c2ecf20Sopenharmony_ci else 6358c2ecf20Sopenharmony_ci drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins); 6368c2ecf20Sopenharmony_ci } else { 6378c2ecf20Sopenharmony_ci if (finish) 6388c2ecf20Sopenharmony_ci drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins); 6398c2ecf20Sopenharmony_ci else 6408c2ecf20Sopenharmony_ci drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins); 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci if (IS_ERR(drl)) { 6438c2ecf20Sopenharmony_ci ntfs_error(NULL, "Merge failed."); 6448c2ecf20Sopenharmony_ci return drl; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci ntfs_free(srl); 6478c2ecf20Sopenharmony_ci if (marker) { 6488c2ecf20Sopenharmony_ci ntfs_debug("Triggering marker code."); 6498c2ecf20Sopenharmony_ci for (ds = dend; drl[ds].length; ds++) 6508c2ecf20Sopenharmony_ci ; 6518c2ecf20Sopenharmony_ci /* We only need to care if @srl ended after @drl. */ 6528c2ecf20Sopenharmony_ci if (drl[ds].vcn <= marker_vcn) { 6538c2ecf20Sopenharmony_ci int slots = 0; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (drl[ds].vcn == marker_vcn) { 6568c2ecf20Sopenharmony_ci ntfs_debug("Old marker = 0x%llx, replacing " 6578c2ecf20Sopenharmony_ci "with LCN_ENOENT.", 6588c2ecf20Sopenharmony_ci (unsigned long long) 6598c2ecf20Sopenharmony_ci drl[ds].lcn); 6608c2ecf20Sopenharmony_ci drl[ds].lcn = LCN_ENOENT; 6618c2ecf20Sopenharmony_ci goto finished; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci /* 6648c2ecf20Sopenharmony_ci * We need to create an unmapped runlist element in 6658c2ecf20Sopenharmony_ci * @drl or extend an existing one before adding the 6668c2ecf20Sopenharmony_ci * ENOENT terminator. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ci if (drl[ds].lcn == LCN_ENOENT) { 6698c2ecf20Sopenharmony_ci ds--; 6708c2ecf20Sopenharmony_ci slots = 1; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci if (drl[ds].lcn != LCN_RL_NOT_MAPPED) { 6738c2ecf20Sopenharmony_ci /* Add an unmapped runlist element. */ 6748c2ecf20Sopenharmony_ci if (!slots) { 6758c2ecf20Sopenharmony_ci drl = ntfs_rl_realloc_nofail(drl, ds, 6768c2ecf20Sopenharmony_ci ds + 2); 6778c2ecf20Sopenharmony_ci slots = 2; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci ds++; 6808c2ecf20Sopenharmony_ci /* Need to set vcn if it isn't set already. */ 6818c2ecf20Sopenharmony_ci if (slots != 1) 6828c2ecf20Sopenharmony_ci drl[ds].vcn = drl[ds - 1].vcn + 6838c2ecf20Sopenharmony_ci drl[ds - 1].length; 6848c2ecf20Sopenharmony_ci drl[ds].lcn = LCN_RL_NOT_MAPPED; 6858c2ecf20Sopenharmony_ci /* We now used up a slot. */ 6868c2ecf20Sopenharmony_ci slots--; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci drl[ds].length = marker_vcn - drl[ds].vcn; 6898c2ecf20Sopenharmony_ci /* Finally add the ENOENT terminator. */ 6908c2ecf20Sopenharmony_ci ds++; 6918c2ecf20Sopenharmony_ci if (!slots) 6928c2ecf20Sopenharmony_ci drl = ntfs_rl_realloc_nofail(drl, ds, ds + 1); 6938c2ecf20Sopenharmony_ci drl[ds].vcn = marker_vcn; 6948c2ecf20Sopenharmony_ci drl[ds].lcn = LCN_ENOENT; 6958c2ecf20Sopenharmony_ci drl[ds].length = (s64)0; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cifinished: 7018c2ecf20Sopenharmony_ci /* The merge was completed successfully. */ 7028c2ecf20Sopenharmony_ci ntfs_debug("Merged runlist:"); 7038c2ecf20Sopenharmony_ci ntfs_debug_dump_runlist(drl); 7048c2ecf20Sopenharmony_ci return drl; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci/** 7088c2ecf20Sopenharmony_ci * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist 7098c2ecf20Sopenharmony_ci * @vol: ntfs volume on which the attribute resides 7108c2ecf20Sopenharmony_ci * @attr: attribute record whose mapping pairs array to decompress 7118c2ecf20Sopenharmony_ci * @old_rl: optional runlist in which to insert @attr's runlist 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlist @old_rl. 7148c2ecf20Sopenharmony_ci * 7158c2ecf20Sopenharmony_ci * Decompress the attribute @attr's mapping pairs array into a runlist. On 7168c2ecf20Sopenharmony_ci * success, return the decompressed runlist. 7178c2ecf20Sopenharmony_ci * 7188c2ecf20Sopenharmony_ci * If @old_rl is not NULL, decompressed runlist is inserted into the 7198c2ecf20Sopenharmony_ci * appropriate place in @old_rl and the resultant, combined runlist is 7208c2ecf20Sopenharmony_ci * returned. The original @old_rl is deallocated. 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * On error, return -errno. @old_rl is left unmodified in that case. 7238c2ecf20Sopenharmony_ci * 7248c2ecf20Sopenharmony_ci * The following error codes are defined: 7258c2ecf20Sopenharmony_ci * -ENOMEM - Not enough memory to allocate runlist array. 7268c2ecf20Sopenharmony_ci * -EIO - Corrupt runlist. 7278c2ecf20Sopenharmony_ci * -EINVAL - Invalid parameters were passed in. 7288c2ecf20Sopenharmony_ci * -ERANGE - The two runlists overlap. 7298c2ecf20Sopenharmony_ci * 7308c2ecf20Sopenharmony_ci * FIXME: For now we take the conceptionally simplest approach of creating the 7318c2ecf20Sopenharmony_ci * new runlist disregarding the already existing one and then splicing the 7328c2ecf20Sopenharmony_ci * two into one, if that is possible (we check for overlap and discard the new 7338c2ecf20Sopenharmony_ci * runlist if overlap present before returning ERR_PTR(-ERANGE)). 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_cirunlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, 7368c2ecf20Sopenharmony_ci const ATTR_RECORD *attr, runlist_element *old_rl) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci VCN vcn; /* Current vcn. */ 7398c2ecf20Sopenharmony_ci LCN lcn; /* Current lcn. */ 7408c2ecf20Sopenharmony_ci s64 deltaxcn; /* Change in [vl]cn. */ 7418c2ecf20Sopenharmony_ci runlist_element *rl; /* The output runlist. */ 7428c2ecf20Sopenharmony_ci u8 *buf; /* Current position in mapping pairs array. */ 7438c2ecf20Sopenharmony_ci u8 *attr_end; /* End of attribute. */ 7448c2ecf20Sopenharmony_ci int rlsize; /* Size of runlist buffer. */ 7458c2ecf20Sopenharmony_ci u16 rlpos; /* Current runlist position in units of 7468c2ecf20Sopenharmony_ci runlist_elements. */ 7478c2ecf20Sopenharmony_ci u8 b; /* Current byte offset in buf. */ 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci#ifdef DEBUG 7508c2ecf20Sopenharmony_ci /* Make sure attr exists and is non-resident. */ 7518c2ecf20Sopenharmony_ci if (!attr || !attr->non_resident || sle64_to_cpu( 7528c2ecf20Sopenharmony_ci attr->data.non_resident.lowest_vcn) < (VCN)0) { 7538c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Invalid arguments."); 7548c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci#endif 7578c2ecf20Sopenharmony_ci /* Start at vcn = lowest_vcn and lcn 0. */ 7588c2ecf20Sopenharmony_ci vcn = sle64_to_cpu(attr->data.non_resident.lowest_vcn); 7598c2ecf20Sopenharmony_ci lcn = 0; 7608c2ecf20Sopenharmony_ci /* Get start of the mapping pairs array. */ 7618c2ecf20Sopenharmony_ci buf = (u8*)attr + le16_to_cpu( 7628c2ecf20Sopenharmony_ci attr->data.non_resident.mapping_pairs_offset); 7638c2ecf20Sopenharmony_ci attr_end = (u8*)attr + le32_to_cpu(attr->length); 7648c2ecf20Sopenharmony_ci if (unlikely(buf < (u8*)attr || buf > attr_end)) { 7658c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Corrupt attribute."); 7668c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci /* If the mapping pairs array is valid but empty, nothing to do. */ 7698c2ecf20Sopenharmony_ci if (!vcn && !*buf) 7708c2ecf20Sopenharmony_ci return old_rl; 7718c2ecf20Sopenharmony_ci /* Current position in runlist array. */ 7728c2ecf20Sopenharmony_ci rlpos = 0; 7738c2ecf20Sopenharmony_ci /* Allocate first page and set current runlist size to one page. */ 7748c2ecf20Sopenharmony_ci rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE); 7758c2ecf20Sopenharmony_ci if (unlikely(!rl)) 7768c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 7778c2ecf20Sopenharmony_ci /* Insert unmapped starting element if necessary. */ 7788c2ecf20Sopenharmony_ci if (vcn) { 7798c2ecf20Sopenharmony_ci rl->vcn = 0; 7808c2ecf20Sopenharmony_ci rl->lcn = LCN_RL_NOT_MAPPED; 7818c2ecf20Sopenharmony_ci rl->length = vcn; 7828c2ecf20Sopenharmony_ci rlpos++; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci while (buf < attr_end && *buf) { 7858c2ecf20Sopenharmony_ci /* 7868c2ecf20Sopenharmony_ci * Allocate more memory if needed, including space for the 7878c2ecf20Sopenharmony_ci * not-mapped and terminator elements. ntfs_malloc_nofs() 7888c2ecf20Sopenharmony_ci * operates on whole pages only. 7898c2ecf20Sopenharmony_ci */ 7908c2ecf20Sopenharmony_ci if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) { 7918c2ecf20Sopenharmony_ci runlist_element *rl2; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE); 7948c2ecf20Sopenharmony_ci if (unlikely(!rl2)) { 7958c2ecf20Sopenharmony_ci ntfs_free(rl); 7968c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci memcpy(rl2, rl, rlsize); 7998c2ecf20Sopenharmony_ci ntfs_free(rl); 8008c2ecf20Sopenharmony_ci rl = rl2; 8018c2ecf20Sopenharmony_ci rlsize += PAGE_SIZE; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci /* Enter the current vcn into the current runlist element. */ 8048c2ecf20Sopenharmony_ci rl[rlpos].vcn = vcn; 8058c2ecf20Sopenharmony_ci /* 8068c2ecf20Sopenharmony_ci * Get the change in vcn, i.e. the run length in clusters. 8078c2ecf20Sopenharmony_ci * Doing it this way ensures that we signextend negative values. 8088c2ecf20Sopenharmony_ci * A negative run length doesn't make any sense, but hey, I 8098c2ecf20Sopenharmony_ci * didn't make up the NTFS specs and Windows NT4 treats the run 8108c2ecf20Sopenharmony_ci * length as a signed value so that's how it is... 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci b = *buf & 0xf; 8138c2ecf20Sopenharmony_ci if (b) { 8148c2ecf20Sopenharmony_ci if (unlikely(buf + b > attr_end)) 8158c2ecf20Sopenharmony_ci goto io_error; 8168c2ecf20Sopenharmony_ci for (deltaxcn = (s8)buf[b--]; b; b--) 8178c2ecf20Sopenharmony_ci deltaxcn = (deltaxcn << 8) + buf[b]; 8188c2ecf20Sopenharmony_ci } else { /* The length entry is compulsory. */ 8198c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Missing length entry in mapping " 8208c2ecf20Sopenharmony_ci "pairs array."); 8218c2ecf20Sopenharmony_ci deltaxcn = (s64)-1; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci /* 8248c2ecf20Sopenharmony_ci * Assume a negative length to indicate data corruption and 8258c2ecf20Sopenharmony_ci * hence clean-up and return NULL. 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci if (unlikely(deltaxcn < 0)) { 8288c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Invalid length in mapping pairs " 8298c2ecf20Sopenharmony_ci "array."); 8308c2ecf20Sopenharmony_ci goto err_out; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci /* 8338c2ecf20Sopenharmony_ci * Enter the current run length into the current runlist 8348c2ecf20Sopenharmony_ci * element. 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci rl[rlpos].length = deltaxcn; 8378c2ecf20Sopenharmony_ci /* Increment the current vcn by the current run length. */ 8388c2ecf20Sopenharmony_ci vcn += deltaxcn; 8398c2ecf20Sopenharmony_ci /* 8408c2ecf20Sopenharmony_ci * There might be no lcn change at all, as is the case for 8418c2ecf20Sopenharmony_ci * sparse clusters on NTFS 3.0+, in which case we set the lcn 8428c2ecf20Sopenharmony_ci * to LCN_HOLE. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_ci if (!(*buf & 0xf0)) 8458c2ecf20Sopenharmony_ci rl[rlpos].lcn = LCN_HOLE; 8468c2ecf20Sopenharmony_ci else { 8478c2ecf20Sopenharmony_ci /* Get the lcn change which really can be negative. */ 8488c2ecf20Sopenharmony_ci u8 b2 = *buf & 0xf; 8498c2ecf20Sopenharmony_ci b = b2 + ((*buf >> 4) & 0xf); 8508c2ecf20Sopenharmony_ci if (buf + b > attr_end) 8518c2ecf20Sopenharmony_ci goto io_error; 8528c2ecf20Sopenharmony_ci for (deltaxcn = (s8)buf[b--]; b > b2; b--) 8538c2ecf20Sopenharmony_ci deltaxcn = (deltaxcn << 8) + buf[b]; 8548c2ecf20Sopenharmony_ci /* Change the current lcn to its new value. */ 8558c2ecf20Sopenharmony_ci lcn += deltaxcn; 8568c2ecf20Sopenharmony_ci#ifdef DEBUG 8578c2ecf20Sopenharmony_ci /* 8588c2ecf20Sopenharmony_ci * On NTFS 1.2-, apparently can have lcn == -1 to 8598c2ecf20Sopenharmony_ci * indicate a hole. But we haven't verified ourselves 8608c2ecf20Sopenharmony_ci * whether it is really the lcn or the deltaxcn that is 8618c2ecf20Sopenharmony_ci * -1. So if either is found give us a message so we 8628c2ecf20Sopenharmony_ci * can investigate it further! 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci if (vol->major_ver < 3) { 8658c2ecf20Sopenharmony_ci if (unlikely(deltaxcn == (LCN)-1)) 8668c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "lcn delta == -1"); 8678c2ecf20Sopenharmony_ci if (unlikely(lcn == (LCN)-1)) 8688c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "lcn == -1"); 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci#endif 8718c2ecf20Sopenharmony_ci /* Check lcn is not below -1. */ 8728c2ecf20Sopenharmony_ci if (unlikely(lcn < (LCN)-1)) { 8738c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Invalid LCN < -1 in " 8748c2ecf20Sopenharmony_ci "mapping pairs array."); 8758c2ecf20Sopenharmony_ci goto err_out; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci /* Enter the current lcn into the runlist element. */ 8788c2ecf20Sopenharmony_ci rl[rlpos].lcn = lcn; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci /* Get to the next runlist element. */ 8818c2ecf20Sopenharmony_ci rlpos++; 8828c2ecf20Sopenharmony_ci /* Increment the buffer position to the next mapping pair. */ 8838c2ecf20Sopenharmony_ci buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci if (unlikely(buf >= attr_end)) 8868c2ecf20Sopenharmony_ci goto io_error; 8878c2ecf20Sopenharmony_ci /* 8888c2ecf20Sopenharmony_ci * If there is a highest_vcn specified, it must be equal to the final 8898c2ecf20Sopenharmony_ci * vcn in the runlist - 1, or something has gone badly wrong. 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn); 8928c2ecf20Sopenharmony_ci if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) { 8938c2ecf20Sopenharmony_cimpa_err: 8948c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Corrupt mapping pairs array in " 8958c2ecf20Sopenharmony_ci "non-resident attribute."); 8968c2ecf20Sopenharmony_ci goto err_out; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci /* Setup not mapped runlist element if this is the base extent. */ 8998c2ecf20Sopenharmony_ci if (!attr->data.non_resident.lowest_vcn) { 9008c2ecf20Sopenharmony_ci VCN max_cluster; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci max_cluster = ((sle64_to_cpu( 9038c2ecf20Sopenharmony_ci attr->data.non_resident.allocated_size) + 9048c2ecf20Sopenharmony_ci vol->cluster_size - 1) >> 9058c2ecf20Sopenharmony_ci vol->cluster_size_bits) - 1; 9068c2ecf20Sopenharmony_ci /* 9078c2ecf20Sopenharmony_ci * A highest_vcn of zero means this is a single extent 9088c2ecf20Sopenharmony_ci * attribute so simply terminate the runlist with LCN_ENOENT). 9098c2ecf20Sopenharmony_ci */ 9108c2ecf20Sopenharmony_ci if (deltaxcn) { 9118c2ecf20Sopenharmony_ci /* 9128c2ecf20Sopenharmony_ci * If there is a difference between the highest_vcn and 9138c2ecf20Sopenharmony_ci * the highest cluster, the runlist is either corrupt 9148c2ecf20Sopenharmony_ci * or, more likely, there are more extents following 9158c2ecf20Sopenharmony_ci * this one. 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_ci if (deltaxcn < max_cluster) { 9188c2ecf20Sopenharmony_ci ntfs_debug("More extents to follow; deltaxcn " 9198c2ecf20Sopenharmony_ci "= 0x%llx, max_cluster = " 9208c2ecf20Sopenharmony_ci "0x%llx", 9218c2ecf20Sopenharmony_ci (unsigned long long)deltaxcn, 9228c2ecf20Sopenharmony_ci (unsigned long long) 9238c2ecf20Sopenharmony_ci max_cluster); 9248c2ecf20Sopenharmony_ci rl[rlpos].vcn = vcn; 9258c2ecf20Sopenharmony_ci vcn += rl[rlpos].length = max_cluster - 9268c2ecf20Sopenharmony_ci deltaxcn; 9278c2ecf20Sopenharmony_ci rl[rlpos].lcn = LCN_RL_NOT_MAPPED; 9288c2ecf20Sopenharmony_ci rlpos++; 9298c2ecf20Sopenharmony_ci } else if (unlikely(deltaxcn > max_cluster)) { 9308c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Corrupt attribute. " 9318c2ecf20Sopenharmony_ci "deltaxcn = 0x%llx, " 9328c2ecf20Sopenharmony_ci "max_cluster = 0x%llx", 9338c2ecf20Sopenharmony_ci (unsigned long long)deltaxcn, 9348c2ecf20Sopenharmony_ci (unsigned long long) 9358c2ecf20Sopenharmony_ci max_cluster); 9368c2ecf20Sopenharmony_ci goto mpa_err; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci rl[rlpos].lcn = LCN_ENOENT; 9408c2ecf20Sopenharmony_ci } else /* Not the base extent. There may be more extents to follow. */ 9418c2ecf20Sopenharmony_ci rl[rlpos].lcn = LCN_RL_NOT_MAPPED; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* Setup terminating runlist element. */ 9448c2ecf20Sopenharmony_ci rl[rlpos].vcn = vcn; 9458c2ecf20Sopenharmony_ci rl[rlpos].length = (s64)0; 9468c2ecf20Sopenharmony_ci /* If no existing runlist was specified, we are done. */ 9478c2ecf20Sopenharmony_ci if (!old_rl) { 9488c2ecf20Sopenharmony_ci ntfs_debug("Mapping pairs array successfully decompressed:"); 9498c2ecf20Sopenharmony_ci ntfs_debug_dump_runlist(rl); 9508c2ecf20Sopenharmony_ci return rl; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci /* Now combine the new and old runlists checking for overlaps. */ 9538c2ecf20Sopenharmony_ci old_rl = ntfs_runlists_merge(old_rl, rl); 9548c2ecf20Sopenharmony_ci if (!IS_ERR(old_rl)) 9558c2ecf20Sopenharmony_ci return old_rl; 9568c2ecf20Sopenharmony_ci ntfs_free(rl); 9578c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to merge runlists."); 9588c2ecf20Sopenharmony_ci return old_rl; 9598c2ecf20Sopenharmony_ciio_error: 9608c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Corrupt attribute."); 9618c2ecf20Sopenharmony_cierr_out: 9628c2ecf20Sopenharmony_ci ntfs_free(rl); 9638c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci/** 9678c2ecf20Sopenharmony_ci * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist 9688c2ecf20Sopenharmony_ci * @rl: runlist to use for conversion 9698c2ecf20Sopenharmony_ci * @vcn: vcn to convert 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * Convert the virtual cluster number @vcn of an attribute into a logical 9728c2ecf20Sopenharmony_ci * cluster number (lcn) of a device using the runlist @rl to map vcns to their 9738c2ecf20Sopenharmony_ci * corresponding lcns. 9748c2ecf20Sopenharmony_ci * 9758c2ecf20Sopenharmony_ci * It is up to the caller to serialize access to the runlist @rl. 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci * Since lcns must be >= 0, we use negative return codes with special meaning: 9788c2ecf20Sopenharmony_ci * 9798c2ecf20Sopenharmony_ci * Return code Meaning / Description 9808c2ecf20Sopenharmony_ci * ================================================== 9818c2ecf20Sopenharmony_ci * LCN_HOLE Hole / not allocated on disk. 9828c2ecf20Sopenharmony_ci * LCN_RL_NOT_MAPPED This is part of the runlist which has not been 9838c2ecf20Sopenharmony_ci * inserted into the runlist yet. 9848c2ecf20Sopenharmony_ci * LCN_ENOENT There is no such vcn in the attribute. 9858c2ecf20Sopenharmony_ci * 9868c2ecf20Sopenharmony_ci * Locking: - The caller must have locked the runlist (for reading or writing). 9878c2ecf20Sopenharmony_ci * - This function does not touch the lock, nor does it modify the 9888c2ecf20Sopenharmony_ci * runlist. 9898c2ecf20Sopenharmony_ci */ 9908c2ecf20Sopenharmony_ciLCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci int i; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci BUG_ON(vcn < 0); 9958c2ecf20Sopenharmony_ci /* 9968c2ecf20Sopenharmony_ci * If rl is NULL, assume that we have found an unmapped runlist. The 9978c2ecf20Sopenharmony_ci * caller can then attempt to map it and fail appropriately if 9988c2ecf20Sopenharmony_ci * necessary. 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ci if (unlikely(!rl)) 10018c2ecf20Sopenharmony_ci return LCN_RL_NOT_MAPPED; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* Catch out of lower bounds vcn. */ 10048c2ecf20Sopenharmony_ci if (unlikely(vcn < rl[0].vcn)) 10058c2ecf20Sopenharmony_ci return LCN_ENOENT; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci for (i = 0; likely(rl[i].length); i++) { 10088c2ecf20Sopenharmony_ci if (unlikely(vcn < rl[i+1].vcn)) { 10098c2ecf20Sopenharmony_ci if (likely(rl[i].lcn >= (LCN)0)) 10108c2ecf20Sopenharmony_ci return rl[i].lcn + (vcn - rl[i].vcn); 10118c2ecf20Sopenharmony_ci return rl[i].lcn; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci /* 10158c2ecf20Sopenharmony_ci * The terminator element is setup to the correct value, i.e. one of 10168c2ecf20Sopenharmony_ci * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT. 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_ci if (likely(rl[i].lcn < (LCN)0)) 10198c2ecf20Sopenharmony_ci return rl[i].lcn; 10208c2ecf20Sopenharmony_ci /* Just in case... We could replace this with BUG() some day. */ 10218c2ecf20Sopenharmony_ci return LCN_ENOENT; 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci#ifdef NTFS_RW 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci/** 10278c2ecf20Sopenharmony_ci * ntfs_rl_find_vcn_nolock - find a vcn in a runlist 10288c2ecf20Sopenharmony_ci * @rl: runlist to search 10298c2ecf20Sopenharmony_ci * @vcn: vcn to find 10308c2ecf20Sopenharmony_ci * 10318c2ecf20Sopenharmony_ci * Find the virtual cluster number @vcn in the runlist @rl and return the 10328c2ecf20Sopenharmony_ci * address of the runlist element containing the @vcn on success. 10338c2ecf20Sopenharmony_ci * 10348c2ecf20Sopenharmony_ci * Return NULL if @rl is NULL or @vcn is in an unmapped part/out of bounds of 10358c2ecf20Sopenharmony_ci * the runlist. 10368c2ecf20Sopenharmony_ci * 10378c2ecf20Sopenharmony_ci * Locking: The runlist must be locked on entry. 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_cirunlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl, const VCN vcn) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci BUG_ON(vcn < 0); 10428c2ecf20Sopenharmony_ci if (unlikely(!rl || vcn < rl[0].vcn)) 10438c2ecf20Sopenharmony_ci return NULL; 10448c2ecf20Sopenharmony_ci while (likely(rl->length)) { 10458c2ecf20Sopenharmony_ci if (unlikely(vcn < rl[1].vcn)) { 10468c2ecf20Sopenharmony_ci if (likely(rl->lcn >= LCN_HOLE)) 10478c2ecf20Sopenharmony_ci return rl; 10488c2ecf20Sopenharmony_ci return NULL; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci rl++; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci if (likely(rl->lcn == LCN_ENOENT)) 10538c2ecf20Sopenharmony_ci return rl; 10548c2ecf20Sopenharmony_ci return NULL; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci/** 10588c2ecf20Sopenharmony_ci * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number 10598c2ecf20Sopenharmony_ci * @n: number for which to get the number of bytes for 10608c2ecf20Sopenharmony_ci * 10618c2ecf20Sopenharmony_ci * Return the number of bytes required to store @n unambiguously as 10628c2ecf20Sopenharmony_ci * a signed number. 10638c2ecf20Sopenharmony_ci * 10648c2ecf20Sopenharmony_ci * This is used in the context of the mapping pairs array to determine how 10658c2ecf20Sopenharmony_ci * many bytes will be needed in the array to store a given logical cluster 10668c2ecf20Sopenharmony_ci * number (lcn) or a specific run length. 10678c2ecf20Sopenharmony_ci * 10688c2ecf20Sopenharmony_ci * Return the number of bytes written. This function cannot fail. 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_cistatic inline int ntfs_get_nr_significant_bytes(const s64 n) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci s64 l = n; 10738c2ecf20Sopenharmony_ci int i; 10748c2ecf20Sopenharmony_ci s8 j; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci i = 0; 10778c2ecf20Sopenharmony_ci do { 10788c2ecf20Sopenharmony_ci l >>= 8; 10798c2ecf20Sopenharmony_ci i++; 10808c2ecf20Sopenharmony_ci } while (l != 0 && l != -1); 10818c2ecf20Sopenharmony_ci j = (n >> 8 * (i - 1)) & 0xff; 10828c2ecf20Sopenharmony_ci /* If the sign bit is wrong, we need an extra byte. */ 10838c2ecf20Sopenharmony_ci if ((n < 0 && j >= 0) || (n > 0 && j < 0)) 10848c2ecf20Sopenharmony_ci i++; 10858c2ecf20Sopenharmony_ci return i; 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci/** 10898c2ecf20Sopenharmony_ci * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array 10908c2ecf20Sopenharmony_ci * @vol: ntfs volume (needed for the ntfs version) 10918c2ecf20Sopenharmony_ci * @rl: locked runlist to determine the size of the mapping pairs of 10928c2ecf20Sopenharmony_ci * @first_vcn: first vcn which to include in the mapping pairs array 10938c2ecf20Sopenharmony_ci * @last_vcn: last vcn which to include in the mapping pairs array 10948c2ecf20Sopenharmony_ci * 10958c2ecf20Sopenharmony_ci * Walk the locked runlist @rl and calculate the size in bytes of the mapping 10968c2ecf20Sopenharmony_ci * pairs array corresponding to the runlist @rl, starting at vcn @first_vcn and 10978c2ecf20Sopenharmony_ci * finishing with vcn @last_vcn. 10988c2ecf20Sopenharmony_ci * 10998c2ecf20Sopenharmony_ci * A @last_vcn of -1 means end of runlist and in that case the size of the 11008c2ecf20Sopenharmony_ci * mapping pairs array corresponding to the runlist starting at vcn @first_vcn 11018c2ecf20Sopenharmony_ci * and finishing at the end of the runlist is determined. 11028c2ecf20Sopenharmony_ci * 11038c2ecf20Sopenharmony_ci * This for example allows us to allocate a buffer of the right size when 11048c2ecf20Sopenharmony_ci * building the mapping pairs array. 11058c2ecf20Sopenharmony_ci * 11068c2ecf20Sopenharmony_ci * If @rl is NULL, just return 1 (for the single terminator byte). 11078c2ecf20Sopenharmony_ci * 11088c2ecf20Sopenharmony_ci * Return the calculated size in bytes on success. On error, return -errno. 11098c2ecf20Sopenharmony_ci * The following error codes are defined: 11108c2ecf20Sopenharmony_ci * -EINVAL - Run list contains unmapped elements. Make sure to only pass 11118c2ecf20Sopenharmony_ci * fully mapped runlists to this function. 11128c2ecf20Sopenharmony_ci * -EIO - The runlist is corrupt. 11138c2ecf20Sopenharmony_ci * 11148c2ecf20Sopenharmony_ci * Locking: @rl must be locked on entry (either for reading or writing), it 11158c2ecf20Sopenharmony_ci * remains locked throughout, and is left locked upon return. 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_ciint ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, 11188c2ecf20Sopenharmony_ci const runlist_element *rl, const VCN first_vcn, 11198c2ecf20Sopenharmony_ci const VCN last_vcn) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci LCN prev_lcn; 11228c2ecf20Sopenharmony_ci int rls; 11238c2ecf20Sopenharmony_ci bool the_end = false; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci BUG_ON(first_vcn < 0); 11268c2ecf20Sopenharmony_ci BUG_ON(last_vcn < -1); 11278c2ecf20Sopenharmony_ci BUG_ON(last_vcn >= 0 && first_vcn > last_vcn); 11288c2ecf20Sopenharmony_ci if (!rl) { 11298c2ecf20Sopenharmony_ci BUG_ON(first_vcn); 11308c2ecf20Sopenharmony_ci BUG_ON(last_vcn > 0); 11318c2ecf20Sopenharmony_ci return 1; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci /* Skip to runlist element containing @first_vcn. */ 11348c2ecf20Sopenharmony_ci while (rl->length && first_vcn >= rl[1].vcn) 11358c2ecf20Sopenharmony_ci rl++; 11368c2ecf20Sopenharmony_ci if (unlikely((!rl->length && first_vcn > rl->vcn) || 11378c2ecf20Sopenharmony_ci first_vcn < rl->vcn)) 11388c2ecf20Sopenharmony_ci return -EINVAL; 11398c2ecf20Sopenharmony_ci prev_lcn = 0; 11408c2ecf20Sopenharmony_ci /* Always need the termining zero byte. */ 11418c2ecf20Sopenharmony_ci rls = 1; 11428c2ecf20Sopenharmony_ci /* Do the first partial run if present. */ 11438c2ecf20Sopenharmony_ci if (first_vcn > rl->vcn) { 11448c2ecf20Sopenharmony_ci s64 delta, length = rl->length; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* We know rl->length != 0 already. */ 11478c2ecf20Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 11488c2ecf20Sopenharmony_ci goto err_out; 11498c2ecf20Sopenharmony_ci /* 11508c2ecf20Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 11518c2ecf20Sopenharmony_ci * run length. 11528c2ecf20Sopenharmony_ci */ 11538c2ecf20Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 11548c2ecf20Sopenharmony_ci s64 s1 = last_vcn + 1; 11558c2ecf20Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 11568c2ecf20Sopenharmony_ci length = s1 - rl->vcn; 11578c2ecf20Sopenharmony_ci the_end = true; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci delta = first_vcn - rl->vcn; 11608c2ecf20Sopenharmony_ci /* Header byte + length. */ 11618c2ecf20Sopenharmony_ci rls += 1 + ntfs_get_nr_significant_bytes(length - delta); 11628c2ecf20Sopenharmony_ci /* 11638c2ecf20Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 11648c2ecf20Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 11658c2ecf20Sopenharmony_ci * zero space. On earlier NTFS versions we just store the lcn. 11668c2ecf20Sopenharmony_ci * Note: this assumes that on NTFS 1.2-, holes are stored with 11678c2ecf20Sopenharmony_ci * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). 11688c2ecf20Sopenharmony_ci */ 11698c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 11708c2ecf20Sopenharmony_ci prev_lcn = rl->lcn; 11718c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0)) 11728c2ecf20Sopenharmony_ci prev_lcn += delta; 11738c2ecf20Sopenharmony_ci /* Change in lcn. */ 11748c2ecf20Sopenharmony_ci rls += ntfs_get_nr_significant_bytes(prev_lcn); 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci /* Go to next runlist element. */ 11778c2ecf20Sopenharmony_ci rl++; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci /* Do the full runs. */ 11808c2ecf20Sopenharmony_ci for (; rl->length && !the_end; rl++) { 11818c2ecf20Sopenharmony_ci s64 length = rl->length; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 11848c2ecf20Sopenharmony_ci goto err_out; 11858c2ecf20Sopenharmony_ci /* 11868c2ecf20Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 11878c2ecf20Sopenharmony_ci * run length. 11888c2ecf20Sopenharmony_ci */ 11898c2ecf20Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 11908c2ecf20Sopenharmony_ci s64 s1 = last_vcn + 1; 11918c2ecf20Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 11928c2ecf20Sopenharmony_ci length = s1 - rl->vcn; 11938c2ecf20Sopenharmony_ci the_end = true; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci /* Header byte + length. */ 11968c2ecf20Sopenharmony_ci rls += 1 + ntfs_get_nr_significant_bytes(length); 11978c2ecf20Sopenharmony_ci /* 11988c2ecf20Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 11998c2ecf20Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 12008c2ecf20Sopenharmony_ci * zero space. On earlier NTFS versions we just store the lcn. 12018c2ecf20Sopenharmony_ci * Note: this assumes that on NTFS 1.2-, holes are stored with 12028c2ecf20Sopenharmony_ci * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). 12038c2ecf20Sopenharmony_ci */ 12048c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 12058c2ecf20Sopenharmony_ci /* Change in lcn. */ 12068c2ecf20Sopenharmony_ci rls += ntfs_get_nr_significant_bytes(rl->lcn - 12078c2ecf20Sopenharmony_ci prev_lcn); 12088c2ecf20Sopenharmony_ci prev_lcn = rl->lcn; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci return rls; 12128c2ecf20Sopenharmony_cierr_out: 12138c2ecf20Sopenharmony_ci if (rl->lcn == LCN_RL_NOT_MAPPED) 12148c2ecf20Sopenharmony_ci rls = -EINVAL; 12158c2ecf20Sopenharmony_ci else 12168c2ecf20Sopenharmony_ci rls = -EIO; 12178c2ecf20Sopenharmony_ci return rls; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci/** 12218c2ecf20Sopenharmony_ci * ntfs_write_significant_bytes - write the significant bytes of a number 12228c2ecf20Sopenharmony_ci * @dst: destination buffer to write to 12238c2ecf20Sopenharmony_ci * @dst_max: pointer to last byte of destination buffer for bounds checking 12248c2ecf20Sopenharmony_ci * @n: number whose significant bytes to write 12258c2ecf20Sopenharmony_ci * 12268c2ecf20Sopenharmony_ci * Store in @dst, the minimum bytes of the number @n which are required to 12278c2ecf20Sopenharmony_ci * identify @n unambiguously as a signed number, taking care not to exceed 12288c2ecf20Sopenharmony_ci * @dest_max, the maximum position within @dst to which we are allowed to 12298c2ecf20Sopenharmony_ci * write. 12308c2ecf20Sopenharmony_ci * 12318c2ecf20Sopenharmony_ci * This is used when building the mapping pairs array of a runlist to compress 12328c2ecf20Sopenharmony_ci * a given logical cluster number (lcn) or a specific run length to the minimum 12338c2ecf20Sopenharmony_ci * size possible. 12348c2ecf20Sopenharmony_ci * 12358c2ecf20Sopenharmony_ci * Return the number of bytes written on success. On error, i.e. the 12368c2ecf20Sopenharmony_ci * destination buffer @dst is too small, return -ENOSPC. 12378c2ecf20Sopenharmony_ci */ 12388c2ecf20Sopenharmony_cistatic inline int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max, 12398c2ecf20Sopenharmony_ci const s64 n) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci s64 l = n; 12428c2ecf20Sopenharmony_ci int i; 12438c2ecf20Sopenharmony_ci s8 j; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci i = 0; 12468c2ecf20Sopenharmony_ci do { 12478c2ecf20Sopenharmony_ci if (unlikely(dst > dst_max)) 12488c2ecf20Sopenharmony_ci goto err_out; 12498c2ecf20Sopenharmony_ci *dst++ = l & 0xffll; 12508c2ecf20Sopenharmony_ci l >>= 8; 12518c2ecf20Sopenharmony_ci i++; 12528c2ecf20Sopenharmony_ci } while (l != 0 && l != -1); 12538c2ecf20Sopenharmony_ci j = (n >> 8 * (i - 1)) & 0xff; 12548c2ecf20Sopenharmony_ci /* If the sign bit is wrong, we need an extra byte. */ 12558c2ecf20Sopenharmony_ci if (n < 0 && j >= 0) { 12568c2ecf20Sopenharmony_ci if (unlikely(dst > dst_max)) 12578c2ecf20Sopenharmony_ci goto err_out; 12588c2ecf20Sopenharmony_ci i++; 12598c2ecf20Sopenharmony_ci *dst = (s8)-1; 12608c2ecf20Sopenharmony_ci } else if (n > 0 && j < 0) { 12618c2ecf20Sopenharmony_ci if (unlikely(dst > dst_max)) 12628c2ecf20Sopenharmony_ci goto err_out; 12638c2ecf20Sopenharmony_ci i++; 12648c2ecf20Sopenharmony_ci *dst = (s8)0; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci return i; 12678c2ecf20Sopenharmony_cierr_out: 12688c2ecf20Sopenharmony_ci return -ENOSPC; 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci/** 12728c2ecf20Sopenharmony_ci * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist 12738c2ecf20Sopenharmony_ci * @vol: ntfs volume (needed for the ntfs version) 12748c2ecf20Sopenharmony_ci * @dst: destination buffer to which to write the mapping pairs array 12758c2ecf20Sopenharmony_ci * @dst_len: size of destination buffer @dst in bytes 12768c2ecf20Sopenharmony_ci * @rl: locked runlist for which to build the mapping pairs array 12778c2ecf20Sopenharmony_ci * @first_vcn: first vcn which to include in the mapping pairs array 12788c2ecf20Sopenharmony_ci * @last_vcn: last vcn which to include in the mapping pairs array 12798c2ecf20Sopenharmony_ci * @stop_vcn: first vcn outside destination buffer on success or -ENOSPC 12808c2ecf20Sopenharmony_ci * 12818c2ecf20Sopenharmony_ci * Create the mapping pairs array from the locked runlist @rl, starting at vcn 12828c2ecf20Sopenharmony_ci * @first_vcn and finishing with vcn @last_vcn and save the array in @dst. 12838c2ecf20Sopenharmony_ci * @dst_len is the size of @dst in bytes and it should be at least equal to the 12848c2ecf20Sopenharmony_ci * value obtained by calling ntfs_get_size_for_mapping_pairs(). 12858c2ecf20Sopenharmony_ci * 12868c2ecf20Sopenharmony_ci * A @last_vcn of -1 means end of runlist and in that case the mapping pairs 12878c2ecf20Sopenharmony_ci * array corresponding to the runlist starting at vcn @first_vcn and finishing 12888c2ecf20Sopenharmony_ci * at the end of the runlist is created. 12898c2ecf20Sopenharmony_ci * 12908c2ecf20Sopenharmony_ci * If @rl is NULL, just write a single terminator byte to @dst. 12918c2ecf20Sopenharmony_ci * 12928c2ecf20Sopenharmony_ci * On success or -ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to 12938c2ecf20Sopenharmony_ci * the first vcn outside the destination buffer. Note that on error, @dst has 12948c2ecf20Sopenharmony_ci * been filled with all the mapping pairs that will fit, thus it can be treated 12958c2ecf20Sopenharmony_ci * as partial success, in that a new attribute extent needs to be created or 12968c2ecf20Sopenharmony_ci * the next extent has to be used and the mapping pairs build has to be 12978c2ecf20Sopenharmony_ci * continued with @first_vcn set to *@stop_vcn. 12988c2ecf20Sopenharmony_ci * 12998c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error. The following error codes are 13008c2ecf20Sopenharmony_ci * defined: 13018c2ecf20Sopenharmony_ci * -EINVAL - Run list contains unmapped elements. Make sure to only pass 13028c2ecf20Sopenharmony_ci * fully mapped runlists to this function. 13038c2ecf20Sopenharmony_ci * -EIO - The runlist is corrupt. 13048c2ecf20Sopenharmony_ci * -ENOSPC - The destination buffer is too small. 13058c2ecf20Sopenharmony_ci * 13068c2ecf20Sopenharmony_ci * Locking: @rl must be locked on entry (either for reading or writing), it 13078c2ecf20Sopenharmony_ci * remains locked throughout, and is left locked upon return. 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_ciint ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, 13108c2ecf20Sopenharmony_ci const int dst_len, const runlist_element *rl, 13118c2ecf20Sopenharmony_ci const VCN first_vcn, const VCN last_vcn, VCN *const stop_vcn) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci LCN prev_lcn; 13148c2ecf20Sopenharmony_ci s8 *dst_max, *dst_next; 13158c2ecf20Sopenharmony_ci int err = -ENOSPC; 13168c2ecf20Sopenharmony_ci bool the_end = false; 13178c2ecf20Sopenharmony_ci s8 len_len, lcn_len; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci BUG_ON(first_vcn < 0); 13208c2ecf20Sopenharmony_ci BUG_ON(last_vcn < -1); 13218c2ecf20Sopenharmony_ci BUG_ON(last_vcn >= 0 && first_vcn > last_vcn); 13228c2ecf20Sopenharmony_ci BUG_ON(dst_len < 1); 13238c2ecf20Sopenharmony_ci if (!rl) { 13248c2ecf20Sopenharmony_ci BUG_ON(first_vcn); 13258c2ecf20Sopenharmony_ci BUG_ON(last_vcn > 0); 13268c2ecf20Sopenharmony_ci if (stop_vcn) 13278c2ecf20Sopenharmony_ci *stop_vcn = 0; 13288c2ecf20Sopenharmony_ci /* Terminator byte. */ 13298c2ecf20Sopenharmony_ci *dst = 0; 13308c2ecf20Sopenharmony_ci return 0; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci /* Skip to runlist element containing @first_vcn. */ 13338c2ecf20Sopenharmony_ci while (rl->length && first_vcn >= rl[1].vcn) 13348c2ecf20Sopenharmony_ci rl++; 13358c2ecf20Sopenharmony_ci if (unlikely((!rl->length && first_vcn > rl->vcn) || 13368c2ecf20Sopenharmony_ci first_vcn < rl->vcn)) 13378c2ecf20Sopenharmony_ci return -EINVAL; 13388c2ecf20Sopenharmony_ci /* 13398c2ecf20Sopenharmony_ci * @dst_max is used for bounds checking in 13408c2ecf20Sopenharmony_ci * ntfs_write_significant_bytes(). 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ci dst_max = dst + dst_len - 1; 13438c2ecf20Sopenharmony_ci prev_lcn = 0; 13448c2ecf20Sopenharmony_ci /* Do the first partial run if present. */ 13458c2ecf20Sopenharmony_ci if (first_vcn > rl->vcn) { 13468c2ecf20Sopenharmony_ci s64 delta, length = rl->length; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* We know rl->length != 0 already. */ 13498c2ecf20Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 13508c2ecf20Sopenharmony_ci goto err_out; 13518c2ecf20Sopenharmony_ci /* 13528c2ecf20Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 13538c2ecf20Sopenharmony_ci * run length. 13548c2ecf20Sopenharmony_ci */ 13558c2ecf20Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 13568c2ecf20Sopenharmony_ci s64 s1 = last_vcn + 1; 13578c2ecf20Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 13588c2ecf20Sopenharmony_ci length = s1 - rl->vcn; 13598c2ecf20Sopenharmony_ci the_end = true; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci delta = first_vcn - rl->vcn; 13628c2ecf20Sopenharmony_ci /* Write length. */ 13638c2ecf20Sopenharmony_ci len_len = ntfs_write_significant_bytes(dst + 1, dst_max, 13648c2ecf20Sopenharmony_ci length - delta); 13658c2ecf20Sopenharmony_ci if (unlikely(len_len < 0)) 13668c2ecf20Sopenharmony_ci goto size_err; 13678c2ecf20Sopenharmony_ci /* 13688c2ecf20Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 13698c2ecf20Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 13708c2ecf20Sopenharmony_ci * zero space. On earlier NTFS versions we just write the lcn 13718c2ecf20Sopenharmony_ci * change. FIXME: Do we need to write the lcn change or just 13728c2ecf20Sopenharmony_ci * the lcn in that case? Not sure as I have never seen this 13738c2ecf20Sopenharmony_ci * case on NT4. - We assume that we just need to write the lcn 13748c2ecf20Sopenharmony_ci * change until someone tells us otherwise... (AIA) 13758c2ecf20Sopenharmony_ci */ 13768c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 13778c2ecf20Sopenharmony_ci prev_lcn = rl->lcn; 13788c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0)) 13798c2ecf20Sopenharmony_ci prev_lcn += delta; 13808c2ecf20Sopenharmony_ci /* Write change in lcn. */ 13818c2ecf20Sopenharmony_ci lcn_len = ntfs_write_significant_bytes(dst + 1 + 13828c2ecf20Sopenharmony_ci len_len, dst_max, prev_lcn); 13838c2ecf20Sopenharmony_ci if (unlikely(lcn_len < 0)) 13848c2ecf20Sopenharmony_ci goto size_err; 13858c2ecf20Sopenharmony_ci } else 13868c2ecf20Sopenharmony_ci lcn_len = 0; 13878c2ecf20Sopenharmony_ci dst_next = dst + len_len + lcn_len + 1; 13888c2ecf20Sopenharmony_ci if (unlikely(dst_next > dst_max)) 13898c2ecf20Sopenharmony_ci goto size_err; 13908c2ecf20Sopenharmony_ci /* Update header byte. */ 13918c2ecf20Sopenharmony_ci *dst = lcn_len << 4 | len_len; 13928c2ecf20Sopenharmony_ci /* Position at next mapping pairs array element. */ 13938c2ecf20Sopenharmony_ci dst = dst_next; 13948c2ecf20Sopenharmony_ci /* Go to next runlist element. */ 13958c2ecf20Sopenharmony_ci rl++; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci /* Do the full runs. */ 13988c2ecf20Sopenharmony_ci for (; rl->length && !the_end; rl++) { 13998c2ecf20Sopenharmony_ci s64 length = rl->length; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (unlikely(length < 0 || rl->lcn < LCN_HOLE)) 14028c2ecf20Sopenharmony_ci goto err_out; 14038c2ecf20Sopenharmony_ci /* 14048c2ecf20Sopenharmony_ci * If @stop_vcn is given and finishes inside this run, cap the 14058c2ecf20Sopenharmony_ci * run length. 14068c2ecf20Sopenharmony_ci */ 14078c2ecf20Sopenharmony_ci if (unlikely(last_vcn >= 0 && rl[1].vcn > last_vcn)) { 14088c2ecf20Sopenharmony_ci s64 s1 = last_vcn + 1; 14098c2ecf20Sopenharmony_ci if (unlikely(rl[1].vcn > s1)) 14108c2ecf20Sopenharmony_ci length = s1 - rl->vcn; 14118c2ecf20Sopenharmony_ci the_end = true; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci /* Write length. */ 14148c2ecf20Sopenharmony_ci len_len = ntfs_write_significant_bytes(dst + 1, dst_max, 14158c2ecf20Sopenharmony_ci length); 14168c2ecf20Sopenharmony_ci if (unlikely(len_len < 0)) 14178c2ecf20Sopenharmony_ci goto size_err; 14188c2ecf20Sopenharmony_ci /* 14198c2ecf20Sopenharmony_ci * If the logical cluster number (lcn) denotes a hole and we 14208c2ecf20Sopenharmony_ci * are on NTFS 3.0+, we don't store it at all, i.e. we need 14218c2ecf20Sopenharmony_ci * zero space. On earlier NTFS versions we just write the lcn 14228c2ecf20Sopenharmony_ci * change. FIXME: Do we need to write the lcn change or just 14238c2ecf20Sopenharmony_ci * the lcn in that case? Not sure as I have never seen this 14248c2ecf20Sopenharmony_ci * case on NT4. - We assume that we just need to write the lcn 14258c2ecf20Sopenharmony_ci * change until someone tells us otherwise... (AIA) 14268c2ecf20Sopenharmony_ci */ 14278c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0 || vol->major_ver < 3)) { 14288c2ecf20Sopenharmony_ci /* Write change in lcn. */ 14298c2ecf20Sopenharmony_ci lcn_len = ntfs_write_significant_bytes(dst + 1 + 14308c2ecf20Sopenharmony_ci len_len, dst_max, rl->lcn - prev_lcn); 14318c2ecf20Sopenharmony_ci if (unlikely(lcn_len < 0)) 14328c2ecf20Sopenharmony_ci goto size_err; 14338c2ecf20Sopenharmony_ci prev_lcn = rl->lcn; 14348c2ecf20Sopenharmony_ci } else 14358c2ecf20Sopenharmony_ci lcn_len = 0; 14368c2ecf20Sopenharmony_ci dst_next = dst + len_len + lcn_len + 1; 14378c2ecf20Sopenharmony_ci if (unlikely(dst_next > dst_max)) 14388c2ecf20Sopenharmony_ci goto size_err; 14398c2ecf20Sopenharmony_ci /* Update header byte. */ 14408c2ecf20Sopenharmony_ci *dst = lcn_len << 4 | len_len; 14418c2ecf20Sopenharmony_ci /* Position at next mapping pairs array element. */ 14428c2ecf20Sopenharmony_ci dst = dst_next; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci /* Success. */ 14458c2ecf20Sopenharmony_ci err = 0; 14468c2ecf20Sopenharmony_cisize_err: 14478c2ecf20Sopenharmony_ci /* Set stop vcn. */ 14488c2ecf20Sopenharmony_ci if (stop_vcn) 14498c2ecf20Sopenharmony_ci *stop_vcn = rl->vcn; 14508c2ecf20Sopenharmony_ci /* Add terminator byte. */ 14518c2ecf20Sopenharmony_ci *dst = 0; 14528c2ecf20Sopenharmony_ci return err; 14538c2ecf20Sopenharmony_cierr_out: 14548c2ecf20Sopenharmony_ci if (rl->lcn == LCN_RL_NOT_MAPPED) 14558c2ecf20Sopenharmony_ci err = -EINVAL; 14568c2ecf20Sopenharmony_ci else 14578c2ecf20Sopenharmony_ci err = -EIO; 14588c2ecf20Sopenharmony_ci return err; 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci/** 14628c2ecf20Sopenharmony_ci * ntfs_rl_truncate_nolock - truncate a runlist starting at a specified vcn 14638c2ecf20Sopenharmony_ci * @vol: ntfs volume (needed for error output) 14648c2ecf20Sopenharmony_ci * @runlist: runlist to truncate 14658c2ecf20Sopenharmony_ci * @new_length: the new length of the runlist in VCNs 14668c2ecf20Sopenharmony_ci * 14678c2ecf20Sopenharmony_ci * Truncate the runlist described by @runlist as well as the memory buffer 14688c2ecf20Sopenharmony_ci * holding the runlist elements to a length of @new_length VCNs. 14698c2ecf20Sopenharmony_ci * 14708c2ecf20Sopenharmony_ci * If @new_length lies within the runlist, the runlist elements with VCNs of 14718c2ecf20Sopenharmony_ci * @new_length and above are discarded. As a special case if @new_length is 14728c2ecf20Sopenharmony_ci * zero, the runlist is discarded and set to NULL. 14738c2ecf20Sopenharmony_ci * 14748c2ecf20Sopenharmony_ci * If @new_length lies beyond the runlist, a sparse runlist element is added to 14758c2ecf20Sopenharmony_ci * the end of the runlist @runlist or if the last runlist element is a sparse 14768c2ecf20Sopenharmony_ci * one already, this is extended. 14778c2ecf20Sopenharmony_ci * 14788c2ecf20Sopenharmony_ci * Note, no checking is done for unmapped runlist elements. It is assumed that 14798c2ecf20Sopenharmony_ci * the caller has mapped any elements that need to be mapped already. 14808c2ecf20Sopenharmony_ci * 14818c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error. 14828c2ecf20Sopenharmony_ci * 14838c2ecf20Sopenharmony_ci * Locking: The caller must hold @runlist->lock for writing. 14848c2ecf20Sopenharmony_ci */ 14858c2ecf20Sopenharmony_ciint ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist, 14868c2ecf20Sopenharmony_ci const s64 new_length) 14878c2ecf20Sopenharmony_ci{ 14888c2ecf20Sopenharmony_ci runlist_element *rl; 14898c2ecf20Sopenharmony_ci int old_size; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci ntfs_debug("Entering for new_length 0x%llx.", (long long)new_length); 14928c2ecf20Sopenharmony_ci BUG_ON(!runlist); 14938c2ecf20Sopenharmony_ci BUG_ON(new_length < 0); 14948c2ecf20Sopenharmony_ci rl = runlist->rl; 14958c2ecf20Sopenharmony_ci if (!new_length) { 14968c2ecf20Sopenharmony_ci ntfs_debug("Freeing runlist."); 14978c2ecf20Sopenharmony_ci runlist->rl = NULL; 14988c2ecf20Sopenharmony_ci if (rl) 14998c2ecf20Sopenharmony_ci ntfs_free(rl); 15008c2ecf20Sopenharmony_ci return 0; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci if (unlikely(!rl)) { 15038c2ecf20Sopenharmony_ci /* 15048c2ecf20Sopenharmony_ci * Create a runlist consisting of a sparse runlist element of 15058c2ecf20Sopenharmony_ci * length @new_length followed by a terminator runlist element. 15068c2ecf20Sopenharmony_ci */ 15078c2ecf20Sopenharmony_ci rl = ntfs_malloc_nofs(PAGE_SIZE); 15088c2ecf20Sopenharmony_ci if (unlikely(!rl)) { 15098c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Not enough memory to allocate " 15108c2ecf20Sopenharmony_ci "runlist element buffer."); 15118c2ecf20Sopenharmony_ci return -ENOMEM; 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci runlist->rl = rl; 15148c2ecf20Sopenharmony_ci rl[1].length = rl->vcn = 0; 15158c2ecf20Sopenharmony_ci rl->lcn = LCN_HOLE; 15168c2ecf20Sopenharmony_ci rl[1].vcn = rl->length = new_length; 15178c2ecf20Sopenharmony_ci rl[1].lcn = LCN_ENOENT; 15188c2ecf20Sopenharmony_ci return 0; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci BUG_ON(new_length < rl->vcn); 15218c2ecf20Sopenharmony_ci /* Find @new_length in the runlist. */ 15228c2ecf20Sopenharmony_ci while (likely(rl->length && new_length >= rl[1].vcn)) 15238c2ecf20Sopenharmony_ci rl++; 15248c2ecf20Sopenharmony_ci /* 15258c2ecf20Sopenharmony_ci * If not at the end of the runlist we need to shrink it. 15268c2ecf20Sopenharmony_ci * If at the end of the runlist we need to expand it. 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_ci if (rl->length) { 15298c2ecf20Sopenharmony_ci runlist_element *trl; 15308c2ecf20Sopenharmony_ci bool is_end; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci ntfs_debug("Shrinking runlist."); 15338c2ecf20Sopenharmony_ci /* Determine the runlist size. */ 15348c2ecf20Sopenharmony_ci trl = rl + 1; 15358c2ecf20Sopenharmony_ci while (likely(trl->length)) 15368c2ecf20Sopenharmony_ci trl++; 15378c2ecf20Sopenharmony_ci old_size = trl - runlist->rl + 1; 15388c2ecf20Sopenharmony_ci /* Truncate the run. */ 15398c2ecf20Sopenharmony_ci rl->length = new_length - rl->vcn; 15408c2ecf20Sopenharmony_ci /* 15418c2ecf20Sopenharmony_ci * If a run was partially truncated, make the following runlist 15428c2ecf20Sopenharmony_ci * element a terminator. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci is_end = false; 15458c2ecf20Sopenharmony_ci if (rl->length) { 15468c2ecf20Sopenharmony_ci rl++; 15478c2ecf20Sopenharmony_ci if (!rl->length) 15488c2ecf20Sopenharmony_ci is_end = true; 15498c2ecf20Sopenharmony_ci rl->vcn = new_length; 15508c2ecf20Sopenharmony_ci rl->length = 0; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci rl->lcn = LCN_ENOENT; 15538c2ecf20Sopenharmony_ci /* Reallocate memory if necessary. */ 15548c2ecf20Sopenharmony_ci if (!is_end) { 15558c2ecf20Sopenharmony_ci int new_size = rl - runlist->rl + 1; 15568c2ecf20Sopenharmony_ci rl = ntfs_rl_realloc(runlist->rl, old_size, new_size); 15578c2ecf20Sopenharmony_ci if (IS_ERR(rl)) 15588c2ecf20Sopenharmony_ci ntfs_warning(vol->sb, "Failed to shrink " 15598c2ecf20Sopenharmony_ci "runlist buffer. This just " 15608c2ecf20Sopenharmony_ci "wastes a bit of memory " 15618c2ecf20Sopenharmony_ci "temporarily so we ignore it " 15628c2ecf20Sopenharmony_ci "and return success."); 15638c2ecf20Sopenharmony_ci else 15648c2ecf20Sopenharmony_ci runlist->rl = rl; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci } else if (likely(/* !rl->length && */ new_length > rl->vcn)) { 15678c2ecf20Sopenharmony_ci ntfs_debug("Expanding runlist."); 15688c2ecf20Sopenharmony_ci /* 15698c2ecf20Sopenharmony_ci * If there is a previous runlist element and it is a sparse 15708c2ecf20Sopenharmony_ci * one, extend it. Otherwise need to add a new, sparse runlist 15718c2ecf20Sopenharmony_ci * element. 15728c2ecf20Sopenharmony_ci */ 15738c2ecf20Sopenharmony_ci if ((rl > runlist->rl) && ((rl - 1)->lcn == LCN_HOLE)) 15748c2ecf20Sopenharmony_ci (rl - 1)->length = new_length - (rl - 1)->vcn; 15758c2ecf20Sopenharmony_ci else { 15768c2ecf20Sopenharmony_ci /* Determine the runlist size. */ 15778c2ecf20Sopenharmony_ci old_size = rl - runlist->rl + 1; 15788c2ecf20Sopenharmony_ci /* Reallocate memory if necessary. */ 15798c2ecf20Sopenharmony_ci rl = ntfs_rl_realloc(runlist->rl, old_size, 15808c2ecf20Sopenharmony_ci old_size + 1); 15818c2ecf20Sopenharmony_ci if (IS_ERR(rl)) { 15828c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to expand runlist " 15838c2ecf20Sopenharmony_ci "buffer, aborting."); 15848c2ecf20Sopenharmony_ci return PTR_ERR(rl); 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci runlist->rl = rl; 15878c2ecf20Sopenharmony_ci /* 15888c2ecf20Sopenharmony_ci * Set @rl to the same runlist element in the new 15898c2ecf20Sopenharmony_ci * runlist as before in the old runlist. 15908c2ecf20Sopenharmony_ci */ 15918c2ecf20Sopenharmony_ci rl += old_size - 1; 15928c2ecf20Sopenharmony_ci /* Add a new, sparse runlist element. */ 15938c2ecf20Sopenharmony_ci rl->lcn = LCN_HOLE; 15948c2ecf20Sopenharmony_ci rl->length = new_length - rl->vcn; 15958c2ecf20Sopenharmony_ci /* Add a new terminator runlist element. */ 15968c2ecf20Sopenharmony_ci rl++; 15978c2ecf20Sopenharmony_ci rl->length = 0; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci rl->vcn = new_length; 16008c2ecf20Sopenharmony_ci rl->lcn = LCN_ENOENT; 16018c2ecf20Sopenharmony_ci } else /* if (unlikely(!rl->length && new_length == rl->vcn)) */ { 16028c2ecf20Sopenharmony_ci /* Runlist already has same size as requested. */ 16038c2ecf20Sopenharmony_ci rl->lcn = LCN_ENOENT; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci ntfs_debug("Done."); 16068c2ecf20Sopenharmony_ci return 0; 16078c2ecf20Sopenharmony_ci} 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci/** 16108c2ecf20Sopenharmony_ci * ntfs_rl_punch_nolock - punch a hole into a runlist 16118c2ecf20Sopenharmony_ci * @vol: ntfs volume (needed for error output) 16128c2ecf20Sopenharmony_ci * @runlist: runlist to punch a hole into 16138c2ecf20Sopenharmony_ci * @start: starting VCN of the hole to be created 16148c2ecf20Sopenharmony_ci * @length: size of the hole to be created in units of clusters 16158c2ecf20Sopenharmony_ci * 16168c2ecf20Sopenharmony_ci * Punch a hole into the runlist @runlist starting at VCN @start and of size 16178c2ecf20Sopenharmony_ci * @length clusters. 16188c2ecf20Sopenharmony_ci * 16198c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error, in which case @runlist has not been 16208c2ecf20Sopenharmony_ci * modified. 16218c2ecf20Sopenharmony_ci * 16228c2ecf20Sopenharmony_ci * If @start and/or @start + @length are outside the runlist return error code 16238c2ecf20Sopenharmony_ci * -ENOENT. 16248c2ecf20Sopenharmony_ci * 16258c2ecf20Sopenharmony_ci * If the runlist contains unmapped or error elements between @start and @start 16268c2ecf20Sopenharmony_ci * + @length return error code -EINVAL. 16278c2ecf20Sopenharmony_ci * 16288c2ecf20Sopenharmony_ci * Locking: The caller must hold @runlist->lock for writing. 16298c2ecf20Sopenharmony_ci */ 16308c2ecf20Sopenharmony_ciint ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist, 16318c2ecf20Sopenharmony_ci const VCN start, const s64 length) 16328c2ecf20Sopenharmony_ci{ 16338c2ecf20Sopenharmony_ci const VCN end = start + length; 16348c2ecf20Sopenharmony_ci s64 delta; 16358c2ecf20Sopenharmony_ci runlist_element *rl, *rl_end, *rl_real_end, *trl; 16368c2ecf20Sopenharmony_ci int old_size; 16378c2ecf20Sopenharmony_ci bool lcn_fixup = false; 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci ntfs_debug("Entering for start 0x%llx, length 0x%llx.", 16408c2ecf20Sopenharmony_ci (long long)start, (long long)length); 16418c2ecf20Sopenharmony_ci BUG_ON(!runlist); 16428c2ecf20Sopenharmony_ci BUG_ON(start < 0); 16438c2ecf20Sopenharmony_ci BUG_ON(length < 0); 16448c2ecf20Sopenharmony_ci BUG_ON(end < 0); 16458c2ecf20Sopenharmony_ci rl = runlist->rl; 16468c2ecf20Sopenharmony_ci if (unlikely(!rl)) { 16478c2ecf20Sopenharmony_ci if (likely(!start && !length)) 16488c2ecf20Sopenharmony_ci return 0; 16498c2ecf20Sopenharmony_ci return -ENOENT; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci /* Find @start in the runlist. */ 16528c2ecf20Sopenharmony_ci while (likely(rl->length && start >= rl[1].vcn)) 16538c2ecf20Sopenharmony_ci rl++; 16548c2ecf20Sopenharmony_ci rl_end = rl; 16558c2ecf20Sopenharmony_ci /* Find @end in the runlist. */ 16568c2ecf20Sopenharmony_ci while (likely(rl_end->length && end >= rl_end[1].vcn)) { 16578c2ecf20Sopenharmony_ci /* Verify there are no unmapped or error elements. */ 16588c2ecf20Sopenharmony_ci if (unlikely(rl_end->lcn < LCN_HOLE)) 16598c2ecf20Sopenharmony_ci return -EINVAL; 16608c2ecf20Sopenharmony_ci rl_end++; 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci /* Check the last element. */ 16638c2ecf20Sopenharmony_ci if (unlikely(rl_end->length && rl_end->lcn < LCN_HOLE)) 16648c2ecf20Sopenharmony_ci return -EINVAL; 16658c2ecf20Sopenharmony_ci /* This covers @start being out of bounds, too. */ 16668c2ecf20Sopenharmony_ci if (!rl_end->length && end > rl_end->vcn) 16678c2ecf20Sopenharmony_ci return -ENOENT; 16688c2ecf20Sopenharmony_ci if (!length) 16698c2ecf20Sopenharmony_ci return 0; 16708c2ecf20Sopenharmony_ci if (!rl->length) 16718c2ecf20Sopenharmony_ci return -ENOENT; 16728c2ecf20Sopenharmony_ci rl_real_end = rl_end; 16738c2ecf20Sopenharmony_ci /* Determine the runlist size. */ 16748c2ecf20Sopenharmony_ci while (likely(rl_real_end->length)) 16758c2ecf20Sopenharmony_ci rl_real_end++; 16768c2ecf20Sopenharmony_ci old_size = rl_real_end - runlist->rl + 1; 16778c2ecf20Sopenharmony_ci /* If @start is in a hole simply extend the hole. */ 16788c2ecf20Sopenharmony_ci if (rl->lcn == LCN_HOLE) { 16798c2ecf20Sopenharmony_ci /* 16808c2ecf20Sopenharmony_ci * If both @start and @end are in the same sparse run, we are 16818c2ecf20Sopenharmony_ci * done. 16828c2ecf20Sopenharmony_ci */ 16838c2ecf20Sopenharmony_ci if (end <= rl[1].vcn) { 16848c2ecf20Sopenharmony_ci ntfs_debug("Done (requested hole is already sparse)."); 16858c2ecf20Sopenharmony_ci return 0; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ciextend_hole: 16888c2ecf20Sopenharmony_ci /* Extend the hole. */ 16898c2ecf20Sopenharmony_ci rl->length = end - rl->vcn; 16908c2ecf20Sopenharmony_ci /* If @end is in a hole, merge it with the current one. */ 16918c2ecf20Sopenharmony_ci if (rl_end->lcn == LCN_HOLE) { 16928c2ecf20Sopenharmony_ci rl_end++; 16938c2ecf20Sopenharmony_ci rl->length = rl_end->vcn - rl->vcn; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci /* We have done the hole. Now deal with the remaining tail. */ 16968c2ecf20Sopenharmony_ci rl++; 16978c2ecf20Sopenharmony_ci /* Cut out all runlist elements up to @end. */ 16988c2ecf20Sopenharmony_ci if (rl < rl_end) 16998c2ecf20Sopenharmony_ci memmove(rl, rl_end, (rl_real_end - rl_end + 1) * 17008c2ecf20Sopenharmony_ci sizeof(*rl)); 17018c2ecf20Sopenharmony_ci /* Adjust the beginning of the tail if necessary. */ 17028c2ecf20Sopenharmony_ci if (end > rl->vcn) { 17038c2ecf20Sopenharmony_ci delta = end - rl->vcn; 17048c2ecf20Sopenharmony_ci rl->vcn = end; 17058c2ecf20Sopenharmony_ci rl->length -= delta; 17068c2ecf20Sopenharmony_ci /* Only adjust the lcn if it is real. */ 17078c2ecf20Sopenharmony_ci if (rl->lcn >= 0) 17088c2ecf20Sopenharmony_ci rl->lcn += delta; 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_cishrink_allocation: 17118c2ecf20Sopenharmony_ci /* Reallocate memory if the allocation changed. */ 17128c2ecf20Sopenharmony_ci if (rl < rl_end) { 17138c2ecf20Sopenharmony_ci rl = ntfs_rl_realloc(runlist->rl, old_size, 17148c2ecf20Sopenharmony_ci old_size - (rl_end - rl)); 17158c2ecf20Sopenharmony_ci if (IS_ERR(rl)) 17168c2ecf20Sopenharmony_ci ntfs_warning(vol->sb, "Failed to shrink " 17178c2ecf20Sopenharmony_ci "runlist buffer. This just " 17188c2ecf20Sopenharmony_ci "wastes a bit of memory " 17198c2ecf20Sopenharmony_ci "temporarily so we ignore it " 17208c2ecf20Sopenharmony_ci "and return success."); 17218c2ecf20Sopenharmony_ci else 17228c2ecf20Sopenharmony_ci runlist->rl = rl; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci ntfs_debug("Done (extend hole)."); 17258c2ecf20Sopenharmony_ci return 0; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci /* 17288c2ecf20Sopenharmony_ci * If @start is at the beginning of a run things are easier as there is 17298c2ecf20Sopenharmony_ci * no need to split the first run. 17308c2ecf20Sopenharmony_ci */ 17318c2ecf20Sopenharmony_ci if (start == rl->vcn) { 17328c2ecf20Sopenharmony_ci /* 17338c2ecf20Sopenharmony_ci * @start is at the beginning of a run. 17348c2ecf20Sopenharmony_ci * 17358c2ecf20Sopenharmony_ci * If the previous run is sparse, extend its hole. 17368c2ecf20Sopenharmony_ci * 17378c2ecf20Sopenharmony_ci * If @end is not in the same run, switch the run to be sparse 17388c2ecf20Sopenharmony_ci * and extend the newly created hole. 17398c2ecf20Sopenharmony_ci * 17408c2ecf20Sopenharmony_ci * Thus both of these cases reduce the problem to the above 17418c2ecf20Sopenharmony_ci * case of "@start is in a hole". 17428c2ecf20Sopenharmony_ci */ 17438c2ecf20Sopenharmony_ci if (rl > runlist->rl && (rl - 1)->lcn == LCN_HOLE) { 17448c2ecf20Sopenharmony_ci rl--; 17458c2ecf20Sopenharmony_ci goto extend_hole; 17468c2ecf20Sopenharmony_ci } 17478c2ecf20Sopenharmony_ci if (end >= rl[1].vcn) { 17488c2ecf20Sopenharmony_ci rl->lcn = LCN_HOLE; 17498c2ecf20Sopenharmony_ci goto extend_hole; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci /* 17528c2ecf20Sopenharmony_ci * The final case is when @end is in the same run as @start. 17538c2ecf20Sopenharmony_ci * For this need to split the run into two. One run for the 17548c2ecf20Sopenharmony_ci * sparse region between the beginning of the old run, i.e. 17558c2ecf20Sopenharmony_ci * @start, and @end and one for the remaining non-sparse 17568c2ecf20Sopenharmony_ci * region, i.e. between @end and the end of the old run. 17578c2ecf20Sopenharmony_ci */ 17588c2ecf20Sopenharmony_ci trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1); 17598c2ecf20Sopenharmony_ci if (IS_ERR(trl)) 17608c2ecf20Sopenharmony_ci goto enomem_out; 17618c2ecf20Sopenharmony_ci old_size++; 17628c2ecf20Sopenharmony_ci if (runlist->rl != trl) { 17638c2ecf20Sopenharmony_ci rl = trl + (rl - runlist->rl); 17648c2ecf20Sopenharmony_ci rl_end = trl + (rl_end - runlist->rl); 17658c2ecf20Sopenharmony_ci rl_real_end = trl + (rl_real_end - runlist->rl); 17668c2ecf20Sopenharmony_ci runlist->rl = trl; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_cisplit_end: 17698c2ecf20Sopenharmony_ci /* Shift all the runs up by one. */ 17708c2ecf20Sopenharmony_ci memmove(rl + 1, rl, (rl_real_end - rl + 1) * sizeof(*rl)); 17718c2ecf20Sopenharmony_ci /* Finally, setup the two split runs. */ 17728c2ecf20Sopenharmony_ci rl->lcn = LCN_HOLE; 17738c2ecf20Sopenharmony_ci rl->length = length; 17748c2ecf20Sopenharmony_ci rl++; 17758c2ecf20Sopenharmony_ci rl->vcn += length; 17768c2ecf20Sopenharmony_ci /* Only adjust the lcn if it is real. */ 17778c2ecf20Sopenharmony_ci if (rl->lcn >= 0 || lcn_fixup) 17788c2ecf20Sopenharmony_ci rl->lcn += length; 17798c2ecf20Sopenharmony_ci rl->length -= length; 17808c2ecf20Sopenharmony_ci ntfs_debug("Done (split one)."); 17818c2ecf20Sopenharmony_ci return 0; 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci /* 17848c2ecf20Sopenharmony_ci * @start is neither in a hole nor at the beginning of a run. 17858c2ecf20Sopenharmony_ci * 17868c2ecf20Sopenharmony_ci * If @end is in a hole, things are easier as simply truncating the run 17878c2ecf20Sopenharmony_ci * @start is in to end at @start - 1, deleting all runs after that up 17888c2ecf20Sopenharmony_ci * to @end, and finally extending the beginning of the run @end is in 17898c2ecf20Sopenharmony_ci * to be @start is all that is needed. 17908c2ecf20Sopenharmony_ci */ 17918c2ecf20Sopenharmony_ci if (rl_end->lcn == LCN_HOLE) { 17928c2ecf20Sopenharmony_ci /* Truncate the run containing @start. */ 17938c2ecf20Sopenharmony_ci rl->length = start - rl->vcn; 17948c2ecf20Sopenharmony_ci rl++; 17958c2ecf20Sopenharmony_ci /* Cut out all runlist elements up to @end. */ 17968c2ecf20Sopenharmony_ci if (rl < rl_end) 17978c2ecf20Sopenharmony_ci memmove(rl, rl_end, (rl_real_end - rl_end + 1) * 17988c2ecf20Sopenharmony_ci sizeof(*rl)); 17998c2ecf20Sopenharmony_ci /* Extend the beginning of the run @end is in to be @start. */ 18008c2ecf20Sopenharmony_ci rl->vcn = start; 18018c2ecf20Sopenharmony_ci rl->length = rl[1].vcn - start; 18028c2ecf20Sopenharmony_ci goto shrink_allocation; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci /* 18058c2ecf20Sopenharmony_ci * If @end is not in a hole there are still two cases to distinguish. 18068c2ecf20Sopenharmony_ci * Either @end is or is not in the same run as @start. 18078c2ecf20Sopenharmony_ci * 18088c2ecf20Sopenharmony_ci * The second case is easier as it can be reduced to an already solved 18098c2ecf20Sopenharmony_ci * problem by truncating the run @start is in to end at @start - 1. 18108c2ecf20Sopenharmony_ci * Then, if @end is in the next run need to split the run into a sparse 18118c2ecf20Sopenharmony_ci * run followed by a non-sparse run (already covered above) and if @end 18128c2ecf20Sopenharmony_ci * is not in the next run switching it to be sparse, again reduces the 18138c2ecf20Sopenharmony_ci * problem to the already covered case of "@start is in a hole". 18148c2ecf20Sopenharmony_ci */ 18158c2ecf20Sopenharmony_ci if (end >= rl[1].vcn) { 18168c2ecf20Sopenharmony_ci /* 18178c2ecf20Sopenharmony_ci * If @end is not in the next run, reduce the problem to the 18188c2ecf20Sopenharmony_ci * case of "@start is in a hole". 18198c2ecf20Sopenharmony_ci */ 18208c2ecf20Sopenharmony_ci if (rl[1].length && end >= rl[2].vcn) { 18218c2ecf20Sopenharmony_ci /* Truncate the run containing @start. */ 18228c2ecf20Sopenharmony_ci rl->length = start - rl->vcn; 18238c2ecf20Sopenharmony_ci rl++; 18248c2ecf20Sopenharmony_ci rl->vcn = start; 18258c2ecf20Sopenharmony_ci rl->lcn = LCN_HOLE; 18268c2ecf20Sopenharmony_ci goto extend_hole; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 1); 18298c2ecf20Sopenharmony_ci if (IS_ERR(trl)) 18308c2ecf20Sopenharmony_ci goto enomem_out; 18318c2ecf20Sopenharmony_ci old_size++; 18328c2ecf20Sopenharmony_ci if (runlist->rl != trl) { 18338c2ecf20Sopenharmony_ci rl = trl + (rl - runlist->rl); 18348c2ecf20Sopenharmony_ci rl_end = trl + (rl_end - runlist->rl); 18358c2ecf20Sopenharmony_ci rl_real_end = trl + (rl_real_end - runlist->rl); 18368c2ecf20Sopenharmony_ci runlist->rl = trl; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci /* Truncate the run containing @start. */ 18398c2ecf20Sopenharmony_ci rl->length = start - rl->vcn; 18408c2ecf20Sopenharmony_ci rl++; 18418c2ecf20Sopenharmony_ci /* 18428c2ecf20Sopenharmony_ci * @end is in the next run, reduce the problem to the case 18438c2ecf20Sopenharmony_ci * where "@start is at the beginning of a run and @end is in 18448c2ecf20Sopenharmony_ci * the same run as @start". 18458c2ecf20Sopenharmony_ci */ 18468c2ecf20Sopenharmony_ci delta = rl->vcn - start; 18478c2ecf20Sopenharmony_ci rl->vcn = start; 18488c2ecf20Sopenharmony_ci if (rl->lcn >= 0) { 18498c2ecf20Sopenharmony_ci rl->lcn -= delta; 18508c2ecf20Sopenharmony_ci /* Need this in case the lcn just became negative. */ 18518c2ecf20Sopenharmony_ci lcn_fixup = true; 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci rl->length += delta; 18548c2ecf20Sopenharmony_ci goto split_end; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci /* 18578c2ecf20Sopenharmony_ci * The first case from above, i.e. @end is in the same run as @start. 18588c2ecf20Sopenharmony_ci * We need to split the run into three. One run for the non-sparse 18598c2ecf20Sopenharmony_ci * region between the beginning of the old run and @start, one for the 18608c2ecf20Sopenharmony_ci * sparse region between @start and @end, and one for the remaining 18618c2ecf20Sopenharmony_ci * non-sparse region, i.e. between @end and the end of the old run. 18628c2ecf20Sopenharmony_ci */ 18638c2ecf20Sopenharmony_ci trl = ntfs_rl_realloc(runlist->rl, old_size, old_size + 2); 18648c2ecf20Sopenharmony_ci if (IS_ERR(trl)) 18658c2ecf20Sopenharmony_ci goto enomem_out; 18668c2ecf20Sopenharmony_ci old_size += 2; 18678c2ecf20Sopenharmony_ci if (runlist->rl != trl) { 18688c2ecf20Sopenharmony_ci rl = trl + (rl - runlist->rl); 18698c2ecf20Sopenharmony_ci rl_end = trl + (rl_end - runlist->rl); 18708c2ecf20Sopenharmony_ci rl_real_end = trl + (rl_real_end - runlist->rl); 18718c2ecf20Sopenharmony_ci runlist->rl = trl; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci /* Shift all the runs up by two. */ 18748c2ecf20Sopenharmony_ci memmove(rl + 2, rl, (rl_real_end - rl + 1) * sizeof(*rl)); 18758c2ecf20Sopenharmony_ci /* Finally, setup the three split runs. */ 18768c2ecf20Sopenharmony_ci rl->length = start - rl->vcn; 18778c2ecf20Sopenharmony_ci rl++; 18788c2ecf20Sopenharmony_ci rl->vcn = start; 18798c2ecf20Sopenharmony_ci rl->lcn = LCN_HOLE; 18808c2ecf20Sopenharmony_ci rl->length = length; 18818c2ecf20Sopenharmony_ci rl++; 18828c2ecf20Sopenharmony_ci delta = end - rl->vcn; 18838c2ecf20Sopenharmony_ci rl->vcn = end; 18848c2ecf20Sopenharmony_ci rl->lcn += delta; 18858c2ecf20Sopenharmony_ci rl->length -= delta; 18868c2ecf20Sopenharmony_ci ntfs_debug("Done (split both)."); 18878c2ecf20Sopenharmony_ci return 0; 18888c2ecf20Sopenharmony_cienomem_out: 18898c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Not enough memory to extend runlist buffer."); 18908c2ecf20Sopenharmony_ci return -ENOMEM; 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci#endif /* NTFS_RW */ 1894