1*a48555c3Sreinoud /* $NetBSD: udf_allocation.c,v 1.13 2008/07/18 16:21:12 reinoud Exp $ */ 2e979c658Sreinoud 3e979c658Sreinoud /* 4e979c658Sreinoud * Copyright (c) 2006, 2008 Reinoud Zandijk 5e979c658Sreinoud * All rights reserved. 6e979c658Sreinoud * 7e979c658Sreinoud * Redistribution and use in source and binary forms, with or without 8e979c658Sreinoud * modification, are permitted provided that the following conditions 9e979c658Sreinoud * are met: 10e979c658Sreinoud * 1. Redistributions of source code must retain the above copyright 11e979c658Sreinoud * notice, this list of conditions and the following disclaimer. 12e979c658Sreinoud * 2. Redistributions in binary form must reproduce the above copyright 13e979c658Sreinoud * notice, this list of conditions and the following disclaimer in the 14e979c658Sreinoud * documentation and/or other materials provided with the distribution. 15e979c658Sreinoud * 16e979c658Sreinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17e979c658Sreinoud * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18e979c658Sreinoud * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19e979c658Sreinoud * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20e979c658Sreinoud * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21e979c658Sreinoud * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22e979c658Sreinoud * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23e979c658Sreinoud * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24e979c658Sreinoud * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25e979c658Sreinoud * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26e979c658Sreinoud * 27e979c658Sreinoud */ 28e979c658Sreinoud 29e979c658Sreinoud #include <sys/cdefs.h> 30e979c658Sreinoud #ifndef lint 31*a48555c3Sreinoud __KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.13 2008/07/18 16:21:12 reinoud Exp $"); 32e979c658Sreinoud #endif /* not lint */ 33e979c658Sreinoud 34e979c658Sreinoud 35e979c658Sreinoud #if defined(_KERNEL_OPT) 36e979c658Sreinoud #include "opt_quota.h" 37e979c658Sreinoud #include "opt_compat_netbsd.h" 38e979c658Sreinoud #endif 39e979c658Sreinoud 40e979c658Sreinoud /* TODO strip */ 41e979c658Sreinoud #include <sys/param.h> 42e979c658Sreinoud #include <sys/systm.h> 43e979c658Sreinoud #include <sys/sysctl.h> 44e979c658Sreinoud #include <sys/namei.h> 45e979c658Sreinoud #include <sys/proc.h> 46e979c658Sreinoud #include <sys/kernel.h> 47e979c658Sreinoud #include <sys/vnode.h> 48e979c658Sreinoud #include <miscfs/genfs/genfs_node.h> 49e979c658Sreinoud #include <sys/mount.h> 50e979c658Sreinoud #include <sys/buf.h> 51e979c658Sreinoud #include <sys/file.h> 52e979c658Sreinoud #include <sys/device.h> 53e979c658Sreinoud #include <sys/disklabel.h> 54e979c658Sreinoud #include <sys/ioctl.h> 55e979c658Sreinoud #include <sys/malloc.h> 56e979c658Sreinoud #include <sys/dirent.h> 57e979c658Sreinoud #include <sys/stat.h> 58e979c658Sreinoud #include <sys/conf.h> 59e979c658Sreinoud #include <sys/kauth.h> 60e979c658Sreinoud #include <sys/kthread.h> 61e979c658Sreinoud #include <dev/clock_subr.h> 62e979c658Sreinoud 63e979c658Sreinoud #include <fs/udf/ecma167-udf.h> 64e979c658Sreinoud #include <fs/udf/udf_mount.h> 65e979c658Sreinoud 66e979c658Sreinoud #if defined(_KERNEL_OPT) 67e979c658Sreinoud #include "opt_udf.h" 68e979c658Sreinoud #endif 69e979c658Sreinoud 70e979c658Sreinoud #include "udf.h" 71e979c658Sreinoud #include "udf_subr.h" 72e979c658Sreinoud #include "udf_bswap.h" 73e979c658Sreinoud 74e979c658Sreinoud 75e979c658Sreinoud #define VTOI(vnode) ((struct udf_node *) vnode->v_data) 76e979c658Sreinoud 77e979c658Sreinoud static void udf_record_allocation_in_node(struct udf_mount *ump, 78e979c658Sreinoud struct buf *buf, uint16_t vpart_num, uint64_t *mapping, 79e979c658Sreinoud struct long_ad *node_ad_cpy); 80e979c658Sreinoud 81e979c658Sreinoud /* 82e979c658Sreinoud * IDEA/BUSY: Each udf_node gets its own extentwalker state for all operations; 83e979c658Sreinoud * this will hopefully/likely reduce O(nlog(n)) to O(1) for most functionality 84e979c658Sreinoud * since actions are most likely sequencial and thus seeking doesn't need 85e979c658Sreinoud * searching for the same or adjacent position again. 86e979c658Sreinoud */ 87e979c658Sreinoud 88e979c658Sreinoud /* --------------------------------------------------------------------- */ 894d5c88faSreinoud 90d61a135aSreinoud #if 0 91e979c658Sreinoud #if 1 92e979c658Sreinoud static void 93e979c658Sreinoud udf_node_dump(struct udf_node *udf_node) { 94e979c658Sreinoud struct file_entry *fe; 95e979c658Sreinoud struct extfile_entry *efe; 96e979c658Sreinoud struct icb_tag *icbtag; 974d5c88faSreinoud struct long_ad s_ad; 98e979c658Sreinoud uint64_t inflen; 994d5c88faSreinoud uint32_t icbflags, addr_type; 100e979c658Sreinoud uint32_t len, lb_num; 1014d5c88faSreinoud uint32_t flags; 102e979c658Sreinoud int part_num; 1034d5c88faSreinoud int lb_size, eof, slot; 104e979c658Sreinoud 105d3bf9c7bSreinoud if ((udf_verbose & UDF_DEBUG_NODEDUMP) == 0) 106e979c658Sreinoud return; 107e979c658Sreinoud 108e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 109e979c658Sreinoud 110e979c658Sreinoud fe = udf_node->fe; 111e979c658Sreinoud efe = udf_node->efe; 112e979c658Sreinoud if (fe) { 113e979c658Sreinoud icbtag = &fe->icbtag; 114e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 115e979c658Sreinoud } else { 116e979c658Sreinoud icbtag = &efe->icbtag; 117e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 118e979c658Sreinoud } 119e979c658Sreinoud 120e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 121e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 122e979c658Sreinoud 1234d5c88faSreinoud printf("udf_node_dump %p :\n", udf_node); 124e979c658Sreinoud 125e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1264d5c88faSreinoud printf("\tIntern alloc, len = %"PRIu64"\n", inflen); 127e979c658Sreinoud return; 128e979c658Sreinoud } 129e979c658Sreinoud 1304d5c88faSreinoud printf("\tInflen = %"PRIu64"\n", inflen); 131e979c658Sreinoud printf("\t\t"); 1324d5c88faSreinoud 1334d5c88faSreinoud slot = 0; 1344d5c88faSreinoud for (;;) { 1354d5c88faSreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1364d5c88faSreinoud if (eof) 1374d5c88faSreinoud break; 1384d5c88faSreinoud part_num = udf_rw16(s_ad.loc.part_num); 1394d5c88faSreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 1404d5c88faSreinoud len = udf_rw32(s_ad.len); 141e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 142e979c658Sreinoud len = UDF_EXT_LEN(len); 1434d5c88faSreinoud 144e979c658Sreinoud printf("["); 145e979c658Sreinoud if (part_num >= 0) 146e979c658Sreinoud printf("part %d, ", part_num); 147e979c658Sreinoud printf("lb_num %d, len %d", lb_num, len); 148e979c658Sreinoud if (flags) 149d3bf9c7bSreinoud printf(", flags %d", flags>>30); 150e979c658Sreinoud printf("] "); 1514d5c88faSreinoud 1524d5c88faSreinoud if (flags == UDF_EXT_REDIRECT) { 1534d5c88faSreinoud printf("\n\textent END\n\tallocation extent\n\t\t"); 154e979c658Sreinoud } 1554d5c88faSreinoud 1564d5c88faSreinoud slot++; 1574d5c88faSreinoud } 1584d5c88faSreinoud printf("\n\tl_ad END\n\n"); 159e979c658Sreinoud } 160e979c658Sreinoud #else 161e979c658Sreinoud #define udf_node_dump(a) 162e979c658Sreinoud #endif 163e979c658Sreinoud 1645eeb4f69Sreinoud 1655eeb4f69Sreinoud static void 1665eeb4f69Sreinoud udf_assert_allocated(struct udf_mount *ump, uint16_t vpart_num, 1675eeb4f69Sreinoud uint32_t lb_num, uint32_t num_lb) 1685eeb4f69Sreinoud { 1695eeb4f69Sreinoud struct udf_bitmap *bitmap; 1705eeb4f69Sreinoud struct part_desc *pdesc; 1715eeb4f69Sreinoud uint32_t ptov; 1725eeb4f69Sreinoud uint32_t bitval; 1735eeb4f69Sreinoud uint8_t *bpos; 1745eeb4f69Sreinoud int bit; 1755eeb4f69Sreinoud int phys_part; 1765eeb4f69Sreinoud int ok; 1775eeb4f69Sreinoud 178d3bf9c7bSreinoud DPRINTF(PARANOIA, ("udf_assert_allocated: check virt lbnum %d " 1795eeb4f69Sreinoud "part %d + %d sect\n", lb_num, vpart_num, num_lb)); 1805eeb4f69Sreinoud 1815eeb4f69Sreinoud /* get partition backing up this vpart_num */ 1825eeb4f69Sreinoud pdesc = ump->partitions[ump->vtop[vpart_num]]; 1835eeb4f69Sreinoud 1845eeb4f69Sreinoud switch (ump->vtop_tp[vpart_num]) { 1855eeb4f69Sreinoud case UDF_VTOP_TYPE_PHYS : 1865eeb4f69Sreinoud case UDF_VTOP_TYPE_SPARABLE : 1875eeb4f69Sreinoud /* free space to freed or unallocated space bitmap */ 1885eeb4f69Sreinoud ptov = udf_rw32(pdesc->start_loc); 1895eeb4f69Sreinoud phys_part = ump->vtop[vpart_num]; 1905eeb4f69Sreinoud 1915eeb4f69Sreinoud /* use unallocated bitmap */ 1925eeb4f69Sreinoud bitmap = &ump->part_unalloc_bits[phys_part]; 1935eeb4f69Sreinoud 1945eeb4f69Sreinoud /* if no bitmaps are defined, bail out */ 1955eeb4f69Sreinoud if (bitmap->bits == NULL) 1965eeb4f69Sreinoud break; 1975eeb4f69Sreinoud 1985eeb4f69Sreinoud /* check bits */ 1995eeb4f69Sreinoud KASSERT(bitmap->bits); 2005eeb4f69Sreinoud ok = 1; 2015eeb4f69Sreinoud bpos = bitmap->bits + lb_num/8; 2025eeb4f69Sreinoud bit = lb_num % 8; 2035eeb4f69Sreinoud while (num_lb > 0) { 2045eeb4f69Sreinoud bitval = (1 << bit); 2055eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : check %d, %p, bit %d\n", 2065eeb4f69Sreinoud lb_num, bpos, bit)); 2075eeb4f69Sreinoud KASSERT(bitmap->bits + lb_num/8 == bpos); 2085eeb4f69Sreinoud if (*bpos & bitval) { 2095eeb4f69Sreinoud printf("\tlb_num %d is NOT marked busy\n", 2105eeb4f69Sreinoud lb_num); 2115eeb4f69Sreinoud ok = 0; 2125eeb4f69Sreinoud } 2135eeb4f69Sreinoud lb_num++; num_lb--; 2145eeb4f69Sreinoud bit = (bit + 1) % 8; 2155eeb4f69Sreinoud if (bit == 0) 2165eeb4f69Sreinoud bpos++; 2175eeb4f69Sreinoud } 2185eeb4f69Sreinoud if (!ok) { 2195eeb4f69Sreinoud /* KASSERT(0); */ 2205eeb4f69Sreinoud } 2215eeb4f69Sreinoud 2225eeb4f69Sreinoud break; 2235eeb4f69Sreinoud case UDF_VTOP_TYPE_VIRT : 2245eeb4f69Sreinoud /* TODO check space */ 2255eeb4f69Sreinoud KASSERT(num_lb == 1); 2265eeb4f69Sreinoud break; 2275eeb4f69Sreinoud case UDF_VTOP_TYPE_META : 2285eeb4f69Sreinoud /* TODO check space in the metadata bitmap */ 2295eeb4f69Sreinoud default: 2305eeb4f69Sreinoud /* not implemented */ 2315eeb4f69Sreinoud break; 2325eeb4f69Sreinoud } 2335eeb4f69Sreinoud } 2345eeb4f69Sreinoud 2355eeb4f69Sreinoud 236e979c658Sreinoud static void 237e979c658Sreinoud udf_node_sanity_check(struct udf_node *udf_node, 238e979c658Sreinoud uint64_t *cnt_inflen, uint64_t *cnt_logblksrec) { 239e979c658Sreinoud struct file_entry *fe; 240e979c658Sreinoud struct extfile_entry *efe; 241e979c658Sreinoud struct icb_tag *icbtag; 2424d5c88faSreinoud struct long_ad s_ad; 243e979c658Sreinoud uint64_t inflen, logblksrec; 2444d5c88faSreinoud uint32_t icbflags, addr_type; 2454d5c88faSreinoud uint32_t len, lb_num, l_ea, l_ad, max_l_ad; 2465eeb4f69Sreinoud uint16_t part_num; 2474d5c88faSreinoud int dscr_size, lb_size, flags, whole_lb; 2484d5c88faSreinoud int slot, eof; 249e979c658Sreinoud 2505eeb4f69Sreinoud // KASSERT(mutex_owned(&udf_node->ump->allocate_mutex)); 251e979c658Sreinoud 252d3bf9c7bSreinoud if (1) 253d3bf9c7bSreinoud udf_node_dump(udf_node); 254d3bf9c7bSreinoud 255e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 256e979c658Sreinoud 257e979c658Sreinoud fe = udf_node->fe; 258e979c658Sreinoud efe = udf_node->efe; 259e979c658Sreinoud if (fe) { 260e979c658Sreinoud icbtag = &fe->icbtag; 261e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 262e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 2634d5c88faSreinoud logblksrec = udf_rw64(fe->logblks_rec); 264e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 2654d5c88faSreinoud l_ea = udf_rw32(fe->l_ea); 266e979c658Sreinoud } else { 267e979c658Sreinoud icbtag = &efe->icbtag; 268e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 269e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 2704d5c88faSreinoud logblksrec = udf_rw64(efe->logblks_rec); 271e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 2724d5c88faSreinoud l_ea = udf_rw32(efe->l_ea); 273e979c658Sreinoud } 274e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 275e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 276e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 277e979c658Sreinoud 278e979c658Sreinoud /* reset counters */ 279e979c658Sreinoud *cnt_inflen = 0; 280e979c658Sreinoud *cnt_logblksrec = 0; 281e979c658Sreinoud 282e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 283e979c658Sreinoud KASSERT(l_ad <= max_l_ad); 284e979c658Sreinoud KASSERT(l_ad == inflen); 285e979c658Sreinoud *cnt_inflen = inflen; 286e979c658Sreinoud return; 287e979c658Sreinoud } 288e979c658Sreinoud 289e979c658Sreinoud /* start counting */ 290e979c658Sreinoud whole_lb = 1; 2914d5c88faSreinoud slot = 0; 2924d5c88faSreinoud for (;;) { 2934d5c88faSreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2944d5c88faSreinoud if (eof) 2954d5c88faSreinoud break; 296e979c658Sreinoud KASSERT(whole_lb == 1); 2974d5c88faSreinoud 2984d5c88faSreinoud part_num = udf_rw16(s_ad.loc.part_num); 2994d5c88faSreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 3004d5c88faSreinoud len = udf_rw32(s_ad.len); 301e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 302e979c658Sreinoud len = UDF_EXT_LEN(len); 3034d5c88faSreinoud 304d7699664Sreinoud if (flags != UDF_EXT_REDIRECT) { 305e979c658Sreinoud *cnt_inflen += len; 306e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 307e979c658Sreinoud *cnt_logblksrec += (len + lb_size -1) / lb_size; 308e979c658Sreinoud } 309d7699664Sreinoud } else { 310d7699664Sreinoud KASSERT(len == lb_size); 311d7699664Sreinoud } 3125eeb4f69Sreinoud /* check allocation */ 3135eeb4f69Sreinoud if (flags == UDF_EXT_ALLOCATED) 3145eeb4f69Sreinoud udf_assert_allocated(udf_node->ump, part_num, lb_num, 3155eeb4f69Sreinoud (len + lb_size - 1) / lb_size); 316af39897aSreinoud 317af39897aSreinoud /* check whole lb */ 318e979c658Sreinoud whole_lb = ((len % lb_size) == 0); 3194d5c88faSreinoud 3204d5c88faSreinoud slot++; 321e979c658Sreinoud } 322e979c658Sreinoud /* rest should be zero (ad_off > l_ad < max_l_ad - adlen) */ 323e979c658Sreinoud 324e979c658Sreinoud KASSERT(*cnt_inflen == inflen); 325e979c658Sreinoud KASSERT(*cnt_logblksrec == logblksrec); 326e979c658Sreinoud 3275eeb4f69Sreinoud // KASSERT(mutex_owned(&udf_node->ump->allocate_mutex)); 328e979c658Sreinoud } 329e979c658Sreinoud #else 330d61a135aSreinoud static void 331d61a135aSreinoud udf_node_sanity_check(struct udf_node *udf_node, 332d61a135aSreinoud uint64_t *cnt_inflen, uint64_t *cnt_logblksrec) { 333d61a135aSreinoud struct file_entry *fe; 334d61a135aSreinoud struct extfile_entry *efe; 335d61a135aSreinoud struct icb_tag *icbtag; 336d61a135aSreinoud uint64_t inflen, logblksrec; 337d61a135aSreinoud int dscr_size, lb_size; 338d61a135aSreinoud 339d61a135aSreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 340d61a135aSreinoud 341d61a135aSreinoud fe = udf_node->fe; 342d61a135aSreinoud efe = udf_node->efe; 343d61a135aSreinoud if (fe) { 344d61a135aSreinoud icbtag = &fe->icbtag; 345d61a135aSreinoud inflen = udf_rw64(fe->inf_len); 346d61a135aSreinoud dscr_size = sizeof(struct file_entry) -1; 347d61a135aSreinoud logblksrec = udf_rw64(fe->logblks_rec); 348d61a135aSreinoud } else { 349d61a135aSreinoud icbtag = &efe->icbtag; 350d61a135aSreinoud inflen = udf_rw64(efe->inf_len); 351d61a135aSreinoud dscr_size = sizeof(struct extfile_entry) -1; 352d61a135aSreinoud logblksrec = udf_rw64(efe->logblks_rec); 353d61a135aSreinoud } 354d61a135aSreinoud *cnt_logblksrec = logblksrec; 355d61a135aSreinoud *cnt_inflen = inflen; 356d61a135aSreinoud } 357e979c658Sreinoud #endif 358e979c658Sreinoud 359e979c658Sreinoud /* --------------------------------------------------------------------- */ 360e979c658Sreinoud 361e979c658Sreinoud int 362e979c658Sreinoud udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, 363e979c658Sreinoud uint32_t *lb_numres, uint32_t *extres) 364e979c658Sreinoud { 365e979c658Sreinoud struct part_desc *pdesc; 366e979c658Sreinoud struct spare_map_entry *sme; 367e979c658Sreinoud struct long_ad s_icb_loc; 368e979c658Sreinoud uint64_t foffset, end_foffset; 369e979c658Sreinoud uint32_t lb_size, len; 370e979c658Sreinoud uint32_t lb_num, lb_rel, lb_packet; 371e979c658Sreinoud uint32_t udf_rw32_lbmap, ext_offset; 372e979c658Sreinoud uint16_t vpart; 373e979c658Sreinoud int rel, part, error, eof, slot, flags; 374e979c658Sreinoud 375e979c658Sreinoud assert(ump && icb_loc && lb_numres); 376e979c658Sreinoud 377e979c658Sreinoud vpart = udf_rw16(icb_loc->loc.part_num); 378e979c658Sreinoud lb_num = udf_rw32(icb_loc->loc.lb_num); 379e979c658Sreinoud if (vpart > UDF_VTOP_RAWPART) 380e979c658Sreinoud return EINVAL; 381e979c658Sreinoud 382e979c658Sreinoud translate_again: 383e979c658Sreinoud part = ump->vtop[vpart]; 384e979c658Sreinoud pdesc = ump->partitions[part]; 385e979c658Sreinoud 386e979c658Sreinoud switch (ump->vtop_tp[vpart]) { 387e979c658Sreinoud case UDF_VTOP_TYPE_RAW : 388e979c658Sreinoud /* 1:1 to the end of the device */ 389e979c658Sreinoud *lb_numres = lb_num; 390e979c658Sreinoud *extres = INT_MAX; 391e979c658Sreinoud return 0; 392e979c658Sreinoud case UDF_VTOP_TYPE_PHYS : 393e979c658Sreinoud /* transform into its disc logical block */ 394e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 395e979c658Sreinoud return EINVAL; 396e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 397e979c658Sreinoud 398e979c658Sreinoud /* extent from here to the end of the partition */ 399e979c658Sreinoud *extres = udf_rw32(pdesc->part_len) - lb_num; 400e979c658Sreinoud return 0; 401e979c658Sreinoud case UDF_VTOP_TYPE_VIRT : 402e979c658Sreinoud /* only maps one logical block, lookup in VAT */ 403e979c658Sreinoud if (lb_num >= ump->vat_entries) /* XXX > or >= ? */ 404e979c658Sreinoud return EINVAL; 405e979c658Sreinoud 406e979c658Sreinoud /* lookup in virtual allocation table file */ 407e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 408e979c658Sreinoud error = udf_vat_read(ump->vat_node, 409e979c658Sreinoud (uint8_t *) &udf_rw32_lbmap, 4, 410e979c658Sreinoud ump->vat_offset + lb_num * 4); 411e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 412e979c658Sreinoud 413e979c658Sreinoud if (error) 414e979c658Sreinoud return error; 415e979c658Sreinoud 416e979c658Sreinoud lb_num = udf_rw32(udf_rw32_lbmap); 417e979c658Sreinoud 418e979c658Sreinoud /* transform into its disc logical block */ 419e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 420e979c658Sreinoud return EINVAL; 421e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 422e979c658Sreinoud 423e979c658Sreinoud /* just one logical block */ 424e979c658Sreinoud *extres = 1; 425e979c658Sreinoud return 0; 426e979c658Sreinoud case UDF_VTOP_TYPE_SPARABLE : 427e979c658Sreinoud /* check if the packet containing the lb_num is remapped */ 428e979c658Sreinoud lb_packet = lb_num / ump->sparable_packet_size; 429e979c658Sreinoud lb_rel = lb_num % ump->sparable_packet_size; 430e979c658Sreinoud 431e979c658Sreinoud for (rel = 0; rel < udf_rw16(ump->sparing_table->rt_l); rel++) { 432e979c658Sreinoud sme = &ump->sparing_table->entries[rel]; 433e979c658Sreinoud if (lb_packet == udf_rw32(sme->org)) { 434e979c658Sreinoud /* NOTE maps to absolute disc logical block! */ 435e979c658Sreinoud *lb_numres = udf_rw32(sme->map) + lb_rel; 436e979c658Sreinoud *extres = ump->sparable_packet_size - lb_rel; 437e979c658Sreinoud return 0; 438e979c658Sreinoud } 439e979c658Sreinoud } 440e979c658Sreinoud 441e979c658Sreinoud /* transform into its disc logical block */ 442e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 443e979c658Sreinoud return EINVAL; 444e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 445e979c658Sreinoud 446e979c658Sreinoud /* rest of block */ 447e979c658Sreinoud *extres = ump->sparable_packet_size - lb_rel; 448e979c658Sreinoud return 0; 449e979c658Sreinoud case UDF_VTOP_TYPE_META : 450e979c658Sreinoud /* we have to look into the file's allocation descriptors */ 451e979c658Sreinoud 452e979c658Sreinoud /* use metadatafile allocation mutex */ 453e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 454e979c658Sreinoud 455e979c658Sreinoud UDF_LOCK_NODE(ump->metadata_node, 0); 456e979c658Sreinoud 457e979c658Sreinoud /* get first overlapping extent */ 458e979c658Sreinoud foffset = 0; 459e979c658Sreinoud slot = 0; 460e979c658Sreinoud for (;;) { 461e979c658Sreinoud udf_get_adslot(ump->metadata_node, 462e979c658Sreinoud slot, &s_icb_loc, &eof); 463ca7a0d4eSreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, " 464ca7a0d4eSreinoud "len = %d, lb_num = %d, part = %d\n", 465ca7a0d4eSreinoud slot, eof, 466ca7a0d4eSreinoud UDF_EXT_FLAGS(udf_rw32(s_icb_loc.len)), 467ca7a0d4eSreinoud UDF_EXT_LEN(udf_rw32(s_icb_loc.len)), 468ca7a0d4eSreinoud udf_rw32(s_icb_loc.loc.lb_num), 469ca7a0d4eSreinoud udf_rw16(s_icb_loc.loc.part_num))); 470e979c658Sreinoud if (eof) { 471e979c658Sreinoud DPRINTF(TRANSLATE, 472e979c658Sreinoud ("Meta partition translation " 473e979c658Sreinoud "failed: can't seek location\n")); 474e979c658Sreinoud UDF_UNLOCK_NODE(ump->metadata_node, 0); 475e979c658Sreinoud return EINVAL; 476e979c658Sreinoud } 477e979c658Sreinoud len = udf_rw32(s_icb_loc.len); 478e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 479e979c658Sreinoud len = UDF_EXT_LEN(len); 480e979c658Sreinoud 481ca7a0d4eSreinoud if (flags == UDF_EXT_REDIRECT) { 482ca7a0d4eSreinoud slot++; 483ca7a0d4eSreinoud continue; 484ca7a0d4eSreinoud } 485ca7a0d4eSreinoud 486e979c658Sreinoud end_foffset = foffset + len; 487e979c658Sreinoud 488e979c658Sreinoud if (end_foffset > lb_num * lb_size) 489e979c658Sreinoud break; /* found */ 490e979c658Sreinoud foffset = end_foffset; 491e979c658Sreinoud slot++; 492e979c658Sreinoud } 493e979c658Sreinoud /* found overlapping slot */ 494e979c658Sreinoud ext_offset = lb_num * lb_size - foffset; 495e979c658Sreinoud 496e979c658Sreinoud /* process extent offset */ 497e979c658Sreinoud lb_num = udf_rw32(s_icb_loc.loc.lb_num); 498e979c658Sreinoud vpart = udf_rw16(s_icb_loc.loc.part_num); 499e979c658Sreinoud lb_num += (ext_offset + lb_size -1) / lb_size; 500e979c658Sreinoud len -= ext_offset; 501e979c658Sreinoud ext_offset = 0; 502e979c658Sreinoud 503e979c658Sreinoud flags = UDF_EXT_FLAGS(s_icb_loc.len); 504e979c658Sreinoud 505e979c658Sreinoud UDF_UNLOCK_NODE(ump->metadata_node, 0); 506e979c658Sreinoud if (flags != UDF_EXT_ALLOCATED) { 507e979c658Sreinoud DPRINTF(TRANSLATE, ("Metadata partition translation " 508e979c658Sreinoud "failed: not allocated\n")); 509e979c658Sreinoud return EINVAL; 510e979c658Sreinoud } 511e979c658Sreinoud 512e979c658Sreinoud /* 513e979c658Sreinoud * vpart and lb_num are updated, translate again since we 514e979c658Sreinoud * might be mapped on sparable media 515e979c658Sreinoud */ 516e979c658Sreinoud goto translate_again; 517e979c658Sreinoud default: 518e979c658Sreinoud printf("UDF vtop translation scheme %d unimplemented yet\n", 519e979c658Sreinoud ump->vtop_tp[vpart]); 520e979c658Sreinoud } 521e979c658Sreinoud 522e979c658Sreinoud return EINVAL; 523e979c658Sreinoud } 524e979c658Sreinoud 525e979c658Sreinoud /* --------------------------------------------------------------------- */ 526e979c658Sreinoud 527e979c658Sreinoud /* 528e979c658Sreinoud * Translate an extent (in logical_blocks) into logical block numbers; used 529e979c658Sreinoud * for read and write operations. DOESNT't check extents. 530e979c658Sreinoud */ 531e979c658Sreinoud 532e979c658Sreinoud int 533e979c658Sreinoud udf_translate_file_extent(struct udf_node *udf_node, 534e979c658Sreinoud uint32_t from, uint32_t num_lb, 535e979c658Sreinoud uint64_t *map) 536e979c658Sreinoud { 537e979c658Sreinoud struct udf_mount *ump; 538e979c658Sreinoud struct icb_tag *icbtag; 539e979c658Sreinoud struct long_ad t_ad, s_ad; 540e979c658Sreinoud uint64_t transsec; 541e979c658Sreinoud uint64_t foffset, end_foffset; 542e979c658Sreinoud uint32_t transsec32; 543e979c658Sreinoud uint32_t lb_size; 544e979c658Sreinoud uint32_t ext_offset; 545e979c658Sreinoud uint32_t lb_num, len; 546e979c658Sreinoud uint32_t overlap, translen; 547e979c658Sreinoud uint16_t vpart_num; 548e979c658Sreinoud int eof, error, flags; 549e979c658Sreinoud int slot, addr_type, icbflags; 550e979c658Sreinoud 551e979c658Sreinoud if (!udf_node) 552e979c658Sreinoud return ENOENT; 553e979c658Sreinoud 554e979c658Sreinoud KASSERT(num_lb > 0); 555e979c658Sreinoud 556e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 557e979c658Sreinoud 558e979c658Sreinoud /* initialise derivative vars */ 559e979c658Sreinoud ump = udf_node->ump; 560e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 561e979c658Sreinoud 562e979c658Sreinoud if (udf_node->fe) { 563e979c658Sreinoud icbtag = &udf_node->fe->icbtag; 564e979c658Sreinoud } else { 565e979c658Sreinoud icbtag = &udf_node->efe->icbtag; 566e979c658Sreinoud } 567e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 568e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 569e979c658Sreinoud 570e979c658Sreinoud /* do the work */ 571e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 572e979c658Sreinoud *map = UDF_TRANS_INTERN; 573e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 574e979c658Sreinoud return 0; 575e979c658Sreinoud } 576e979c658Sreinoud 577e979c658Sreinoud /* find first overlapping extent */ 578e979c658Sreinoud foffset = 0; 579e979c658Sreinoud slot = 0; 580e979c658Sreinoud for (;;) { 581e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 582e5ee8341Sreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, len = %d, " 583e5ee8341Sreinoud "lb_num = %d, part = %d\n", slot, eof, 584e5ee8341Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)), 585e5ee8341Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 586e5ee8341Sreinoud udf_rw32(s_ad.loc.lb_num), 587e5ee8341Sreinoud udf_rw16(s_ad.loc.part_num))); 588e979c658Sreinoud if (eof) { 589e979c658Sreinoud DPRINTF(TRANSLATE, 590e979c658Sreinoud ("Translate file extent " 591e979c658Sreinoud "failed: can't seek location\n")); 592e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 593e979c658Sreinoud return EINVAL; 594e979c658Sreinoud } 595e979c658Sreinoud len = udf_rw32(s_ad.len); 596e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 597e979c658Sreinoud len = UDF_EXT_LEN(len); 598e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 599e979c658Sreinoud 600e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 601e979c658Sreinoud slot++; 602e979c658Sreinoud continue; 603e979c658Sreinoud } 604e979c658Sreinoud 605e979c658Sreinoud end_foffset = foffset + len; 606e979c658Sreinoud 607e979c658Sreinoud if (end_foffset > from * lb_size) 608e979c658Sreinoud break; /* found */ 609e979c658Sreinoud foffset = end_foffset; 610e979c658Sreinoud slot++; 611e979c658Sreinoud } 612e979c658Sreinoud /* found overlapping slot */ 613e979c658Sreinoud ext_offset = from * lb_size - foffset; 614e979c658Sreinoud 615e979c658Sreinoud for (;;) { 616e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 617e5ee8341Sreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, len = %d, " 618e5ee8341Sreinoud "lb_num = %d, part = %d\n", slot, eof, 619e5ee8341Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)), 620e5ee8341Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 621e5ee8341Sreinoud udf_rw32(s_ad.loc.lb_num), 622e5ee8341Sreinoud udf_rw16(s_ad.loc.part_num))); 623e979c658Sreinoud if (eof) { 624e979c658Sreinoud DPRINTF(TRANSLATE, 625e979c658Sreinoud ("Translate file extent " 626e979c658Sreinoud "failed: past eof\n")); 627e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 628e979c658Sreinoud return EINVAL; 629e979c658Sreinoud } 630e979c658Sreinoud 631e979c658Sreinoud len = udf_rw32(s_ad.len); 632e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 633e979c658Sreinoud len = UDF_EXT_LEN(len); 634e979c658Sreinoud 635e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 636e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 637e979c658Sreinoud 638e979c658Sreinoud end_foffset = foffset + len; 639e979c658Sreinoud 640e979c658Sreinoud /* process extent, don't forget to advance on ext_offset! */ 641e979c658Sreinoud lb_num += (ext_offset + lb_size -1) / lb_size; 642e979c658Sreinoud overlap = (len - ext_offset + lb_size -1) / lb_size; 643e979c658Sreinoud ext_offset = 0; 644e979c658Sreinoud 645e979c658Sreinoud /* 646e979c658Sreinoud * note that the while(){} is nessisary for the extent that 647e979c658Sreinoud * the udf_translate_vtop() returns doens't have to span the 648e979c658Sreinoud * whole extent. 649e979c658Sreinoud */ 650e979c658Sreinoud 651e979c658Sreinoud overlap = MIN(overlap, num_lb); 652e5ee8341Sreinoud while (overlap && (flags != UDF_EXT_REDIRECT)) { 653e979c658Sreinoud switch (flags) { 654e979c658Sreinoud case UDF_EXT_FREE : 655e979c658Sreinoud case UDF_EXT_ALLOCATED_BUT_NOT_USED : 656e979c658Sreinoud transsec = UDF_TRANS_ZERO; 657e979c658Sreinoud translen = overlap; 658e979c658Sreinoud while (overlap && num_lb && translen) { 659e979c658Sreinoud *map++ = transsec; 660e979c658Sreinoud lb_num++; 661e979c658Sreinoud overlap--; num_lb--; translen--; 662e979c658Sreinoud } 663e979c658Sreinoud break; 664e979c658Sreinoud case UDF_EXT_ALLOCATED : 665e979c658Sreinoud t_ad.loc.lb_num = udf_rw32(lb_num); 666e979c658Sreinoud t_ad.loc.part_num = udf_rw16(vpart_num); 667e979c658Sreinoud error = udf_translate_vtop(ump, 668e979c658Sreinoud &t_ad, &transsec32, &translen); 669e979c658Sreinoud transsec = transsec32; 670e979c658Sreinoud if (error) { 671e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 672e979c658Sreinoud return error; 673e979c658Sreinoud } 674e979c658Sreinoud while (overlap && num_lb && translen) { 675e979c658Sreinoud *map++ = transsec; 676e979c658Sreinoud lb_num++; transsec++; 677e979c658Sreinoud overlap--; num_lb--; translen--; 678e979c658Sreinoud } 679e979c658Sreinoud break; 680e5ee8341Sreinoud default: 681e5ee8341Sreinoud DPRINTF(TRANSLATE, 682e5ee8341Sreinoud ("Translate file extent " 683e5ee8341Sreinoud "failed: bad flags %x\n", flags)); 684e5ee8341Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 685e5ee8341Sreinoud return EINVAL; 686e979c658Sreinoud } 687e979c658Sreinoud } 688e979c658Sreinoud if (num_lb == 0) 689e979c658Sreinoud break; 690e979c658Sreinoud 691e979c658Sreinoud if (flags != UDF_EXT_REDIRECT) 692e979c658Sreinoud foffset = end_foffset; 693e979c658Sreinoud slot++; 694e979c658Sreinoud } 695e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 696e979c658Sreinoud 697e979c658Sreinoud return 0; 698e979c658Sreinoud } 699e979c658Sreinoud 700e979c658Sreinoud /* --------------------------------------------------------------------- */ 701e979c658Sreinoud 702e979c658Sreinoud static int 703e979c658Sreinoud udf_search_free_vatloc(struct udf_mount *ump, uint32_t *lbnumres) 704e979c658Sreinoud { 705e979c658Sreinoud uint32_t lb_size, lb_num, lb_map, udf_rw32_lbmap; 706e979c658Sreinoud uint8_t *blob; 707e979c658Sreinoud int entry, chunk, found, error; 708e979c658Sreinoud 709e979c658Sreinoud KASSERT(ump); 710e979c658Sreinoud KASSERT(ump->logical_vol); 711e979c658Sreinoud 712e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 713e979c658Sreinoud blob = malloc(lb_size, M_UDFTEMP, M_WAITOK); 714e979c658Sreinoud 715e979c658Sreinoud /* TODO static allocation of search chunk */ 716e979c658Sreinoud 717e979c658Sreinoud lb_num = MIN(ump->vat_entries, ump->vat_last_free_lb); 718e979c658Sreinoud found = 0; 719e979c658Sreinoud error = 0; 720e979c658Sreinoud entry = 0; 721e979c658Sreinoud do { 722e979c658Sreinoud chunk = MIN(lb_size, (ump->vat_entries - lb_num) * 4); 723e979c658Sreinoud if (chunk <= 0) 724e979c658Sreinoud break; 725e979c658Sreinoud /* load in chunk */ 726e979c658Sreinoud error = udf_vat_read(ump->vat_node, blob, chunk, 727e979c658Sreinoud ump->vat_offset + lb_num * 4); 728e979c658Sreinoud 729e979c658Sreinoud if (error) 730e979c658Sreinoud break; 731e979c658Sreinoud 732e979c658Sreinoud /* search this chunk */ 733e979c658Sreinoud for (entry=0; entry < chunk /4; entry++, lb_num++) { 734e979c658Sreinoud udf_rw32_lbmap = *((uint32_t *) (blob + entry * 4)); 735e979c658Sreinoud lb_map = udf_rw32(udf_rw32_lbmap); 736e979c658Sreinoud if (lb_map == 0xffffffff) { 737e979c658Sreinoud found = 1; 738e979c658Sreinoud break; 739e979c658Sreinoud } 740e979c658Sreinoud } 741e979c658Sreinoud } while (!found); 742e979c658Sreinoud if (error) { 743e979c658Sreinoud printf("udf_search_free_vatloc: error reading in vat chunk " 744e979c658Sreinoud "(lb %d, size %d)\n", lb_num, chunk); 745e979c658Sreinoud } 746e979c658Sreinoud 747e979c658Sreinoud if (!found) { 748e979c658Sreinoud /* extend VAT */ 749e979c658Sreinoud DPRINTF(WRITE, ("udf_search_free_vatloc: extending\n")); 750e979c658Sreinoud lb_num = ump->vat_entries; 751e979c658Sreinoud ump->vat_entries++; 752e979c658Sreinoud } 753e979c658Sreinoud 754e979c658Sreinoud /* mark entry with initialiser just in case */ 755e979c658Sreinoud lb_map = udf_rw32(0xfffffffe); 756e979c658Sreinoud udf_vat_write(ump->vat_node, (uint8_t *) &lb_map, 4, 757e979c658Sreinoud ump->vat_offset + lb_num *4); 758e979c658Sreinoud ump->vat_last_free_lb = lb_num; 759e979c658Sreinoud 760e979c658Sreinoud free(blob, M_UDFTEMP); 761e979c658Sreinoud *lbnumres = lb_num; 762e979c658Sreinoud return 0; 763e979c658Sreinoud } 764e979c658Sreinoud 765e979c658Sreinoud 766e979c658Sreinoud static void 767e979c658Sreinoud udf_bitmap_allocate(struct udf_bitmap *bitmap, int ismetadata, 768e979c658Sreinoud uint32_t ptov, uint32_t *num_lb, uint64_t *pmappos, uint64_t *lmappos) 769e979c658Sreinoud { 770e979c658Sreinoud uint32_t offset, lb_num, bit; 771e979c658Sreinoud int32_t diff; 772e979c658Sreinoud uint8_t *bpos; 773e979c658Sreinoud int pass; 774e979c658Sreinoud 775e979c658Sreinoud if (!ismetadata) { 776e979c658Sreinoud /* heuristic to keep the two pointers not too close */ 777e979c658Sreinoud diff = bitmap->data_pos - bitmap->metadata_pos; 778e979c658Sreinoud if ((diff >= 0) && (diff < 1024)) 779e979c658Sreinoud bitmap->data_pos = bitmap->metadata_pos + 1024; 780e979c658Sreinoud } 781e979c658Sreinoud offset = ismetadata ? bitmap->metadata_pos : bitmap->data_pos; 782e979c658Sreinoud offset &= ~7; 783e979c658Sreinoud for (pass = 0; pass < 2; pass++) { 784e979c658Sreinoud if (offset >= bitmap->max_offset) 785e979c658Sreinoud offset = 0; 786e979c658Sreinoud 787e979c658Sreinoud while (offset < bitmap->max_offset) { 788e979c658Sreinoud if (*num_lb == 0) 789e979c658Sreinoud break; 790e979c658Sreinoud 791e979c658Sreinoud /* use first bit not set */ 792e979c658Sreinoud bpos = bitmap->bits + offset/8; 7935eeb4f69Sreinoud bit = ffs(*bpos); /* returns 0 or 1..8 */ 794e979c658Sreinoud if (bit == 0) { 795e979c658Sreinoud offset += 8; 796e979c658Sreinoud continue; 797e979c658Sreinoud } 7985eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : allocate %d, %p, bit %d\n", 7995eeb4f69Sreinoud offset + bit -1, bpos, bit-1)); 800e979c658Sreinoud *bpos &= ~(1 << (bit-1)); 801e979c658Sreinoud lb_num = offset + bit-1; 802e979c658Sreinoud *lmappos++ = lb_num; 803e979c658Sreinoud *pmappos++ = lb_num + ptov; 804e979c658Sreinoud *num_lb = *num_lb - 1; 805e979c658Sreinoud // offset = (offset & ~7); 806e979c658Sreinoud } 807e979c658Sreinoud } 808e979c658Sreinoud 809e979c658Sreinoud if (ismetadata) { 810e979c658Sreinoud bitmap->metadata_pos = offset; 811e979c658Sreinoud } else { 812e979c658Sreinoud bitmap->data_pos = offset; 813e979c658Sreinoud } 814e979c658Sreinoud } 815e979c658Sreinoud 816e979c658Sreinoud 817e979c658Sreinoud static void 818e979c658Sreinoud udf_bitmap_free(struct udf_bitmap *bitmap, uint32_t lb_num, uint32_t num_lb) 819e979c658Sreinoud { 820e979c658Sreinoud uint32_t offset; 821e979c658Sreinoud uint32_t bit, bitval; 822e979c658Sreinoud uint8_t *bpos; 823e979c658Sreinoud 824e979c658Sreinoud offset = lb_num; 825e979c658Sreinoud 826e979c658Sreinoud /* starter bits */ 827e979c658Sreinoud bpos = bitmap->bits + offset/8; 828e979c658Sreinoud bit = offset % 8; 829e979c658Sreinoud while ((bit != 0) && (num_lb > 0)) { 830e979c658Sreinoud bitval = (1 << bit); 831e979c658Sreinoud KASSERT((*bpos & bitval) == 0); 8325eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : free %d, %p, %d\n", 8335eeb4f69Sreinoud offset, bpos, bit)); 834e979c658Sreinoud *bpos |= bitval; 835e979c658Sreinoud offset++; num_lb--; 836e979c658Sreinoud bit = (bit + 1) % 8; 837e979c658Sreinoud } 838e979c658Sreinoud if (num_lb == 0) 839e979c658Sreinoud return; 840e979c658Sreinoud 841e979c658Sreinoud /* whole bytes */ 842e979c658Sreinoud KASSERT(bit == 0); 843e979c658Sreinoud bpos = bitmap->bits + offset / 8; 844e979c658Sreinoud while (num_lb >= 8) { 845e979c658Sreinoud KASSERT((*bpos == 0)); 8465eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : free %d + 8, %p\n", offset, bpos)); 847e979c658Sreinoud *bpos = 255; 848e979c658Sreinoud offset += 8; num_lb -= 8; 849e979c658Sreinoud bpos++; 850e979c658Sreinoud } 851e979c658Sreinoud 852e979c658Sreinoud /* stop bits */ 853e979c658Sreinoud KASSERT(num_lb < 8); 854e979c658Sreinoud bit = 0; 855e979c658Sreinoud while (num_lb > 0) { 856e979c658Sreinoud bitval = (1 << bit); 857e979c658Sreinoud KASSERT((*bpos & bitval) == 0); 8585eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : free %d, %p, %d\n", 8595eeb4f69Sreinoud offset, bpos, bit)); 860e979c658Sreinoud *bpos |= bitval; 861e979c658Sreinoud offset++; num_lb--; 862e979c658Sreinoud bit = (bit + 1) % 8; 863e979c658Sreinoud } 864e979c658Sreinoud } 865e979c658Sreinoud 866e979c658Sreinoud 867e979c658Sreinoud /* allocate a contiguous sequence of sectornumbers */ 868e979c658Sreinoud static int 869e979c658Sreinoud udf_allocate_space(struct udf_mount *ump, int ismetadata, int alloc_type, 870e979c658Sreinoud int num_lb, uint16_t *alloc_partp, 871e979c658Sreinoud uint64_t *lmapping, uint64_t *pmapping) 872e979c658Sreinoud { 873e979c658Sreinoud struct mmc_trackinfo *alloc_track, *other_track; 874e979c658Sreinoud struct udf_bitmap *bitmap; 875e979c658Sreinoud struct part_desc *pdesc; 876e979c658Sreinoud struct logvol_int_desc *lvid; 877e979c658Sreinoud uint64_t *lmappos, *pmappos; 878e979c658Sreinoud uint32_t ptov, lb_num, *freepos, free_lbs; 879e979c658Sreinoud int lb_size, alloc_num_lb; 880e979c658Sreinoud int alloc_part; 881e979c658Sreinoud int error; 882e979c658Sreinoud 883e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 884e979c658Sreinoud 885e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 886e979c658Sreinoud KASSERT(lb_size == ump->discinfo.sector_size); 887e979c658Sreinoud 888e979c658Sreinoud if (ismetadata) { 889e979c658Sreinoud alloc_part = ump->metadata_part; 890e979c658Sreinoud alloc_track = &ump->metadata_track; 891e979c658Sreinoud other_track = &ump->data_track; 892e979c658Sreinoud } else { 893e979c658Sreinoud alloc_part = ump->data_part; 894e979c658Sreinoud alloc_track = &ump->data_track; 895e979c658Sreinoud other_track = &ump->metadata_track; 896e979c658Sreinoud } 897e979c658Sreinoud 898e979c658Sreinoud *alloc_partp = alloc_part; 899e979c658Sreinoud 900e979c658Sreinoud error = 0; 901e979c658Sreinoud /* XXX check disc space */ 902e979c658Sreinoud 903e979c658Sreinoud pdesc = ump->partitions[ump->vtop[alloc_part]]; 904e979c658Sreinoud lmappos = lmapping; 905e979c658Sreinoud pmappos = pmapping; 906e979c658Sreinoud 907e979c658Sreinoud switch (alloc_type) { 908e979c658Sreinoud case UDF_ALLOC_VAT : 909e979c658Sreinoud /* search empty slot in VAT file */ 910e979c658Sreinoud KASSERT(num_lb == 1); 911e979c658Sreinoud error = udf_search_free_vatloc(ump, &lb_num); 912e979c658Sreinoud if (!error) { 913e979c658Sreinoud *lmappos = lb_num; 914e979c658Sreinoud *pmappos = 0; /* will get late-allocated */ 915e979c658Sreinoud } 916e979c658Sreinoud break; 917e979c658Sreinoud case UDF_ALLOC_SEQUENTIAL : 918e979c658Sreinoud /* sequential allocation on recordable media */ 919e979c658Sreinoud /* calculate offset from physical base partition */ 920e979c658Sreinoud ptov = udf_rw32(pdesc->start_loc); 921e979c658Sreinoud 922e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 923e979c658Sreinoud *pmappos++ = alloc_track->next_writable; 924e979c658Sreinoud *lmappos++ = alloc_track->next_writable - ptov; 925e979c658Sreinoud alloc_track->next_writable++; 926e979c658Sreinoud alloc_track->free_blocks--; 927e979c658Sreinoud } 928e979c658Sreinoud if (alloc_track->tracknr == other_track->tracknr) 929e979c658Sreinoud memcpy(other_track, alloc_track, 930e979c658Sreinoud sizeof(struct mmc_trackinfo)); 931e979c658Sreinoud break; 932e979c658Sreinoud case UDF_ALLOC_SPACEMAP : 933e979c658Sreinoud ptov = udf_rw32(pdesc->start_loc); 934e979c658Sreinoud 935e979c658Sreinoud /* allocate on unallocated bits page */ 936e979c658Sreinoud alloc_num_lb = num_lb; 937e979c658Sreinoud bitmap = &ump->part_unalloc_bits[alloc_part]; 938e979c658Sreinoud udf_bitmap_allocate(bitmap, ismetadata, ptov, &alloc_num_lb, 939e979c658Sreinoud pmappos, lmappos); 940e979c658Sreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 941e979c658Sreinoud if (alloc_num_lb) { 942e979c658Sreinoud /* TODO convert freed to unalloc and try again */ 943e979c658Sreinoud /* free allocated piece for now */ 944e979c658Sreinoud lmappos = lmapping; 945e979c658Sreinoud for (lb_num=0; lb_num < num_lb-alloc_num_lb; lb_num++) { 946e979c658Sreinoud udf_bitmap_free(bitmap, *lmappos++, 1); 947e979c658Sreinoud } 948e979c658Sreinoud error = ENOSPC; 949e979c658Sreinoud } 950e979c658Sreinoud if (!error) { 951e979c658Sreinoud /* adjust freecount */ 952e979c658Sreinoud lvid = ump->logvol_integrity; 953e979c658Sreinoud freepos = &lvid->tables[0] + alloc_part; 954e979c658Sreinoud free_lbs = udf_rw32(*freepos); 955e979c658Sreinoud *freepos = udf_rw32(free_lbs - num_lb); 956e979c658Sreinoud } 957e979c658Sreinoud break; 958e979c658Sreinoud case UDF_ALLOC_METABITMAP : 959e979c658Sreinoud case UDF_ALLOC_METASEQUENTIAL : 960e979c658Sreinoud case UDF_ALLOC_RELAXEDSEQUENTIAL : 961e979c658Sreinoud printf("ALERT: udf_allocate_space : allocation %d " 962e979c658Sreinoud "not implemented yet!\n", alloc_type); 963e979c658Sreinoud /* TODO implement, doesn't have to be contiguous */ 964e979c658Sreinoud error = ENOSPC; 965e979c658Sreinoud break; 966e979c658Sreinoud } 967e979c658Sreinoud 968e979c658Sreinoud #ifdef DEBUG 969e979c658Sreinoud if (udf_verbose & UDF_DEBUG_ALLOC) { 970e979c658Sreinoud lmappos = lmapping; 971e979c658Sreinoud pmappos = pmapping; 972e979c658Sreinoud printf("udf_allocate_space, mapping l->p:\n"); 973e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 974e979c658Sreinoud printf("\t%"PRIu64" -> %"PRIu64"\n", 975e979c658Sreinoud *lmappos++, *pmappos++); 976e979c658Sreinoud } 977e979c658Sreinoud } 978e979c658Sreinoud #endif 979e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 980e979c658Sreinoud 981e979c658Sreinoud return error; 982e979c658Sreinoud } 983e979c658Sreinoud 984e979c658Sreinoud /* --------------------------------------------------------------------- */ 985e979c658Sreinoud 986e979c658Sreinoud void 987e979c658Sreinoud udf_free_allocated_space(struct udf_mount *ump, uint32_t lb_num, 988e979c658Sreinoud uint16_t vpart_num, uint32_t num_lb) 989e979c658Sreinoud { 990e979c658Sreinoud struct udf_bitmap *bitmap; 991e979c658Sreinoud struct part_desc *pdesc; 992e979c658Sreinoud struct logvol_int_desc *lvid; 993e979c658Sreinoud uint32_t ptov, lb_map, udf_rw32_lbmap; 994e979c658Sreinoud uint32_t *freepos, free_lbs; 995e979c658Sreinoud int phys_part; 996e979c658Sreinoud int error; 997e979c658Sreinoud 998e979c658Sreinoud DPRINTF(ALLOC, ("udf_free_allocated_space: freeing virt lbnum %d " 999e979c658Sreinoud "part %d + %d sect\n", lb_num, vpart_num, num_lb)); 1000e979c658Sreinoud 1001d3bf9c7bSreinoud /* no use freeing zero length */ 1002d3bf9c7bSreinoud if (num_lb == 0) 1003d3bf9c7bSreinoud return; 1004d3bf9c7bSreinoud 1005e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 1006e979c658Sreinoud 1007e979c658Sreinoud /* get partition backing up this vpart_num */ 1008e979c658Sreinoud pdesc = ump->partitions[ump->vtop[vpart_num]]; 1009e979c658Sreinoud 1010e979c658Sreinoud switch (ump->vtop_tp[vpart_num]) { 1011e979c658Sreinoud case UDF_VTOP_TYPE_PHYS : 1012e979c658Sreinoud case UDF_VTOP_TYPE_SPARABLE : 1013e979c658Sreinoud /* free space to freed or unallocated space bitmap */ 1014e979c658Sreinoud ptov = udf_rw32(pdesc->start_loc); 1015e979c658Sreinoud phys_part = ump->vtop[vpart_num]; 1016e979c658Sreinoud 1017e979c658Sreinoud /* first try freed space bitmap */ 1018e979c658Sreinoud bitmap = &ump->part_freed_bits[phys_part]; 1019e979c658Sreinoud 1020e979c658Sreinoud /* if not defined, use unallocated bitmap */ 1021e979c658Sreinoud if (bitmap->bits == NULL) 1022e979c658Sreinoud bitmap = &ump->part_unalloc_bits[phys_part]; 1023e979c658Sreinoud 1024e979c658Sreinoud /* if no bitmaps are defined, bail out */ 1025e979c658Sreinoud if (bitmap->bits == NULL) 1026e979c658Sreinoud break; 1027e979c658Sreinoud 1028e979c658Sreinoud /* free bits if its defined */ 1029e979c658Sreinoud KASSERT(bitmap->bits); 1030e979c658Sreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 1031e979c658Sreinoud udf_bitmap_free(bitmap, lb_num, num_lb); 1032e979c658Sreinoud 1033e979c658Sreinoud /* adjust freecount */ 1034e979c658Sreinoud lvid = ump->logvol_integrity; 1035e979c658Sreinoud freepos = &lvid->tables[0] + vpart_num; 1036e979c658Sreinoud free_lbs = udf_rw32(*freepos); 1037e979c658Sreinoud *freepos = udf_rw32(free_lbs + num_lb); 1038e979c658Sreinoud break; 1039e979c658Sreinoud case UDF_VTOP_TYPE_VIRT : 1040e979c658Sreinoud /* free this VAT entry */ 1041e979c658Sreinoud KASSERT(num_lb == 1); 1042e979c658Sreinoud 1043e979c658Sreinoud lb_map = 0xffffffff; 1044e979c658Sreinoud udf_rw32_lbmap = udf_rw32(lb_map); 1045e979c658Sreinoud error = udf_vat_write(ump->vat_node, 1046e979c658Sreinoud (uint8_t *) &udf_rw32_lbmap, 4, 1047e979c658Sreinoud ump->vat_offset + lb_num * 4); 1048e979c658Sreinoud KASSERT(error == 0); 1049e979c658Sreinoud ump->vat_last_free_lb = MIN(ump->vat_last_free_lb, lb_num); 1050e979c658Sreinoud break; 1051e979c658Sreinoud case UDF_VTOP_TYPE_META : 1052e979c658Sreinoud /* free space in the metadata bitmap */ 1053e979c658Sreinoud default: 1054e979c658Sreinoud printf("ALERT: udf_free_allocated_space : allocation %d " 1055e979c658Sreinoud "not implemented yet!\n", ump->vtop_tp[vpart_num]); 1056e979c658Sreinoud break; 1057e979c658Sreinoud } 1058e979c658Sreinoud 1059e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 1060e979c658Sreinoud } 1061e979c658Sreinoud 1062e979c658Sreinoud /* --------------------------------------------------------------------- */ 1063e979c658Sreinoud 1064e979c658Sreinoud int 1065e979c658Sreinoud udf_pre_allocate_space(struct udf_mount *ump, int udf_c_type, int num_lb, 1066e979c658Sreinoud uint16_t *alloc_partp, uint64_t *lmapping, uint64_t *pmapping) 1067e979c658Sreinoud { 1068e979c658Sreinoud int ismetadata, alloc_type; 1069e979c658Sreinoud 1070e979c658Sreinoud ismetadata = (udf_c_type == UDF_C_NODE); 1071e979c658Sreinoud alloc_type = ismetadata? ump->meta_alloc : ump->data_alloc; 1072e979c658Sreinoud 1073e979c658Sreinoud #ifdef DIAGNOSTIC 1074e979c658Sreinoud if ((alloc_type == UDF_ALLOC_VAT) && (udf_c_type != UDF_C_NODE)) { 1075e979c658Sreinoud panic("udf_pre_allocate_space: bad c_type on VAT!\n"); 1076e979c658Sreinoud } 1077e979c658Sreinoud #endif 1078e979c658Sreinoud 1079e979c658Sreinoud /* reserve size for VAT allocated data */ 1080e979c658Sreinoud if (alloc_type == UDF_ALLOC_VAT) { 1081e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 1082e979c658Sreinoud ump->uncomitted_lb += num_lb; 1083e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 1084e979c658Sreinoud } 1085e979c658Sreinoud 1086e979c658Sreinoud return udf_allocate_space(ump, ismetadata, alloc_type, 1087e979c658Sreinoud num_lb, alloc_partp, lmapping, pmapping); 1088e979c658Sreinoud } 1089e979c658Sreinoud 1090e979c658Sreinoud /* --------------------------------------------------------------------- */ 1091e979c658Sreinoud 1092e979c658Sreinoud /* 1093e979c658Sreinoud * Allocate a buf on disc for direct write out. The space doesn't have to be 1094e979c658Sreinoud * contiguous as the caller takes care of this. 1095e979c658Sreinoud */ 1096e979c658Sreinoud 1097e979c658Sreinoud void 1098e979c658Sreinoud udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, 1099e979c658Sreinoud uint64_t *lmapping, uint64_t *pmapping, struct long_ad *node_ad_cpy) 1100e979c658Sreinoud { 1101e979c658Sreinoud struct udf_node *udf_node = VTOI(buf->b_vp); 1102e979c658Sreinoud uint16_t vpart_num; 1103e979c658Sreinoud int lb_size, blks, udf_c_type; 1104e979c658Sreinoud int ismetadata, alloc_type; 1105e979c658Sreinoud int num_lb; 1106e979c658Sreinoud int error, s; 1107e979c658Sreinoud 1108e979c658Sreinoud /* 1109e979c658Sreinoud * for each sector in the buf, allocate a sector on disc and record 1110e979c658Sreinoud * its position in the provided mapping array. 1111e979c658Sreinoud * 1112e979c658Sreinoud * If its userdata or FIDs, record its location in its node. 1113e979c658Sreinoud */ 1114e979c658Sreinoud 1115e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 1116e979c658Sreinoud num_lb = (buf->b_bcount + lb_size -1) / lb_size; 1117e979c658Sreinoud blks = lb_size / DEV_BSIZE; 1118e979c658Sreinoud udf_c_type = buf->b_udf_c_type; 1119e979c658Sreinoud 1120e979c658Sreinoud KASSERT(lb_size == ump->discinfo.sector_size); 1121e979c658Sreinoud 1122e979c658Sreinoud ismetadata = (udf_c_type == UDF_C_NODE); 1123e979c658Sreinoud alloc_type = ismetadata? ump->meta_alloc : ump->data_alloc; 1124e979c658Sreinoud 1125e979c658Sreinoud #ifdef DIAGNOSTIC 1126e979c658Sreinoud if ((alloc_type == UDF_ALLOC_VAT) && (udf_c_type != UDF_C_NODE)) { 1127e979c658Sreinoud panic("udf_late_allocate_buf: bad c_type on VAT!\n"); 1128e979c658Sreinoud } 1129e979c658Sreinoud #endif 1130e979c658Sreinoud 1131e979c658Sreinoud if (udf_c_type == UDF_C_NODE) { 1132e979c658Sreinoud /* if not VAT, its allready allocated */ 1133e979c658Sreinoud if (alloc_type != UDF_ALLOC_VAT) 1134e979c658Sreinoud return; 1135e979c658Sreinoud 1136e979c658Sreinoud /* allocate sequential */ 1137e979c658Sreinoud alloc_type = UDF_ALLOC_SEQUENTIAL; 1138e979c658Sreinoud } 1139e979c658Sreinoud 1140e979c658Sreinoud error = udf_allocate_space(ump, ismetadata, alloc_type, 1141e979c658Sreinoud num_lb, &vpart_num, lmapping, pmapping); 1142e979c658Sreinoud if (error) { 1143e979c658Sreinoud /* ARGH! we've not done our accounting right! */ 1144e979c658Sreinoud panic("UDF disc allocation accounting gone wrong"); 1145e979c658Sreinoud } 1146e979c658Sreinoud 1147e979c658Sreinoud /* commit our sector count */ 1148e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 1149e979c658Sreinoud if (num_lb > ump->uncomitted_lb) { 1150e979c658Sreinoud ump->uncomitted_lb = 0; 1151e979c658Sreinoud } else { 1152e979c658Sreinoud ump->uncomitted_lb -= num_lb; 1153e979c658Sreinoud } 1154e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 1155e979c658Sreinoud 1156e979c658Sreinoud buf->b_blkno = (*pmapping) * blks; 1157e979c658Sreinoud 1158e979c658Sreinoud /* If its userdata or FIDs, record its allocation in its node. */ 1159e979c658Sreinoud if ((udf_c_type == UDF_C_USERDATA) || (udf_c_type == UDF_C_FIDS)) { 1160e979c658Sreinoud udf_record_allocation_in_node(ump, buf, vpart_num, lmapping, 1161e979c658Sreinoud node_ad_cpy); 1162e979c658Sreinoud /* decrement our outstanding bufs counter */ 1163e979c658Sreinoud s = splbio(); 1164e979c658Sreinoud udf_node->outstanding_bufs--; 1165e979c658Sreinoud splx(s); 1166e979c658Sreinoud } 1167e979c658Sreinoud } 1168e979c658Sreinoud 1169e979c658Sreinoud /* --------------------------------------------------------------------- */ 1170e979c658Sreinoud 1171e979c658Sreinoud /* 1172e979c658Sreinoud * Try to merge a1 with the new piece a2. udf_ads_merge returns error when not 1173e979c658Sreinoud * possible (anymore); a2 returns the rest piece. 1174e979c658Sreinoud */ 1175e979c658Sreinoud 1176e979c658Sreinoud static int 1177e979c658Sreinoud udf_ads_merge(uint32_t lb_size, struct long_ad *a1, struct long_ad *a2) 1178e979c658Sreinoud { 1179e979c658Sreinoud uint32_t max_len, merge_len; 1180e979c658Sreinoud uint32_t a1_len, a2_len; 1181e979c658Sreinoud uint32_t a1_flags, a2_flags; 1182e979c658Sreinoud uint32_t a1_lbnum, a2_lbnum; 1183e979c658Sreinoud uint16_t a1_part, a2_part; 1184e979c658Sreinoud 1185e979c658Sreinoud max_len = ((UDF_EXT_MAXLEN / lb_size) * lb_size); 1186e979c658Sreinoud 1187e979c658Sreinoud a1_flags = UDF_EXT_FLAGS(udf_rw32(a1->len)); 1188e979c658Sreinoud a1_len = UDF_EXT_LEN(udf_rw32(a1->len)); 1189e979c658Sreinoud a1_lbnum = udf_rw32(a1->loc.lb_num); 1190e979c658Sreinoud a1_part = udf_rw16(a1->loc.part_num); 1191e979c658Sreinoud 1192e979c658Sreinoud a2_flags = UDF_EXT_FLAGS(udf_rw32(a2->len)); 1193e979c658Sreinoud a2_len = UDF_EXT_LEN(udf_rw32(a2->len)); 1194e979c658Sreinoud a2_lbnum = udf_rw32(a2->loc.lb_num); 1195e979c658Sreinoud a2_part = udf_rw16(a2->loc.part_num); 1196e979c658Sreinoud 1197e979c658Sreinoud /* defines same space */ 1198e979c658Sreinoud if (a1_flags != a2_flags) 1199e979c658Sreinoud return 1; 1200e979c658Sreinoud 1201e979c658Sreinoud if (a1_flags != UDF_EXT_FREE) { 1202e979c658Sreinoud /* the same partition */ 1203e979c658Sreinoud if (a1_part != a2_part) 1204e979c658Sreinoud return 1; 1205e979c658Sreinoud 1206e979c658Sreinoud /* a2 is successor of a1 */ 1207e979c658Sreinoud if (a1_lbnum * lb_size + a1_len != a2_lbnum * lb_size) 1208e979c658Sreinoud return 1; 1209e979c658Sreinoud } 1210e979c658Sreinoud 1211e979c658Sreinoud /* merge as most from a2 if possible */ 1212e979c658Sreinoud merge_len = MIN(a2_len, max_len - a1_len); 1213e979c658Sreinoud a1_len += merge_len; 1214e979c658Sreinoud a2_len -= merge_len; 1215e979c658Sreinoud a2_lbnum += merge_len/lb_size; 1216e979c658Sreinoud 1217e979c658Sreinoud a1->len = udf_rw32(a1_len | a1_flags); 1218e979c658Sreinoud a2->len = udf_rw32(a2_len | a2_flags); 1219e979c658Sreinoud a2->loc.lb_num = udf_rw32(a2_lbnum); 1220e979c658Sreinoud 1221e979c658Sreinoud if (a2_len > 0) 1222e979c658Sreinoud return 1; 1223e979c658Sreinoud 1224e979c658Sreinoud /* there is space over to merge */ 1225e979c658Sreinoud return 0; 1226e979c658Sreinoud } 1227e979c658Sreinoud 1228e979c658Sreinoud /* --------------------------------------------------------------------- */ 1229e979c658Sreinoud 1230e979c658Sreinoud static void 1231e979c658Sreinoud udf_wipe_adslots(struct udf_node *udf_node) 1232e979c658Sreinoud { 1233e979c658Sreinoud struct file_entry *fe; 1234e979c658Sreinoud struct extfile_entry *efe; 1235e979c658Sreinoud struct alloc_ext_entry *ext; 1236e979c658Sreinoud uint64_t inflen, objsize; 1237e979c658Sreinoud uint32_t lb_size, dscr_size, l_ea, l_ad, max_l_ad, crclen; 1238e979c658Sreinoud uint8_t *data_pos; 1239e979c658Sreinoud int extnr; 1240e979c658Sreinoud 1241e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1242e979c658Sreinoud 1243e979c658Sreinoud fe = udf_node->fe; 1244e979c658Sreinoud efe = udf_node->efe; 1245e979c658Sreinoud if (fe) { 1246e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 1247e979c658Sreinoud objsize = inflen; 1248e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1249e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1250e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 1251e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 1252e979c658Sreinoud } else { 1253e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 1254e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 1255e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1256e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1257e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 1258e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 1259e979c658Sreinoud } 1260e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1261e979c658Sreinoud 1262e979c658Sreinoud /* wipe fe/efe */ 1263e979c658Sreinoud memset(data_pos, 0, max_l_ad); 1264e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea; 1265e979c658Sreinoud if (fe) { 1266e979c658Sreinoud fe->l_ad = udf_rw32(0); 1267e979c658Sreinoud fe->logblks_rec = udf_rw64(0); 1268e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 1269e979c658Sreinoud } else { 1270e979c658Sreinoud efe->l_ad = udf_rw32(0); 1271e979c658Sreinoud efe->logblks_rec = udf_rw64(0); 1272e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 1273e979c658Sreinoud } 1274e979c658Sreinoud 1275e979c658Sreinoud /* wipe all allocation extent entries */ 1276e979c658Sreinoud for (extnr = 0; extnr < udf_node->num_extensions; extnr++) { 1277e979c658Sreinoud ext = udf_node->ext[extnr]; 1278e979c658Sreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 12794d5c88faSreinoud data_pos = (uint8_t *) ext->data; 1280e979c658Sreinoud max_l_ad = lb_size - dscr_size; 1281e979c658Sreinoud memset(data_pos, 0, max_l_ad); 1282e979c658Sreinoud ext->l_ad = udf_rw32(0); 1283e979c658Sreinoud 1284e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH; 1285e979c658Sreinoud ext->tag.desc_crc_len = udf_rw32(crclen); 1286e979c658Sreinoud } 12874d5c88faSreinoud udf_node->i_flags |= IN_NODE_REBUILD; 1288e979c658Sreinoud } 1289e979c658Sreinoud 1290e979c658Sreinoud /* --------------------------------------------------------------------- */ 1291e979c658Sreinoud 1292e979c658Sreinoud void 1293e979c658Sreinoud udf_get_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb, 1294e979c658Sreinoud int *eof) { 1295e979c658Sreinoud struct file_entry *fe; 1296e979c658Sreinoud struct extfile_entry *efe; 1297e979c658Sreinoud struct alloc_ext_entry *ext; 1298e979c658Sreinoud struct icb_tag *icbtag; 1299e979c658Sreinoud struct short_ad *short_ad; 13004d5c88faSreinoud struct long_ad *long_ad, l_icb; 1301e979c658Sreinoud uint32_t offset; 13024d5c88faSreinoud uint32_t lb_size, dscr_size, l_ea, l_ad, flags; 1303e979c658Sreinoud uint8_t *data_pos; 1304e979c658Sreinoud int icbflags, addr_type, adlen, extnr; 1305e979c658Sreinoud 1306e979c658Sreinoud /* determine what descriptor we are in */ 1307e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1308e979c658Sreinoud 1309e979c658Sreinoud fe = udf_node->fe; 1310e979c658Sreinoud efe = udf_node->efe; 1311e979c658Sreinoud if (fe) { 1312e979c658Sreinoud icbtag = &fe->icbtag; 1313e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1314e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1315e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 1316e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 1317e979c658Sreinoud } else { 1318e979c658Sreinoud icbtag = &efe->icbtag; 1319e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1320e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1321e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 1322e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 1323e979c658Sreinoud } 1324e979c658Sreinoud 1325e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1326e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1327e979c658Sreinoud 1328e979c658Sreinoud /* just in case we're called on an intern, its EOF */ 1329e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1330e979c658Sreinoud memset(icb, 0, sizeof(struct long_ad)); 1331e979c658Sreinoud *eof = 1; 1332e979c658Sreinoud return; 1333e979c658Sreinoud } 1334e979c658Sreinoud 1335e979c658Sreinoud adlen = 0; 1336e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1337e979c658Sreinoud adlen = sizeof(struct short_ad); 1338e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1339e979c658Sreinoud adlen = sizeof(struct long_ad); 1340e979c658Sreinoud } 1341e979c658Sreinoud 1342e979c658Sreinoud /* if offset too big, we go to the allocation extensions */ 1343e979c658Sreinoud offset = slot * adlen; 134435d8dddaSreinoud extnr = -1; 13454d5c88faSreinoud while (offset >= l_ad) { 13464d5c88faSreinoud /* check if our last entry is a redirect */ 13474d5c88faSreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 13484d5c88faSreinoud short_ad = (struct short_ad *) (data_pos + l_ad-adlen); 13494d5c88faSreinoud l_icb.len = short_ad->len; 13504d5c88faSreinoud l_icb.loc.part_num = udf_node->loc.loc.part_num; 13514d5c88faSreinoud l_icb.loc.lb_num = short_ad->lb_num; 13524d5c88faSreinoud } else { 13534d5c88faSreinoud KASSERT(addr_type == UDF_ICB_LONG_ALLOC); 13544d5c88faSreinoud long_ad = (struct long_ad *) (data_pos + l_ad-adlen); 13554d5c88faSreinoud l_icb = *long_ad; 13564d5c88faSreinoud } 13574d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(l_icb.len)); 13584d5c88faSreinoud if (flags != UDF_EXT_REDIRECT) { 1359e979c658Sreinoud l_ad = 0; /* force EOF */ 1360e979c658Sreinoud break; 1361e979c658Sreinoud } 13624d5c88faSreinoud 13634d5c88faSreinoud /* advance to next extent */ 13644d5c88faSreinoud extnr++; 13654d5c88faSreinoud if (extnr >= udf_node->num_extensions) { 13664d5c88faSreinoud l_ad = 0; /* force EOF */ 13674d5c88faSreinoud break; 13684d5c88faSreinoud } 13694d5c88faSreinoud offset = offset - l_ad; 13704d5c88faSreinoud ext = udf_node->ext[extnr]; 13714d5c88faSreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 13724d5c88faSreinoud l_ad = udf_rw32(ext->l_ad); 13734d5c88faSreinoud data_pos = (uint8_t *) ext + dscr_size; 1374e979c658Sreinoud } 1375e979c658Sreinoud 13764d5c88faSreinoud /* XXX l_ad == 0 should be enough to check */ 1377e979c658Sreinoud *eof = (offset >= l_ad) || (l_ad == 0); 1378e979c658Sreinoud if (*eof) { 13794d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("returning EOF, extnr %d, offset %d, " 13804d5c88faSreinoud "l_ad %d\n", extnr, offset, l_ad)); 1381e979c658Sreinoud memset(icb, 0, sizeof(struct long_ad)); 1382e979c658Sreinoud return; 1383e979c658Sreinoud } 1384e979c658Sreinoud 1385e979c658Sreinoud /* get the element */ 1386e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1387e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 1388e979c658Sreinoud icb->len = short_ad->len; 1389ca7a0d4eSreinoud icb->loc.part_num = udf_node->loc.loc.part_num; 1390e979c658Sreinoud icb->loc.lb_num = short_ad->lb_num; 1391e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1392e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 1393e979c658Sreinoud *icb = *long_ad; 1394e979c658Sreinoud } 13954d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("returning element : v %d, lb %d, len %d, " 13964d5c88faSreinoud "flags %d\n", icb->loc.part_num, icb->loc.lb_num, 13974d5c88faSreinoud UDF_EXT_LEN(icb->len), UDF_EXT_FLAGS(icb->len))); 1398e979c658Sreinoud } 1399e979c658Sreinoud 1400e979c658Sreinoud /* --------------------------------------------------------------------- */ 1401e979c658Sreinoud 1402e979c658Sreinoud int 14034d5c88faSreinoud udf_append_adslot(struct udf_node *udf_node, int *slot, struct long_ad *icb) { 14044d5c88faSreinoud struct udf_mount *ump = udf_node->ump; 1405*a48555c3Sreinoud union dscrptr *dscr, *extdscr; 1406e979c658Sreinoud struct file_entry *fe; 1407e979c658Sreinoud struct extfile_entry *efe; 1408e979c658Sreinoud struct alloc_ext_entry *ext; 1409e979c658Sreinoud struct icb_tag *icbtag; 1410e979c658Sreinoud struct short_ad *short_ad; 14114d5c88faSreinoud struct long_ad *long_ad, o_icb, l_icb; 1412e979c658Sreinoud uint64_t logblks_rec, *logblks_rec_p; 14134d5c88faSreinoud uint64_t lmapping, pmapping; 14144d5c88faSreinoud uint32_t offset, rest, len, lb_num; 1415e979c658Sreinoud uint32_t lb_size, dscr_size, l_ea, l_ad, *l_ad_p, max_l_ad, crclen; 14164d5c88faSreinoud uint32_t flags; 14174d5c88faSreinoud uint16_t vpart_num; 1418e979c658Sreinoud uint8_t *data_pos; 1419e979c658Sreinoud int icbflags, addr_type, adlen, extnr; 14204d5c88faSreinoud int error; 1421e979c658Sreinoud 1422e979c658Sreinoud /* determine what descriptor we are in */ 14234d5c88faSreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 1424e979c658Sreinoud 1425e979c658Sreinoud fe = udf_node->fe; 1426e979c658Sreinoud efe = udf_node->efe; 1427e979c658Sreinoud if (fe) { 1428e979c658Sreinoud icbtag = &fe->icbtag; 1429e979c658Sreinoud dscr = (union dscrptr *) fe; 1430e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1431e979c658Sreinoud 1432e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1433e979c658Sreinoud l_ad_p = &fe->l_ad; 1434e979c658Sreinoud logblks_rec_p = &fe->logblks_rec; 1435e979c658Sreinoud } else { 1436e979c658Sreinoud icbtag = &efe->icbtag; 1437e979c658Sreinoud dscr = (union dscrptr *) efe; 1438e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1439e979c658Sreinoud 1440e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1441e979c658Sreinoud l_ad_p = &efe->l_ad; 1442e979c658Sreinoud logblks_rec_p = &efe->logblks_rec; 1443e979c658Sreinoud } 1444e979c658Sreinoud data_pos = (uint8_t *) dscr + dscr_size + l_ea; 1445e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1446e979c658Sreinoud 1447e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1448e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1449e979c658Sreinoud 1450e979c658Sreinoud /* just in case we're called on an intern, its EOF */ 1451e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1452e979c658Sreinoud panic("udf_append_adslot on UDF_ICB_INTERN_ALLOC\n"); 1453e979c658Sreinoud } 1454e979c658Sreinoud 1455e979c658Sreinoud adlen = 0; 1456e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1457e979c658Sreinoud adlen = sizeof(struct short_ad); 1458e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1459e979c658Sreinoud adlen = sizeof(struct long_ad); 1460e979c658Sreinoud } 1461e979c658Sreinoud 14625eeb4f69Sreinoud /* clean up given long_ad */ 14635eeb4f69Sreinoud #ifdef DIAGNOSTIC 14644d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(icb->len)); 14654d5c88faSreinoud if (flags == UDF_EXT_FREE) { 14665eeb4f69Sreinoud if ((udf_rw16(icb->loc.part_num) != 0) || 14675eeb4f69Sreinoud (udf_rw32(icb->loc.lb_num) != 0)) 14685eeb4f69Sreinoud printf("UDF: warning, cleaning long_ad marked free\n"); 14695eeb4f69Sreinoud icb->loc.part_num = udf_rw16(0); 14705eeb4f69Sreinoud icb->loc.lb_num = udf_rw32(0); 14715eeb4f69Sreinoud } 14725eeb4f69Sreinoud #endif 14735eeb4f69Sreinoud 1474e979c658Sreinoud /* if offset too big, we go to the allocation extensions */ 14754d5c88faSreinoud l_ad = udf_rw32(*l_ad_p); 14764d5c88faSreinoud offset = (*slot) * adlen; 14774d5c88faSreinoud extnr = -1; 14784d5c88faSreinoud while (offset >= l_ad) { 14794d5c88faSreinoud /* check if our last entry is a redirect */ 14804d5c88faSreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 14814d5c88faSreinoud short_ad = (struct short_ad *) (data_pos + l_ad-adlen); 14824d5c88faSreinoud l_icb.len = short_ad->len; 14834d5c88faSreinoud l_icb.loc.part_num = udf_node->loc.loc.part_num; 14844d5c88faSreinoud l_icb.loc.lb_num = short_ad->lb_num; 14854d5c88faSreinoud } else { 14864d5c88faSreinoud KASSERT(addr_type == UDF_ICB_LONG_ALLOC); 14874d5c88faSreinoud long_ad = (struct long_ad *) (data_pos + l_ad-adlen); 14884d5c88faSreinoud l_icb = *long_ad; 14894d5c88faSreinoud } 14904d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(l_icb.len)); 14914d5c88faSreinoud if (flags != UDF_EXT_REDIRECT) { 14924d5c88faSreinoud /* only one past the last one is adressable */ 14934d5c88faSreinoud break; 14944d5c88faSreinoud } 14954d5c88faSreinoud 14964d5c88faSreinoud /* advance to next extent */ 14974d5c88faSreinoud extnr++; 14984d5c88faSreinoud KASSERT(extnr < udf_node->num_extensions); 14994d5c88faSreinoud offset = offset - l_ad; 15004d5c88faSreinoud 1501e979c658Sreinoud ext = udf_node->ext[extnr]; 1502e979c658Sreinoud dscr = (union dscrptr *) ext; 1503e979c658Sreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 1504e979c658Sreinoud max_l_ad = lb_size - dscr_size; 15054d5c88faSreinoud l_ad_p = &ext->l_ad; 15064d5c88faSreinoud l_ad = udf_rw32(*l_ad_p); 15074d5c88faSreinoud data_pos = (uint8_t *) ext + dscr_size; 1508e979c658Sreinoud } 15094d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("append, ext %d, offset %d, l_ad %d\n", 15104d5c88faSreinoud extnr, offset, udf_rw32(*l_ad_p))); 15114d5c88faSreinoud KASSERT(l_ad == udf_rw32(*l_ad_p)); 15124d5c88faSreinoud 1513e979c658Sreinoud /* offset is offset within the current (E)FE/AED */ 1514e979c658Sreinoud l_ad = udf_rw32(*l_ad_p); 1515e979c658Sreinoud crclen = udf_rw32(dscr->tag.desc_crc_len); 1516e979c658Sreinoud logblks_rec = udf_rw64(*logblks_rec_p); 1517e979c658Sreinoud 1518e979c658Sreinoud /* overwriting old piece? */ 1519e979c658Sreinoud if (offset < l_ad) { 1520e979c658Sreinoud /* overwrite entry; compensate for the old element */ 1521e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1522e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 1523e979c658Sreinoud o_icb.len = short_ad->len; 1524e979c658Sreinoud o_icb.loc.part_num = udf_rw16(0); /* ignore */ 1525e979c658Sreinoud o_icb.loc.lb_num = short_ad->lb_num; 1526e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1527e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 1528e979c658Sreinoud o_icb = *long_ad; 1529e979c658Sreinoud } else { 1530e979c658Sreinoud panic("Invalid address type in udf_append_adslot\n"); 1531e979c658Sreinoud } 1532e979c658Sreinoud 1533e979c658Sreinoud len = udf_rw32(o_icb.len); 1534e979c658Sreinoud if (UDF_EXT_FLAGS(len) == UDF_EXT_ALLOCATED) { 1535e979c658Sreinoud /* adjust counts */ 1536e979c658Sreinoud len = UDF_EXT_LEN(len); 1537e979c658Sreinoud logblks_rec -= (len + lb_size -1) / lb_size; 1538e979c658Sreinoud } 1539e979c658Sreinoud } 1540e979c658Sreinoud 15414d5c88faSreinoud /* check if we're not appending a redirection */ 15424d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(icb->len)); 15434d5c88faSreinoud KASSERT(flags != UDF_EXT_REDIRECT); 15444d5c88faSreinoud 15454d5c88faSreinoud /* round down available space */ 15464d5c88faSreinoud rest = adlen * ((max_l_ad - offset) / adlen); 1547e979c658Sreinoud if (rest <= adlen) { 15484d5c88faSreinoud /* have to append aed, see if we already have a spare one */ 15494d5c88faSreinoud extnr++; 15504d5c88faSreinoud ext = udf_node->ext[extnr]; 15514d5c88faSreinoud l_icb = udf_node->ext_loc[extnr]; 15524d5c88faSreinoud if (ext == NULL) { 15534d5c88faSreinoud DPRINTF(ALLOC,("adding allocation extent %d\n", extnr)); 15544d5c88faSreinoud error = udf_pre_allocate_space(ump, UDF_C_NODE, 1, 15554d5c88faSreinoud &vpart_num, &lmapping, &pmapping); 15564d5c88faSreinoud lb_num = lmapping; 15574d5c88faSreinoud if (error) 15584d5c88faSreinoud return error; 15594d5c88faSreinoud 15604d5c88faSreinoud /* initialise pointer to location */ 15614d5c88faSreinoud memset(&l_icb, 0, sizeof(struct long_ad)); 15624d5c88faSreinoud l_icb.len = udf_rw32(lb_size | UDF_EXT_REDIRECT); 15634d5c88faSreinoud l_icb.loc.lb_num = udf_rw32(lb_num); 15644d5c88faSreinoud l_icb.loc.part_num = udf_rw16(vpart_num); 15654d5c88faSreinoud 15664d5c88faSreinoud /* create new aed descriptor */ 1567*a48555c3Sreinoud udf_create_logvol_dscr(ump, udf_node, &l_icb, &extdscr); 1568*a48555c3Sreinoud ext = &extdscr->aee; 15694d5c88faSreinoud 15704d5c88faSreinoud udf_inittag(ump, &ext->tag, TAGID_ALLOCEXTENT, lb_num); 15714d5c88faSreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 15724d5c88faSreinoud max_l_ad = lb_size - dscr_size; 15734d5c88faSreinoud memset(ext->data, 0, max_l_ad); 15744d5c88faSreinoud ext->l_ad = udf_rw32(0); 15754d5c88faSreinoud ext->tag.desc_crc_len = 15764d5c88faSreinoud udf_rw32(dscr_size - UDF_DESC_TAG_LENGTH); 15774d5c88faSreinoud 15784d5c88faSreinoud /* declare aed */ 15794d5c88faSreinoud udf_node->num_extensions++; 15804d5c88faSreinoud udf_node->ext_loc[extnr] = l_icb; 15814d5c88faSreinoud udf_node->ext[extnr] = ext; 15824d5c88faSreinoud } 15834d5c88faSreinoud /* add redirect and adjust l_ad and crclen for old descr */ 15844d5c88faSreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 15854d5c88faSreinoud short_ad = (struct short_ad *) (data_pos + offset); 15864d5c88faSreinoud short_ad->len = l_icb.len; 15874d5c88faSreinoud short_ad->lb_num = l_icb.loc.lb_num; 15884d5c88faSreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 15894d5c88faSreinoud long_ad = (struct long_ad *) (data_pos + offset); 15904d5c88faSreinoud *long_ad = l_icb; 15914d5c88faSreinoud } 15924d5c88faSreinoud l_ad += adlen; 15934d5c88faSreinoud crclen += adlen; 15944d5c88faSreinoud dscr->tag.desc_crc_len = udf_rw32(crclen); 15954d5c88faSreinoud *l_ad_p = udf_rw32(l_ad); 15964d5c88faSreinoud 15974d5c88faSreinoud /* advance to the new extension */ 15984d5c88faSreinoud KASSERT(ext != NULL); 15994d5c88faSreinoud dscr = (union dscrptr *) ext; 16004d5c88faSreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 16014d5c88faSreinoud max_l_ad = lb_size - dscr_size; 16024d5c88faSreinoud data_pos = (uint8_t *) dscr + dscr_size; 16034d5c88faSreinoud 16044d5c88faSreinoud l_ad_p = &ext->l_ad; 16054d5c88faSreinoud l_ad = udf_rw32(*l_ad_p); 16064d5c88faSreinoud crclen = udf_rw32(dscr->tag.desc_crc_len); 16074d5c88faSreinoud offset = 0; 16084d5c88faSreinoud 16094d5c88faSreinoud /* adjust callees slot count for link insert */ 16104d5c88faSreinoud *slot += 1; 1611e979c658Sreinoud } 1612e979c658Sreinoud 1613e979c658Sreinoud /* write out the element */ 16144d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("adding element : %p : v %d, lb %d, " 16154d5c88faSreinoud "len %d, flags %d\n", data_pos + offset, 16164d5c88faSreinoud icb->loc.part_num, icb->loc.lb_num, 16174d5c88faSreinoud UDF_EXT_LEN(icb->len), UDF_EXT_FLAGS(icb->len))); 1618e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1619e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 1620e979c658Sreinoud short_ad->len = icb->len; 1621e979c658Sreinoud short_ad->lb_num = icb->loc.lb_num; 1622e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1623e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 1624e979c658Sreinoud *long_ad = *icb; 1625e979c658Sreinoud } 1626e979c658Sreinoud 1627e979c658Sreinoud /* adjust logblks recorded count */ 16284d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(icb->len)); 16294d5c88faSreinoud if (flags == UDF_EXT_ALLOCATED) 1630e979c658Sreinoud logblks_rec += (UDF_EXT_LEN(icb->len) + lb_size -1) / lb_size; 1631e979c658Sreinoud *logblks_rec_p = udf_rw64(logblks_rec); 1632e979c658Sreinoud 1633e979c658Sreinoud /* adjust l_ad and crclen when needed */ 1634e979c658Sreinoud if (offset >= l_ad) { 1635e979c658Sreinoud l_ad += adlen; 1636e979c658Sreinoud crclen += adlen; 1637e979c658Sreinoud dscr->tag.desc_crc_len = udf_rw32(crclen); 1638e979c658Sreinoud *l_ad_p = udf_rw32(l_ad); 1639e979c658Sreinoud } 1640e979c658Sreinoud 1641e979c658Sreinoud return 0; 1642e979c658Sreinoud } 1643e979c658Sreinoud 1644e979c658Sreinoud /* --------------------------------------------------------------------- */ 1645e979c658Sreinoud 16464d5c88faSreinoud static void 16474d5c88faSreinoud udf_count_alloc_exts(struct udf_node *udf_node) 16484d5c88faSreinoud { 16494d5c88faSreinoud struct long_ad s_ad; 16504d5c88faSreinoud uint32_t lb_num, len, flags; 16514d5c88faSreinoud uint16_t vpart_num; 16524d5c88faSreinoud int slot, eof; 16534d5c88faSreinoud int num_extents, extnr; 16544d5c88faSreinoud int lb_size; 16554d5c88faSreinoud 16564d5c88faSreinoud if (udf_node->num_extensions == 0) 16574d5c88faSreinoud return; 16584d5c88faSreinoud 16594d5c88faSreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 16604d5c88faSreinoud /* count number of allocation extents in use */ 16614d5c88faSreinoud num_extents = 0; 16624d5c88faSreinoud slot = 0; 16634d5c88faSreinoud for (;;) { 16644d5c88faSreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 16654d5c88faSreinoud if (eof) 16664d5c88faSreinoud break; 16674d5c88faSreinoud len = udf_rw32(s_ad.len); 16684d5c88faSreinoud flags = UDF_EXT_FLAGS(len); 16694d5c88faSreinoud 16704d5c88faSreinoud if (flags == UDF_EXT_REDIRECT) 16714d5c88faSreinoud num_extents++; 16724d5c88faSreinoud 16734d5c88faSreinoud slot++; 16744d5c88faSreinoud } 16754d5c88faSreinoud 16764d5c88faSreinoud DPRINTF(ALLOC, ("udf_count_alloc_ext counted %d live extents\n", 16774d5c88faSreinoud num_extents)); 16784d5c88faSreinoud 16794d5c88faSreinoud /* XXX choice: we could delay freeing them on node writeout */ 16804d5c88faSreinoud /* free excess entries */ 16814d5c88faSreinoud extnr = num_extents; 16824d5c88faSreinoud for (;extnr < udf_node->num_extensions; extnr++) { 16834d5c88faSreinoud DPRINTF(ALLOC, ("freeing alloc ext %d\n", extnr)); 16844d5c88faSreinoud /* free dscriptor */ 16854d5c88faSreinoud s_ad = udf_node->ext_loc[extnr]; 16864d5c88faSreinoud udf_free_logvol_dscr(udf_node->ump, &s_ad, 16874d5c88faSreinoud udf_node->ext[extnr]); 16884d5c88faSreinoud udf_node->ext[extnr] = NULL; 16894d5c88faSreinoud 16904d5c88faSreinoud /* free disc space */ 16914d5c88faSreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 16924d5c88faSreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 16934d5c88faSreinoud udf_free_allocated_space(udf_node->ump, lb_num, vpart_num, 1); 16944d5c88faSreinoud 16954d5c88faSreinoud memset(&udf_node->ext_loc[extnr], 0, sizeof(struct long_ad)); 16964d5c88faSreinoud } 16974d5c88faSreinoud 16984d5c88faSreinoud /* set our new number of allocation extents */ 16994d5c88faSreinoud udf_node->num_extensions = num_extents; 17004d5c88faSreinoud } 17014d5c88faSreinoud 17024d5c88faSreinoud 17034d5c88faSreinoud /* --------------------------------------------------------------------- */ 17044d5c88faSreinoud 1705e979c658Sreinoud /* 1706e979c658Sreinoud * Adjust the node's allocation descriptors to reflect the new mapping; do 1707e979c658Sreinoud * take note that we might glue to existing allocation descriptors. 1708e979c658Sreinoud * 1709e979c658Sreinoud * XXX Note there can only be one allocation being recorded/mount; maybe 1710e979c658Sreinoud * explicit allocation in shedule thread? 1711e979c658Sreinoud */ 1712e979c658Sreinoud 1713e979c658Sreinoud static void 1714e979c658Sreinoud udf_record_allocation_in_node(struct udf_mount *ump, struct buf *buf, 1715e979c658Sreinoud uint16_t vpart_num, uint64_t *mapping, struct long_ad *node_ad_cpy) 1716e979c658Sreinoud { 1717e979c658Sreinoud struct vnode *vp = buf->b_vp; 1718e979c658Sreinoud struct udf_node *udf_node = VTOI(vp); 1719e979c658Sreinoud struct file_entry *fe; 1720e979c658Sreinoud struct extfile_entry *efe; 1721e979c658Sreinoud struct icb_tag *icbtag; 1722e979c658Sreinoud struct long_ad s_ad, c_ad; 1723e979c658Sreinoud uint64_t inflen, from, till; 1724e979c658Sreinoud uint64_t foffset, end_foffset, restart_foffset; 1725e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 1726e979c658Sreinoud uint32_t num_lb, len, flags, lb_num; 1727e979c658Sreinoud uint32_t run_start; 17285eeb4f69Sreinoud uint32_t slot_offset, replace_len, replace; 1729e979c658Sreinoud int addr_type, icbflags; 1730e979c658Sreinoud int udf_c_type = buf->b_udf_c_type; 1731e979c658Sreinoud int lb_size, run_length, eof; 1732e979c658Sreinoud int slot, cpy_slot, cpy_slots, restart_slot; 1733e979c658Sreinoud int error; 1734e979c658Sreinoud 1735e979c658Sreinoud DPRINTF(ALLOC, ("udf_record_allocation_in_node\n")); 1736e979c658Sreinoud 1737e979c658Sreinoud /* sanity check ... should be panic ? */ 1738e979c658Sreinoud if ((udf_c_type != UDF_C_USERDATA) && (udf_c_type != UDF_C_FIDS)) 1739e979c658Sreinoud return; 1740e979c658Sreinoud 1741e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1742e979c658Sreinoud 1743e979c658Sreinoud /* do the job */ 1744e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); /* XXX can deadlock ? */ 17455eeb4f69Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 1746e979c658Sreinoud 1747e979c658Sreinoud fe = udf_node->fe; 1748e979c658Sreinoud efe = udf_node->efe; 1749e979c658Sreinoud if (fe) { 1750e979c658Sreinoud icbtag = &fe->icbtag; 1751e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 1752e979c658Sreinoud } else { 1753e979c658Sreinoud icbtag = &efe->icbtag; 1754e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 1755e979c658Sreinoud } 1756e979c658Sreinoud 1757e979c658Sreinoud /* do check if `till' is not past file information length */ 1758e979c658Sreinoud from = buf->b_lblkno * lb_size; 1759e979c658Sreinoud till = MIN(inflen, from + buf->b_resid); 1760e979c658Sreinoud 1761e979c658Sreinoud num_lb = (till - from + lb_size -1) / lb_size; 1762e979c658Sreinoud 17635eeb4f69Sreinoud DPRINTF(ALLOC, ("record allocation from %"PRIu64" + %d\n", from, buf->b_bcount)); 1764e979c658Sreinoud 1765e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1766e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1767e979c658Sreinoud 1768e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1769e979c658Sreinoud /* nothing to do */ 1770e979c658Sreinoud /* XXX clean up rest of node? just in case? */ 1771e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1772e979c658Sreinoud return; 1773e979c658Sreinoud } 1774e979c658Sreinoud 1775e979c658Sreinoud slot = 0; 1776e979c658Sreinoud cpy_slot = 0; 1777e979c658Sreinoud foffset = 0; 1778e979c658Sreinoud 1779e979c658Sreinoud /* 1) copy till first overlap piece to the rewrite buffer */ 1780e979c658Sreinoud for (;;) { 1781e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1782e979c658Sreinoud if (eof) { 1783e979c658Sreinoud DPRINTF(WRITE, 1784e979c658Sreinoud ("Record allocation in node " 1785e979c658Sreinoud "failed: encountered EOF\n")); 1786e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1787e979c658Sreinoud buf->b_error = EINVAL; 1788e979c658Sreinoud return; 1789e979c658Sreinoud } 1790e979c658Sreinoud len = udf_rw32(s_ad.len); 1791e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1792e979c658Sreinoud len = UDF_EXT_LEN(len); 1793e979c658Sreinoud 1794e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 1795e979c658Sreinoud slot++; 1796e979c658Sreinoud continue; 1797e979c658Sreinoud } 1798e979c658Sreinoud 1799e979c658Sreinoud end_foffset = foffset + len; 1800e979c658Sreinoud if (end_foffset > from) 1801e979c658Sreinoud break; /* found */ 1802e979c658Sreinoud 1803e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1804e979c658Sreinoud 1805e979c658Sreinoud DPRINTF(ALLOC, ("\t1: vp %d, lb %d, len %d, flags %d " 1806e979c658Sreinoud "-> stack\n", 1807e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1808e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1809e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1810e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1811e979c658Sreinoud 1812e979c658Sreinoud foffset = end_foffset; 1813e979c658Sreinoud slot++; 1814e979c658Sreinoud } 1815e979c658Sreinoud restart_slot = slot; 1816e979c658Sreinoud restart_foffset = foffset; 1817e979c658Sreinoud 1818e979c658Sreinoud /* 2) trunc overlapping slot at overlap and copy it */ 1819e979c658Sreinoud slot_offset = from - foffset; 1820e979c658Sreinoud if (slot_offset > 0) { 1821e979c658Sreinoud DPRINTF(ALLOC, ("\tslot_offset = %d, flags = %d (%d)\n", 1822e979c658Sreinoud slot_offset, flags >> 30, flags)); 1823e979c658Sreinoud 1824e979c658Sreinoud s_ad.len = udf_rw32(slot_offset | flags); 1825e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1826e979c658Sreinoud 1827e979c658Sreinoud DPRINTF(ALLOC, ("\t2: vp %d, lb %d, len %d, flags %d " 1828e979c658Sreinoud "-> stack\n", 1829e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1830e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1831e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1832e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1833e979c658Sreinoud } 1834e979c658Sreinoud foffset += slot_offset; 1835e979c658Sreinoud 1836e979c658Sreinoud /* 3) insert new mappings */ 1837e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 1838e979c658Sreinoud lb_num = 0; 1839e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 1840e979c658Sreinoud run_start = mapping[lb_num]; 1841e979c658Sreinoud run_length = 1; 1842e979c658Sreinoud while (lb_num < num_lb-1) { 1843e979c658Sreinoud if (mapping[lb_num+1] != mapping[lb_num]+1) 1844e979c658Sreinoud if (mapping[lb_num+1] != mapping[lb_num]) 1845e979c658Sreinoud break; 1846e979c658Sreinoud run_length++; 1847e979c658Sreinoud lb_num++; 1848e979c658Sreinoud } 1849e979c658Sreinoud /* insert slot for this mapping */ 1850e979c658Sreinoud len = run_length * lb_size; 1851e979c658Sreinoud 1852e979c658Sreinoud /* bounds checking */ 1853e979c658Sreinoud if (foffset + len > till) 1854e979c658Sreinoud len = till - foffset; 1855e979c658Sreinoud KASSERT(foffset + len <= inflen); 1856e979c658Sreinoud 1857e979c658Sreinoud s_ad.len = udf_rw32(len | UDF_EXT_ALLOCATED); 1858e979c658Sreinoud s_ad.loc.part_num = udf_rw16(vpart_num); 1859e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(run_start); 1860e979c658Sreinoud 1861e979c658Sreinoud foffset += len; 1862e979c658Sreinoud 1863e979c658Sreinoud /* paranoia */ 1864e979c658Sreinoud if (len == 0) { 1865e979c658Sreinoud DPRINTF(WRITE, 1866e979c658Sreinoud ("Record allocation in node " 1867e979c658Sreinoud "failed: insert failed\n")); 1868e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1869e979c658Sreinoud buf->b_error = EINVAL; 1870e979c658Sreinoud return; 1871e979c658Sreinoud } 1872e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1873e979c658Sreinoud 1874e979c658Sreinoud DPRINTF(ALLOC, ("\t3: insert new mapping vp %d lb %d, len %d, " 1875e979c658Sreinoud "flags %d -> stack\n", 1876e979c658Sreinoud udf_rw16(s_ad.loc.part_num), udf_rw32(s_ad.loc.lb_num), 1877e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1878e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1879e979c658Sreinoud } 1880e979c658Sreinoud 1881e979c658Sreinoud /* 4) pop replaced length */ 1882e979c658Sreinoud slot = restart_slot; 1883e979c658Sreinoud foffset = restart_foffset; 1884e979c658Sreinoud 18855eeb4f69Sreinoud replace_len = till - foffset; /* total amount of bytes to pop */ 1886af39897aSreinoud slot_offset = from - foffset; /* offset in first encounted slot */ 18875eeb4f69Sreinoud KASSERT((slot_offset % lb_size) == 0); 18885eeb4f69Sreinoud 1889e979c658Sreinoud for (;;) { 1890e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1891e979c658Sreinoud if (eof) 1892e979c658Sreinoud break; 1893e979c658Sreinoud 1894e979c658Sreinoud len = udf_rw32(s_ad.len); 1895e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1896e979c658Sreinoud len = UDF_EXT_LEN(len); 1897e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 1898e979c658Sreinoud 1899e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 1900e979c658Sreinoud slot++; 1901e979c658Sreinoud continue; 1902e979c658Sreinoud } 1903e979c658Sreinoud 1904af39897aSreinoud DPRINTF(ALLOC, ("\t4i: got slot %d, slot_offset %d, " 19055eeb4f69Sreinoud "replace_len %d, " 1906af39897aSreinoud "vp %d, lb %d, len %d, flags %d\n", 19075eeb4f69Sreinoud slot, slot_offset, replace_len, 1908af39897aSreinoud udf_rw16(s_ad.loc.part_num), 1909e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1910e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1911e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1912e979c658Sreinoud 19135eeb4f69Sreinoud /* adjust for slot offset */ 19145eeb4f69Sreinoud if (slot_offset) { 19155eeb4f69Sreinoud DPRINTF(ALLOC, ("\t4s: skipping %d\n", slot_offset)); 19165eeb4f69Sreinoud lb_num += slot_offset / lb_size; 1917e979c658Sreinoud len -= slot_offset; 1918e979c658Sreinoud foffset += slot_offset; 19195eeb4f69Sreinoud replace_len -= slot_offset; 1920af39897aSreinoud 19215eeb4f69Sreinoud /* mark adjusted */ 19225eeb4f69Sreinoud slot_offset = 0; 19235eeb4f69Sreinoud } 19245eeb4f69Sreinoud 19255eeb4f69Sreinoud /* advance for (the rest of) this slot */ 19265eeb4f69Sreinoud replace = MIN(len, replace_len); 19275eeb4f69Sreinoud DPRINTF(ALLOC, ("\t4d: replacing %d\n", replace)); 19285eeb4f69Sreinoud 19295eeb4f69Sreinoud /* advance for this slot */ 19305eeb4f69Sreinoud if (replace) { 1931d3bf9c7bSreinoud /* note: dont round DOWN on num_lb since we then 1932d3bf9c7bSreinoud * forget the last partial one */ 19335eeb4f69Sreinoud num_lb = (replace + lb_size - 1) / lb_size; 19345eeb4f69Sreinoud if (flags != UDF_EXT_FREE) { 1935e979c658Sreinoud udf_free_allocated_space(ump, lb_num, 1936e979c658Sreinoud udf_rw16(s_ad.loc.part_num), num_lb); 1937e979c658Sreinoud } 19385eeb4f69Sreinoud lb_num += num_lb; 19395eeb4f69Sreinoud len -= replace; 19405eeb4f69Sreinoud foffset += replace; 19415eeb4f69Sreinoud replace_len -= replace; 19425eeb4f69Sreinoud } 1943af39897aSreinoud 19445eeb4f69Sreinoud /* do we have a slot tail ? */ 1945e979c658Sreinoud if (len) { 19465eeb4f69Sreinoud KASSERT(foffset % lb_size == 0); 1947e979c658Sreinoud 1948e979c658Sreinoud /* we arrived at our point, push remainder */ 1949e979c658Sreinoud s_ad.len = udf_rw32(len | flags); 1950e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(lb_num); 19515eeb4f69Sreinoud if (flags == UDF_EXT_FREE) 19525eeb4f69Sreinoud s_ad.loc.lb_num = udf_rw32(0); 1953e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1954e979c658Sreinoud foffset += len; 1955e979c658Sreinoud slot++; 1956e979c658Sreinoud 1957e979c658Sreinoud DPRINTF(ALLOC, ("\t4: vp %d, lb %d, len %d, flags %d " 1958e979c658Sreinoud "-> stack\n", 1959e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1960e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1961e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1962e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1963e979c658Sreinoud break; 1964e979c658Sreinoud } 19655eeb4f69Sreinoud 1966e979c658Sreinoud slot++; 1967e979c658Sreinoud } 1968e979c658Sreinoud 1969e979c658Sreinoud /* 5) copy remainder */ 1970e979c658Sreinoud for (;;) { 1971e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1972e979c658Sreinoud if (eof) 1973e979c658Sreinoud break; 1974e979c658Sreinoud 1975e979c658Sreinoud len = udf_rw32(s_ad.len); 1976e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1977e979c658Sreinoud len = UDF_EXT_LEN(len); 1978e979c658Sreinoud 1979e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 1980e979c658Sreinoud slot++; 1981e979c658Sreinoud continue; 1982e979c658Sreinoud } 1983e979c658Sreinoud 1984e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1985e979c658Sreinoud 1986e979c658Sreinoud DPRINTF(ALLOC, ("\t5: insert new mapping " 1987e979c658Sreinoud "vp %d lb %d, len %d, flags %d " 1988e979c658Sreinoud "-> stack\n", 1989e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1990e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1991e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1992e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1993e979c658Sreinoud 1994e979c658Sreinoud slot++; 1995e979c658Sreinoud } 1996e979c658Sreinoud 1997e979c658Sreinoud /* 6) reset node descriptors */ 1998e979c658Sreinoud udf_wipe_adslots(udf_node); 1999e979c658Sreinoud 2000e979c658Sreinoud /* 7) copy back extents; merge when possible. Recounting on the fly */ 2001e979c658Sreinoud cpy_slots = cpy_slot; 2002e979c658Sreinoud 2003e979c658Sreinoud c_ad = node_ad_cpy[0]; 2004e979c658Sreinoud slot = 0; 2005e979c658Sreinoud DPRINTF(ALLOC, ("\t7s: stack -> got mapping vp %d " 2006e979c658Sreinoud "lb %d, len %d, flags %d\n", 2007e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2008e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2009e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2010e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2011e979c658Sreinoud 2012e979c658Sreinoud for (cpy_slot = 1; cpy_slot < cpy_slots; cpy_slot++) { 2013e979c658Sreinoud s_ad = node_ad_cpy[cpy_slot]; 2014e979c658Sreinoud 2015e979c658Sreinoud DPRINTF(ALLOC, ("\t7i: stack -> got mapping vp %d " 2016e979c658Sreinoud "lb %d, len %d, flags %d\n", 2017e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2018e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2019e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2020e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2021e979c658Sreinoud 2022e979c658Sreinoud /* see if we can merge */ 2023e979c658Sreinoud if (udf_ads_merge(lb_size, &c_ad, &s_ad)) { 2024e979c658Sreinoud /* not mergable (anymore) */ 2025e979c658Sreinoud DPRINTF(ALLOC, ("\t7: appending vp %d lb %d, " 2026e979c658Sreinoud "len %d, flags %d\n", 2027e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2028e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2029e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2030e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2031e979c658Sreinoud 20324d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2033e979c658Sreinoud if (error) { 2034e979c658Sreinoud buf->b_error = error; 2035e979c658Sreinoud goto out; 2036e979c658Sreinoud } 2037e979c658Sreinoud c_ad = s_ad; 2038e979c658Sreinoud slot++; 2039e979c658Sreinoud } 2040e979c658Sreinoud } 2041e979c658Sreinoud 2042e979c658Sreinoud /* 8) push rest slot (if any) */ 2043e979c658Sreinoud if (UDF_EXT_LEN(c_ad.len) > 0) { 2044e979c658Sreinoud DPRINTF(ALLOC, ("\t8: last append vp %d lb %d, " 2045e979c658Sreinoud "len %d, flags %d\n", 2046e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2047e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2048e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2049e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2050e979c658Sreinoud 20514d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2052e979c658Sreinoud if (error) { 2053e979c658Sreinoud buf->b_error = error; 2054e979c658Sreinoud goto out; 2055e979c658Sreinoud } 2056e979c658Sreinoud } 2057e979c658Sreinoud 2058e979c658Sreinoud out: 20594d5c88faSreinoud udf_count_alloc_exts(udf_node); 20604d5c88faSreinoud 2061e979c658Sreinoud /* the node's descriptors should now be sane */ 2062e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 20635eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2064e979c658Sreinoud 2065e979c658Sreinoud KASSERT(orig_inflen == new_inflen); 2066e979c658Sreinoud KASSERT(new_lbrec >= orig_lbrec); 2067e979c658Sreinoud 2068e979c658Sreinoud return; 2069e979c658Sreinoud } 2070e979c658Sreinoud 2071e979c658Sreinoud /* --------------------------------------------------------------------- */ 2072e979c658Sreinoud 2073e979c658Sreinoud int 2074e979c658Sreinoud udf_grow_node(struct udf_node *udf_node, uint64_t new_size) 2075e979c658Sreinoud { 2076e979c658Sreinoud union dscrptr *dscr; 2077e979c658Sreinoud struct vnode *vp = udf_node->vnode; 2078e979c658Sreinoud struct udf_mount *ump = udf_node->ump; 2079e979c658Sreinoud struct file_entry *fe; 2080e979c658Sreinoud struct extfile_entry *efe; 2081e979c658Sreinoud struct icb_tag *icbtag; 2082e979c658Sreinoud struct long_ad c_ad, s_ad; 2083e979c658Sreinoud uint64_t size_diff, old_size, inflen, objsize, chunk, append_len; 2084e979c658Sreinoud uint64_t foffset, end_foffset; 2085e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 2086e979c658Sreinoud uint32_t lb_size, dscr_size, crclen, lastblock_grow; 2087e979c658Sreinoud uint32_t len, flags, max_len; 2088e979c658Sreinoud uint32_t max_l_ad, l_ad, l_ea; 2089e979c658Sreinoud uint8_t *data_pos, *evacuated_data; 2090e979c658Sreinoud int icbflags, addr_type; 2091e979c658Sreinoud int slot, cpy_slot; 2092e979c658Sreinoud int eof, error; 2093e979c658Sreinoud 2094e979c658Sreinoud DPRINTF(ALLOC, ("udf_grow_node\n")); 2095e979c658Sreinoud 2096e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 20975eeb4f69Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 20985eeb4f69Sreinoud 2099e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 2100e979c658Sreinoud max_len = ((UDF_EXT_MAXLEN / lb_size) * lb_size); 2101e979c658Sreinoud 2102e979c658Sreinoud fe = udf_node->fe; 2103e979c658Sreinoud efe = udf_node->efe; 2104e979c658Sreinoud if (fe) { 2105e979c658Sreinoud dscr = (union dscrptr *) fe; 2106e979c658Sreinoud icbtag = &fe->icbtag; 2107e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 2108e979c658Sreinoud objsize = inflen; 2109e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 2110e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 2111e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 2112e979c658Sreinoud } else { 2113e979c658Sreinoud dscr = (union dscrptr *) efe; 2114e979c658Sreinoud icbtag = &efe->icbtag; 2115e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 2116e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 2117e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 2118e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 2119e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 2120e979c658Sreinoud } 2121e979c658Sreinoud data_pos = (uint8_t *) dscr + dscr_size + l_ea; 2122e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 2123e979c658Sreinoud 2124e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 2125e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2126e979c658Sreinoud 2127e979c658Sreinoud old_size = inflen; 2128e979c658Sreinoud size_diff = new_size - old_size; 2129e979c658Sreinoud 2130e979c658Sreinoud DPRINTF(ALLOC, ("\tfrom %"PRIu64" to %"PRIu64"\n", old_size, new_size)); 2131e979c658Sreinoud 2132e979c658Sreinoud evacuated_data = NULL; 2133e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 2134e979c658Sreinoud if (l_ad + size_diff <= max_l_ad) { 2135e979c658Sreinoud /* only reflect size change directly in the node */ 2136e979c658Sreinoud inflen += size_diff; 2137e979c658Sreinoud objsize += size_diff; 2138e979c658Sreinoud l_ad += size_diff; 2139e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 2140e979c658Sreinoud if (fe) { 2141e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2142e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 2143e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 2144e979c658Sreinoud } else { 2145e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2146e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2147e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 2148e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 2149e979c658Sreinoud } 2150e979c658Sreinoud error = 0; 2151e979c658Sreinoud 2152e979c658Sreinoud /* set new size for uvm */ 2153e979c658Sreinoud uvm_vnp_setsize(vp, old_size); 2154e979c658Sreinoud uvm_vnp_setwritesize(vp, new_size); 2155e979c658Sreinoud 2156e979c658Sreinoud #if 0 2157e979c658Sreinoud /* zero append space in buffer */ 2158e979c658Sreinoud uvm_vnp_zerorange(vp, old_size, new_size - old_size); 2159e979c658Sreinoud #endif 2160e979c658Sreinoud 21615eeb4f69Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 21625eeb4f69Sreinoud 2163e979c658Sreinoud /* unlock */ 2164e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2165e979c658Sreinoud 2166e979c658Sreinoud KASSERT(new_inflen == orig_inflen + size_diff); 2167e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2168e979c658Sreinoud KASSERT(new_lbrec == 0); 2169e979c658Sreinoud return 0; 2170e979c658Sreinoud } 2171e979c658Sreinoud 2172e979c658Sreinoud DPRINTF(ALLOC, ("\tCONVERT from internal\n")); 2173e979c658Sreinoud 2174e979c658Sreinoud if (old_size > 0) { 2175e979c658Sreinoud /* allocate some space and copy in the stuff to keep */ 2176e979c658Sreinoud evacuated_data = malloc(lb_size, M_UDFTEMP, M_WAITOK); 2177e979c658Sreinoud memset(evacuated_data, 0, lb_size); 2178e979c658Sreinoud 2179e979c658Sreinoud /* node is locked, so safe to exit mutex */ 2180e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2181e979c658Sreinoud 2182e979c658Sreinoud /* read in using the `normal' vn_rdwr() */ 2183e979c658Sreinoud error = vn_rdwr(UIO_READ, udf_node->vnode, 2184e979c658Sreinoud evacuated_data, old_size, 0, 2185e979c658Sreinoud UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED, 2186e979c658Sreinoud FSCRED, NULL, NULL); 2187e979c658Sreinoud 2188e979c658Sreinoud /* enter again */ 2189e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 2190e979c658Sreinoud } 2191e979c658Sreinoud 2192e979c658Sreinoud /* convert to a normal alloc */ 2193e979c658Sreinoud /* XXX HOWTO selecting allocation method ? */ 2194e979c658Sreinoud icbflags &= ~UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2195e979c658Sreinoud icbflags |= UDF_ICB_LONG_ALLOC; /* XXX or SHORT_ALLOC */ 2196e979c658Sreinoud icbtag->flags = udf_rw16(icbflags); 2197e979c658Sreinoud 2198e979c658Sreinoud /* wipe old descriptor space */ 2199e979c658Sreinoud udf_wipe_adslots(udf_node); 2200e979c658Sreinoud 2201e979c658Sreinoud memset(&c_ad, 0, sizeof(struct long_ad)); 2202e979c658Sreinoud c_ad.len = udf_rw32(old_size | UDF_EXT_FREE); 2203e979c658Sreinoud c_ad.loc.part_num = udf_rw16(0); /* not relevant */ 2204e979c658Sreinoud c_ad.loc.lb_num = udf_rw32(0); /* not relevant */ 2205e979c658Sreinoud 2206e979c658Sreinoud slot = 0; 2207e979c658Sreinoud } else { 2208e979c658Sreinoud /* goto the last entry (if any) */ 2209e979c658Sreinoud slot = 0; 2210e979c658Sreinoud cpy_slot = 0; 2211e979c658Sreinoud foffset = 0; 2212e979c658Sreinoud memset(&c_ad, 0, sizeof(struct long_ad)); 2213e979c658Sreinoud for (;;) { 2214e979c658Sreinoud udf_get_adslot(udf_node, slot, &c_ad, &eof); 2215e979c658Sreinoud if (eof) 2216e979c658Sreinoud break; 2217e979c658Sreinoud 2218e979c658Sreinoud len = udf_rw32(c_ad.len); 2219e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2220e979c658Sreinoud len = UDF_EXT_LEN(len); 2221e979c658Sreinoud 2222e979c658Sreinoud end_foffset = foffset + len; 2223e979c658Sreinoud if (flags != UDF_EXT_REDIRECT) 2224e979c658Sreinoud foffset = end_foffset; 2225e979c658Sreinoud 2226e979c658Sreinoud slot++; 2227e979c658Sreinoud } 2228e979c658Sreinoud /* at end of adslots */ 2229e979c658Sreinoud 2230e979c658Sreinoud /* special case if the old size was zero, then there is no last slot */ 2231e979c658Sreinoud if (old_size == 0) { 2232e979c658Sreinoud c_ad.len = udf_rw32(0 | UDF_EXT_FREE); 2233e979c658Sreinoud c_ad.loc.part_num = udf_rw16(0); /* not relevant */ 2234e979c658Sreinoud c_ad.loc.lb_num = udf_rw32(0); /* not relevant */ 2235e979c658Sreinoud } else { 2236e979c658Sreinoud /* refetch last slot */ 2237e979c658Sreinoud slot--; 2238e979c658Sreinoud udf_get_adslot(udf_node, slot, &c_ad, &eof); 2239e979c658Sreinoud } 2240e979c658Sreinoud } 2241e979c658Sreinoud 2242e979c658Sreinoud /* 2243e979c658Sreinoud * If the length of the last slot is not a multiple of lb_size, adjust 2244e979c658Sreinoud * length so that it is; don't forget to adjust `append_len'! relevant for 2245e979c658Sreinoud * extending existing files 2246e979c658Sreinoud */ 2247e979c658Sreinoud len = udf_rw32(c_ad.len); 2248e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2249e979c658Sreinoud len = UDF_EXT_LEN(len); 2250e979c658Sreinoud 2251e979c658Sreinoud lastblock_grow = 0; 2252e979c658Sreinoud if (len % lb_size > 0) { 2253e979c658Sreinoud lastblock_grow = lb_size - (len % lb_size); 2254e979c658Sreinoud lastblock_grow = MIN(size_diff, lastblock_grow); 2255e979c658Sreinoud len += lastblock_grow; 2256e979c658Sreinoud c_ad.len = udf_rw32(len | flags); 2257e979c658Sreinoud 2258e979c658Sreinoud /* TODO zero appened space in buffer! */ 2259e979c658Sreinoud /* using uvm_vnp_zerorange(vp, old_size, new_size - old_size); ? */ 2260e979c658Sreinoud } 2261e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 2262e979c658Sreinoud 2263e979c658Sreinoud /* size_diff can be bigger than allowed, so grow in chunks */ 2264e979c658Sreinoud append_len = size_diff - lastblock_grow; 2265e979c658Sreinoud while (append_len > 0) { 2266e979c658Sreinoud chunk = MIN(append_len, max_len); 2267e979c658Sreinoud s_ad.len = udf_rw32(chunk | UDF_EXT_FREE); 2268e979c658Sreinoud s_ad.loc.part_num = udf_rw16(0); 2269e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(0); 2270e979c658Sreinoud 2271e979c658Sreinoud if (udf_ads_merge(lb_size, &c_ad, &s_ad)) { 2272e979c658Sreinoud /* not mergable (anymore) */ 22734d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2274e979c658Sreinoud if (error) 2275e979c658Sreinoud goto errorout; 2276e979c658Sreinoud slot++; 2277e979c658Sreinoud c_ad = s_ad; 2278e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 2279e979c658Sreinoud } 2280e979c658Sreinoud append_len -= chunk; 2281e979c658Sreinoud } 2282e979c658Sreinoud 2283e979c658Sreinoud /* if there is a rest piece in the accumulator, append it */ 2284af39897aSreinoud if (UDF_EXT_LEN(udf_rw32(c_ad.len)) > 0) { 22854d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2286e979c658Sreinoud if (error) 2287e979c658Sreinoud goto errorout; 2288e979c658Sreinoud slot++; 2289e979c658Sreinoud } 2290e979c658Sreinoud 2291e979c658Sreinoud /* if there is a rest piece that didn't fit, append it */ 2292af39897aSreinoud if (UDF_EXT_LEN(udf_rw32(s_ad.len)) > 0) { 22934d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &s_ad); 2294e979c658Sreinoud if (error) 2295e979c658Sreinoud goto errorout; 2296e979c658Sreinoud slot++; 2297e979c658Sreinoud } 2298e979c658Sreinoud 2299e979c658Sreinoud inflen += size_diff; 2300e979c658Sreinoud objsize += size_diff; 2301e979c658Sreinoud if (fe) { 2302e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2303e979c658Sreinoud } else { 2304e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2305e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2306e979c658Sreinoud } 2307e979c658Sreinoud error = 0; 2308e979c658Sreinoud 2309e979c658Sreinoud if (evacuated_data) { 2310e979c658Sreinoud /* set new write size for uvm */ 2311e979c658Sreinoud uvm_vnp_setwritesize(vp, old_size); 2312e979c658Sreinoud 2313e979c658Sreinoud /* write out evacuated data */ 2314e979c658Sreinoud error = vn_rdwr(UIO_WRITE, udf_node->vnode, 2315e979c658Sreinoud evacuated_data, old_size, 0, 2316e979c658Sreinoud UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED, 2317e979c658Sreinoud FSCRED, NULL, NULL); 2318e979c658Sreinoud uvm_vnp_setsize(vp, old_size); 2319e979c658Sreinoud } 2320e979c658Sreinoud 2321e979c658Sreinoud errorout: 2322e979c658Sreinoud if (evacuated_data) 2323e979c658Sreinoud free(evacuated_data, M_UDFTEMP); 2324e979c658Sreinoud 23254d5c88faSreinoud udf_count_alloc_exts(udf_node); 23264d5c88faSreinoud 2327e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 23285eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 23295eeb4f69Sreinoud 2330e979c658Sreinoud KASSERT(new_inflen == orig_inflen + size_diff); 2331e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2332e979c658Sreinoud 2333e979c658Sreinoud return error; 2334e979c658Sreinoud } 2335e979c658Sreinoud 2336e979c658Sreinoud /* --------------------------------------------------------------------- */ 2337e979c658Sreinoud 2338e979c658Sreinoud int 2339e979c658Sreinoud udf_shrink_node(struct udf_node *udf_node, uint64_t new_size) 2340e979c658Sreinoud { 2341e979c658Sreinoud struct vnode *vp = udf_node->vnode; 2342e979c658Sreinoud struct udf_mount *ump = udf_node->ump; 2343e979c658Sreinoud struct file_entry *fe; 2344e979c658Sreinoud struct extfile_entry *efe; 2345e979c658Sreinoud struct icb_tag *icbtag; 2346e979c658Sreinoud struct long_ad c_ad, s_ad, *node_ad_cpy; 2347e979c658Sreinoud uint64_t size_diff, old_size, inflen, objsize; 2348e979c658Sreinoud uint64_t foffset, end_foffset; 2349e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 2350e979c658Sreinoud uint32_t lb_size, dscr_size, crclen; 2351e979c658Sreinoud uint32_t slot_offset; 2352e979c658Sreinoud uint32_t len, flags, max_len; 2353e979c658Sreinoud uint32_t num_lb, lb_num; 2354e979c658Sreinoud uint32_t max_l_ad, l_ad, l_ea; 2355e979c658Sreinoud uint16_t vpart_num; 2356e979c658Sreinoud uint8_t *data_pos; 2357e979c658Sreinoud int icbflags, addr_type; 2358e979c658Sreinoud int slot, cpy_slot, cpy_slots; 2359e979c658Sreinoud int eof, error; 2360e979c658Sreinoud 2361e979c658Sreinoud DPRINTF(ALLOC, ("udf_shrink_node\n")); 2362e979c658Sreinoud 2363e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 23645eeb4f69Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 23655eeb4f69Sreinoud 2366e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 2367e979c658Sreinoud max_len = ((UDF_EXT_MAXLEN / lb_size) * lb_size); 2368e979c658Sreinoud 2369e979c658Sreinoud /* do the work */ 2370e979c658Sreinoud fe = udf_node->fe; 2371e979c658Sreinoud efe = udf_node->efe; 2372e979c658Sreinoud if (fe) { 2373e979c658Sreinoud icbtag = &fe->icbtag; 2374e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 2375e979c658Sreinoud objsize = inflen; 2376e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 2377e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 2378e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 2379e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 2380e979c658Sreinoud } else { 2381e979c658Sreinoud icbtag = &efe->icbtag; 2382e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 2383e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 2384e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 2385e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 2386e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 2387e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 2388e979c658Sreinoud } 2389e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 2390e979c658Sreinoud 2391e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 2392e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2393e979c658Sreinoud 2394e979c658Sreinoud old_size = inflen; 2395e979c658Sreinoud size_diff = old_size - new_size; 2396e979c658Sreinoud 2397e979c658Sreinoud DPRINTF(ALLOC, ("\tfrom %"PRIu64" to %"PRIu64"\n", old_size, new_size)); 2398e979c658Sreinoud 2399e979c658Sreinoud /* shrink the node to its new size */ 2400e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 2401e979c658Sreinoud /* only reflect size change directly in the node */ 2402e979c658Sreinoud KASSERT(new_size <= max_l_ad); 2403e979c658Sreinoud inflen -= size_diff; 2404e979c658Sreinoud objsize -= size_diff; 2405e979c658Sreinoud l_ad -= size_diff; 2406e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 2407e979c658Sreinoud if (fe) { 2408e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2409e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 2410e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 2411e979c658Sreinoud } else { 2412e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2413e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2414e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 2415e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 2416e979c658Sreinoud } 2417e979c658Sreinoud error = 0; 241814d24a67Sreinoud 241914d24a67Sreinoud /* clear the space in the descriptor */ 242014d24a67Sreinoud KASSERT(old_size > new_size); 242114d24a67Sreinoud memset(data_pos + new_size, 0, old_size - new_size); 242214d24a67Sreinoud 2423e979c658Sreinoud /* TODO zero appened space in buffer! */ 2424e979c658Sreinoud /* using uvm_vnp_zerorange(vp, old_size, old_size - new_size); ? */ 2425e979c658Sreinoud 2426e979c658Sreinoud /* set new size for uvm */ 2427e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 2428e979c658Sreinoud 2429e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 24305eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 24315eeb4f69Sreinoud 2432e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 2433e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2434e979c658Sreinoud KASSERT(new_lbrec == 0); 2435e979c658Sreinoud 2436e979c658Sreinoud return 0; 2437e979c658Sreinoud } 2438e979c658Sreinoud 2439e979c658Sreinoud /* setup node cleanup extents copy space */ 2440e979c658Sreinoud node_ad_cpy = malloc(lb_size * UDF_MAX_ALLOC_EXTENTS, 2441e979c658Sreinoud M_UDFMNT, M_WAITOK); 2442e979c658Sreinoud memset(node_ad_cpy, 0, lb_size * UDF_MAX_ALLOC_EXTENTS); 2443e979c658Sreinoud 2444e979c658Sreinoud /* 2445e979c658Sreinoud * Shrink the node by releasing the allocations and truncate the last 2446e979c658Sreinoud * allocation to the new size. If the new size fits into the 2447e979c658Sreinoud * allocation descriptor itself, transform it into an 2448e979c658Sreinoud * UDF_ICB_INTERN_ALLOC. 2449e979c658Sreinoud */ 2450e979c658Sreinoud slot = 0; 2451e979c658Sreinoud cpy_slot = 0; 2452e979c658Sreinoud foffset = 0; 2453e979c658Sreinoud 2454e979c658Sreinoud /* 1) copy till first overlap piece to the rewrite buffer */ 2455e979c658Sreinoud for (;;) { 2456e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2457e979c658Sreinoud if (eof) { 2458e979c658Sreinoud DPRINTF(WRITE, 2459e979c658Sreinoud ("Shrink node failed: " 2460e979c658Sreinoud "encountered EOF\n")); 2461e979c658Sreinoud error = EINVAL; 2462e979c658Sreinoud goto errorout; /* panic? */ 2463e979c658Sreinoud } 2464e979c658Sreinoud len = udf_rw32(s_ad.len); 2465e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2466e979c658Sreinoud len = UDF_EXT_LEN(len); 2467e979c658Sreinoud 2468e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 2469e979c658Sreinoud slot++; 2470e979c658Sreinoud continue; 2471e979c658Sreinoud } 2472e979c658Sreinoud 2473e979c658Sreinoud end_foffset = foffset + len; 2474e979c658Sreinoud if (end_foffset > new_size) 2475e979c658Sreinoud break; /* found */ 2476e979c658Sreinoud 2477e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2478e979c658Sreinoud 2479e979c658Sreinoud DPRINTF(ALLOC, ("\t1: vp %d, lb %d, len %d, flags %d " 2480e979c658Sreinoud "-> stack\n", 2481e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2482e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2483e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2484e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2485e979c658Sreinoud 2486e979c658Sreinoud foffset = end_foffset; 2487e979c658Sreinoud slot++; 2488e979c658Sreinoud } 2489e979c658Sreinoud slot_offset = new_size - foffset; 2490e979c658Sreinoud 2491e979c658Sreinoud /* 2) trunc overlapping slot at overlap and copy it */ 2492e979c658Sreinoud if (slot_offset > 0) { 2493e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 2494e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 2495e979c658Sreinoud 2496e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 2497d3bf9c7bSreinoud /* note: round DOWN on num_lb */ 2498e979c658Sreinoud lb_num += (slot_offset + lb_size -1) / lb_size; 2499d3bf9c7bSreinoud num_lb = (len - slot_offset) / lb_size; 2500e979c658Sreinoud 2501e979c658Sreinoud udf_free_allocated_space(ump, lb_num, vpart_num, num_lb); 2502e979c658Sreinoud } 2503e979c658Sreinoud 2504e979c658Sreinoud s_ad.len = udf_rw32(slot_offset | flags); 2505e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2506e979c658Sreinoud slot++; 2507e979c658Sreinoud 2508e979c658Sreinoud DPRINTF(ALLOC, ("\t2: vp %d, lb %d, len %d, flags %d " 2509e979c658Sreinoud "-> stack\n", 2510e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2511e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2512e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2513e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2514e979c658Sreinoud } 2515e979c658Sreinoud 2516e979c658Sreinoud /* 3) delete remainder */ 2517e979c658Sreinoud for (;;) { 2518e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2519e979c658Sreinoud if (eof) 2520e979c658Sreinoud break; 2521e979c658Sreinoud 2522e979c658Sreinoud len = udf_rw32(s_ad.len); 2523e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2524e979c658Sreinoud len = UDF_EXT_LEN(len); 2525e979c658Sreinoud 2526e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 2527e979c658Sreinoud slot++; 2528e979c658Sreinoud continue; 2529e979c658Sreinoud } 2530e979c658Sreinoud 2531e979c658Sreinoud DPRINTF(ALLOC, ("\t3: delete remainder " 2532e979c658Sreinoud "vp %d lb %d, len %d, flags %d\n", 2533e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2534e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2535e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2536e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2537e979c658Sreinoud 2538e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 2539e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 2540e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 2541e979c658Sreinoud num_lb = (len + lb_size - 1) / lb_size; 2542e979c658Sreinoud 2543e979c658Sreinoud udf_free_allocated_space(ump, lb_num, vpart_num, 2544e979c658Sreinoud num_lb); 2545e979c658Sreinoud } 2546e979c658Sreinoud 2547e979c658Sreinoud slot++; 2548e979c658Sreinoud } 2549e979c658Sreinoud 2550e979c658Sreinoud /* 4) if it will fit into the descriptor then convert */ 2551e979c658Sreinoud if (new_size < max_l_ad) { 2552e979c658Sreinoud /* 2553e979c658Sreinoud * resque/evacuate old piece by reading it in, and convert it 2554e979c658Sreinoud * to internal alloc. 2555e979c658Sreinoud */ 2556e979c658Sreinoud if (new_size == 0) { 2557e979c658Sreinoud /* XXX/TODO only for zero sizing now */ 2558e979c658Sreinoud udf_wipe_adslots(udf_node); 2559e979c658Sreinoud 2560e979c658Sreinoud icbflags &= ~UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2561e979c658Sreinoud icbflags |= UDF_ICB_INTERN_ALLOC; 2562e979c658Sreinoud icbtag->flags = udf_rw16(icbflags); 2563e979c658Sreinoud 2564e979c658Sreinoud inflen -= size_diff; KASSERT(inflen == 0); 2565e979c658Sreinoud objsize -= size_diff; 2566e979c658Sreinoud l_ad = new_size; 2567e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 2568e979c658Sreinoud if (fe) { 2569e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2570e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 2571e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 2572e979c658Sreinoud } else { 2573e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2574e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2575e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 2576e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 2577e979c658Sreinoud } 2578e979c658Sreinoud /* eventually copy in evacuated piece */ 2579e979c658Sreinoud /* set new size for uvm */ 2580e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 2581e979c658Sreinoud 2582e979c658Sreinoud free(node_ad_cpy, M_UDFMNT); 25835eeb4f69Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 25845eeb4f69Sreinoud 2585e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2586e979c658Sreinoud 2587e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 2588e979c658Sreinoud KASSERT(new_inflen == 0); 2589e979c658Sreinoud KASSERT(new_lbrec == 0); 2590e979c658Sreinoud 2591e979c658Sreinoud return 0; 2592e979c658Sreinoud } 2593e979c658Sreinoud 2594e979c658Sreinoud printf("UDF_SHRINK_NODE: could convert to internal alloc!\n"); 2595e979c658Sreinoud } 2596e979c658Sreinoud 2597e979c658Sreinoud /* 5) reset node descriptors */ 2598e979c658Sreinoud udf_wipe_adslots(udf_node); 2599e979c658Sreinoud 2600e979c658Sreinoud /* 6) copy back extents; merge when possible. Recounting on the fly */ 2601e979c658Sreinoud cpy_slots = cpy_slot; 2602e979c658Sreinoud 2603e979c658Sreinoud c_ad = node_ad_cpy[0]; 2604e979c658Sreinoud slot = 0; 2605e979c658Sreinoud for (cpy_slot = 1; cpy_slot < cpy_slots; cpy_slot++) { 2606e979c658Sreinoud s_ad = node_ad_cpy[cpy_slot]; 2607e979c658Sreinoud 2608e979c658Sreinoud DPRINTF(ALLOC, ("\t6: stack -> got mapping vp %d " 2609e979c658Sreinoud "lb %d, len %d, flags %d\n", 2610e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2611e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2612e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2613e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2614e979c658Sreinoud 2615e979c658Sreinoud /* see if we can merge */ 2616e979c658Sreinoud if (udf_ads_merge(lb_size, &c_ad, &s_ad)) { 2617e979c658Sreinoud /* not mergable (anymore) */ 2618e979c658Sreinoud DPRINTF(ALLOC, ("\t6: appending vp %d lb %d, " 2619e979c658Sreinoud "len %d, flags %d\n", 2620e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2621e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2622e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2623e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2624e979c658Sreinoud 26254d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2626e979c658Sreinoud if (error) 2627e979c658Sreinoud goto errorout; /* panic? */ 2628e979c658Sreinoud c_ad = s_ad; 2629e979c658Sreinoud slot++; 2630e979c658Sreinoud } 2631e979c658Sreinoud } 2632e979c658Sreinoud 2633e979c658Sreinoud /* 7) push rest slot (if any) */ 2634e979c658Sreinoud if (UDF_EXT_LEN(c_ad.len) > 0) { 2635e979c658Sreinoud DPRINTF(ALLOC, ("\t7: last append vp %d lb %d, " 2636e979c658Sreinoud "len %d, flags %d\n", 2637e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2638e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2639e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2640e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2641e979c658Sreinoud 26424d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2643e979c658Sreinoud if (error) 2644e979c658Sreinoud goto errorout; /* panic? */ 2645e979c658Sreinoud ; 2646e979c658Sreinoud } 2647e979c658Sreinoud 2648e979c658Sreinoud inflen -= size_diff; 2649e979c658Sreinoud objsize -= size_diff; 2650e979c658Sreinoud if (fe) { 2651e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2652e979c658Sreinoud } else { 2653e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2654e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2655e979c658Sreinoud } 2656e979c658Sreinoud error = 0; 2657e979c658Sreinoud 2658e979c658Sreinoud /* set new size for uvm */ 2659e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 2660e979c658Sreinoud 2661e979c658Sreinoud errorout: 2662e979c658Sreinoud free(node_ad_cpy, M_UDFMNT); 2663e979c658Sreinoud 26644d5c88faSreinoud udf_count_alloc_exts(udf_node); 26654d5c88faSreinoud 2666e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 26675eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 26685eeb4f69Sreinoud 2669e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 2670e979c658Sreinoud 2671e979c658Sreinoud return error; 2672e979c658Sreinoud } 2673e979c658Sreinoud 2674