1*6c7e5f2aSad /* $NetBSD: udf_allocation.c,v 1.41 2020/04/23 21:47:08 ad 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*6c7e5f2aSad __KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.41 2020/04/23 21:47:08 ad Exp $"); 32e979c658Sreinoud #endif /* not lint */ 33e979c658Sreinoud 34e979c658Sreinoud 35e979c658Sreinoud #if defined(_KERNEL_OPT) 36e979c658Sreinoud #include "opt_compat_netbsd.h" 37e979c658Sreinoud #endif 38e979c658Sreinoud 39e979c658Sreinoud /* TODO strip */ 40e979c658Sreinoud #include <sys/param.h> 41e979c658Sreinoud #include <sys/systm.h> 42e979c658Sreinoud #include <sys/sysctl.h> 43e979c658Sreinoud #include <sys/namei.h> 44e979c658Sreinoud #include <sys/proc.h> 45e979c658Sreinoud #include <sys/kernel.h> 46e979c658Sreinoud #include <sys/vnode.h> 47e979c658Sreinoud #include <miscfs/genfs/genfs_node.h> 48e979c658Sreinoud #include <sys/mount.h> 49e979c658Sreinoud #include <sys/buf.h> 50e979c658Sreinoud #include <sys/file.h> 51e979c658Sreinoud #include <sys/device.h> 52e979c658Sreinoud #include <sys/disklabel.h> 53e979c658Sreinoud #include <sys/ioctl.h> 54e979c658Sreinoud #include <sys/malloc.h> 55e979c658Sreinoud #include <sys/dirent.h> 56e979c658Sreinoud #include <sys/stat.h> 57e979c658Sreinoud #include <sys/conf.h> 58e979c658Sreinoud #include <sys/kauth.h> 59e979c658Sreinoud #include <sys/kthread.h> 60e979c658Sreinoud #include <dev/clock_subr.h> 61e979c658Sreinoud 62e979c658Sreinoud #include <fs/udf/ecma167-udf.h> 63e979c658Sreinoud #include <fs/udf/udf_mount.h> 64e979c658Sreinoud 65e979c658Sreinoud #include "udf.h" 66e979c658Sreinoud #include "udf_subr.h" 67e979c658Sreinoud #include "udf_bswap.h" 68e979c658Sreinoud 69e979c658Sreinoud 70e979c658Sreinoud #define VTOI(vnode) ((struct udf_node *) vnode->v_data) 71e979c658Sreinoud 72e979c658Sreinoud static void udf_record_allocation_in_node(struct udf_mount *ump, 73e979c658Sreinoud struct buf *buf, uint16_t vpart_num, uint64_t *mapping, 74e979c658Sreinoud struct long_ad *node_ad_cpy); 75e979c658Sreinoud 761196d96dSreinoud static void udf_collect_free_space_for_vpart(struct udf_mount *ump, 771196d96dSreinoud uint16_t vpart_num, uint32_t num_lb); 781196d96dSreinoud 79330482f6Sreinoud static int udf_ads_merge(uint32_t max_len, uint32_t lb_size, struct long_ad *a1, struct long_ad *a2); 801196d96dSreinoud static void udf_wipe_adslots(struct udf_node *udf_node); 811196d96dSreinoud static void udf_count_alloc_exts(struct udf_node *udf_node); 821196d96dSreinoud 83e979c658Sreinoud 84e979c658Sreinoud /* --------------------------------------------------------------------- */ 854d5c88faSreinoud 86d61a135aSreinoud #if 0 87e979c658Sreinoud #if 1 88e979c658Sreinoud static void 89e979c658Sreinoud udf_node_dump(struct udf_node *udf_node) { 90e979c658Sreinoud struct file_entry *fe; 91e979c658Sreinoud struct extfile_entry *efe; 92e979c658Sreinoud struct icb_tag *icbtag; 934d5c88faSreinoud struct long_ad s_ad; 94e979c658Sreinoud uint64_t inflen; 954d5c88faSreinoud uint32_t icbflags, addr_type; 96e979c658Sreinoud uint32_t len, lb_num; 974d5c88faSreinoud uint32_t flags; 98e979c658Sreinoud int part_num; 994d5c88faSreinoud int lb_size, eof, slot; 100e979c658Sreinoud 101d3bf9c7bSreinoud if ((udf_verbose & UDF_DEBUG_NODEDUMP) == 0) 102e979c658Sreinoud return; 103e979c658Sreinoud 104e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 105e979c658Sreinoud 106e979c658Sreinoud fe = udf_node->fe; 107e979c658Sreinoud efe = udf_node->efe; 108e979c658Sreinoud if (fe) { 109e979c658Sreinoud icbtag = &fe->icbtag; 110e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 111e979c658Sreinoud } else { 112e979c658Sreinoud icbtag = &efe->icbtag; 113e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 114e979c658Sreinoud } 115e979c658Sreinoud 116e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 117e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 118e979c658Sreinoud 1194d5c88faSreinoud printf("udf_node_dump %p :\n", udf_node); 120e979c658Sreinoud 121e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1224d5c88faSreinoud printf("\tIntern alloc, len = %"PRIu64"\n", inflen); 123e979c658Sreinoud return; 124e979c658Sreinoud } 125e979c658Sreinoud 1264d5c88faSreinoud printf("\tInflen = %"PRIu64"\n", inflen); 127e979c658Sreinoud printf("\t\t"); 1284d5c88faSreinoud 1294d5c88faSreinoud slot = 0; 1304d5c88faSreinoud for (;;) { 1314d5c88faSreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1324d5c88faSreinoud if (eof) 1334d5c88faSreinoud break; 1344d5c88faSreinoud part_num = udf_rw16(s_ad.loc.part_num); 1354d5c88faSreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 1364d5c88faSreinoud len = udf_rw32(s_ad.len); 137e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 138e979c658Sreinoud len = UDF_EXT_LEN(len); 1394d5c88faSreinoud 140e979c658Sreinoud printf("["); 141e979c658Sreinoud if (part_num >= 0) 142e979c658Sreinoud printf("part %d, ", part_num); 143e979c658Sreinoud printf("lb_num %d, len %d", lb_num, len); 144e979c658Sreinoud if (flags) 145d3bf9c7bSreinoud printf(", flags %d", flags>>30); 146e979c658Sreinoud printf("] "); 1474d5c88faSreinoud 1484d5c88faSreinoud if (flags == UDF_EXT_REDIRECT) { 1494d5c88faSreinoud printf("\n\textent END\n\tallocation extent\n\t\t"); 150e979c658Sreinoud } 1514d5c88faSreinoud 1524d5c88faSreinoud slot++; 1534d5c88faSreinoud } 1544d5c88faSreinoud printf("\n\tl_ad END\n\n"); 155e979c658Sreinoud } 156e979c658Sreinoud #else 157e979c658Sreinoud #define udf_node_dump(a) 158e979c658Sreinoud #endif 159e979c658Sreinoud 1605eeb4f69Sreinoud 1615eeb4f69Sreinoud static void 1625eeb4f69Sreinoud udf_assert_allocated(struct udf_mount *ump, uint16_t vpart_num, 1635eeb4f69Sreinoud uint32_t lb_num, uint32_t num_lb) 1645eeb4f69Sreinoud { 1655eeb4f69Sreinoud struct udf_bitmap *bitmap; 1665eeb4f69Sreinoud struct part_desc *pdesc; 1675eeb4f69Sreinoud uint32_t ptov; 1685eeb4f69Sreinoud uint32_t bitval; 1695eeb4f69Sreinoud uint8_t *bpos; 1705eeb4f69Sreinoud int bit; 1715eeb4f69Sreinoud int phys_part; 1725eeb4f69Sreinoud int ok; 1735eeb4f69Sreinoud 174d3bf9c7bSreinoud DPRINTF(PARANOIA, ("udf_assert_allocated: check virt lbnum %d " 1755eeb4f69Sreinoud "part %d + %d sect\n", lb_num, vpart_num, num_lb)); 1765eeb4f69Sreinoud 1775eeb4f69Sreinoud /* get partition backing up this vpart_num */ 1785eeb4f69Sreinoud pdesc = ump->partitions[ump->vtop[vpart_num]]; 1795eeb4f69Sreinoud 1805eeb4f69Sreinoud switch (ump->vtop_tp[vpart_num]) { 1815eeb4f69Sreinoud case UDF_VTOP_TYPE_PHYS : 1825eeb4f69Sreinoud case UDF_VTOP_TYPE_SPARABLE : 1835eeb4f69Sreinoud /* free space to freed or unallocated space bitmap */ 1845eeb4f69Sreinoud ptov = udf_rw32(pdesc->start_loc); 1855eeb4f69Sreinoud phys_part = ump->vtop[vpart_num]; 1865eeb4f69Sreinoud 1875eeb4f69Sreinoud /* use unallocated bitmap */ 1885eeb4f69Sreinoud bitmap = &ump->part_unalloc_bits[phys_part]; 1895eeb4f69Sreinoud 1905eeb4f69Sreinoud /* if no bitmaps are defined, bail out */ 1915eeb4f69Sreinoud if (bitmap->bits == NULL) 1925eeb4f69Sreinoud break; 1935eeb4f69Sreinoud 1945eeb4f69Sreinoud /* check bits */ 1955eeb4f69Sreinoud KASSERT(bitmap->bits); 1965eeb4f69Sreinoud ok = 1; 1975eeb4f69Sreinoud bpos = bitmap->bits + lb_num/8; 1985eeb4f69Sreinoud bit = lb_num % 8; 1995eeb4f69Sreinoud while (num_lb > 0) { 2005eeb4f69Sreinoud bitval = (1 << bit); 2015eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : check %d, %p, bit %d\n", 2025eeb4f69Sreinoud lb_num, bpos, bit)); 2035eeb4f69Sreinoud KASSERT(bitmap->bits + lb_num/8 == bpos); 2045eeb4f69Sreinoud if (*bpos & bitval) { 2055eeb4f69Sreinoud printf("\tlb_num %d is NOT marked busy\n", 2065eeb4f69Sreinoud lb_num); 2075eeb4f69Sreinoud ok = 0; 2085eeb4f69Sreinoud } 2095eeb4f69Sreinoud lb_num++; num_lb--; 2105eeb4f69Sreinoud bit = (bit + 1) % 8; 2115eeb4f69Sreinoud if (bit == 0) 2125eeb4f69Sreinoud bpos++; 2135eeb4f69Sreinoud } 2145eeb4f69Sreinoud if (!ok) { 2155eeb4f69Sreinoud /* KASSERT(0); */ 2165eeb4f69Sreinoud } 2175eeb4f69Sreinoud 2185eeb4f69Sreinoud break; 2195eeb4f69Sreinoud case UDF_VTOP_TYPE_VIRT : 2205eeb4f69Sreinoud /* TODO check space */ 2215eeb4f69Sreinoud KASSERT(num_lb == 1); 2225eeb4f69Sreinoud break; 2235eeb4f69Sreinoud case UDF_VTOP_TYPE_META : 2245eeb4f69Sreinoud /* TODO check space in the metadata bitmap */ 2255eeb4f69Sreinoud default: 2265eeb4f69Sreinoud /* not implemented */ 2275eeb4f69Sreinoud break; 2285eeb4f69Sreinoud } 2295eeb4f69Sreinoud } 2305eeb4f69Sreinoud 2315eeb4f69Sreinoud 232e979c658Sreinoud static void 233e979c658Sreinoud udf_node_sanity_check(struct udf_node *udf_node, 234a287d23dSreinoud uint64_t *cnt_inflen, uint64_t *cnt_logblksrec) 235a287d23dSreinoud { 236a287d23dSreinoud union dscrptr *dscr; 237e979c658Sreinoud struct file_entry *fe; 238e979c658Sreinoud struct extfile_entry *efe; 239e979c658Sreinoud struct icb_tag *icbtag; 2404d5c88faSreinoud struct long_ad s_ad; 241e979c658Sreinoud uint64_t inflen, logblksrec; 2424d5c88faSreinoud uint32_t icbflags, addr_type; 2434d5c88faSreinoud uint32_t len, lb_num, l_ea, l_ad, max_l_ad; 2445eeb4f69Sreinoud uint16_t part_num; 245a287d23dSreinoud uint8_t *data_pos; 2464d5c88faSreinoud int dscr_size, lb_size, flags, whole_lb; 247a287d23dSreinoud int i, slot, eof; 248e979c658Sreinoud 2495eeb4f69Sreinoud // KASSERT(mutex_owned(&udf_node->ump->allocate_mutex)); 250e979c658Sreinoud 251d3bf9c7bSreinoud if (1) 252d3bf9c7bSreinoud udf_node_dump(udf_node); 253d3bf9c7bSreinoud 254e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 255e979c658Sreinoud 256e979c658Sreinoud fe = udf_node->fe; 257e979c658Sreinoud efe = udf_node->efe; 258e979c658Sreinoud if (fe) { 259a287d23dSreinoud dscr = (union dscrptr *) 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 { 267a287d23dSreinoud dscr = (union dscrptr *) efe; 268e979c658Sreinoud icbtag = &efe->icbtag; 269e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 270e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 2714d5c88faSreinoud logblksrec = udf_rw64(efe->logblks_rec); 272e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 2734d5c88faSreinoud l_ea = udf_rw32(efe->l_ea); 274e979c658Sreinoud } 275a287d23dSreinoud data_pos = (uint8_t *) dscr + dscr_size + l_ea; 276e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 277e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 278e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 279e979c658Sreinoud 280a287d23dSreinoud /* check if tail is zero */ 281a287d23dSreinoud DPRINTF(PARANOIA, ("Sanity check blank tail\n")); 282a287d23dSreinoud for (i = l_ad; i < max_l_ad; i++) { 283a287d23dSreinoud if (data_pos[i] != 0) 284a287d23dSreinoud printf( "sanity_check: violation: node byte %d " 285a287d23dSreinoud "has value %d\n", i, data_pos[i]); 286a287d23dSreinoud } 287a287d23dSreinoud 288e979c658Sreinoud /* reset counters */ 289e979c658Sreinoud *cnt_inflen = 0; 290e979c658Sreinoud *cnt_logblksrec = 0; 291e979c658Sreinoud 292e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 293e979c658Sreinoud KASSERT(l_ad <= max_l_ad); 294e979c658Sreinoud KASSERT(l_ad == inflen); 295e979c658Sreinoud *cnt_inflen = inflen; 296e979c658Sreinoud return; 297e979c658Sreinoud } 298e979c658Sreinoud 299e979c658Sreinoud /* start counting */ 300e979c658Sreinoud whole_lb = 1; 3014d5c88faSreinoud slot = 0; 3024d5c88faSreinoud for (;;) { 3034d5c88faSreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 3044d5c88faSreinoud if (eof) 3054d5c88faSreinoud break; 306e979c658Sreinoud KASSERT(whole_lb == 1); 3074d5c88faSreinoud 3084d5c88faSreinoud part_num = udf_rw16(s_ad.loc.part_num); 3094d5c88faSreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 3104d5c88faSreinoud len = udf_rw32(s_ad.len); 311e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 312e979c658Sreinoud len = UDF_EXT_LEN(len); 3134d5c88faSreinoud 314d7699664Sreinoud if (flags != UDF_EXT_REDIRECT) { 315e979c658Sreinoud *cnt_inflen += len; 316e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 317e979c658Sreinoud *cnt_logblksrec += (len + lb_size -1) / lb_size; 318e979c658Sreinoud } 319d7699664Sreinoud } else { 320d7699664Sreinoud KASSERT(len == lb_size); 321d7699664Sreinoud } 3225eeb4f69Sreinoud /* check allocation */ 3235eeb4f69Sreinoud if (flags == UDF_EXT_ALLOCATED) 3245eeb4f69Sreinoud udf_assert_allocated(udf_node->ump, part_num, lb_num, 3255eeb4f69Sreinoud (len + lb_size - 1) / lb_size); 326af39897aSreinoud 327af39897aSreinoud /* check whole lb */ 328e979c658Sreinoud whole_lb = ((len % lb_size) == 0); 3294d5c88faSreinoud 3304d5c88faSreinoud slot++; 331e979c658Sreinoud } 332e979c658Sreinoud /* rest should be zero (ad_off > l_ad < max_l_ad - adlen) */ 333e979c658Sreinoud 334e979c658Sreinoud KASSERT(*cnt_inflen == inflen); 335e979c658Sreinoud KASSERT(*cnt_logblksrec == logblksrec); 336e979c658Sreinoud 3375eeb4f69Sreinoud // KASSERT(mutex_owned(&udf_node->ump->allocate_mutex)); 338e979c658Sreinoud } 339e979c658Sreinoud #else 340d61a135aSreinoud static void 341d61a135aSreinoud udf_node_sanity_check(struct udf_node *udf_node, 342d61a135aSreinoud uint64_t *cnt_inflen, uint64_t *cnt_logblksrec) { 343d61a135aSreinoud struct file_entry *fe; 344d61a135aSreinoud struct extfile_entry *efe; 345d61a135aSreinoud uint64_t inflen, logblksrec; 346d61a135aSreinoud 347d61a135aSreinoud fe = udf_node->fe; 348d61a135aSreinoud efe = udf_node->efe; 349d61a135aSreinoud if (fe) { 350d61a135aSreinoud inflen = udf_rw64(fe->inf_len); 351d61a135aSreinoud logblksrec = udf_rw64(fe->logblks_rec); 352d61a135aSreinoud } else { 353d61a135aSreinoud inflen = udf_rw64(efe->inf_len); 354d61a135aSreinoud logblksrec = udf_rw64(efe->logblks_rec); 355d61a135aSreinoud } 356d61a135aSreinoud *cnt_logblksrec = logblksrec; 357d61a135aSreinoud *cnt_inflen = inflen; 358d61a135aSreinoud } 359e979c658Sreinoud #endif 360e979c658Sreinoud 361e979c658Sreinoud /* --------------------------------------------------------------------- */ 362e979c658Sreinoud 363706de0e5Sreinoud void 364706de0e5Sreinoud udf_calc_freespace(struct udf_mount *ump, uint64_t *sizeblks, uint64_t *freeblks) 365706de0e5Sreinoud { 366706de0e5Sreinoud struct logvol_int_desc *lvid; 367706de0e5Sreinoud uint32_t *pos1, *pos2; 368706de0e5Sreinoud int vpart, num_vpart; 369706de0e5Sreinoud 370706de0e5Sreinoud lvid = ump->logvol_integrity; 371706de0e5Sreinoud *freeblks = *sizeblks = 0; 372706de0e5Sreinoud 373706de0e5Sreinoud /* 374706de0e5Sreinoud * Sequentials media report free space directly (CD/DVD/BD-R), for the 375706de0e5Sreinoud * other media we need the logical volume integrity. 376706de0e5Sreinoud * 377706de0e5Sreinoud * We sum all free space up here regardless of type. 378706de0e5Sreinoud */ 379706de0e5Sreinoud 380706de0e5Sreinoud KASSERT(lvid); 381706de0e5Sreinoud num_vpart = udf_rw32(lvid->num_part); 382706de0e5Sreinoud 383706de0e5Sreinoud if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) { 384706de0e5Sreinoud /* use track info directly summing if there are 2 open */ 385706de0e5Sreinoud /* XXX assumption at most two tracks open */ 386706de0e5Sreinoud *freeblks = ump->data_track.free_blocks; 387706de0e5Sreinoud if (ump->data_track.tracknr != ump->metadata_track.tracknr) 388706de0e5Sreinoud *freeblks += ump->metadata_track.free_blocks; 389706de0e5Sreinoud *sizeblks = ump->discinfo.last_possible_lba; 390706de0e5Sreinoud } else { 391706de0e5Sreinoud /* free and used space for mountpoint based on logvol integrity */ 392706de0e5Sreinoud for (vpart = 0; vpart < num_vpart; vpart++) { 393706de0e5Sreinoud pos1 = &lvid->tables[0] + vpart; 394706de0e5Sreinoud pos2 = &lvid->tables[0] + num_vpart + vpart; 395706de0e5Sreinoud if (udf_rw32(*pos1) != (uint32_t) -1) { 396706de0e5Sreinoud *freeblks += udf_rw32(*pos1); 397706de0e5Sreinoud *sizeblks += udf_rw32(*pos2); 398706de0e5Sreinoud } 399706de0e5Sreinoud } 400706de0e5Sreinoud } 401706de0e5Sreinoud /* adjust for accounted uncommitted blocks */ 402706de0e5Sreinoud for (vpart = 0; vpart < num_vpart; vpart++) 403706de0e5Sreinoud *freeblks -= ump->uncommitted_lbs[vpart]; 404706de0e5Sreinoud 405706de0e5Sreinoud if (*freeblks > UDF_DISC_SLACK) { 406706de0e5Sreinoud *freeblks -= UDF_DISC_SLACK; 407706de0e5Sreinoud } else { 408706de0e5Sreinoud *freeblks = 0; 409706de0e5Sreinoud } 410706de0e5Sreinoud } 411706de0e5Sreinoud 412706de0e5Sreinoud 413706de0e5Sreinoud static void 414706de0e5Sreinoud udf_calc_vpart_freespace(struct udf_mount *ump, uint16_t vpart_num, uint64_t *freeblks) 415706de0e5Sreinoud { 416706de0e5Sreinoud struct logvol_int_desc *lvid; 417706de0e5Sreinoud uint32_t *pos1; 418706de0e5Sreinoud 419706de0e5Sreinoud lvid = ump->logvol_integrity; 420706de0e5Sreinoud *freeblks = 0; 421706de0e5Sreinoud 422706de0e5Sreinoud /* 423706de0e5Sreinoud * Sequentials media report free space directly (CD/DVD/BD-R), for the 424706de0e5Sreinoud * other media we need the logical volume integrity. 425706de0e5Sreinoud * 426706de0e5Sreinoud * We sum all free space up here regardless of type. 427706de0e5Sreinoud */ 428706de0e5Sreinoud 429706de0e5Sreinoud KASSERT(lvid); 430706de0e5Sreinoud if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) { 431706de0e5Sreinoud /* XXX assumption at most two tracks open */ 432706de0e5Sreinoud if (vpart_num == ump->data_part) { 433706de0e5Sreinoud *freeblks = ump->data_track.free_blocks; 434706de0e5Sreinoud } else { 435706de0e5Sreinoud *freeblks = ump->metadata_track.free_blocks; 436706de0e5Sreinoud } 437706de0e5Sreinoud } else { 438706de0e5Sreinoud /* free and used space for mountpoint based on logvol integrity */ 439706de0e5Sreinoud pos1 = &lvid->tables[0] + vpart_num; 440706de0e5Sreinoud if (udf_rw32(*pos1) != (uint32_t) -1) 441706de0e5Sreinoud *freeblks += udf_rw32(*pos1); 442706de0e5Sreinoud } 443706de0e5Sreinoud 444706de0e5Sreinoud /* adjust for accounted uncommitted blocks */ 4451196d96dSreinoud if (*freeblks > ump->uncommitted_lbs[vpart_num]) { 446706de0e5Sreinoud *freeblks -= ump->uncommitted_lbs[vpart_num]; 4471196d96dSreinoud } else { 4481196d96dSreinoud *freeblks = 0; 4491196d96dSreinoud } 450706de0e5Sreinoud } 451706de0e5Sreinoud 452706de0e5Sreinoud /* --------------------------------------------------------------------- */ 453706de0e5Sreinoud 454e979c658Sreinoud int 455e979c658Sreinoud udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, 456e979c658Sreinoud uint32_t *lb_numres, uint32_t *extres) 457e979c658Sreinoud { 458e979c658Sreinoud struct part_desc *pdesc; 459e979c658Sreinoud struct spare_map_entry *sme; 460e979c658Sreinoud struct long_ad s_icb_loc; 461e979c658Sreinoud uint64_t foffset, end_foffset; 462e979c658Sreinoud uint32_t lb_size, len; 463e979c658Sreinoud uint32_t lb_num, lb_rel, lb_packet; 464e979c658Sreinoud uint32_t udf_rw32_lbmap, ext_offset; 465e979c658Sreinoud uint16_t vpart; 466e979c658Sreinoud int rel, part, error, eof, slot, flags; 467e979c658Sreinoud 468e979c658Sreinoud assert(ump && icb_loc && lb_numres); 469e979c658Sreinoud 470e979c658Sreinoud vpart = udf_rw16(icb_loc->loc.part_num); 471e979c658Sreinoud lb_num = udf_rw32(icb_loc->loc.lb_num); 472e979c658Sreinoud if (vpart > UDF_VTOP_RAWPART) 473e979c658Sreinoud return EINVAL; 474e979c658Sreinoud 475e979c658Sreinoud translate_again: 476e979c658Sreinoud part = ump->vtop[vpart]; 477e979c658Sreinoud pdesc = ump->partitions[part]; 478e979c658Sreinoud 479e979c658Sreinoud switch (ump->vtop_tp[vpart]) { 480e979c658Sreinoud case UDF_VTOP_TYPE_RAW : 481e979c658Sreinoud /* 1:1 to the end of the device */ 482e979c658Sreinoud *lb_numres = lb_num; 483e979c658Sreinoud *extres = INT_MAX; 484e979c658Sreinoud return 0; 485e979c658Sreinoud case UDF_VTOP_TYPE_PHYS : 486e979c658Sreinoud /* transform into its disc logical block */ 487e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 488e979c658Sreinoud return EINVAL; 489e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 490e979c658Sreinoud 491e979c658Sreinoud /* extent from here to the end of the partition */ 492e979c658Sreinoud *extres = udf_rw32(pdesc->part_len) - lb_num; 493e979c658Sreinoud return 0; 494e979c658Sreinoud case UDF_VTOP_TYPE_VIRT : 495e979c658Sreinoud /* only maps one logical block, lookup in VAT */ 496e979c658Sreinoud if (lb_num >= ump->vat_entries) /* XXX > or >= ? */ 497e979c658Sreinoud return EINVAL; 498e979c658Sreinoud 499e979c658Sreinoud /* lookup in virtual allocation table file */ 500e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 501e979c658Sreinoud error = udf_vat_read(ump->vat_node, 502e979c658Sreinoud (uint8_t *) &udf_rw32_lbmap, 4, 503e979c658Sreinoud ump->vat_offset + lb_num * 4); 504e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 505e979c658Sreinoud 506e979c658Sreinoud if (error) 507e979c658Sreinoud return error; 508e979c658Sreinoud 509e979c658Sreinoud lb_num = udf_rw32(udf_rw32_lbmap); 510e979c658Sreinoud 511e979c658Sreinoud /* transform into its disc logical block */ 512e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 513e979c658Sreinoud return EINVAL; 514e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 515e979c658Sreinoud 516e979c658Sreinoud /* just one logical block */ 517e979c658Sreinoud *extres = 1; 518e979c658Sreinoud return 0; 519e979c658Sreinoud case UDF_VTOP_TYPE_SPARABLE : 520e979c658Sreinoud /* check if the packet containing the lb_num is remapped */ 521e979c658Sreinoud lb_packet = lb_num / ump->sparable_packet_size; 522e979c658Sreinoud lb_rel = lb_num % ump->sparable_packet_size; 523e979c658Sreinoud 524e979c658Sreinoud for (rel = 0; rel < udf_rw16(ump->sparing_table->rt_l); rel++) { 525e979c658Sreinoud sme = &ump->sparing_table->entries[rel]; 526e979c658Sreinoud if (lb_packet == udf_rw32(sme->org)) { 527e979c658Sreinoud /* NOTE maps to absolute disc logical block! */ 528e979c658Sreinoud *lb_numres = udf_rw32(sme->map) + lb_rel; 529e979c658Sreinoud *extres = ump->sparable_packet_size - lb_rel; 530e979c658Sreinoud return 0; 531e979c658Sreinoud } 532e979c658Sreinoud } 533e979c658Sreinoud 534e979c658Sreinoud /* transform into its disc logical block */ 535e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 536e979c658Sreinoud return EINVAL; 537e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 538e979c658Sreinoud 539e979c658Sreinoud /* rest of block */ 540e979c658Sreinoud *extres = ump->sparable_packet_size - lb_rel; 541e979c658Sreinoud return 0; 542e979c658Sreinoud case UDF_VTOP_TYPE_META : 543e979c658Sreinoud /* we have to look into the file's allocation descriptors */ 544e979c658Sreinoud 545e979c658Sreinoud /* use metadatafile allocation mutex */ 546e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 547e979c658Sreinoud 548e979c658Sreinoud UDF_LOCK_NODE(ump->metadata_node, 0); 549e979c658Sreinoud 550e979c658Sreinoud /* get first overlapping extent */ 551e979c658Sreinoud foffset = 0; 552e979c658Sreinoud slot = 0; 553e979c658Sreinoud for (;;) { 554e979c658Sreinoud udf_get_adslot(ump->metadata_node, 555e979c658Sreinoud slot, &s_icb_loc, &eof); 556ca7a0d4eSreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, " 557ca7a0d4eSreinoud "len = %d, lb_num = %d, part = %d\n", 558ca7a0d4eSreinoud slot, eof, 559ca7a0d4eSreinoud UDF_EXT_FLAGS(udf_rw32(s_icb_loc.len)), 560ca7a0d4eSreinoud UDF_EXT_LEN(udf_rw32(s_icb_loc.len)), 561ca7a0d4eSreinoud udf_rw32(s_icb_loc.loc.lb_num), 562ca7a0d4eSreinoud udf_rw16(s_icb_loc.loc.part_num))); 563e979c658Sreinoud if (eof) { 564e979c658Sreinoud DPRINTF(TRANSLATE, 565e979c658Sreinoud ("Meta partition translation " 566e979c658Sreinoud "failed: can't seek location\n")); 567e979c658Sreinoud UDF_UNLOCK_NODE(ump->metadata_node, 0); 568e979c658Sreinoud return EINVAL; 569e979c658Sreinoud } 570e979c658Sreinoud len = udf_rw32(s_icb_loc.len); 571e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 572e979c658Sreinoud len = UDF_EXT_LEN(len); 573e979c658Sreinoud 574ca7a0d4eSreinoud if (flags == UDF_EXT_REDIRECT) { 575ca7a0d4eSreinoud slot++; 576ca7a0d4eSreinoud continue; 577ca7a0d4eSreinoud } 578ca7a0d4eSreinoud 579e979c658Sreinoud end_foffset = foffset + len; 580e979c658Sreinoud 581e6be79eaSreinoud if (end_foffset > (uint64_t) lb_num * lb_size) 582e979c658Sreinoud break; /* found */ 583e979c658Sreinoud foffset = end_foffset; 584e979c658Sreinoud slot++; 585e979c658Sreinoud } 586e979c658Sreinoud /* found overlapping slot */ 587e979c658Sreinoud ext_offset = lb_num * lb_size - foffset; 588e979c658Sreinoud 589e979c658Sreinoud /* process extent offset */ 590e979c658Sreinoud lb_num = udf_rw32(s_icb_loc.loc.lb_num); 591e979c658Sreinoud vpart = udf_rw16(s_icb_loc.loc.part_num); 592e979c658Sreinoud lb_num += (ext_offset + lb_size -1) / lb_size; 593e979c658Sreinoud ext_offset = 0; 594e979c658Sreinoud 595e979c658Sreinoud UDF_UNLOCK_NODE(ump->metadata_node, 0); 596e979c658Sreinoud if (flags != UDF_EXT_ALLOCATED) { 597e979c658Sreinoud DPRINTF(TRANSLATE, ("Metadata partition translation " 598e979c658Sreinoud "failed: not allocated\n")); 599e979c658Sreinoud return EINVAL; 600e979c658Sreinoud } 601e979c658Sreinoud 602e979c658Sreinoud /* 603e979c658Sreinoud * vpart and lb_num are updated, translate again since we 604e979c658Sreinoud * might be mapped on sparable media 605e979c658Sreinoud */ 606e979c658Sreinoud goto translate_again; 607e979c658Sreinoud default: 608e979c658Sreinoud printf("UDF vtop translation scheme %d unimplemented yet\n", 609e979c658Sreinoud ump->vtop_tp[vpart]); 610e979c658Sreinoud } 611e979c658Sreinoud 612e979c658Sreinoud return EINVAL; 613e979c658Sreinoud } 614e979c658Sreinoud 61571c9aa33Sreinoud 61671c9aa33Sreinoud /* XXX provisional primitive braindead version */ 61771c9aa33Sreinoud /* TODO use ext_res */ 61871c9aa33Sreinoud void 61971c9aa33Sreinoud udf_translate_vtop_list(struct udf_mount *ump, uint32_t sectors, 62071c9aa33Sreinoud uint16_t vpart_num, uint64_t *lmapping, uint64_t *pmapping) 62171c9aa33Sreinoud { 62271c9aa33Sreinoud struct long_ad loc; 62371c9aa33Sreinoud uint32_t lb_numres, ext_res; 62471c9aa33Sreinoud int sector; 62571c9aa33Sreinoud 62671c9aa33Sreinoud for (sector = 0; sector < sectors; sector++) { 62771c9aa33Sreinoud memset(&loc, 0, sizeof(struct long_ad)); 62871c9aa33Sreinoud loc.loc.part_num = udf_rw16(vpart_num); 62971c9aa33Sreinoud loc.loc.lb_num = udf_rw32(*lmapping); 63071c9aa33Sreinoud udf_translate_vtop(ump, &loc, &lb_numres, &ext_res); 63171c9aa33Sreinoud *pmapping = lb_numres; 63271c9aa33Sreinoud lmapping++; pmapping++; 63371c9aa33Sreinoud } 63471c9aa33Sreinoud } 63571c9aa33Sreinoud 63671c9aa33Sreinoud 637e979c658Sreinoud /* --------------------------------------------------------------------- */ 638e979c658Sreinoud 639e979c658Sreinoud /* 640e979c658Sreinoud * Translate an extent (in logical_blocks) into logical block numbers; used 641e979c658Sreinoud * for read and write operations. DOESNT't check extents. 642e979c658Sreinoud */ 643e979c658Sreinoud 644e979c658Sreinoud int 645e979c658Sreinoud udf_translate_file_extent(struct udf_node *udf_node, 646e979c658Sreinoud uint32_t from, uint32_t num_lb, 647e979c658Sreinoud uint64_t *map) 648e979c658Sreinoud { 649e979c658Sreinoud struct udf_mount *ump; 650e979c658Sreinoud struct icb_tag *icbtag; 651e979c658Sreinoud struct long_ad t_ad, s_ad; 652e979c658Sreinoud uint64_t transsec; 653e979c658Sreinoud uint64_t foffset, end_foffset; 654e979c658Sreinoud uint32_t transsec32; 655e979c658Sreinoud uint32_t lb_size; 656e979c658Sreinoud uint32_t ext_offset; 657e979c658Sreinoud uint32_t lb_num, len; 658e979c658Sreinoud uint32_t overlap, translen; 659e979c658Sreinoud uint16_t vpart_num; 660e979c658Sreinoud int eof, error, flags; 661e979c658Sreinoud int slot, addr_type, icbflags; 662e979c658Sreinoud 663e979c658Sreinoud if (!udf_node) 664e979c658Sreinoud return ENOENT; 665e979c658Sreinoud 666e979c658Sreinoud KASSERT(num_lb > 0); 667e979c658Sreinoud 668e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 669e979c658Sreinoud 670e979c658Sreinoud /* initialise derivative vars */ 671e979c658Sreinoud ump = udf_node->ump; 672e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 673e979c658Sreinoud 674e979c658Sreinoud if (udf_node->fe) { 675e979c658Sreinoud icbtag = &udf_node->fe->icbtag; 676e979c658Sreinoud } else { 677e979c658Sreinoud icbtag = &udf_node->efe->icbtag; 678e979c658Sreinoud } 679e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 680e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 681e979c658Sreinoud 682e979c658Sreinoud /* do the work */ 683e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 684e979c658Sreinoud *map = UDF_TRANS_INTERN; 685e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 686e979c658Sreinoud return 0; 687e979c658Sreinoud } 688e979c658Sreinoud 689e979c658Sreinoud /* find first overlapping extent */ 690e979c658Sreinoud foffset = 0; 691e979c658Sreinoud slot = 0; 692e979c658Sreinoud for (;;) { 693e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 694e5ee8341Sreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, len = %d, " 695e5ee8341Sreinoud "lb_num = %d, part = %d\n", slot, eof, 696e5ee8341Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)), 697e5ee8341Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 698e5ee8341Sreinoud udf_rw32(s_ad.loc.lb_num), 699e5ee8341Sreinoud udf_rw16(s_ad.loc.part_num))); 700e979c658Sreinoud if (eof) { 701e979c658Sreinoud DPRINTF(TRANSLATE, 702e979c658Sreinoud ("Translate file extent " 703e979c658Sreinoud "failed: can't seek location\n")); 704e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 705e979c658Sreinoud return EINVAL; 706e979c658Sreinoud } 707e979c658Sreinoud len = udf_rw32(s_ad.len); 708e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 709e979c658Sreinoud len = UDF_EXT_LEN(len); 710e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 711e979c658Sreinoud 712e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 713e979c658Sreinoud slot++; 714e979c658Sreinoud continue; 715e979c658Sreinoud } 716e979c658Sreinoud 717e979c658Sreinoud end_foffset = foffset + len; 718e979c658Sreinoud 719e6be79eaSreinoud if (end_foffset > (uint64_t) from * lb_size) 720e979c658Sreinoud break; /* found */ 721e979c658Sreinoud foffset = end_foffset; 722e979c658Sreinoud slot++; 723e979c658Sreinoud } 724e979c658Sreinoud /* found overlapping slot */ 725e6be79eaSreinoud ext_offset = (uint64_t) from * lb_size - foffset; 726e979c658Sreinoud 727e979c658Sreinoud for (;;) { 728e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 729e5ee8341Sreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, len = %d, " 730e5ee8341Sreinoud "lb_num = %d, part = %d\n", slot, eof, 731e5ee8341Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)), 732e5ee8341Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 733e5ee8341Sreinoud udf_rw32(s_ad.loc.lb_num), 734e5ee8341Sreinoud udf_rw16(s_ad.loc.part_num))); 735e979c658Sreinoud if (eof) { 736e979c658Sreinoud DPRINTF(TRANSLATE, 737e979c658Sreinoud ("Translate file extent " 738e979c658Sreinoud "failed: past eof\n")); 739e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 740e979c658Sreinoud return EINVAL; 741e979c658Sreinoud } 742e979c658Sreinoud 743e979c658Sreinoud len = udf_rw32(s_ad.len); 744e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 745e979c658Sreinoud len = UDF_EXT_LEN(len); 746e979c658Sreinoud 747e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 748e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 749e979c658Sreinoud 750e979c658Sreinoud end_foffset = foffset + len; 751e979c658Sreinoud 752e979c658Sreinoud /* process extent, don't forget to advance on ext_offset! */ 753e979c658Sreinoud lb_num += (ext_offset + lb_size -1) / lb_size; 754e979c658Sreinoud overlap = (len - ext_offset + lb_size -1) / lb_size; 755e979c658Sreinoud ext_offset = 0; 756e979c658Sreinoud 757e979c658Sreinoud /* 758e979c658Sreinoud * note that the while(){} is nessisary for the extent that 759e979c658Sreinoud * the udf_translate_vtop() returns doens't have to span the 760e979c658Sreinoud * whole extent. 761e979c658Sreinoud */ 762e979c658Sreinoud 763e979c658Sreinoud overlap = MIN(overlap, num_lb); 764e5ee8341Sreinoud while (overlap && (flags != UDF_EXT_REDIRECT)) { 765e979c658Sreinoud switch (flags) { 766e979c658Sreinoud case UDF_EXT_FREE : 767e979c658Sreinoud case UDF_EXT_ALLOCATED_BUT_NOT_USED : 768e979c658Sreinoud transsec = UDF_TRANS_ZERO; 769e979c658Sreinoud translen = overlap; 770e979c658Sreinoud while (overlap && num_lb && translen) { 771e979c658Sreinoud *map++ = transsec; 772e979c658Sreinoud lb_num++; 773e979c658Sreinoud overlap--; num_lb--; translen--; 774e979c658Sreinoud } 775e979c658Sreinoud break; 776e979c658Sreinoud case UDF_EXT_ALLOCATED : 777e979c658Sreinoud t_ad.loc.lb_num = udf_rw32(lb_num); 778e979c658Sreinoud t_ad.loc.part_num = udf_rw16(vpart_num); 779e979c658Sreinoud error = udf_translate_vtop(ump, 780e979c658Sreinoud &t_ad, &transsec32, &translen); 781e979c658Sreinoud transsec = transsec32; 782e979c658Sreinoud if (error) { 783e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 784e979c658Sreinoud return error; 785e979c658Sreinoud } 786e979c658Sreinoud while (overlap && num_lb && translen) { 787e979c658Sreinoud *map++ = transsec; 788e979c658Sreinoud lb_num++; transsec++; 789e979c658Sreinoud overlap--; num_lb--; translen--; 790e979c658Sreinoud } 791e979c658Sreinoud break; 792e5ee8341Sreinoud default: 793e5ee8341Sreinoud DPRINTF(TRANSLATE, 794e5ee8341Sreinoud ("Translate file extent " 795e5ee8341Sreinoud "failed: bad flags %x\n", flags)); 796e5ee8341Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 797e5ee8341Sreinoud return EINVAL; 798e979c658Sreinoud } 799e979c658Sreinoud } 800e979c658Sreinoud if (num_lb == 0) 801e979c658Sreinoud break; 802e979c658Sreinoud 803e979c658Sreinoud if (flags != UDF_EXT_REDIRECT) 804e979c658Sreinoud foffset = end_foffset; 805e979c658Sreinoud slot++; 806e979c658Sreinoud } 807e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 808e979c658Sreinoud 809e979c658Sreinoud return 0; 810e979c658Sreinoud } 811e979c658Sreinoud 812e979c658Sreinoud /* --------------------------------------------------------------------- */ 813e979c658Sreinoud 814e979c658Sreinoud static int 815e979c658Sreinoud udf_search_free_vatloc(struct udf_mount *ump, uint32_t *lbnumres) 816e979c658Sreinoud { 817e979c658Sreinoud uint32_t lb_size, lb_num, lb_map, udf_rw32_lbmap; 818e979c658Sreinoud uint8_t *blob; 819e979c658Sreinoud int entry, chunk, found, error; 820e979c658Sreinoud 821e979c658Sreinoud KASSERT(ump); 822e979c658Sreinoud KASSERT(ump->logical_vol); 823e979c658Sreinoud 824e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 825e979c658Sreinoud blob = malloc(lb_size, M_UDFTEMP, M_WAITOK); 826e979c658Sreinoud 827e979c658Sreinoud /* TODO static allocation of search chunk */ 828e979c658Sreinoud 829e979c658Sreinoud lb_num = MIN(ump->vat_entries, ump->vat_last_free_lb); 830e979c658Sreinoud found = 0; 831e979c658Sreinoud error = 0; 832e979c658Sreinoud entry = 0; 833e979c658Sreinoud do { 834e979c658Sreinoud chunk = MIN(lb_size, (ump->vat_entries - lb_num) * 4); 835e979c658Sreinoud if (chunk <= 0) 836e979c658Sreinoud break; 837e979c658Sreinoud /* load in chunk */ 838e979c658Sreinoud error = udf_vat_read(ump->vat_node, blob, chunk, 839e979c658Sreinoud ump->vat_offset + lb_num * 4); 840e979c658Sreinoud 841e979c658Sreinoud if (error) 842e979c658Sreinoud break; 843e979c658Sreinoud 844e979c658Sreinoud /* search this chunk */ 845e979c658Sreinoud for (entry=0; entry < chunk /4; entry++, lb_num++) { 846e979c658Sreinoud udf_rw32_lbmap = *((uint32_t *) (blob + entry * 4)); 847e979c658Sreinoud lb_map = udf_rw32(udf_rw32_lbmap); 848e979c658Sreinoud if (lb_map == 0xffffffff) { 849e979c658Sreinoud found = 1; 850e979c658Sreinoud break; 851e979c658Sreinoud } 852e979c658Sreinoud } 853e979c658Sreinoud } while (!found); 854e979c658Sreinoud if (error) { 855e979c658Sreinoud printf("udf_search_free_vatloc: error reading in vat chunk " 856e979c658Sreinoud "(lb %d, size %d)\n", lb_num, chunk); 857e979c658Sreinoud } 858e979c658Sreinoud 859e979c658Sreinoud if (!found) { 860e979c658Sreinoud /* extend VAT */ 861e979c658Sreinoud DPRINTF(WRITE, ("udf_search_free_vatloc: extending\n")); 862e979c658Sreinoud lb_num = ump->vat_entries; 863e979c658Sreinoud ump->vat_entries++; 864e979c658Sreinoud } 865e979c658Sreinoud 866e979c658Sreinoud /* mark entry with initialiser just in case */ 867e979c658Sreinoud lb_map = udf_rw32(0xfffffffe); 868e979c658Sreinoud udf_vat_write(ump->vat_node, (uint8_t *) &lb_map, 4, 869e979c658Sreinoud ump->vat_offset + lb_num *4); 870e979c658Sreinoud ump->vat_last_free_lb = lb_num; 871e979c658Sreinoud 872e979c658Sreinoud free(blob, M_UDFTEMP); 873e979c658Sreinoud *lbnumres = lb_num; 874e979c658Sreinoud return 0; 875e979c658Sreinoud } 876e979c658Sreinoud 877e979c658Sreinoud 878e979c658Sreinoud static void 879e979c658Sreinoud udf_bitmap_allocate(struct udf_bitmap *bitmap, int ismetadata, 88071c9aa33Sreinoud uint32_t *num_lb, uint64_t *lmappos) 881e979c658Sreinoud { 882e979c658Sreinoud uint32_t offset, lb_num, bit; 883e979c658Sreinoud int32_t diff; 884e979c658Sreinoud uint8_t *bpos; 885e979c658Sreinoud int pass; 886e979c658Sreinoud 887e979c658Sreinoud if (!ismetadata) { 888e979c658Sreinoud /* heuristic to keep the two pointers not too close */ 889e979c658Sreinoud diff = bitmap->data_pos - bitmap->metadata_pos; 890e979c658Sreinoud if ((diff >= 0) && (diff < 1024)) 891e979c658Sreinoud bitmap->data_pos = bitmap->metadata_pos + 1024; 892e979c658Sreinoud } 893e979c658Sreinoud offset = ismetadata ? bitmap->metadata_pos : bitmap->data_pos; 894e979c658Sreinoud offset &= ~7; 895e979c658Sreinoud for (pass = 0; pass < 2; pass++) { 896e979c658Sreinoud if (offset >= bitmap->max_offset) 897e979c658Sreinoud offset = 0; 898e979c658Sreinoud 899e979c658Sreinoud while (offset < bitmap->max_offset) { 900e979c658Sreinoud if (*num_lb == 0) 901e979c658Sreinoud break; 902e979c658Sreinoud 903e979c658Sreinoud /* use first bit not set */ 904e979c658Sreinoud bpos = bitmap->bits + offset/8; 9055eeb4f69Sreinoud bit = ffs(*bpos); /* returns 0 or 1..8 */ 906e979c658Sreinoud if (bit == 0) { 907e979c658Sreinoud offset += 8; 908e979c658Sreinoud continue; 909e979c658Sreinoud } 910b9f5db93Sreinoud 911b9f5db93Sreinoud /* check for ffs overshoot */ 912b9f5db93Sreinoud if (offset + bit-1 >= bitmap->max_offset) { 913b9f5db93Sreinoud offset = bitmap->max_offset; 914b9f5db93Sreinoud break; 915b9f5db93Sreinoud } 916b9f5db93Sreinoud 9175eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : allocate %d, %p, bit %d\n", 9185eeb4f69Sreinoud offset + bit -1, bpos, bit-1)); 919e979c658Sreinoud *bpos &= ~(1 << (bit-1)); 920e979c658Sreinoud lb_num = offset + bit-1; 921e979c658Sreinoud *lmappos++ = lb_num; 922e979c658Sreinoud *num_lb = *num_lb - 1; 923e979c658Sreinoud // offset = (offset & ~7); 924e979c658Sreinoud } 925e979c658Sreinoud } 926e979c658Sreinoud 927e979c658Sreinoud if (ismetadata) { 928e979c658Sreinoud bitmap->metadata_pos = offset; 929e979c658Sreinoud } else { 930e979c658Sreinoud bitmap->data_pos = offset; 931e979c658Sreinoud } 932e979c658Sreinoud } 933e979c658Sreinoud 934e979c658Sreinoud 935e979c658Sreinoud static void 936e979c658Sreinoud udf_bitmap_free(struct udf_bitmap *bitmap, uint32_t lb_num, uint32_t num_lb) 937e979c658Sreinoud { 938e979c658Sreinoud uint32_t offset; 939e979c658Sreinoud uint32_t bit, bitval; 940e979c658Sreinoud uint8_t *bpos; 941e979c658Sreinoud 942e979c658Sreinoud offset = lb_num; 943e979c658Sreinoud 944e979c658Sreinoud /* starter bits */ 945e979c658Sreinoud bpos = bitmap->bits + offset/8; 946e979c658Sreinoud bit = offset % 8; 947e979c658Sreinoud while ((bit != 0) && (num_lb > 0)) { 948e979c658Sreinoud bitval = (1 << bit); 949e979c658Sreinoud KASSERT((*bpos & bitval) == 0); 9505eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : free %d, %p, %d\n", 9515eeb4f69Sreinoud offset, bpos, bit)); 952e979c658Sreinoud *bpos |= bitval; 953e979c658Sreinoud offset++; num_lb--; 954e979c658Sreinoud bit = (bit + 1) % 8; 955e979c658Sreinoud } 956e979c658Sreinoud if (num_lb == 0) 957e979c658Sreinoud return; 958e979c658Sreinoud 959e979c658Sreinoud /* whole bytes */ 960e979c658Sreinoud KASSERT(bit == 0); 961e979c658Sreinoud bpos = bitmap->bits + offset / 8; 962e979c658Sreinoud while (num_lb >= 8) { 963e979c658Sreinoud KASSERT((*bpos == 0)); 9645eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : free %d + 8, %p\n", offset, bpos)); 965e979c658Sreinoud *bpos = 255; 966e979c658Sreinoud offset += 8; num_lb -= 8; 967e979c658Sreinoud bpos++; 968e979c658Sreinoud } 969e979c658Sreinoud 970e979c658Sreinoud /* stop bits */ 971e979c658Sreinoud KASSERT(num_lb < 8); 972e979c658Sreinoud bit = 0; 973e979c658Sreinoud while (num_lb > 0) { 974e979c658Sreinoud bitval = (1 << bit); 975e979c658Sreinoud KASSERT((*bpos & bitval) == 0); 9765eeb4f69Sreinoud DPRINTF(PARANOIA, ("XXX : free %d, %p, %d\n", 9775eeb4f69Sreinoud offset, bpos, bit)); 978e979c658Sreinoud *bpos |= bitval; 979e979c658Sreinoud offset++; num_lb--; 980e979c658Sreinoud bit = (bit + 1) % 8; 981e979c658Sreinoud } 982e979c658Sreinoud } 983e979c658Sreinoud 9841196d96dSreinoud 9851196d96dSreinoud static uint32_t 9861196d96dSreinoud udf_bitmap_check_trunc_free(struct udf_bitmap *bitmap, uint32_t to_trunc) 9871196d96dSreinoud { 9881196d96dSreinoud uint32_t seq_free, offset; 9891196d96dSreinoud uint8_t *bpos; 9901196d96dSreinoud uint8_t bit, bitval; 9911196d96dSreinoud 9921196d96dSreinoud DPRINTF(RESERVE, ("\ttrying to trunc %d bits from bitmap\n", to_trunc)); 9931196d96dSreinoud offset = bitmap->max_offset - to_trunc; 9941196d96dSreinoud 9951196d96dSreinoud /* starter bits (if any) */ 9961196d96dSreinoud bpos = bitmap->bits + offset/8; 9971196d96dSreinoud bit = offset % 8; 9981196d96dSreinoud seq_free = 0; 9991196d96dSreinoud while (to_trunc > 0) { 10001196d96dSreinoud seq_free++; 10011196d96dSreinoud bitval = (1 << bit); 10021196d96dSreinoud if (!(*bpos & bitval)) 10031196d96dSreinoud seq_free = 0; 10040162ff03Schristos to_trunc--; 10051196d96dSreinoud bit++; 10061196d96dSreinoud if (bit == 8) { 10071196d96dSreinoud bpos++; 10081196d96dSreinoud bit = 0; 10091196d96dSreinoud } 10101196d96dSreinoud } 10111196d96dSreinoud 10121196d96dSreinoud DPRINTF(RESERVE, ("\tfound %d sequential free bits in bitmap\n", seq_free)); 10131196d96dSreinoud return seq_free; 10141196d96dSreinoud } 10151196d96dSreinoud 1016706de0e5Sreinoud /* --------------------------------------------------------------------- */ 1017e979c658Sreinoud 1018706de0e5Sreinoud /* 1019706de0e5Sreinoud * We check for overall disc space with a margin to prevent critical 1020706de0e5Sreinoud * conditions. If disc space is low we try to force a sync() to improve our 1021706de0e5Sreinoud * estimates. When confronted with meta-data partition size shortage we know 1022706de0e5Sreinoud * we have to check if it can be extended and we need to extend it when 1023706de0e5Sreinoud * needed. 1024706de0e5Sreinoud * 1025706de0e5Sreinoud * A 2nd strategy we could use when disc space is getting low on a disc 1026706de0e5Sreinoud * formatted with a meta-data partition is to see if there are sparse areas in 1027706de0e5Sreinoud * the meta-data partition and free blocks there for extra data. 1028706de0e5Sreinoud */ 1029706de0e5Sreinoud 1030706de0e5Sreinoud void 1031706de0e5Sreinoud udf_do_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, 1032706de0e5Sreinoud uint16_t vpart_num, uint32_t num_lb) 1033706de0e5Sreinoud { 1034706de0e5Sreinoud ump->uncommitted_lbs[vpart_num] += num_lb; 1035706de0e5Sreinoud if (udf_node) 1036706de0e5Sreinoud udf_node->uncommitted_lbs += num_lb; 1037706de0e5Sreinoud } 1038706de0e5Sreinoud 1039706de0e5Sreinoud 1040706de0e5Sreinoud void 1041706de0e5Sreinoud udf_do_unreserve_space(struct udf_mount *ump, struct udf_node *udf_node, 1042706de0e5Sreinoud uint16_t vpart_num, uint32_t num_lb) 1043706de0e5Sreinoud { 1044706de0e5Sreinoud ump->uncommitted_lbs[vpart_num] -= num_lb; 1045706de0e5Sreinoud if (ump->uncommitted_lbs[vpart_num] < 0) { 1046706de0e5Sreinoud DPRINTF(RESERVE, ("UDF: underflow on partition reservation, " 1047706de0e5Sreinoud "part %d: %d\n", vpart_num, 1048706de0e5Sreinoud ump->uncommitted_lbs[vpart_num])); 1049706de0e5Sreinoud ump->uncommitted_lbs[vpart_num] = 0; 1050706de0e5Sreinoud } 1051706de0e5Sreinoud if (udf_node) { 1052706de0e5Sreinoud udf_node->uncommitted_lbs -= num_lb; 1053706de0e5Sreinoud if (udf_node->uncommitted_lbs < 0) { 1054706de0e5Sreinoud DPRINTF(RESERVE, ("UDF: underflow of node " 1055706de0e5Sreinoud "reservation : %d\n", 1056706de0e5Sreinoud udf_node->uncommitted_lbs)); 1057706de0e5Sreinoud udf_node->uncommitted_lbs = 0; 1058706de0e5Sreinoud } 1059706de0e5Sreinoud } 1060706de0e5Sreinoud } 1061706de0e5Sreinoud 1062706de0e5Sreinoud 1063706de0e5Sreinoud int 1064706de0e5Sreinoud udf_reserve_space(struct udf_mount *ump, struct udf_node *udf_node, 1065706de0e5Sreinoud int udf_c_type, uint16_t vpart_num, uint32_t num_lb, int can_fail) 1066706de0e5Sreinoud { 1067706de0e5Sreinoud uint64_t freeblks; 1068706de0e5Sreinoud uint64_t slack; 1069706de0e5Sreinoud int i, error; 1070706de0e5Sreinoud 1071706de0e5Sreinoud slack = 0; 1072706de0e5Sreinoud if (can_fail) 1073706de0e5Sreinoud slack = UDF_DISC_SLACK; 1074706de0e5Sreinoud 1075706de0e5Sreinoud error = 0; 1076706de0e5Sreinoud mutex_enter(&ump->allocate_mutex); 1077706de0e5Sreinoud 1078706de0e5Sreinoud /* check if there is enough space available */ 10791196d96dSreinoud for (i = 0; i < 3; i++) { /* XXX arbitrary number */ 1080706de0e5Sreinoud udf_calc_vpart_freespace(ump, vpart_num, &freeblks); 1081706de0e5Sreinoud if (num_lb + slack < freeblks) 1082706de0e5Sreinoud break; 1083706de0e5Sreinoud /* issue SYNC */ 1084706de0e5Sreinoud DPRINTF(RESERVE, ("udf_reserve_space: issuing sync\n")); 1085706de0e5Sreinoud mutex_exit(&ump->allocate_mutex); 1086706de0e5Sreinoud udf_do_sync(ump, FSCRED, 0); 10871196d96dSreinoud /* 1/8 second wait */ 1088ed215c41Shannken kpause("udfsync2", false, hz/8, NULL); 1089706de0e5Sreinoud mutex_enter(&ump->allocate_mutex); 1090706de0e5Sreinoud } 1091706de0e5Sreinoud 1092706de0e5Sreinoud /* check if there is enough space available now */ 1093706de0e5Sreinoud udf_calc_vpart_freespace(ump, vpart_num, &freeblks); 1094706de0e5Sreinoud if (num_lb + slack >= freeblks) { 10951196d96dSreinoud DPRINTF(RESERVE, ("udf_reserve_space: try to redistribute " 10961196d96dSreinoud "partition space\n")); 10971196d96dSreinoud DPRINTF(RESERVE, ("\tvpart %d, type %d is full\n", 10981196d96dSreinoud vpart_num, ump->vtop_alloc[vpart_num])); 10991196d96dSreinoud /* Try to redistribute space if possible */ 11001196d96dSreinoud udf_collect_free_space_for_vpart(ump, vpart_num, num_lb + slack); 1101706de0e5Sreinoud } 1102706de0e5Sreinoud 1103706de0e5Sreinoud /* check if there is enough space available now */ 1104706de0e5Sreinoud udf_calc_vpart_freespace(ump, vpart_num, &freeblks); 1105706de0e5Sreinoud if (num_lb + slack <= freeblks) { 1106706de0e5Sreinoud udf_do_reserve_space(ump, udf_node, vpart_num, num_lb); 1107706de0e5Sreinoud } else { 1108706de0e5Sreinoud DPRINTF(RESERVE, ("udf_reserve_space: out of disc space\n")); 1109706de0e5Sreinoud error = ENOSPC; 1110706de0e5Sreinoud } 1111706de0e5Sreinoud 1112706de0e5Sreinoud mutex_exit(&ump->allocate_mutex); 1113706de0e5Sreinoud return error; 1114706de0e5Sreinoud } 1115706de0e5Sreinoud 1116706de0e5Sreinoud 1117706de0e5Sreinoud void 1118706de0e5Sreinoud udf_cleanup_reservation(struct udf_node *udf_node) 1119706de0e5Sreinoud { 1120706de0e5Sreinoud struct udf_mount *ump = udf_node->ump; 1121706de0e5Sreinoud int vpart_num; 1122706de0e5Sreinoud 1123706de0e5Sreinoud mutex_enter(&ump->allocate_mutex); 1124706de0e5Sreinoud 1125706de0e5Sreinoud /* compensate for overlapping blocks */ 1126706de0e5Sreinoud DPRINTF(RESERVE, ("UDF: overlapped %d blocks in count\n", udf_node->uncommitted_lbs)); 1127706de0e5Sreinoud 1128706de0e5Sreinoud vpart_num = udf_get_record_vpart(ump, udf_get_c_type(udf_node)); 1129706de0e5Sreinoud udf_do_unreserve_space(ump, udf_node, vpart_num, udf_node->uncommitted_lbs); 1130706de0e5Sreinoud 1131706de0e5Sreinoud DPRINTF(RESERVE, ("\ttotal now %d\n", ump->uncommitted_lbs[vpart_num])); 1132706de0e5Sreinoud 1133706de0e5Sreinoud /* sanity */ 1134706de0e5Sreinoud if (ump->uncommitted_lbs[vpart_num] < 0) 1135706de0e5Sreinoud ump->uncommitted_lbs[vpart_num] = 0; 1136706de0e5Sreinoud 1137706de0e5Sreinoud mutex_exit(&ump->allocate_mutex); 1138706de0e5Sreinoud } 1139706de0e5Sreinoud 1140706de0e5Sreinoud /* --------------------------------------------------------------------- */ 1141706de0e5Sreinoud 1142706de0e5Sreinoud /* 1143706de0e5Sreinoud * Allocate an extent of given length on given virt. partition. It doesn't 1144706de0e5Sreinoud * have to be one stretch. 1145706de0e5Sreinoud */ 1146706de0e5Sreinoud 1147706de0e5Sreinoud int 1148706de0e5Sreinoud udf_allocate_space(struct udf_mount *ump, struct udf_node *udf_node, 1149706de0e5Sreinoud int udf_c_type, uint16_t vpart_num, uint32_t num_lb, uint64_t *lmapping) 1150e979c658Sreinoud { 1151e979c658Sreinoud struct mmc_trackinfo *alloc_track, *other_track; 1152e979c658Sreinoud struct udf_bitmap *bitmap; 1153e979c658Sreinoud struct part_desc *pdesc; 1154e979c658Sreinoud struct logvol_int_desc *lvid; 115571c9aa33Sreinoud uint64_t *lmappos; 1156e979c658Sreinoud uint32_t ptov, lb_num, *freepos, free_lbs; 1157a721b8c1Smrg int lb_size __diagused, alloc_num_lb; 1158a287d23dSreinoud int alloc_type, error; 1159a287d23dSreinoud int is_node; 1160e979c658Sreinoud 1161a287d23dSreinoud DPRINTF(CALL, ("udf_allocate_space(ctype %d, vpart %d, num_lb %d\n", 1162a287d23dSreinoud udf_c_type, vpart_num, num_lb)); 1163e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 1164e979c658Sreinoud 1165e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 1166e979c658Sreinoud KASSERT(lb_size == ump->discinfo.sector_size); 1167e979c658Sreinoud 1168a287d23dSreinoud alloc_type = ump->vtop_alloc[vpart_num]; 1169a287d23dSreinoud is_node = (udf_c_type == UDF_C_NODE); 1170e979c658Sreinoud 1171e979c658Sreinoud lmappos = lmapping; 117271c9aa33Sreinoud error = 0; 1173e979c658Sreinoud switch (alloc_type) { 1174e979c658Sreinoud case UDF_ALLOC_VAT : 1175e979c658Sreinoud /* search empty slot in VAT file */ 1176e979c658Sreinoud KASSERT(num_lb == 1); 1177e979c658Sreinoud error = udf_search_free_vatloc(ump, &lb_num); 1178706de0e5Sreinoud if (!error) { 1179e979c658Sreinoud *lmappos = lb_num; 1180706de0e5Sreinoud 1181706de0e5Sreinoud /* reserve on the backing sequential partition since 1182706de0e5Sreinoud * that partition is credited back later */ 1183706de0e5Sreinoud udf_do_reserve_space(ump, udf_node, 1184706de0e5Sreinoud ump->vtop[vpart_num], num_lb); 1185706de0e5Sreinoud } 1186e979c658Sreinoud break; 1187e979c658Sreinoud case UDF_ALLOC_SEQUENTIAL : 1188e979c658Sreinoud /* sequential allocation on recordable media */ 1189a287d23dSreinoud /* get partition backing up this vpart_num_num */ 1190a287d23dSreinoud pdesc = ump->partitions[ump->vtop[vpart_num]]; 119171c9aa33Sreinoud 1192e979c658Sreinoud /* calculate offset from physical base partition */ 1193e979c658Sreinoud ptov = udf_rw32(pdesc->start_loc); 1194e979c658Sreinoud 1195a287d23dSreinoud /* get our track descriptors */ 1196a287d23dSreinoud if (vpart_num == ump->node_part) { 1197a287d23dSreinoud alloc_track = &ump->metadata_track; 1198a287d23dSreinoud other_track = &ump->data_track; 1199a287d23dSreinoud } else { 1200a287d23dSreinoud alloc_track = &ump->data_track; 1201a287d23dSreinoud other_track = &ump->metadata_track; 1202a287d23dSreinoud } 1203a287d23dSreinoud 1204a287d23dSreinoud /* allocate */ 1205e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 1206e979c658Sreinoud *lmappos++ = alloc_track->next_writable - ptov; 1207e979c658Sreinoud alloc_track->next_writable++; 1208e979c658Sreinoud alloc_track->free_blocks--; 1209e979c658Sreinoud } 1210a287d23dSreinoud 1211a287d23dSreinoud /* keep other track up-to-date */ 1212e979c658Sreinoud if (alloc_track->tracknr == other_track->tracknr) 1213e979c658Sreinoud memcpy(other_track, alloc_track, 1214e979c658Sreinoud sizeof(struct mmc_trackinfo)); 1215e979c658Sreinoud break; 1216e979c658Sreinoud case UDF_ALLOC_SPACEMAP : 121771c9aa33Sreinoud /* try to allocate on unallocated bits */ 1218e979c658Sreinoud alloc_num_lb = num_lb; 1219a287d23dSreinoud bitmap = &ump->part_unalloc_bits[vpart_num]; 1220a287d23dSreinoud udf_bitmap_allocate(bitmap, is_node, &alloc_num_lb, lmappos); 1221e979c658Sreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 122271c9aa33Sreinoud 122371c9aa33Sreinoud /* have we allocated all? */ 1224e979c658Sreinoud if (alloc_num_lb) { 1225e979c658Sreinoud /* TODO convert freed to unalloc and try again */ 1226e979c658Sreinoud /* free allocated piece for now */ 1227e979c658Sreinoud lmappos = lmapping; 1228e979c658Sreinoud for (lb_num=0; lb_num < num_lb-alloc_num_lb; lb_num++) { 1229e979c658Sreinoud udf_bitmap_free(bitmap, *lmappos++, 1); 1230e979c658Sreinoud } 1231e979c658Sreinoud error = ENOSPC; 1232e979c658Sreinoud } 1233e979c658Sreinoud if (!error) { 1234e979c658Sreinoud /* adjust freecount */ 1235e979c658Sreinoud lvid = ump->logvol_integrity; 1236a287d23dSreinoud freepos = &lvid->tables[0] + vpart_num; 1237e979c658Sreinoud free_lbs = udf_rw32(*freepos); 1238e979c658Sreinoud *freepos = udf_rw32(free_lbs - num_lb); 1239e979c658Sreinoud } 1240e979c658Sreinoud break; 12413653a532Sreinoud case UDF_ALLOC_METABITMAP : /* UDF 2.50, 2.60 BluRay-RE */ 124271c9aa33Sreinoud /* allocate on metadata unallocated bits */ 124371c9aa33Sreinoud alloc_num_lb = num_lb; 124471c9aa33Sreinoud bitmap = &ump->metadata_unalloc_bits; 1245a287d23dSreinoud udf_bitmap_allocate(bitmap, is_node, &alloc_num_lb, lmappos); 124671c9aa33Sreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 124771c9aa33Sreinoud 124871c9aa33Sreinoud /* have we allocated all? */ 1249a287d23dSreinoud if (alloc_num_lb) { 125071c9aa33Sreinoud /* YIKES! TODO we need to extend the metadata partition */ 125171c9aa33Sreinoud /* free allocated piece for now */ 125271c9aa33Sreinoud lmappos = lmapping; 125371c9aa33Sreinoud for (lb_num=0; lb_num < num_lb-alloc_num_lb; lb_num++) { 125471c9aa33Sreinoud udf_bitmap_free(bitmap, *lmappos++, 1); 125571c9aa33Sreinoud } 125671c9aa33Sreinoud error = ENOSPC; 125771c9aa33Sreinoud } 125871c9aa33Sreinoud if (!error) { 125971c9aa33Sreinoud /* adjust freecount */ 126071c9aa33Sreinoud lvid = ump->logvol_integrity; 1261a287d23dSreinoud freepos = &lvid->tables[0] + vpart_num; 126271c9aa33Sreinoud free_lbs = udf_rw32(*freepos); 126371c9aa33Sreinoud *freepos = udf_rw32(free_lbs - num_lb); 126471c9aa33Sreinoud } 126571c9aa33Sreinoud break; 12663653a532Sreinoud case UDF_ALLOC_METASEQUENTIAL : /* UDF 2.60 BluRay-R */ 12673653a532Sreinoud case UDF_ALLOC_RELAXEDSEQUENTIAL : /* UDF 2.50/~meta BluRay-R */ 1268e979c658Sreinoud printf("ALERT: udf_allocate_space : allocation %d " 1269e979c658Sreinoud "not implemented yet!\n", alloc_type); 1270e979c658Sreinoud /* TODO implement, doesn't have to be contiguous */ 1271e979c658Sreinoud error = ENOSPC; 1272e979c658Sreinoud break; 1273e979c658Sreinoud } 1274e979c658Sreinoud 1275706de0e5Sreinoud if (!error) { 1276706de0e5Sreinoud /* credit our partition since we have committed the space */ 1277706de0e5Sreinoud udf_do_unreserve_space(ump, udf_node, vpart_num, num_lb); 1278706de0e5Sreinoud } 1279706de0e5Sreinoud 1280e979c658Sreinoud #ifdef DEBUG 1281e979c658Sreinoud if (udf_verbose & UDF_DEBUG_ALLOC) { 1282e979c658Sreinoud lmappos = lmapping; 128371c9aa33Sreinoud printf("udf_allocate_space, allocated logical lba :\n"); 1284e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 12859cf321ebSreinoud printf("%s %"PRIu64, (lb_num > 0)?",":"", 128671c9aa33Sreinoud *lmappos++); 1287e979c658Sreinoud } 128871c9aa33Sreinoud printf("\n"); 1289e979c658Sreinoud } 1290e979c658Sreinoud #endif 1291e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 1292e979c658Sreinoud 1293e979c658Sreinoud return error; 1294e979c658Sreinoud } 1295e979c658Sreinoud 1296e979c658Sreinoud /* --------------------------------------------------------------------- */ 1297e979c658Sreinoud 1298e979c658Sreinoud void 1299e979c658Sreinoud udf_free_allocated_space(struct udf_mount *ump, uint32_t lb_num, 1300e979c658Sreinoud uint16_t vpart_num, uint32_t num_lb) 1301e979c658Sreinoud { 1302e979c658Sreinoud struct udf_bitmap *bitmap; 1303e979c658Sreinoud struct logvol_int_desc *lvid; 130477d54b3dSchristos uint32_t lb_map, udf_rw32_lbmap; 1305e979c658Sreinoud uint32_t *freepos, free_lbs; 1306e979c658Sreinoud int phys_part; 1307a721b8c1Smrg int error __diagused; 1308e979c658Sreinoud 1309e979c658Sreinoud DPRINTF(ALLOC, ("udf_free_allocated_space: freeing virt lbnum %d " 1310e979c658Sreinoud "part %d + %d sect\n", lb_num, vpart_num, num_lb)); 1311e979c658Sreinoud 1312d3bf9c7bSreinoud /* no use freeing zero length */ 1313d3bf9c7bSreinoud if (num_lb == 0) 1314d3bf9c7bSreinoud return; 1315d3bf9c7bSreinoud 1316e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 1317e979c658Sreinoud 1318e979c658Sreinoud switch (ump->vtop_tp[vpart_num]) { 1319e979c658Sreinoud case UDF_VTOP_TYPE_PHYS : 1320e979c658Sreinoud case UDF_VTOP_TYPE_SPARABLE : 1321e979c658Sreinoud /* free space to freed or unallocated space bitmap */ 1322e979c658Sreinoud phys_part = ump->vtop[vpart_num]; 1323e979c658Sreinoud 1324e979c658Sreinoud /* first try freed space bitmap */ 1325e979c658Sreinoud bitmap = &ump->part_freed_bits[phys_part]; 1326e979c658Sreinoud 1327e979c658Sreinoud /* if not defined, use unallocated bitmap */ 1328e979c658Sreinoud if (bitmap->bits == NULL) 1329e979c658Sreinoud bitmap = &ump->part_unalloc_bits[phys_part]; 1330e979c658Sreinoud 1331a287d23dSreinoud /* if no bitmaps are defined, bail out; XXX OK? */ 1332e979c658Sreinoud if (bitmap->bits == NULL) 1333e979c658Sreinoud break; 1334e979c658Sreinoud 1335e979c658Sreinoud /* free bits if its defined */ 1336e979c658Sreinoud KASSERT(bitmap->bits); 1337e979c658Sreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 1338e979c658Sreinoud udf_bitmap_free(bitmap, lb_num, num_lb); 1339e979c658Sreinoud 1340e979c658Sreinoud /* adjust freecount */ 1341e979c658Sreinoud lvid = ump->logvol_integrity; 1342e979c658Sreinoud freepos = &lvid->tables[0] + vpart_num; 1343e979c658Sreinoud free_lbs = udf_rw32(*freepos); 1344e979c658Sreinoud *freepos = udf_rw32(free_lbs + num_lb); 1345e979c658Sreinoud break; 1346e979c658Sreinoud case UDF_VTOP_TYPE_VIRT : 1347e979c658Sreinoud /* free this VAT entry */ 1348e979c658Sreinoud KASSERT(num_lb == 1); 1349e979c658Sreinoud 1350e979c658Sreinoud lb_map = 0xffffffff; 1351e979c658Sreinoud udf_rw32_lbmap = udf_rw32(lb_map); 1352e979c658Sreinoud error = udf_vat_write(ump->vat_node, 1353e979c658Sreinoud (uint8_t *) &udf_rw32_lbmap, 4, 1354e979c658Sreinoud ump->vat_offset + lb_num * 4); 1355e979c658Sreinoud KASSERT(error == 0); 1356e979c658Sreinoud ump->vat_last_free_lb = MIN(ump->vat_last_free_lb, lb_num); 1357e979c658Sreinoud break; 1358e979c658Sreinoud case UDF_VTOP_TYPE_META : 1359e979c658Sreinoud /* free space in the metadata bitmap */ 1360a287d23dSreinoud bitmap = &ump->metadata_unalloc_bits; 1361a287d23dSreinoud KASSERT(bitmap->bits); 1362a287d23dSreinoud 1363a287d23dSreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 1364a287d23dSreinoud udf_bitmap_free(bitmap, lb_num, num_lb); 1365a287d23dSreinoud 1366a287d23dSreinoud /* adjust freecount */ 1367a287d23dSreinoud lvid = ump->logvol_integrity; 1368a287d23dSreinoud freepos = &lvid->tables[0] + vpart_num; 1369a287d23dSreinoud free_lbs = udf_rw32(*freepos); 1370a287d23dSreinoud *freepos = udf_rw32(free_lbs + num_lb); 1371a287d23dSreinoud break; 1372e979c658Sreinoud default: 1373e979c658Sreinoud printf("ALERT: udf_free_allocated_space : allocation %d " 1374e979c658Sreinoud "not implemented yet!\n", ump->vtop_tp[vpart_num]); 1375e979c658Sreinoud break; 1376e979c658Sreinoud } 1377e979c658Sreinoud 1378e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 1379e979c658Sreinoud } 1380e979c658Sreinoud 1381e979c658Sreinoud /* --------------------------------------------------------------------- */ 1382e979c658Sreinoud 1383e979c658Sreinoud /* 13841196d96dSreinoud * Special function to synchronise the metadatamirror file when they change on 13851196d96dSreinoud * resizing. When the metadatafile is actually duplicated, this action is a 13861196d96dSreinoud * no-op since they describe different extents on the disc. 13871196d96dSreinoud */ 13881196d96dSreinoud 1389330482f6Sreinoud void 1390330482f6Sreinoud udf_synchronise_metadatamirror_node(struct udf_mount *ump) 13911196d96dSreinoud { 13921196d96dSreinoud struct udf_node *meta_node, *metamirror_node; 13931196d96dSreinoud struct long_ad s_ad; 1394330482f6Sreinoud uint32_t len, flags; 13951196d96dSreinoud int slot, cpy_slot; 13961196d96dSreinoud int error, eof; 13971196d96dSreinoud 13981196d96dSreinoud if (ump->metadata_flags & METADATA_DUPLICATED) 13991196d96dSreinoud return; 14001196d96dSreinoud 14011196d96dSreinoud meta_node = ump->metadata_node; 14021196d96dSreinoud metamirror_node = ump->metadatamirror_node; 14031196d96dSreinoud 14041196d96dSreinoud /* 1) wipe mirror node */ 14051196d96dSreinoud udf_wipe_adslots(metamirror_node); 14061196d96dSreinoud 14071196d96dSreinoud /* 2) copy all node descriptors from the meta_node */ 14081196d96dSreinoud slot = 0; 14091196d96dSreinoud cpy_slot = 0; 14101196d96dSreinoud for (;;) { 14111196d96dSreinoud udf_get_adslot(meta_node, slot, &s_ad, &eof); 14121196d96dSreinoud if (eof) 14131196d96dSreinoud break; 1414330482f6Sreinoud len = udf_rw32(s_ad.len); 1415330482f6Sreinoud flags = UDF_EXT_FLAGS(len); 1416330482f6Sreinoud len = UDF_EXT_LEN(len); 1417330482f6Sreinoud 1418330482f6Sreinoud if (flags == UDF_EXT_REDIRECT) { 1419330482f6Sreinoud slot++; 1420330482f6Sreinoud continue; 1421330482f6Sreinoud } 1422330482f6Sreinoud 14231196d96dSreinoud error = udf_append_adslot(metamirror_node, &cpy_slot, &s_ad); 14241196d96dSreinoud if (error) { 14251196d96dSreinoud /* WTF, this shouldn't happen, what to do now? */ 14261196d96dSreinoud panic("udf_synchronise_metadatamirror_node failed!"); 14271196d96dSreinoud } 1428330482f6Sreinoud cpy_slot++; 14291196d96dSreinoud slot++; 14301196d96dSreinoud } 14311196d96dSreinoud 14321196d96dSreinoud /* 3) adjust metamirror_node size */ 14331196d96dSreinoud if (meta_node->fe) { 14341196d96dSreinoud KASSERT(metamirror_node->fe); 14351196d96dSreinoud metamirror_node->fe->inf_len = meta_node->fe->inf_len; 14361196d96dSreinoud } else { 14371196d96dSreinoud KASSERT(meta_node->efe); 14381196d96dSreinoud KASSERT(metamirror_node->efe); 14391196d96dSreinoud metamirror_node->efe->inf_len = meta_node->efe->inf_len; 14401196d96dSreinoud metamirror_node->efe->obj_size = meta_node->efe->obj_size; 14411196d96dSreinoud } 14421196d96dSreinoud 14431196d96dSreinoud /* for sanity */ 14441196d96dSreinoud udf_count_alloc_exts(metamirror_node); 14451196d96dSreinoud } 14461196d96dSreinoud 14471196d96dSreinoud /* --------------------------------------------------------------------- */ 14481196d96dSreinoud 14491196d96dSreinoud /* 14501196d96dSreinoud * When faced with an out of space but there is still space available on other 14511196d96dSreinoud * partitions, try to redistribute the space. This is only defined for media 14521196d96dSreinoud * using Metadata partitions. 14531196d96dSreinoud * 14541196d96dSreinoud * There are two formats to deal with. Either its a `normal' metadata 14551196d96dSreinoud * partition and we can move blocks between a metadata bitmap and its 14561196d96dSreinoud * companion data spacemap OR its a UDF 2.60 formatted BluRay-R disc with POW 14571196d96dSreinoud * and a metadata partition. 14581196d96dSreinoud */ 14591196d96dSreinoud 1460330482f6Sreinoud /* implementation limit: ump->datapart is the companion partition */ 14611196d96dSreinoud static uint32_t 14621196d96dSreinoud udf_trunc_metadatapart(struct udf_mount *ump, uint32_t num_lb) 14631196d96dSreinoud { 14641196d96dSreinoud struct udf_node *bitmap_node; 14651196d96dSreinoud struct udf_bitmap *bitmap; 14661196d96dSreinoud struct space_bitmap_desc *sbd, *new_sbd; 14671196d96dSreinoud struct logvol_int_desc *lvid; 14681196d96dSreinoud uint64_t inf_len; 1469330482f6Sreinoud uint64_t meta_free_lbs, data_free_lbs, to_trunc; 14701196d96dSreinoud uint32_t *freepos, *sizepos; 1471330482f6Sreinoud uint32_t unit, lb_size; 14721196d96dSreinoud uint16_t meta_vpart_num, data_vpart_num, num_vpart; 1473a721b8c1Smrg int err __diagused; 14741196d96dSreinoud 14751196d96dSreinoud unit = ump->metadata_alloc_unit_size; 14761196d96dSreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 14771196d96dSreinoud lvid = ump->logvol_integrity; 14781196d96dSreinoud 1479330482f6Sreinoud /* XXX 1480330482f6Sreinoud * 1481330482f6Sreinoud * the following checks will fail for BD-R UDF 2.60! but they are 1482330482f6Sreinoud * read-only for now anyway! Its even doubtfull if it is to be allowed 1483330482f6Sreinoud * for these discs. 1484330482f6Sreinoud */ 1485330482f6Sreinoud 14861196d96dSreinoud /* lookup vpart for metadata partition */ 14871196d96dSreinoud meta_vpart_num = ump->node_part; 14881196d96dSreinoud KASSERT(ump->vtop_alloc[meta_vpart_num] == UDF_ALLOC_METABITMAP); 14891196d96dSreinoud 14901196d96dSreinoud /* lookup vpart for data partition */ 14911196d96dSreinoud data_vpart_num = ump->data_part; 14921196d96dSreinoud KASSERT(ump->vtop_alloc[data_vpart_num] == UDF_ALLOC_SPACEMAP); 14931196d96dSreinoud 14941196d96dSreinoud udf_calc_vpart_freespace(ump, data_vpart_num, &data_free_lbs); 14951196d96dSreinoud udf_calc_vpart_freespace(ump, meta_vpart_num, &meta_free_lbs); 14961196d96dSreinoud 14971196d96dSreinoud DPRINTF(RESERVE, ("\tfree space on data partition %"PRIu64" blks\n", data_free_lbs)); 14981196d96dSreinoud DPRINTF(RESERVE, ("\tfree space on metadata partition %"PRIu64" blks\n", meta_free_lbs)); 14991196d96dSreinoud 15001196d96dSreinoud /* give away some of the free meta space, in unit block sizes */ 150128b2fc3aSreinoud to_trunc = meta_free_lbs/4; /* give out a quarter */ 15021196d96dSreinoud to_trunc = MAX(to_trunc, num_lb); 15031196d96dSreinoud to_trunc = unit * ((to_trunc + unit-1) / unit); /* round up */ 15041196d96dSreinoud 15051196d96dSreinoud /* scale down if needed and bail out when out of space */ 15061196d96dSreinoud if (to_trunc >= meta_free_lbs) 15071196d96dSreinoud return num_lb; 15081196d96dSreinoud 15091196d96dSreinoud /* check extent of bits marked free at the end of the map */ 15101196d96dSreinoud bitmap = &ump->metadata_unalloc_bits; 15111196d96dSreinoud to_trunc = udf_bitmap_check_trunc_free(bitmap, to_trunc); 15121196d96dSreinoud to_trunc = unit * (to_trunc / unit); /* round down again */ 15131196d96dSreinoud if (to_trunc == 0) 15141196d96dSreinoud return num_lb; 15151196d96dSreinoud 1516330482f6Sreinoud DPRINTF(RESERVE, ("\ttruncating %"PRIu64" lbs from the metadata bitmap\n", 15171196d96dSreinoud to_trunc)); 15181196d96dSreinoud 15191196d96dSreinoud /* get length of the metadata bitmap node file */ 15201196d96dSreinoud bitmap_node = ump->metadatabitmap_node; 15211196d96dSreinoud if (bitmap_node->fe) { 15221196d96dSreinoud inf_len = udf_rw64(bitmap_node->fe->inf_len); 15231196d96dSreinoud } else { 15241196d96dSreinoud KASSERT(bitmap_node->efe); 15251196d96dSreinoud inf_len = udf_rw64(bitmap_node->efe->inf_len); 15261196d96dSreinoud } 15271196d96dSreinoud inf_len -= to_trunc/8; 15281196d96dSreinoud 15291196d96dSreinoud /* as per [UDF 2.60/2.2.13.6] : */ 15301196d96dSreinoud /* 1) update the SBD in the metadata bitmap file */ 15311196d96dSreinoud sbd = (struct space_bitmap_desc *) bitmap->blob; 1532330482f6Sreinoud sbd->num_bits = udf_rw32(udf_rw32(sbd->num_bits) - to_trunc); 1533330482f6Sreinoud sbd->num_bytes = udf_rw32(udf_rw32(sbd->num_bytes) - to_trunc/8); 15341196d96dSreinoud bitmap->max_offset = udf_rw32(sbd->num_bits); 15351196d96dSreinoud 15361196d96dSreinoud num_vpart = udf_rw32(lvid->num_part); 15371196d96dSreinoud freepos = &lvid->tables[0] + meta_vpart_num; 15381196d96dSreinoud sizepos = &lvid->tables[0] + num_vpart + meta_vpart_num; 15391196d96dSreinoud *freepos = udf_rw32(*freepos) - to_trunc; 15401196d96dSreinoud *sizepos = udf_rw32(*sizepos) - to_trunc; 15411196d96dSreinoud 15421196d96dSreinoud /* realloc bitmap for better memory usage */ 15431df1fda9Sjdolecek new_sbd = realloc(sbd, inf_len, M_UDFVOLD, M_WAITOK); 15441196d96dSreinoud if (new_sbd) { 15451196d96dSreinoud /* update pointers */ 15461196d96dSreinoud ump->metadata_unalloc_dscr = new_sbd; 15471196d96dSreinoud bitmap->blob = (uint8_t *) new_sbd; 15481196d96dSreinoud } 15491196d96dSreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 15501196d96dSreinoud 15511196d96dSreinoud /* 1552330482f6Sreinoud * The truncated space is secured now and can't be allocated anymore. 1553330482f6Sreinoud * Release the allocate mutex so we can shrink the nodes the normal 1554330482f6Sreinoud * way. 15551196d96dSreinoud */ 15561196d96dSreinoud mutex_exit(&ump->allocate_mutex); 15571196d96dSreinoud 15581196d96dSreinoud /* 2) trunc the metadata bitmap information file, freeing blocks */ 15591196d96dSreinoud err = udf_shrink_node(bitmap_node, inf_len); 15601196d96dSreinoud KASSERT(err == 0); 15611196d96dSreinoud 15621196d96dSreinoud /* 3) trunc the metadata file and mirror file, freeing blocks */ 1563330482f6Sreinoud inf_len = (uint64_t) udf_rw32(sbd->num_bits) * lb_size; /* [4/14.12.4] */ 15641196d96dSreinoud err = udf_shrink_node(ump->metadata_node, inf_len); 15651196d96dSreinoud KASSERT(err == 0); 1566330482f6Sreinoud if (ump->metadatamirror_node) { 1567330482f6Sreinoud if (ump->metadata_flags & METADATA_DUPLICATED) { 15681196d96dSreinoud err = udf_shrink_node(ump->metadatamirror_node, inf_len); 1569330482f6Sreinoud } else { 1570330482f6Sreinoud /* extents will be copied on writeout */ 1571330482f6Sreinoud } 15721196d96dSreinoud KASSERT(err == 0); 15731196d96dSreinoud } 15741196d96dSreinoud ump->lvclose |= UDF_WRITE_METAPART_NODES; 15751196d96dSreinoud 15761196d96dSreinoud /* relock before exit */ 15771196d96dSreinoud mutex_enter(&ump->allocate_mutex); 15781196d96dSreinoud 15791196d96dSreinoud if (to_trunc > num_lb) 15801196d96dSreinoud return 0; 15811196d96dSreinoud return num_lb - to_trunc; 15821196d96dSreinoud } 15831196d96dSreinoud 15841196d96dSreinoud 15851196d96dSreinoud static void 15861196d96dSreinoud udf_sparsify_metadatapart(struct udf_mount *ump, uint32_t num_lb) 15871196d96dSreinoud { 15881196d96dSreinoud /* NOT IMPLEMENTED, fail */ 15891196d96dSreinoud } 15901196d96dSreinoud 15911196d96dSreinoud 15921196d96dSreinoud static void 15931196d96dSreinoud udf_collect_free_space_for_vpart(struct udf_mount *ump, 15941196d96dSreinoud uint16_t vpart_num, uint32_t num_lb) 15951196d96dSreinoud { 15961196d96dSreinoud /* allocate mutex is helt */ 15971196d96dSreinoud 15981196d96dSreinoud /* only defined for metadata partitions */ 15991196d96dSreinoud if (ump->vtop_tp[ump->node_part] != UDF_VTOP_TYPE_META) { 16001196d96dSreinoud DPRINTF(RESERVE, ("\tcan't grow/shrink; no metadata partitioning\n")); 16011196d96dSreinoud return; 16021196d96dSreinoud } 16031196d96dSreinoud 16041196d96dSreinoud /* UDF 2.60 BD-R+POW? */ 16051196d96dSreinoud if (ump->vtop_alloc[ump->node_part] == UDF_ALLOC_METASEQUENTIAL) { 16061196d96dSreinoud DPRINTF(RESERVE, ("\tUDF 2.60 BD-R+POW track grow not implemented yet\n")); 16071196d96dSreinoud return; 16081196d96dSreinoud } 16091196d96dSreinoud 16101196d96dSreinoud if (ump->vtop_tp[vpart_num] == UDF_VTOP_TYPE_META) { 16111196d96dSreinoud /* try to grow the meta partition */ 16121196d96dSreinoud DPRINTF(RESERVE, ("\ttrying to grow the meta partition\n")); 16131196d96dSreinoud /* as per [UDF 2.60/2.2.13.5] : extend bitmap and metadata file(s) */ 1614734d8516Sreinoud DPRINTF(NOTIMPL, ("\tgrowing meta partition not implemented yet\n")); 16151196d96dSreinoud } else { 16161196d96dSreinoud /* try to shrink the metadata partition */ 16171196d96dSreinoud DPRINTF(RESERVE, ("\ttrying to shrink the meta partition\n")); 16181196d96dSreinoud /* as per [UDF 2.60/2.2.13.6] : either trunc or make sparse */ 16191196d96dSreinoud num_lb = udf_trunc_metadatapart(ump, num_lb); 16201196d96dSreinoud if (num_lb) 16211196d96dSreinoud udf_sparsify_metadatapart(ump, num_lb); 16221196d96dSreinoud } 16231196d96dSreinoud 16241196d96dSreinoud /* allocate mutex should still be helt */ 16251196d96dSreinoud } 16261196d96dSreinoud 16271196d96dSreinoud /* --------------------------------------------------------------------- */ 16281196d96dSreinoud 16291196d96dSreinoud /* 1630e979c658Sreinoud * Allocate a buf on disc for direct write out. The space doesn't have to be 1631e979c658Sreinoud * contiguous as the caller takes care of this. 1632e979c658Sreinoud */ 1633e979c658Sreinoud 1634e979c658Sreinoud void 1635e979c658Sreinoud udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, 1636a287d23dSreinoud uint64_t *lmapping, struct long_ad *node_ad_cpy, uint16_t *vpart_nump) 1637e979c658Sreinoud { 1638e979c658Sreinoud struct udf_node *udf_node = VTOI(buf->b_vp); 163977d54b3dSchristos int lb_size, udf_c_type; 1640a287d23dSreinoud int vpart_num, num_lb; 1641e979c658Sreinoud int error, s; 1642e979c658Sreinoud 1643e979c658Sreinoud /* 1644e979c658Sreinoud * for each sector in the buf, allocate a sector on disc and record 1645e979c658Sreinoud * its position in the provided mapping array. 1646e979c658Sreinoud * 1647e979c658Sreinoud * If its userdata or FIDs, record its location in its node. 1648e979c658Sreinoud */ 1649e979c658Sreinoud 1650e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 1651e979c658Sreinoud num_lb = (buf->b_bcount + lb_size -1) / lb_size; 1652e979c658Sreinoud udf_c_type = buf->b_udf_c_type; 1653e979c658Sreinoud 1654e979c658Sreinoud KASSERT(lb_size == ump->discinfo.sector_size); 1655e979c658Sreinoud 1656a287d23dSreinoud /* select partition to record the buffer on */ 1657706de0e5Sreinoud vpart_num = *vpart_nump = udf_get_record_vpart(ump, udf_c_type); 1658e979c658Sreinoud 1659e979c658Sreinoud if (udf_c_type == UDF_C_NODE) { 1660e979c658Sreinoud /* if not VAT, its allready allocated */ 1661a287d23dSreinoud if (ump->vtop_alloc[ump->node_part] != UDF_ALLOC_VAT) 1662e979c658Sreinoud return; 1663e979c658Sreinoud 1664a287d23dSreinoud /* allocate on its backing sequential partition */ 1665a287d23dSreinoud vpart_num = ump->data_part; 1666e979c658Sreinoud } 1667e979c658Sreinoud 1668706de0e5Sreinoud /* XXX can this still happen? */ 1669a287d23dSreinoud /* do allocation on the selected partition */ 1670706de0e5Sreinoud error = udf_allocate_space(ump, udf_node, udf_c_type, 1671a287d23dSreinoud vpart_num, num_lb, lmapping); 1672e979c658Sreinoud if (error) { 1673706de0e5Sreinoud /* 1674706de0e5Sreinoud * ARGH! we haven't done our accounting right! it should 1675706de0e5Sreinoud * allways succeed. 1676706de0e5Sreinoud */ 1677e979c658Sreinoud panic("UDF disc allocation accounting gone wrong"); 1678e979c658Sreinoud } 1679e979c658Sreinoud 1680e979c658Sreinoud /* If its userdata or FIDs, record its allocation in its node. */ 168171c9aa33Sreinoud if ((udf_c_type == UDF_C_USERDATA) || 168271c9aa33Sreinoud (udf_c_type == UDF_C_FIDS) || 168371c9aa33Sreinoud (udf_c_type == UDF_C_METADATA_SBM)) 168471c9aa33Sreinoud { 1685a287d23dSreinoud udf_record_allocation_in_node(ump, buf, vpart_num, lmapping, 1686e979c658Sreinoud node_ad_cpy); 1687e979c658Sreinoud /* decrement our outstanding bufs counter */ 1688e979c658Sreinoud s = splbio(); 1689e979c658Sreinoud udf_node->outstanding_bufs--; 1690e979c658Sreinoud splx(s); 1691e979c658Sreinoud } 1692e979c658Sreinoud } 1693e979c658Sreinoud 1694e979c658Sreinoud /* --------------------------------------------------------------------- */ 1695e979c658Sreinoud 1696e979c658Sreinoud /* 1697e979c658Sreinoud * Try to merge a1 with the new piece a2. udf_ads_merge returns error when not 1698e979c658Sreinoud * possible (anymore); a2 returns the rest piece. 1699e979c658Sreinoud */ 1700e979c658Sreinoud 1701e979c658Sreinoud static int 1702330482f6Sreinoud udf_ads_merge(uint32_t max_len, uint32_t lb_size, struct long_ad *a1, struct long_ad *a2) 1703e979c658Sreinoud { 1704330482f6Sreinoud uint32_t merge_len; 1705e979c658Sreinoud uint32_t a1_len, a2_len; 1706e979c658Sreinoud uint32_t a1_flags, a2_flags; 1707e979c658Sreinoud uint32_t a1_lbnum, a2_lbnum; 1708e979c658Sreinoud uint16_t a1_part, a2_part; 1709e979c658Sreinoud 1710e979c658Sreinoud a1_flags = UDF_EXT_FLAGS(udf_rw32(a1->len)); 1711e979c658Sreinoud a1_len = UDF_EXT_LEN(udf_rw32(a1->len)); 1712e979c658Sreinoud a1_lbnum = udf_rw32(a1->loc.lb_num); 1713e979c658Sreinoud a1_part = udf_rw16(a1->loc.part_num); 1714e979c658Sreinoud 1715e979c658Sreinoud a2_flags = UDF_EXT_FLAGS(udf_rw32(a2->len)); 1716e979c658Sreinoud a2_len = UDF_EXT_LEN(udf_rw32(a2->len)); 1717e979c658Sreinoud a2_lbnum = udf_rw32(a2->loc.lb_num); 1718e979c658Sreinoud a2_part = udf_rw16(a2->loc.part_num); 1719e979c658Sreinoud 1720e979c658Sreinoud /* defines same space */ 1721e979c658Sreinoud if (a1_flags != a2_flags) 1722e979c658Sreinoud return 1; 1723e979c658Sreinoud 1724e979c658Sreinoud if (a1_flags != UDF_EXT_FREE) { 1725e979c658Sreinoud /* the same partition */ 1726e979c658Sreinoud if (a1_part != a2_part) 1727e979c658Sreinoud return 1; 1728e979c658Sreinoud 1729e979c658Sreinoud /* a2 is successor of a1 */ 1730e979c658Sreinoud if (a1_lbnum * lb_size + a1_len != a2_lbnum * lb_size) 1731e979c658Sreinoud return 1; 1732e979c658Sreinoud } 1733e979c658Sreinoud 1734e979c658Sreinoud /* merge as most from a2 if possible */ 1735e979c658Sreinoud merge_len = MIN(a2_len, max_len - a1_len); 1736e979c658Sreinoud a1_len += merge_len; 1737e979c658Sreinoud a2_len -= merge_len; 1738e979c658Sreinoud a2_lbnum += merge_len/lb_size; 1739e979c658Sreinoud 1740e979c658Sreinoud a1->len = udf_rw32(a1_len | a1_flags); 1741e979c658Sreinoud a2->len = udf_rw32(a2_len | a2_flags); 1742e979c658Sreinoud a2->loc.lb_num = udf_rw32(a2_lbnum); 1743e979c658Sreinoud 1744e979c658Sreinoud if (a2_len > 0) 1745e979c658Sreinoud return 1; 1746e979c658Sreinoud 1747e979c658Sreinoud /* there is space over to merge */ 1748e979c658Sreinoud return 0; 1749e979c658Sreinoud } 1750e979c658Sreinoud 1751e979c658Sreinoud /* --------------------------------------------------------------------- */ 1752e979c658Sreinoud 1753e979c658Sreinoud static void 1754e979c658Sreinoud udf_wipe_adslots(struct udf_node *udf_node) 1755e979c658Sreinoud { 1756e979c658Sreinoud struct file_entry *fe; 1757e979c658Sreinoud struct extfile_entry *efe; 1758e979c658Sreinoud struct alloc_ext_entry *ext; 175977d54b3dSchristos uint32_t lb_size, dscr_size, l_ea, max_l_ad, crclen; 1760e979c658Sreinoud uint8_t *data_pos; 1761e979c658Sreinoud int extnr; 1762e979c658Sreinoud 1763e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1764e979c658Sreinoud 1765e979c658Sreinoud fe = udf_node->fe; 1766e979c658Sreinoud efe = udf_node->efe; 1767e979c658Sreinoud if (fe) { 1768e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1769e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1770e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 1771e979c658Sreinoud } else { 1772e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1773e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1774e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 1775e979c658Sreinoud } 1776e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1777e979c658Sreinoud 1778e979c658Sreinoud /* wipe fe/efe */ 1779e979c658Sreinoud memset(data_pos, 0, max_l_ad); 1780e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea; 1781e979c658Sreinoud if (fe) { 1782e979c658Sreinoud fe->l_ad = udf_rw32(0); 1783e979c658Sreinoud fe->logblks_rec = udf_rw64(0); 1784fbd470baSreinoud fe->tag.desc_crc_len = udf_rw16(crclen); 1785e979c658Sreinoud } else { 1786e979c658Sreinoud efe->l_ad = udf_rw32(0); 1787e979c658Sreinoud efe->logblks_rec = udf_rw64(0); 1788fbd470baSreinoud efe->tag.desc_crc_len = udf_rw16(crclen); 1789e979c658Sreinoud } 1790e979c658Sreinoud 1791e979c658Sreinoud /* wipe all allocation extent entries */ 1792e979c658Sreinoud for (extnr = 0; extnr < udf_node->num_extensions; extnr++) { 1793e979c658Sreinoud ext = udf_node->ext[extnr]; 1794e979c658Sreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 17954d5c88faSreinoud data_pos = (uint8_t *) ext->data; 1796e979c658Sreinoud max_l_ad = lb_size - dscr_size; 1797e979c658Sreinoud memset(data_pos, 0, max_l_ad); 1798e979c658Sreinoud ext->l_ad = udf_rw32(0); 1799e979c658Sreinoud 1800e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH; 1801fbd470baSreinoud ext->tag.desc_crc_len = udf_rw16(crclen); 1802e979c658Sreinoud } 18034d5c88faSreinoud udf_node->i_flags |= IN_NODE_REBUILD; 1804e979c658Sreinoud } 1805e979c658Sreinoud 1806e979c658Sreinoud /* --------------------------------------------------------------------- */ 1807e979c658Sreinoud 1808e979c658Sreinoud void 1809e979c658Sreinoud udf_get_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb, 1810e979c658Sreinoud int *eof) { 1811e979c658Sreinoud struct file_entry *fe; 1812e979c658Sreinoud struct extfile_entry *efe; 1813e979c658Sreinoud struct alloc_ext_entry *ext; 1814e979c658Sreinoud struct icb_tag *icbtag; 1815e979c658Sreinoud struct short_ad *short_ad; 18164d5c88faSreinoud struct long_ad *long_ad, l_icb; 1817e979c658Sreinoud uint32_t offset; 181877d54b3dSchristos uint32_t dscr_size, l_ea, l_ad, flags; 1819e979c658Sreinoud uint8_t *data_pos; 1820e979c658Sreinoud int icbflags, addr_type, adlen, extnr; 1821e979c658Sreinoud 1822e979c658Sreinoud fe = udf_node->fe; 1823e979c658Sreinoud efe = udf_node->efe; 1824e979c658Sreinoud if (fe) { 1825e979c658Sreinoud icbtag = &fe->icbtag; 1826e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1827e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1828e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 1829e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 1830e979c658Sreinoud } else { 1831e979c658Sreinoud icbtag = &efe->icbtag; 1832e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1833e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1834e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 1835e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 1836e979c658Sreinoud } 1837e979c658Sreinoud 1838e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1839e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1840e979c658Sreinoud 1841e979c658Sreinoud /* just in case we're called on an intern, its EOF */ 1842e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1843e979c658Sreinoud memset(icb, 0, sizeof(struct long_ad)); 1844e979c658Sreinoud *eof = 1; 1845e979c658Sreinoud return; 1846e979c658Sreinoud } 1847e979c658Sreinoud 1848e979c658Sreinoud adlen = 0; 1849e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1850e979c658Sreinoud adlen = sizeof(struct short_ad); 1851e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1852e979c658Sreinoud adlen = sizeof(struct long_ad); 1853e979c658Sreinoud } 1854e979c658Sreinoud 1855e979c658Sreinoud /* if offset too big, we go to the allocation extensions */ 1856e979c658Sreinoud offset = slot * adlen; 185735d8dddaSreinoud extnr = -1; 18584d5c88faSreinoud while (offset >= l_ad) { 18594d5c88faSreinoud /* check if our last entry is a redirect */ 18604d5c88faSreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 18614d5c88faSreinoud short_ad = (struct short_ad *) (data_pos + l_ad-adlen); 18624d5c88faSreinoud l_icb.len = short_ad->len; 18634d5c88faSreinoud l_icb.loc.part_num = udf_node->loc.loc.part_num; 18644d5c88faSreinoud l_icb.loc.lb_num = short_ad->lb_num; 18654d5c88faSreinoud } else { 18664d5c88faSreinoud KASSERT(addr_type == UDF_ICB_LONG_ALLOC); 18674d5c88faSreinoud long_ad = (struct long_ad *) (data_pos + l_ad-adlen); 18684d5c88faSreinoud l_icb = *long_ad; 18694d5c88faSreinoud } 18704d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(l_icb.len)); 18714d5c88faSreinoud if (flags != UDF_EXT_REDIRECT) { 1872e979c658Sreinoud l_ad = 0; /* force EOF */ 1873e979c658Sreinoud break; 1874e979c658Sreinoud } 18754d5c88faSreinoud 18764d5c88faSreinoud /* advance to next extent */ 18774d5c88faSreinoud extnr++; 18784d5c88faSreinoud if (extnr >= udf_node->num_extensions) { 18794d5c88faSreinoud l_ad = 0; /* force EOF */ 18804d5c88faSreinoud break; 18814d5c88faSreinoud } 18824d5c88faSreinoud offset = offset - l_ad; 18834d5c88faSreinoud ext = udf_node->ext[extnr]; 18844d5c88faSreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 18854d5c88faSreinoud l_ad = udf_rw32(ext->l_ad); 18864d5c88faSreinoud data_pos = (uint8_t *) ext + dscr_size; 1887e979c658Sreinoud } 1888e979c658Sreinoud 18894d5c88faSreinoud /* XXX l_ad == 0 should be enough to check */ 1890e979c658Sreinoud *eof = (offset >= l_ad) || (l_ad == 0); 1891e979c658Sreinoud if (*eof) { 18924d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("returning EOF, extnr %d, offset %d, " 18934d5c88faSreinoud "l_ad %d\n", extnr, offset, l_ad)); 1894e979c658Sreinoud memset(icb, 0, sizeof(struct long_ad)); 1895e979c658Sreinoud return; 1896e979c658Sreinoud } 1897e979c658Sreinoud 1898e979c658Sreinoud /* get the element */ 1899e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1900e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 1901e979c658Sreinoud icb->len = short_ad->len; 1902ca7a0d4eSreinoud icb->loc.part_num = udf_node->loc.loc.part_num; 1903e979c658Sreinoud icb->loc.lb_num = short_ad->lb_num; 1904e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1905e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 1906e979c658Sreinoud *icb = *long_ad; 1907e979c658Sreinoud } 19084d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("returning element : v %d, lb %d, len %d, " 19094d5c88faSreinoud "flags %d\n", icb->loc.part_num, icb->loc.lb_num, 19104d5c88faSreinoud UDF_EXT_LEN(icb->len), UDF_EXT_FLAGS(icb->len))); 1911e979c658Sreinoud } 1912e979c658Sreinoud 1913e979c658Sreinoud /* --------------------------------------------------------------------- */ 1914e979c658Sreinoud 1915e979c658Sreinoud int 19164d5c88faSreinoud udf_append_adslot(struct udf_node *udf_node, int *slot, struct long_ad *icb) { 19174d5c88faSreinoud struct udf_mount *ump = udf_node->ump; 1918a48555c3Sreinoud union dscrptr *dscr, *extdscr; 1919e979c658Sreinoud struct file_entry *fe; 1920e979c658Sreinoud struct extfile_entry *efe; 1921e979c658Sreinoud struct alloc_ext_entry *ext; 1922e979c658Sreinoud struct icb_tag *icbtag; 1923e979c658Sreinoud struct short_ad *short_ad; 19244d5c88faSreinoud struct long_ad *long_ad, o_icb, l_icb; 1925e979c658Sreinoud uint64_t logblks_rec, *logblks_rec_p; 192671c9aa33Sreinoud uint64_t lmapping; 19274d5c88faSreinoud uint32_t offset, rest, len, lb_num; 1928e979c658Sreinoud uint32_t lb_size, dscr_size, l_ea, l_ad, *l_ad_p, max_l_ad, crclen; 19294d5c88faSreinoud uint32_t flags; 19304d5c88faSreinoud uint16_t vpart_num; 1931e979c658Sreinoud uint8_t *data_pos; 1932e979c658Sreinoud int icbflags, addr_type, adlen, extnr; 19334d5c88faSreinoud int error; 1934e979c658Sreinoud 19354d5c88faSreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 1936a287d23dSreinoud vpart_num = udf_rw16(udf_node->loc.loc.part_num); 1937e979c658Sreinoud 1938a287d23dSreinoud /* determine what descriptor we are in */ 1939e979c658Sreinoud fe = udf_node->fe; 1940e979c658Sreinoud efe = udf_node->efe; 1941e979c658Sreinoud if (fe) { 1942e979c658Sreinoud icbtag = &fe->icbtag; 1943e979c658Sreinoud dscr = (union dscrptr *) fe; 1944e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1945e979c658Sreinoud 1946e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1947e979c658Sreinoud l_ad_p = &fe->l_ad; 1948e979c658Sreinoud logblks_rec_p = &fe->logblks_rec; 1949e979c658Sreinoud } else { 1950e979c658Sreinoud icbtag = &efe->icbtag; 1951e979c658Sreinoud dscr = (union dscrptr *) efe; 1952e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1953e979c658Sreinoud 1954e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1955e979c658Sreinoud l_ad_p = &efe->l_ad; 1956e979c658Sreinoud logblks_rec_p = &efe->logblks_rec; 1957e979c658Sreinoud } 1958e979c658Sreinoud data_pos = (uint8_t *) dscr + dscr_size + l_ea; 1959e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1960e979c658Sreinoud 1961e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1962e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1963e979c658Sreinoud 1964e979c658Sreinoud /* just in case we're called on an intern, its EOF */ 1965e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1966e979c658Sreinoud panic("udf_append_adslot on UDF_ICB_INTERN_ALLOC\n"); 1967e979c658Sreinoud } 1968e979c658Sreinoud 1969e979c658Sreinoud adlen = 0; 1970e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1971e979c658Sreinoud adlen = sizeof(struct short_ad); 1972e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1973e979c658Sreinoud adlen = sizeof(struct long_ad); 1974e979c658Sreinoud } 1975e979c658Sreinoud 1976a287d23dSreinoud /* clean up given long_ad since it can be a synthesized one */ 19774d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(icb->len)); 19784d5c88faSreinoud if (flags == UDF_EXT_FREE) { 19795eeb4f69Sreinoud icb->loc.part_num = udf_rw16(0); 19805eeb4f69Sreinoud icb->loc.lb_num = udf_rw32(0); 19815eeb4f69Sreinoud } 19825eeb4f69Sreinoud 1983e979c658Sreinoud /* if offset too big, we go to the allocation extensions */ 19844d5c88faSreinoud l_ad = udf_rw32(*l_ad_p); 19854d5c88faSreinoud offset = (*slot) * adlen; 19864d5c88faSreinoud extnr = -1; 19874d5c88faSreinoud while (offset >= l_ad) { 19884d5c88faSreinoud /* check if our last entry is a redirect */ 19894d5c88faSreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 19904d5c88faSreinoud short_ad = (struct short_ad *) (data_pos + l_ad-adlen); 19914d5c88faSreinoud l_icb.len = short_ad->len; 19924d5c88faSreinoud l_icb.loc.part_num = udf_node->loc.loc.part_num; 19934d5c88faSreinoud l_icb.loc.lb_num = short_ad->lb_num; 19944d5c88faSreinoud } else { 19954d5c88faSreinoud KASSERT(addr_type == UDF_ICB_LONG_ALLOC); 19964d5c88faSreinoud long_ad = (struct long_ad *) (data_pos + l_ad-adlen); 19974d5c88faSreinoud l_icb = *long_ad; 19984d5c88faSreinoud } 19994d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(l_icb.len)); 20004d5c88faSreinoud if (flags != UDF_EXT_REDIRECT) { 20014d5c88faSreinoud /* only one past the last one is adressable */ 20024d5c88faSreinoud break; 20034d5c88faSreinoud } 20044d5c88faSreinoud 20054d5c88faSreinoud /* advance to next extent */ 20064d5c88faSreinoud extnr++; 20074d5c88faSreinoud KASSERT(extnr < udf_node->num_extensions); 20084d5c88faSreinoud offset = offset - l_ad; 20094d5c88faSreinoud 2010e979c658Sreinoud ext = udf_node->ext[extnr]; 2011e979c658Sreinoud dscr = (union dscrptr *) ext; 2012e979c658Sreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 2013e979c658Sreinoud max_l_ad = lb_size - dscr_size; 20144d5c88faSreinoud l_ad_p = &ext->l_ad; 20154d5c88faSreinoud l_ad = udf_rw32(*l_ad_p); 20164d5c88faSreinoud data_pos = (uint8_t *) ext + dscr_size; 2017e979c658Sreinoud } 20184d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("append, ext %d, offset %d, l_ad %d\n", 20194d5c88faSreinoud extnr, offset, udf_rw32(*l_ad_p))); 20204d5c88faSreinoud KASSERT(l_ad == udf_rw32(*l_ad_p)); 20214d5c88faSreinoud 2022e979c658Sreinoud /* offset is offset within the current (E)FE/AED */ 2023e979c658Sreinoud l_ad = udf_rw32(*l_ad_p); 2024fbd470baSreinoud crclen = udf_rw16(dscr->tag.desc_crc_len); 2025e979c658Sreinoud logblks_rec = udf_rw64(*logblks_rec_p); 2026e979c658Sreinoud 2027e979c658Sreinoud /* overwriting old piece? */ 2028e979c658Sreinoud if (offset < l_ad) { 2029e979c658Sreinoud /* overwrite entry; compensate for the old element */ 2030e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 2031e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 2032e979c658Sreinoud o_icb.len = short_ad->len; 2033e979c658Sreinoud o_icb.loc.part_num = udf_rw16(0); /* ignore */ 2034e979c658Sreinoud o_icb.loc.lb_num = short_ad->lb_num; 2035e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 2036e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 2037e979c658Sreinoud o_icb = *long_ad; 2038e979c658Sreinoud } else { 2039e979c658Sreinoud panic("Invalid address type in udf_append_adslot\n"); 2040e979c658Sreinoud } 2041e979c658Sreinoud 2042e979c658Sreinoud len = udf_rw32(o_icb.len); 2043e979c658Sreinoud if (UDF_EXT_FLAGS(len) == UDF_EXT_ALLOCATED) { 2044e979c658Sreinoud /* adjust counts */ 2045e979c658Sreinoud len = UDF_EXT_LEN(len); 2046e979c658Sreinoud logblks_rec -= (len + lb_size -1) / lb_size; 2047e979c658Sreinoud } 2048e979c658Sreinoud } 2049e979c658Sreinoud 20504d5c88faSreinoud /* check if we're not appending a redirection */ 20514d5c88faSreinoud flags = UDF_EXT_FLAGS(udf_rw32(icb->len)); 20524d5c88faSreinoud KASSERT(flags != UDF_EXT_REDIRECT); 20534d5c88faSreinoud 20544d5c88faSreinoud /* round down available space */ 20554d5c88faSreinoud rest = adlen * ((max_l_ad - offset) / adlen); 2056e979c658Sreinoud if (rest <= adlen) { 20574d5c88faSreinoud /* have to append aed, see if we already have a spare one */ 20584d5c88faSreinoud extnr++; 20594d5c88faSreinoud ext = udf_node->ext[extnr]; 20604d5c88faSreinoud l_icb = udf_node->ext_loc[extnr]; 20614d5c88faSreinoud if (ext == NULL) { 20624d5c88faSreinoud DPRINTF(ALLOC,("adding allocation extent %d\n", extnr)); 2063a287d23dSreinoud 2064706de0e5Sreinoud error = udf_reserve_space(ump, NULL, UDF_C_NODE, 2065706de0e5Sreinoud vpart_num, 1, /* can fail */ false); 2066706de0e5Sreinoud if (error) { 2067706de0e5Sreinoud printf("UDF: couldn't reserve space for AED!\n"); 2068706de0e5Sreinoud return error; 2069706de0e5Sreinoud } 2070706de0e5Sreinoud error = udf_allocate_space(ump, NULL, UDF_C_NODE, 2071706de0e5Sreinoud vpart_num, 1, &lmapping); 20724d5c88faSreinoud lb_num = lmapping; 20734d5c88faSreinoud if (error) 2074706de0e5Sreinoud panic("UDF: couldn't allocate AED!\n"); 20754d5c88faSreinoud 20764d5c88faSreinoud /* initialise pointer to location */ 20774d5c88faSreinoud memset(&l_icb, 0, sizeof(struct long_ad)); 20784d5c88faSreinoud l_icb.len = udf_rw32(lb_size | UDF_EXT_REDIRECT); 20794d5c88faSreinoud l_icb.loc.lb_num = udf_rw32(lb_num); 20804d5c88faSreinoud l_icb.loc.part_num = udf_rw16(vpart_num); 20814d5c88faSreinoud 20824d5c88faSreinoud /* create new aed descriptor */ 2083a48555c3Sreinoud udf_create_logvol_dscr(ump, udf_node, &l_icb, &extdscr); 2084a48555c3Sreinoud ext = &extdscr->aee; 20854d5c88faSreinoud 20864d5c88faSreinoud udf_inittag(ump, &ext->tag, TAGID_ALLOCEXTENT, lb_num); 20874d5c88faSreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 20884d5c88faSreinoud max_l_ad = lb_size - dscr_size; 20894d5c88faSreinoud memset(ext->data, 0, max_l_ad); 20904d5c88faSreinoud ext->l_ad = udf_rw32(0); 20914d5c88faSreinoud ext->tag.desc_crc_len = 2092fbd470baSreinoud udf_rw16(dscr_size - UDF_DESC_TAG_LENGTH); 20934d5c88faSreinoud 20944d5c88faSreinoud /* declare aed */ 20954d5c88faSreinoud udf_node->num_extensions++; 20964d5c88faSreinoud udf_node->ext_loc[extnr] = l_icb; 20974d5c88faSreinoud udf_node->ext[extnr] = ext; 20984d5c88faSreinoud } 20994d5c88faSreinoud /* add redirect and adjust l_ad and crclen for old descr */ 21004d5c88faSreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 21014d5c88faSreinoud short_ad = (struct short_ad *) (data_pos + offset); 21024d5c88faSreinoud short_ad->len = l_icb.len; 21034d5c88faSreinoud short_ad->lb_num = l_icb.loc.lb_num; 21044d5c88faSreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 21054d5c88faSreinoud long_ad = (struct long_ad *) (data_pos + offset); 21064d5c88faSreinoud *long_ad = l_icb; 21074d5c88faSreinoud } 21084d5c88faSreinoud l_ad += adlen; 21094d5c88faSreinoud crclen += adlen; 2110fbd470baSreinoud dscr->tag.desc_crc_len = udf_rw16(crclen); 21114d5c88faSreinoud *l_ad_p = udf_rw32(l_ad); 21124d5c88faSreinoud 21134d5c88faSreinoud /* advance to the new extension */ 21144d5c88faSreinoud KASSERT(ext != NULL); 21154d5c88faSreinoud dscr = (union dscrptr *) ext; 21164d5c88faSreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 21174d5c88faSreinoud max_l_ad = lb_size - dscr_size; 21184d5c88faSreinoud data_pos = (uint8_t *) dscr + dscr_size; 21194d5c88faSreinoud 21204d5c88faSreinoud l_ad_p = &ext->l_ad; 21214d5c88faSreinoud l_ad = udf_rw32(*l_ad_p); 2122fbd470baSreinoud crclen = udf_rw16(dscr->tag.desc_crc_len); 21234d5c88faSreinoud offset = 0; 21244d5c88faSreinoud 21254d5c88faSreinoud /* adjust callees slot count for link insert */ 21264d5c88faSreinoud *slot += 1; 2127e979c658Sreinoud } 2128e979c658Sreinoud 2129e979c658Sreinoud /* write out the element */ 21304d5c88faSreinoud DPRINTF(PARANOIDADWLK, ("adding element : %p : v %d, lb %d, " 21314d5c88faSreinoud "len %d, flags %d\n", data_pos + offset, 21324d5c88faSreinoud icb->loc.part_num, icb->loc.lb_num, 21334d5c88faSreinoud UDF_EXT_LEN(icb->len), UDF_EXT_FLAGS(icb->len))); 2134e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 2135e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 2136e979c658Sreinoud short_ad->len = icb->len; 2137e979c658Sreinoud short_ad->lb_num = icb->loc.lb_num; 2138e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 2139e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 2140e979c658Sreinoud *long_ad = *icb; 2141e979c658Sreinoud } 2142e979c658Sreinoud 2143e979c658Sreinoud /* adjust logblks recorded count */ 21442b1b74bbSreinoud len = udf_rw32(icb->len); 21452b1b74bbSreinoud flags = UDF_EXT_FLAGS(len); 21464d5c88faSreinoud if (flags == UDF_EXT_ALLOCATED) 21472b1b74bbSreinoud logblks_rec += (UDF_EXT_LEN(len) + lb_size -1) / lb_size; 2148e979c658Sreinoud *logblks_rec_p = udf_rw64(logblks_rec); 2149e979c658Sreinoud 2150e979c658Sreinoud /* adjust l_ad and crclen when needed */ 2151e979c658Sreinoud if (offset >= l_ad) { 2152e979c658Sreinoud l_ad += adlen; 2153e979c658Sreinoud crclen += adlen; 2154fbd470baSreinoud dscr->tag.desc_crc_len = udf_rw16(crclen); 2155e979c658Sreinoud *l_ad_p = udf_rw32(l_ad); 2156e979c658Sreinoud } 2157e979c658Sreinoud 2158e979c658Sreinoud return 0; 2159e979c658Sreinoud } 2160e979c658Sreinoud 2161e979c658Sreinoud /* --------------------------------------------------------------------- */ 2162e979c658Sreinoud 21634d5c88faSreinoud static void 21644d5c88faSreinoud udf_count_alloc_exts(struct udf_node *udf_node) 21654d5c88faSreinoud { 21664d5c88faSreinoud struct long_ad s_ad; 21674d5c88faSreinoud uint32_t lb_num, len, flags; 21684d5c88faSreinoud uint16_t vpart_num; 21694d5c88faSreinoud int slot, eof; 21704d5c88faSreinoud int num_extents, extnr; 21714d5c88faSreinoud 21724d5c88faSreinoud if (udf_node->num_extensions == 0) 21734d5c88faSreinoud return; 21744d5c88faSreinoud 21754d5c88faSreinoud /* count number of allocation extents in use */ 21764d5c88faSreinoud num_extents = 0; 21774d5c88faSreinoud slot = 0; 21784d5c88faSreinoud for (;;) { 21794d5c88faSreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 21804d5c88faSreinoud if (eof) 21814d5c88faSreinoud break; 21824d5c88faSreinoud len = udf_rw32(s_ad.len); 21834d5c88faSreinoud flags = UDF_EXT_FLAGS(len); 21844d5c88faSreinoud 21854d5c88faSreinoud if (flags == UDF_EXT_REDIRECT) 21864d5c88faSreinoud num_extents++; 21874d5c88faSreinoud 21884d5c88faSreinoud slot++; 21894d5c88faSreinoud } 21904d5c88faSreinoud 21914d5c88faSreinoud DPRINTF(ALLOC, ("udf_count_alloc_ext counted %d live extents\n", 21924d5c88faSreinoud num_extents)); 21934d5c88faSreinoud 21944d5c88faSreinoud /* XXX choice: we could delay freeing them on node writeout */ 21954d5c88faSreinoud /* free excess entries */ 21964d5c88faSreinoud extnr = num_extents; 21974d5c88faSreinoud for (;extnr < udf_node->num_extensions; extnr++) { 21984d5c88faSreinoud DPRINTF(ALLOC, ("freeing alloc ext %d\n", extnr)); 21994d5c88faSreinoud /* free dscriptor */ 22004d5c88faSreinoud s_ad = udf_node->ext_loc[extnr]; 22014d5c88faSreinoud udf_free_logvol_dscr(udf_node->ump, &s_ad, 22024d5c88faSreinoud udf_node->ext[extnr]); 22034d5c88faSreinoud udf_node->ext[extnr] = NULL; 22044d5c88faSreinoud 22054d5c88faSreinoud /* free disc space */ 22064d5c88faSreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 22074d5c88faSreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 22084d5c88faSreinoud udf_free_allocated_space(udf_node->ump, lb_num, vpart_num, 1); 22094d5c88faSreinoud 22104d5c88faSreinoud memset(&udf_node->ext_loc[extnr], 0, sizeof(struct long_ad)); 22114d5c88faSreinoud } 22124d5c88faSreinoud 22134d5c88faSreinoud /* set our new number of allocation extents */ 22144d5c88faSreinoud udf_node->num_extensions = num_extents; 22154d5c88faSreinoud } 22164d5c88faSreinoud 22174d5c88faSreinoud 22184d5c88faSreinoud /* --------------------------------------------------------------------- */ 22194d5c88faSreinoud 2220e979c658Sreinoud /* 2221e979c658Sreinoud * Adjust the node's allocation descriptors to reflect the new mapping; do 2222e979c658Sreinoud * take note that we might glue to existing allocation descriptors. 2223e979c658Sreinoud * 2224e979c658Sreinoud * XXX Note there can only be one allocation being recorded/mount; maybe 2225e979c658Sreinoud * explicit allocation in shedule thread? 2226e979c658Sreinoud */ 2227e979c658Sreinoud 2228e979c658Sreinoud static void 2229e979c658Sreinoud udf_record_allocation_in_node(struct udf_mount *ump, struct buf *buf, 2230e979c658Sreinoud uint16_t vpart_num, uint64_t *mapping, struct long_ad *node_ad_cpy) 2231e979c658Sreinoud { 2232e979c658Sreinoud struct vnode *vp = buf->b_vp; 2233e979c658Sreinoud struct udf_node *udf_node = VTOI(vp); 2234e979c658Sreinoud struct file_entry *fe; 2235e979c658Sreinoud struct extfile_entry *efe; 2236e979c658Sreinoud struct icb_tag *icbtag; 2237e979c658Sreinoud struct long_ad s_ad, c_ad; 2238e979c658Sreinoud uint64_t inflen, from, till; 2239e979c658Sreinoud uint64_t foffset, end_foffset, restart_foffset; 2240e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 2241330482f6Sreinoud uint32_t max_len; 2242e979c658Sreinoud uint32_t num_lb, len, flags, lb_num; 2243e979c658Sreinoud uint32_t run_start; 22445eeb4f69Sreinoud uint32_t slot_offset, replace_len, replace; 2245e979c658Sreinoud int addr_type, icbflags; 224671c9aa33Sreinoud // int udf_c_type = buf->b_udf_c_type; 2247e979c658Sreinoud int lb_size, run_length, eof; 2248e979c658Sreinoud int slot, cpy_slot, cpy_slots, restart_slot; 2249e979c658Sreinoud int error; 2250e979c658Sreinoud 2251e979c658Sreinoud DPRINTF(ALLOC, ("udf_record_allocation_in_node\n")); 2252e979c658Sreinoud 225371c9aa33Sreinoud #if 0 225471c9aa33Sreinoud /* XXX disable sanity check for now */ 2255e979c658Sreinoud /* sanity check ... should be panic ? */ 2256e979c658Sreinoud if ((udf_c_type != UDF_C_USERDATA) && (udf_c_type != UDF_C_FIDS)) 2257e979c658Sreinoud return; 225871c9aa33Sreinoud #endif 2259e979c658Sreinoud 2260e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 2261330482f6Sreinoud max_len = ((UDF_EXT_MAXLEN / lb_size) * lb_size); 2262e979c658Sreinoud 2263e979c658Sreinoud /* do the job */ 2264e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); /* XXX can deadlock ? */ 22655eeb4f69Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 2266e979c658Sreinoud 2267e979c658Sreinoud fe = udf_node->fe; 2268e979c658Sreinoud efe = udf_node->efe; 2269e979c658Sreinoud if (fe) { 2270e979c658Sreinoud icbtag = &fe->icbtag; 2271e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 2272e979c658Sreinoud } else { 2273e979c658Sreinoud icbtag = &efe->icbtag; 2274e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 2275e979c658Sreinoud } 2276e979c658Sreinoud 2277e979c658Sreinoud /* do check if `till' is not past file information length */ 2278e979c658Sreinoud from = buf->b_lblkno * lb_size; 2279e979c658Sreinoud till = MIN(inflen, from + buf->b_resid); 2280e979c658Sreinoud 2281e979c658Sreinoud num_lb = (till - from + lb_size -1) / lb_size; 2282e979c658Sreinoud 22835eeb4f69Sreinoud DPRINTF(ALLOC, ("record allocation from %"PRIu64" + %d\n", from, buf->b_bcount)); 2284e979c658Sreinoud 2285e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 2286e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2287e979c658Sreinoud 2288e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 2289e979c658Sreinoud /* nothing to do */ 2290e979c658Sreinoud /* XXX clean up rest of node? just in case? */ 2291e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2292e979c658Sreinoud return; 2293e979c658Sreinoud } 2294e979c658Sreinoud 2295e979c658Sreinoud slot = 0; 2296e979c658Sreinoud cpy_slot = 0; 2297e979c658Sreinoud foffset = 0; 2298e979c658Sreinoud 2299e979c658Sreinoud /* 1) copy till first overlap piece to the rewrite buffer */ 2300e979c658Sreinoud for (;;) { 2301e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2302e979c658Sreinoud if (eof) { 2303e979c658Sreinoud DPRINTF(WRITE, 2304e979c658Sreinoud ("Record allocation in node " 2305e979c658Sreinoud "failed: encountered EOF\n")); 2306e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2307e979c658Sreinoud buf->b_error = EINVAL; 2308e979c658Sreinoud return; 2309e979c658Sreinoud } 2310e979c658Sreinoud len = udf_rw32(s_ad.len); 2311e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2312e979c658Sreinoud len = UDF_EXT_LEN(len); 2313e979c658Sreinoud 2314e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 2315e979c658Sreinoud slot++; 2316e979c658Sreinoud continue; 2317e979c658Sreinoud } 2318e979c658Sreinoud 2319e979c658Sreinoud end_foffset = foffset + len; 2320e979c658Sreinoud if (end_foffset > from) 2321e979c658Sreinoud break; /* found */ 2322e979c658Sreinoud 2323e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2324e979c658Sreinoud 2325e979c658Sreinoud DPRINTF(ALLOC, ("\t1: vp %d, lb %d, len %d, flags %d " 2326e979c658Sreinoud "-> stack\n", 2327e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2328e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2329e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2330e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2331e979c658Sreinoud 2332e979c658Sreinoud foffset = end_foffset; 2333e979c658Sreinoud slot++; 2334e979c658Sreinoud } 2335e979c658Sreinoud restart_slot = slot; 2336e979c658Sreinoud restart_foffset = foffset; 2337e979c658Sreinoud 2338e979c658Sreinoud /* 2) trunc overlapping slot at overlap and copy it */ 2339e979c658Sreinoud slot_offset = from - foffset; 2340e979c658Sreinoud if (slot_offset > 0) { 2341e979c658Sreinoud DPRINTF(ALLOC, ("\tslot_offset = %d, flags = %d (%d)\n", 2342e979c658Sreinoud slot_offset, flags >> 30, flags)); 2343e979c658Sreinoud 2344e979c658Sreinoud s_ad.len = udf_rw32(slot_offset | flags); 2345e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2346e979c658Sreinoud 2347e979c658Sreinoud DPRINTF(ALLOC, ("\t2: vp %d, lb %d, len %d, flags %d " 2348e979c658Sreinoud "-> stack\n", 2349e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2350e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2351e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2352e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2353e979c658Sreinoud } 2354e979c658Sreinoud foffset += slot_offset; 2355e979c658Sreinoud 2356e979c658Sreinoud /* 3) insert new mappings */ 2357e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 2358e979c658Sreinoud lb_num = 0; 2359e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 2360e979c658Sreinoud run_start = mapping[lb_num]; 2361e979c658Sreinoud run_length = 1; 2362e979c658Sreinoud while (lb_num < num_lb-1) { 2363e979c658Sreinoud if (mapping[lb_num+1] != mapping[lb_num]+1) 2364e979c658Sreinoud if (mapping[lb_num+1] != mapping[lb_num]) 2365e979c658Sreinoud break; 2366e979c658Sreinoud run_length++; 2367e979c658Sreinoud lb_num++; 2368e979c658Sreinoud } 2369e979c658Sreinoud /* insert slot for this mapping */ 2370e979c658Sreinoud len = run_length * lb_size; 2371e979c658Sreinoud 2372e979c658Sreinoud /* bounds checking */ 2373e979c658Sreinoud if (foffset + len > till) 2374e979c658Sreinoud len = till - foffset; 2375e979c658Sreinoud KASSERT(foffset + len <= inflen); 2376e979c658Sreinoud 2377e979c658Sreinoud s_ad.len = udf_rw32(len | UDF_EXT_ALLOCATED); 2378e979c658Sreinoud s_ad.loc.part_num = udf_rw16(vpart_num); 2379e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(run_start); 2380e979c658Sreinoud 2381e979c658Sreinoud foffset += len; 2382e979c658Sreinoud 2383e979c658Sreinoud /* paranoia */ 2384e979c658Sreinoud if (len == 0) { 2385e979c658Sreinoud DPRINTF(WRITE, 2386e979c658Sreinoud ("Record allocation in node " 2387e979c658Sreinoud "failed: insert failed\n")); 2388e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2389e979c658Sreinoud buf->b_error = EINVAL; 2390e979c658Sreinoud return; 2391e979c658Sreinoud } 2392e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2393e979c658Sreinoud 2394e979c658Sreinoud DPRINTF(ALLOC, ("\t3: insert new mapping vp %d lb %d, len %d, " 2395e979c658Sreinoud "flags %d -> stack\n", 2396e979c658Sreinoud udf_rw16(s_ad.loc.part_num), udf_rw32(s_ad.loc.lb_num), 2397e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2398e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2399e979c658Sreinoud } 2400e979c658Sreinoud 2401e979c658Sreinoud /* 4) pop replaced length */ 2402e979c658Sreinoud slot = restart_slot; 2403e979c658Sreinoud foffset = restart_foffset; 2404e979c658Sreinoud 24055eeb4f69Sreinoud replace_len = till - foffset; /* total amount of bytes to pop */ 2406af39897aSreinoud slot_offset = from - foffset; /* offset in first encounted slot */ 24075eeb4f69Sreinoud KASSERT((slot_offset % lb_size) == 0); 24085eeb4f69Sreinoud 2409e979c658Sreinoud for (;;) { 2410e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2411e979c658Sreinoud if (eof) 2412e979c658Sreinoud break; 2413e979c658Sreinoud 2414e979c658Sreinoud len = udf_rw32(s_ad.len); 2415e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2416e979c658Sreinoud len = UDF_EXT_LEN(len); 2417e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 2418e979c658Sreinoud 2419e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 2420e979c658Sreinoud slot++; 2421e979c658Sreinoud continue; 2422e979c658Sreinoud } 2423e979c658Sreinoud 2424af39897aSreinoud DPRINTF(ALLOC, ("\t4i: got slot %d, slot_offset %d, " 24255eeb4f69Sreinoud "replace_len %d, " 2426af39897aSreinoud "vp %d, lb %d, len %d, flags %d\n", 24275eeb4f69Sreinoud slot, slot_offset, replace_len, 2428af39897aSreinoud udf_rw16(s_ad.loc.part_num), 2429e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2430e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2431e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2432e979c658Sreinoud 24335eeb4f69Sreinoud /* adjust for slot offset */ 24345eeb4f69Sreinoud if (slot_offset) { 24355eeb4f69Sreinoud DPRINTF(ALLOC, ("\t4s: skipping %d\n", slot_offset)); 24365eeb4f69Sreinoud lb_num += slot_offset / lb_size; 2437e979c658Sreinoud len -= slot_offset; 2438e979c658Sreinoud foffset += slot_offset; 24395eeb4f69Sreinoud replace_len -= slot_offset; 2440af39897aSreinoud 24415eeb4f69Sreinoud /* mark adjusted */ 24425eeb4f69Sreinoud slot_offset = 0; 24435eeb4f69Sreinoud } 24445eeb4f69Sreinoud 24455eeb4f69Sreinoud /* advance for (the rest of) this slot */ 24465eeb4f69Sreinoud replace = MIN(len, replace_len); 24475eeb4f69Sreinoud DPRINTF(ALLOC, ("\t4d: replacing %d\n", replace)); 24485eeb4f69Sreinoud 24495eeb4f69Sreinoud /* advance for this slot */ 24505eeb4f69Sreinoud if (replace) { 2451d3bf9c7bSreinoud /* note: dont round DOWN on num_lb since we then 2452d3bf9c7bSreinoud * forget the last partial one */ 24535eeb4f69Sreinoud num_lb = (replace + lb_size - 1) / lb_size; 24545eeb4f69Sreinoud if (flags != UDF_EXT_FREE) { 2455e979c658Sreinoud udf_free_allocated_space(ump, lb_num, 2456e979c658Sreinoud udf_rw16(s_ad.loc.part_num), num_lb); 2457e979c658Sreinoud } 24585eeb4f69Sreinoud lb_num += num_lb; 24595eeb4f69Sreinoud len -= replace; 24605eeb4f69Sreinoud foffset += replace; 24615eeb4f69Sreinoud replace_len -= replace; 24625eeb4f69Sreinoud } 2463af39897aSreinoud 24645eeb4f69Sreinoud /* do we have a slot tail ? */ 2465e979c658Sreinoud if (len) { 24665eeb4f69Sreinoud KASSERT(foffset % lb_size == 0); 2467e979c658Sreinoud 2468e979c658Sreinoud /* we arrived at our point, push remainder */ 2469e979c658Sreinoud s_ad.len = udf_rw32(len | flags); 2470e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(lb_num); 24715eeb4f69Sreinoud if (flags == UDF_EXT_FREE) 24725eeb4f69Sreinoud s_ad.loc.lb_num = udf_rw32(0); 2473e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2474e979c658Sreinoud foffset += len; 2475e979c658Sreinoud slot++; 2476e979c658Sreinoud 2477e979c658Sreinoud DPRINTF(ALLOC, ("\t4: vp %d, lb %d, len %d, flags %d " 2478e979c658Sreinoud "-> stack\n", 2479e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2480e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2481e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2482e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2483e979c658Sreinoud break; 2484e979c658Sreinoud } 24855eeb4f69Sreinoud 2486e979c658Sreinoud slot++; 2487e979c658Sreinoud } 2488e979c658Sreinoud 2489e979c658Sreinoud /* 5) copy remainder */ 2490e979c658Sreinoud for (;;) { 2491e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2492e979c658Sreinoud if (eof) 2493e979c658Sreinoud break; 2494e979c658Sreinoud 2495e979c658Sreinoud len = udf_rw32(s_ad.len); 2496e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2497e979c658Sreinoud len = UDF_EXT_LEN(len); 2498e979c658Sreinoud 2499e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 2500e979c658Sreinoud slot++; 2501e979c658Sreinoud continue; 2502e979c658Sreinoud } 2503e979c658Sreinoud 2504e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2505e979c658Sreinoud 2506e979c658Sreinoud DPRINTF(ALLOC, ("\t5: insert new mapping " 2507e979c658Sreinoud "vp %d lb %d, len %d, flags %d " 2508e979c658Sreinoud "-> stack\n", 2509e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2510e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2511e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2512e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2513e979c658Sreinoud 2514e979c658Sreinoud slot++; 2515e979c658Sreinoud } 2516e979c658Sreinoud 2517e979c658Sreinoud /* 6) reset node descriptors */ 2518e979c658Sreinoud udf_wipe_adslots(udf_node); 2519e979c658Sreinoud 2520e979c658Sreinoud /* 7) copy back extents; merge when possible. Recounting on the fly */ 2521e979c658Sreinoud cpy_slots = cpy_slot; 2522e979c658Sreinoud 2523e979c658Sreinoud c_ad = node_ad_cpy[0]; 2524e979c658Sreinoud slot = 0; 2525e979c658Sreinoud DPRINTF(ALLOC, ("\t7s: stack -> got mapping vp %d " 2526e979c658Sreinoud "lb %d, len %d, flags %d\n", 2527e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2528e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2529e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2530e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2531e979c658Sreinoud 2532e979c658Sreinoud for (cpy_slot = 1; cpy_slot < cpy_slots; cpy_slot++) { 2533e979c658Sreinoud s_ad = node_ad_cpy[cpy_slot]; 2534e979c658Sreinoud 2535e979c658Sreinoud DPRINTF(ALLOC, ("\t7i: stack -> got mapping vp %d " 2536e979c658Sreinoud "lb %d, len %d, flags %d\n", 2537e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2538e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2539e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2540e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2541e979c658Sreinoud 2542e979c658Sreinoud /* see if we can merge */ 2543330482f6Sreinoud if (udf_ads_merge(max_len, lb_size, &c_ad, &s_ad)) { 2544e979c658Sreinoud /* not mergable (anymore) */ 2545e979c658Sreinoud DPRINTF(ALLOC, ("\t7: appending vp %d lb %d, " 2546e979c658Sreinoud "len %d, flags %d\n", 2547e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2548e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2549e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2550e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2551e979c658Sreinoud 25524d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2553e979c658Sreinoud if (error) { 2554e979c658Sreinoud buf->b_error = error; 2555e979c658Sreinoud goto out; 2556e979c658Sreinoud } 2557e979c658Sreinoud c_ad = s_ad; 2558e979c658Sreinoud slot++; 2559e979c658Sreinoud } 2560e979c658Sreinoud } 2561e979c658Sreinoud 2562e979c658Sreinoud /* 8) push rest slot (if any) */ 2563e979c658Sreinoud if (UDF_EXT_LEN(c_ad.len) > 0) { 2564e979c658Sreinoud DPRINTF(ALLOC, ("\t8: last append vp %d lb %d, " 2565e979c658Sreinoud "len %d, flags %d\n", 2566e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2567e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2568e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2569e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2570e979c658Sreinoud 25714d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2572e979c658Sreinoud if (error) { 2573e979c658Sreinoud buf->b_error = error; 2574e979c658Sreinoud goto out; 2575e979c658Sreinoud } 2576e979c658Sreinoud } 2577e979c658Sreinoud 2578e979c658Sreinoud out: 25794d5c88faSreinoud udf_count_alloc_exts(udf_node); 25804d5c88faSreinoud 2581e979c658Sreinoud /* the node's descriptors should now be sane */ 2582e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 25835eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2584e979c658Sreinoud 2585e979c658Sreinoud KASSERT(orig_inflen == new_inflen); 2586e979c658Sreinoud KASSERT(new_lbrec >= orig_lbrec); 2587e979c658Sreinoud 2588e979c658Sreinoud return; 2589e979c658Sreinoud } 2590e979c658Sreinoud 2591e979c658Sreinoud /* --------------------------------------------------------------------- */ 2592e979c658Sreinoud 2593e979c658Sreinoud int 2594e979c658Sreinoud udf_grow_node(struct udf_node *udf_node, uint64_t new_size) 2595e979c658Sreinoud { 2596e979c658Sreinoud struct vnode *vp = udf_node->vnode; 2597e979c658Sreinoud struct udf_mount *ump = udf_node->ump; 2598e979c658Sreinoud struct file_entry *fe; 2599e979c658Sreinoud struct extfile_entry *efe; 2600e979c658Sreinoud struct icb_tag *icbtag; 2601e979c658Sreinoud struct long_ad c_ad, s_ad; 2602e979c658Sreinoud uint64_t size_diff, old_size, inflen, objsize, chunk, append_len; 2603e979c658Sreinoud uint64_t foffset, end_foffset; 2604e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 2605330482f6Sreinoud uint32_t lb_size, unit_size, dscr_size, crclen, lastblock_grow; 2606a287d23dSreinoud uint32_t icbflags, len, flags, max_len; 2607e979c658Sreinoud uint32_t max_l_ad, l_ad, l_ea; 2608a287d23dSreinoud uint16_t my_part, dst_part; 260977d54b3dSchristos uint8_t *evacuated_data; 2610a287d23dSreinoud int addr_type; 261177d54b3dSchristos int slot; 2612706de0e5Sreinoud int eof, error; 2613e979c658Sreinoud 2614e979c658Sreinoud DPRINTF(ALLOC, ("udf_grow_node\n")); 2615e979c658Sreinoud 2616e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 26175eeb4f69Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 26185eeb4f69Sreinoud 2619e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 2620330482f6Sreinoud 2621330482f6Sreinoud /* max_len in unit's IFF its a metadata node or metadata mirror node */ 2622330482f6Sreinoud unit_size = lb_size; 2623330482f6Sreinoud if ((udf_node == ump->metadata_node) || (udf_node == ump->metadatamirror_node)) 2624330482f6Sreinoud unit_size = ump->metadata_alloc_unit_size * lb_size; 2625330482f6Sreinoud max_len = ((UDF_EXT_MAXLEN / unit_size) * unit_size); 2626e979c658Sreinoud 2627e979c658Sreinoud fe = udf_node->fe; 2628e979c658Sreinoud efe = udf_node->efe; 2629e979c658Sreinoud if (fe) { 2630e979c658Sreinoud icbtag = &fe->icbtag; 2631e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 2632e979c658Sreinoud objsize = inflen; 2633e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 2634e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 2635e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 2636e979c658Sreinoud } else { 2637e979c658Sreinoud icbtag = &efe->icbtag; 2638e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 2639e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 2640e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 2641e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 2642e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 2643e979c658Sreinoud } 2644e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 2645e979c658Sreinoud 2646e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 2647e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2648e979c658Sreinoud 2649e979c658Sreinoud old_size = inflen; 2650e979c658Sreinoud size_diff = new_size - old_size; 2651e979c658Sreinoud 2652e979c658Sreinoud DPRINTF(ALLOC, ("\tfrom %"PRIu64" to %"PRIu64"\n", old_size, new_size)); 2653e979c658Sreinoud 2654e979c658Sreinoud evacuated_data = NULL; 2655e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 2656e979c658Sreinoud if (l_ad + size_diff <= max_l_ad) { 2657e979c658Sreinoud /* only reflect size change directly in the node */ 2658e979c658Sreinoud inflen += size_diff; 2659e979c658Sreinoud objsize += size_diff; 2660e979c658Sreinoud l_ad += size_diff; 2661e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 2662e979c658Sreinoud if (fe) { 2663e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2664e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 2665fbd470baSreinoud fe->tag.desc_crc_len = udf_rw16(crclen); 2666e979c658Sreinoud } else { 2667e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2668e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2669e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 2670fbd470baSreinoud efe->tag.desc_crc_len = udf_rw16(crclen); 2671e979c658Sreinoud } 2672e979c658Sreinoud error = 0; 2673e979c658Sreinoud 2674e979c658Sreinoud /* set new size for uvm */ 2675e979c658Sreinoud uvm_vnp_setwritesize(vp, new_size); 26769acf3303Sreinoud uvm_vnp_setsize(vp, new_size); 2677e979c658Sreinoud 2678e979c658Sreinoud #if 0 2679e979c658Sreinoud /* zero append space in buffer */ 26808fe919f5Shannken ubc_zerorange(&vp->v_uobj, old_size, 2681*6c7e5f2aSad new_size - old_size, UBC_VNODE_FLAGS(vp)); 2682e979c658Sreinoud #endif 2683e979c658Sreinoud 26845eeb4f69Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 26855eeb4f69Sreinoud 2686e979c658Sreinoud /* unlock */ 2687e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2688e979c658Sreinoud 2689e979c658Sreinoud KASSERT(new_inflen == orig_inflen + size_diff); 2690e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2691e979c658Sreinoud KASSERT(new_lbrec == 0); 2692e979c658Sreinoud return 0; 2693e979c658Sreinoud } 2694e979c658Sreinoud 2695e979c658Sreinoud DPRINTF(ALLOC, ("\tCONVERT from internal\n")); 2696e979c658Sreinoud 2697e979c658Sreinoud if (old_size > 0) { 2698e979c658Sreinoud /* allocate some space and copy in the stuff to keep */ 2699e979c658Sreinoud evacuated_data = malloc(lb_size, M_UDFTEMP, M_WAITOK); 2700e979c658Sreinoud memset(evacuated_data, 0, lb_size); 2701e979c658Sreinoud 2702e979c658Sreinoud /* node is locked, so safe to exit mutex */ 2703e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2704e979c658Sreinoud 2705e979c658Sreinoud /* read in using the `normal' vn_rdwr() */ 2706e979c658Sreinoud error = vn_rdwr(UIO_READ, udf_node->vnode, 2707e979c658Sreinoud evacuated_data, old_size, 0, 2708e979c658Sreinoud UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED, 2709e979c658Sreinoud FSCRED, NULL, NULL); 2710e979c658Sreinoud 2711e979c658Sreinoud /* enter again */ 2712e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 2713e979c658Sreinoud } 2714e979c658Sreinoud 2715aa9f26d0Sreinoud /* convert to a normal alloc and select type */ 2716a287d23dSreinoud my_part = udf_rw16(udf_node->loc.loc.part_num); 2717706de0e5Sreinoud dst_part = udf_get_record_vpart(ump, udf_get_c_type(udf_node)); 2718a287d23dSreinoud addr_type = UDF_ICB_SHORT_ALLOC; 2719a287d23dSreinoud if (dst_part != my_part) 2720a287d23dSreinoud addr_type = UDF_ICB_LONG_ALLOC; 2721aa9f26d0Sreinoud 2722e979c658Sreinoud icbflags &= ~UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2723a287d23dSreinoud icbflags |= addr_type; 2724e979c658Sreinoud icbtag->flags = udf_rw16(icbflags); 2725e979c658Sreinoud 2726e979c658Sreinoud /* wipe old descriptor space */ 2727e979c658Sreinoud udf_wipe_adslots(udf_node); 2728e979c658Sreinoud 2729e979c658Sreinoud memset(&c_ad, 0, sizeof(struct long_ad)); 2730e979c658Sreinoud c_ad.len = udf_rw32(old_size | UDF_EXT_FREE); 2731e979c658Sreinoud c_ad.loc.part_num = udf_rw16(0); /* not relevant */ 2732e979c658Sreinoud c_ad.loc.lb_num = udf_rw32(0); /* not relevant */ 2733e979c658Sreinoud 2734e979c658Sreinoud slot = 0; 2735e979c658Sreinoud } else { 2736e979c658Sreinoud /* goto the last entry (if any) */ 2737e979c658Sreinoud slot = 0; 2738e979c658Sreinoud foffset = 0; 2739e979c658Sreinoud memset(&c_ad, 0, sizeof(struct long_ad)); 2740e979c658Sreinoud for (;;) { 2741e979c658Sreinoud udf_get_adslot(udf_node, slot, &c_ad, &eof); 2742e979c658Sreinoud if (eof) 2743e979c658Sreinoud break; 2744e979c658Sreinoud 2745e979c658Sreinoud len = udf_rw32(c_ad.len); 2746e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2747e979c658Sreinoud len = UDF_EXT_LEN(len); 2748e979c658Sreinoud 2749e979c658Sreinoud end_foffset = foffset + len; 2750e979c658Sreinoud if (flags != UDF_EXT_REDIRECT) 2751e979c658Sreinoud foffset = end_foffset; 2752e979c658Sreinoud 2753e979c658Sreinoud slot++; 2754e979c658Sreinoud } 2755e979c658Sreinoud /* at end of adslots */ 2756e979c658Sreinoud 2757e979c658Sreinoud /* special case if the old size was zero, then there is no last slot */ 2758e979c658Sreinoud if (old_size == 0) { 2759e979c658Sreinoud c_ad.len = udf_rw32(0 | UDF_EXT_FREE); 2760e979c658Sreinoud c_ad.loc.part_num = udf_rw16(0); /* not relevant */ 2761e979c658Sreinoud c_ad.loc.lb_num = udf_rw32(0); /* not relevant */ 2762e979c658Sreinoud } else { 2763e979c658Sreinoud /* refetch last slot */ 2764e979c658Sreinoud slot--; 2765e979c658Sreinoud udf_get_adslot(udf_node, slot, &c_ad, &eof); 2766e979c658Sreinoud } 2767e979c658Sreinoud } 2768e979c658Sreinoud 2769e979c658Sreinoud /* 2770e979c658Sreinoud * If the length of the last slot is not a multiple of lb_size, adjust 2771e979c658Sreinoud * length so that it is; don't forget to adjust `append_len'! relevant for 2772e979c658Sreinoud * extending existing files 2773e979c658Sreinoud */ 2774e979c658Sreinoud len = udf_rw32(c_ad.len); 2775e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2776e979c658Sreinoud len = UDF_EXT_LEN(len); 2777e979c658Sreinoud 2778e979c658Sreinoud lastblock_grow = 0; 2779e979c658Sreinoud if (len % lb_size > 0) { 2780e979c658Sreinoud lastblock_grow = lb_size - (len % lb_size); 2781e979c658Sreinoud lastblock_grow = MIN(size_diff, lastblock_grow); 2782e979c658Sreinoud len += lastblock_grow; 2783e979c658Sreinoud c_ad.len = udf_rw32(len | flags); 2784e979c658Sreinoud 2785e979c658Sreinoud /* TODO zero appened space in buffer! */ 27868fe919f5Shannken /* using ubc_zerorange(&vp->v_uobj, old_size, */ 2787*6c7e5f2aSad /* new_size - old_size, UBC_VNODE_FLAGS(vp)); ? */ 2788e979c658Sreinoud } 2789e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 2790e979c658Sreinoud 2791e979c658Sreinoud /* size_diff can be bigger than allowed, so grow in chunks */ 2792e979c658Sreinoud append_len = size_diff - lastblock_grow; 2793e979c658Sreinoud while (append_len > 0) { 2794e979c658Sreinoud chunk = MIN(append_len, max_len); 2795e979c658Sreinoud s_ad.len = udf_rw32(chunk | UDF_EXT_FREE); 2796e979c658Sreinoud s_ad.loc.part_num = udf_rw16(0); 2797e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(0); 2798e979c658Sreinoud 2799330482f6Sreinoud if (udf_ads_merge(max_len, lb_size, &c_ad, &s_ad)) { 2800e979c658Sreinoud /* not mergable (anymore) */ 28014d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2802e979c658Sreinoud if (error) 2803e979c658Sreinoud goto errorout; 2804e979c658Sreinoud slot++; 2805e979c658Sreinoud c_ad = s_ad; 2806e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 2807e979c658Sreinoud } 2808e979c658Sreinoud append_len -= chunk; 2809e979c658Sreinoud } 2810e979c658Sreinoud 2811e979c658Sreinoud /* if there is a rest piece in the accumulator, append it */ 2812af39897aSreinoud if (UDF_EXT_LEN(udf_rw32(c_ad.len)) > 0) { 28134d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 2814e979c658Sreinoud if (error) 2815e979c658Sreinoud goto errorout; 2816e979c658Sreinoud slot++; 2817e979c658Sreinoud } 2818e979c658Sreinoud 2819e979c658Sreinoud /* if there is a rest piece that didn't fit, append it */ 2820af39897aSreinoud if (UDF_EXT_LEN(udf_rw32(s_ad.len)) > 0) { 28214d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &s_ad); 2822e979c658Sreinoud if (error) 2823e979c658Sreinoud goto errorout; 2824e979c658Sreinoud slot++; 2825e979c658Sreinoud } 2826e979c658Sreinoud 2827e979c658Sreinoud inflen += size_diff; 2828e979c658Sreinoud objsize += size_diff; 2829e979c658Sreinoud if (fe) { 2830e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2831e979c658Sreinoud } else { 2832e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2833e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2834e979c658Sreinoud } 2835e979c658Sreinoud error = 0; 2836e979c658Sreinoud 2837e979c658Sreinoud if (evacuated_data) { 2838e979c658Sreinoud /* set new write size for uvm */ 2839e979c658Sreinoud uvm_vnp_setwritesize(vp, old_size); 2840e979c658Sreinoud 2841e979c658Sreinoud /* write out evacuated data */ 2842e979c658Sreinoud error = vn_rdwr(UIO_WRITE, udf_node->vnode, 2843e979c658Sreinoud evacuated_data, old_size, 0, 2844e979c658Sreinoud UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED, 2845e979c658Sreinoud FSCRED, NULL, NULL); 2846e979c658Sreinoud uvm_vnp_setsize(vp, old_size); 2847e979c658Sreinoud } 2848e979c658Sreinoud 2849e979c658Sreinoud errorout: 2850e979c658Sreinoud if (evacuated_data) 2851e979c658Sreinoud free(evacuated_data, M_UDFTEMP); 2852e979c658Sreinoud 28534d5c88faSreinoud udf_count_alloc_exts(udf_node); 28544d5c88faSreinoud 2855e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 28565eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 28575eeb4f69Sreinoud 2858e979c658Sreinoud KASSERT(new_inflen == orig_inflen + size_diff); 2859e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2860e979c658Sreinoud 2861e979c658Sreinoud return error; 2862e979c658Sreinoud } 2863e979c658Sreinoud 2864e979c658Sreinoud /* --------------------------------------------------------------------- */ 2865e979c658Sreinoud 2866e979c658Sreinoud int 2867e979c658Sreinoud udf_shrink_node(struct udf_node *udf_node, uint64_t new_size) 2868e979c658Sreinoud { 2869e979c658Sreinoud struct vnode *vp = udf_node->vnode; 2870e979c658Sreinoud struct udf_mount *ump = udf_node->ump; 2871e979c658Sreinoud struct file_entry *fe; 2872e979c658Sreinoud struct extfile_entry *efe; 2873e979c658Sreinoud struct icb_tag *icbtag; 2874e979c658Sreinoud struct long_ad c_ad, s_ad, *node_ad_cpy; 2875e979c658Sreinoud uint64_t size_diff, old_size, inflen, objsize; 2876e979c658Sreinoud uint64_t foffset, end_foffset; 2877e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 2878330482f6Sreinoud uint32_t lb_size, unit_size, dscr_size, crclen; 28797e99247bSreinoud uint32_t slot_offset, slot_offset_lb; 2880e979c658Sreinoud uint32_t len, flags, max_len; 2881e979c658Sreinoud uint32_t num_lb, lb_num; 2882e979c658Sreinoud uint32_t max_l_ad, l_ad, l_ea; 2883e979c658Sreinoud uint16_t vpart_num; 2884e979c658Sreinoud uint8_t *data_pos; 2885e979c658Sreinoud int icbflags, addr_type; 2886e979c658Sreinoud int slot, cpy_slot, cpy_slots; 2887e979c658Sreinoud int eof, error; 2888e979c658Sreinoud 2889e979c658Sreinoud DPRINTF(ALLOC, ("udf_shrink_node\n")); 2890e979c658Sreinoud 2891e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 28925eeb4f69Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 28935eeb4f69Sreinoud 2894e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 2895330482f6Sreinoud 2896330482f6Sreinoud /* max_len in unit's IFF its a metadata node or metadata mirror node */ 2897330482f6Sreinoud unit_size = lb_size; 2898330482f6Sreinoud if ((udf_node == ump->metadata_node) || (udf_node == ump->metadatamirror_node)) 2899330482f6Sreinoud unit_size = ump->metadata_alloc_unit_size * lb_size; 2900330482f6Sreinoud max_len = ((UDF_EXT_MAXLEN / unit_size) * unit_size); 2901e979c658Sreinoud 2902e979c658Sreinoud /* do the work */ 2903e979c658Sreinoud fe = udf_node->fe; 2904e979c658Sreinoud efe = udf_node->efe; 2905e979c658Sreinoud if (fe) { 2906e979c658Sreinoud icbtag = &fe->icbtag; 2907e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 2908e979c658Sreinoud objsize = inflen; 2909e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 2910e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 2911e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 2912e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 2913e979c658Sreinoud } else { 2914e979c658Sreinoud icbtag = &efe->icbtag; 2915e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 2916e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 2917e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 2918e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 2919e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 2920e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 2921e979c658Sreinoud } 2922e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 2923e979c658Sreinoud 2924e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 2925e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2926e979c658Sreinoud 2927e979c658Sreinoud old_size = inflen; 2928e979c658Sreinoud size_diff = old_size - new_size; 2929e979c658Sreinoud 2930e979c658Sreinoud DPRINTF(ALLOC, ("\tfrom %"PRIu64" to %"PRIu64"\n", old_size, new_size)); 2931e979c658Sreinoud 2932e979c658Sreinoud /* shrink the node to its new size */ 2933e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 2934e979c658Sreinoud /* only reflect size change directly in the node */ 2935e979c658Sreinoud KASSERT(new_size <= max_l_ad); 2936e979c658Sreinoud inflen -= size_diff; 2937e979c658Sreinoud objsize -= size_diff; 2938e979c658Sreinoud l_ad -= size_diff; 2939e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 2940e979c658Sreinoud if (fe) { 2941e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2942e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 2943fbd470baSreinoud fe->tag.desc_crc_len = udf_rw16(crclen); 2944e979c658Sreinoud } else { 2945e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2946e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2947e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 2948fbd470baSreinoud efe->tag.desc_crc_len = udf_rw16(crclen); 2949e979c658Sreinoud } 2950e979c658Sreinoud error = 0; 295114d24a67Sreinoud 295214d24a67Sreinoud /* clear the space in the descriptor */ 295371c16659Sreinoud KASSERT(old_size >= new_size); 295414d24a67Sreinoud memset(data_pos + new_size, 0, old_size - new_size); 295514d24a67Sreinoud 2956e979c658Sreinoud /* TODO zero appened space in buffer! */ 29578fe919f5Shannken /* using ubc_zerorange(&vp->v_uobj, old_size, */ 2958*6c7e5f2aSad /* old_size - new_size, UBC_VNODE_FLAGS(vp)); ? */ 2959e979c658Sreinoud 2960e979c658Sreinoud /* set new size for uvm */ 2961e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 2962e979c658Sreinoud 2963e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 29645eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 29655eeb4f69Sreinoud 2966e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 2967e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2968e979c658Sreinoud KASSERT(new_lbrec == 0); 2969e979c658Sreinoud 2970e979c658Sreinoud return 0; 2971e979c658Sreinoud } 2972e979c658Sreinoud 2973e979c658Sreinoud /* setup node cleanup extents copy space */ 2974e979c658Sreinoud node_ad_cpy = malloc(lb_size * UDF_MAX_ALLOC_EXTENTS, 2975e979c658Sreinoud M_UDFMNT, M_WAITOK); 2976e979c658Sreinoud memset(node_ad_cpy, 0, lb_size * UDF_MAX_ALLOC_EXTENTS); 2977e979c658Sreinoud 2978e979c658Sreinoud /* 2979e979c658Sreinoud * Shrink the node by releasing the allocations and truncate the last 2980e979c658Sreinoud * allocation to the new size. If the new size fits into the 2981e979c658Sreinoud * allocation descriptor itself, transform it into an 2982e979c658Sreinoud * UDF_ICB_INTERN_ALLOC. 2983e979c658Sreinoud */ 2984e979c658Sreinoud slot = 0; 2985e979c658Sreinoud cpy_slot = 0; 2986e979c658Sreinoud foffset = 0; 2987e979c658Sreinoud 2988e979c658Sreinoud /* 1) copy till first overlap piece to the rewrite buffer */ 2989e979c658Sreinoud for (;;) { 2990e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2991e979c658Sreinoud if (eof) { 2992e979c658Sreinoud DPRINTF(WRITE, 2993e979c658Sreinoud ("Shrink node failed: " 2994e979c658Sreinoud "encountered EOF\n")); 2995e979c658Sreinoud error = EINVAL; 2996e979c658Sreinoud goto errorout; /* panic? */ 2997e979c658Sreinoud } 2998e979c658Sreinoud len = udf_rw32(s_ad.len); 2999e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 3000e979c658Sreinoud len = UDF_EXT_LEN(len); 3001e979c658Sreinoud 3002e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 3003e979c658Sreinoud slot++; 3004e979c658Sreinoud continue; 3005e979c658Sreinoud } 3006e979c658Sreinoud 3007e979c658Sreinoud end_foffset = foffset + len; 3008e979c658Sreinoud if (end_foffset > new_size) 3009e979c658Sreinoud break; /* found */ 3010e979c658Sreinoud 3011e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 3012e979c658Sreinoud 3013e979c658Sreinoud DPRINTF(ALLOC, ("\t1: vp %d, lb %d, len %d, flags %d " 3014e979c658Sreinoud "-> stack\n", 3015e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 3016e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 3017e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 3018e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 3019e979c658Sreinoud 3020e979c658Sreinoud foffset = end_foffset; 3021e979c658Sreinoud slot++; 3022e979c658Sreinoud } 3023e979c658Sreinoud slot_offset = new_size - foffset; 3024e979c658Sreinoud 3025e979c658Sreinoud /* 2) trunc overlapping slot at overlap and copy it */ 3026e979c658Sreinoud if (slot_offset > 0) { 3027e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 3028e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 3029e979c658Sreinoud 3030e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 30317e99247bSreinoud /* calculate extent in lb, and offset in lb */ 30327e99247bSreinoud num_lb = (len + lb_size -1) / lb_size; 30337e99247bSreinoud slot_offset_lb = (slot_offset + lb_size -1) / lb_size; 30347e99247bSreinoud 30357e99247bSreinoud /* adjust our slot */ 30367e99247bSreinoud lb_num += slot_offset_lb; 30377e99247bSreinoud num_lb -= slot_offset_lb; 3038e979c658Sreinoud 3039e979c658Sreinoud udf_free_allocated_space(ump, lb_num, vpart_num, num_lb); 3040e979c658Sreinoud } 3041e979c658Sreinoud 3042e979c658Sreinoud s_ad.len = udf_rw32(slot_offset | flags); 3043e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 3044e979c658Sreinoud slot++; 3045e979c658Sreinoud 3046e979c658Sreinoud DPRINTF(ALLOC, ("\t2: vp %d, lb %d, len %d, flags %d " 3047e979c658Sreinoud "-> stack\n", 3048e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 3049e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 3050e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 3051e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 3052e979c658Sreinoud } 3053e979c658Sreinoud 3054e979c658Sreinoud /* 3) delete remainder */ 3055e979c658Sreinoud for (;;) { 3056e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 3057e979c658Sreinoud if (eof) 3058e979c658Sreinoud break; 3059e979c658Sreinoud 3060e979c658Sreinoud len = udf_rw32(s_ad.len); 3061e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 3062e979c658Sreinoud len = UDF_EXT_LEN(len); 3063e979c658Sreinoud 3064e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 3065e979c658Sreinoud slot++; 3066e979c658Sreinoud continue; 3067e979c658Sreinoud } 3068e979c658Sreinoud 3069e979c658Sreinoud DPRINTF(ALLOC, ("\t3: delete remainder " 3070e979c658Sreinoud "vp %d lb %d, len %d, flags %d\n", 3071e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 3072e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 3073e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 3074e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 3075e979c658Sreinoud 3076e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 3077e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 3078e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 3079e979c658Sreinoud num_lb = (len + lb_size - 1) / lb_size; 3080e979c658Sreinoud 3081e979c658Sreinoud udf_free_allocated_space(ump, lb_num, vpart_num, 3082e979c658Sreinoud num_lb); 3083e979c658Sreinoud } 3084e979c658Sreinoud 3085e979c658Sreinoud slot++; 3086e979c658Sreinoud } 3087e979c658Sreinoud 3088e979c658Sreinoud /* 4) if it will fit into the descriptor then convert */ 3089e979c658Sreinoud if (new_size < max_l_ad) { 3090e979c658Sreinoud /* 3091e979c658Sreinoud * resque/evacuate old piece by reading it in, and convert it 3092e979c658Sreinoud * to internal alloc. 3093e979c658Sreinoud */ 3094e979c658Sreinoud if (new_size == 0) { 3095e979c658Sreinoud /* XXX/TODO only for zero sizing now */ 3096e979c658Sreinoud udf_wipe_adslots(udf_node); 3097e979c658Sreinoud 3098e979c658Sreinoud icbflags &= ~UDF_ICB_TAG_FLAGS_ALLOC_MASK; 3099e979c658Sreinoud icbflags |= UDF_ICB_INTERN_ALLOC; 3100e979c658Sreinoud icbtag->flags = udf_rw16(icbflags); 3101e979c658Sreinoud 3102e979c658Sreinoud inflen -= size_diff; KASSERT(inflen == 0); 3103e979c658Sreinoud objsize -= size_diff; 3104e979c658Sreinoud l_ad = new_size; 3105e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 3106e979c658Sreinoud if (fe) { 3107e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 3108e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 3109fbd470baSreinoud fe->tag.desc_crc_len = udf_rw16(crclen); 3110e979c658Sreinoud } else { 3111e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 3112e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 3113e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 3114fbd470baSreinoud efe->tag.desc_crc_len = udf_rw16(crclen); 3115e979c658Sreinoud } 3116e979c658Sreinoud /* eventually copy in evacuated piece */ 3117e979c658Sreinoud /* set new size for uvm */ 3118e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 3119e979c658Sreinoud 3120e979c658Sreinoud free(node_ad_cpy, M_UDFMNT); 31215eeb4f69Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 31225eeb4f69Sreinoud 3123e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 3124e979c658Sreinoud 3125e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 3126e979c658Sreinoud KASSERT(new_inflen == 0); 3127e979c658Sreinoud KASSERT(new_lbrec == 0); 3128e979c658Sreinoud 3129e979c658Sreinoud return 0; 3130e979c658Sreinoud } 3131e979c658Sreinoud 3132e979c658Sreinoud printf("UDF_SHRINK_NODE: could convert to internal alloc!\n"); 3133e979c658Sreinoud } 3134e979c658Sreinoud 3135e979c658Sreinoud /* 5) reset node descriptors */ 3136e979c658Sreinoud udf_wipe_adslots(udf_node); 3137e979c658Sreinoud 3138e979c658Sreinoud /* 6) copy back extents; merge when possible. Recounting on the fly */ 3139e979c658Sreinoud cpy_slots = cpy_slot; 3140e979c658Sreinoud 3141e979c658Sreinoud c_ad = node_ad_cpy[0]; 3142e979c658Sreinoud slot = 0; 3143e979c658Sreinoud for (cpy_slot = 1; cpy_slot < cpy_slots; cpy_slot++) { 3144e979c658Sreinoud s_ad = node_ad_cpy[cpy_slot]; 3145e979c658Sreinoud 3146e979c658Sreinoud DPRINTF(ALLOC, ("\t6: stack -> got mapping vp %d " 3147e979c658Sreinoud "lb %d, len %d, flags %d\n", 3148e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 3149e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 3150e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 3151e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 3152e979c658Sreinoud 3153e979c658Sreinoud /* see if we can merge */ 3154330482f6Sreinoud if (udf_ads_merge(max_len, lb_size, &c_ad, &s_ad)) { 3155e979c658Sreinoud /* not mergable (anymore) */ 3156e979c658Sreinoud DPRINTF(ALLOC, ("\t6: appending vp %d lb %d, " 3157e979c658Sreinoud "len %d, flags %d\n", 3158e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 3159e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 3160e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 3161e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 3162e979c658Sreinoud 31634d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 3164e979c658Sreinoud if (error) 3165e979c658Sreinoud goto errorout; /* panic? */ 3166e979c658Sreinoud c_ad = s_ad; 3167e979c658Sreinoud slot++; 3168e979c658Sreinoud } 3169e979c658Sreinoud } 3170e979c658Sreinoud 3171e979c658Sreinoud /* 7) push rest slot (if any) */ 3172e979c658Sreinoud if (UDF_EXT_LEN(c_ad.len) > 0) { 3173e979c658Sreinoud DPRINTF(ALLOC, ("\t7: last append vp %d lb %d, " 3174e979c658Sreinoud "len %d, flags %d\n", 3175e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 3176e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 3177e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 3178e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 3179e979c658Sreinoud 31804d5c88faSreinoud error = udf_append_adslot(udf_node, &slot, &c_ad); 3181e979c658Sreinoud if (error) 3182e979c658Sreinoud goto errorout; /* panic? */ 3183e979c658Sreinoud ; 3184e979c658Sreinoud } 3185e979c658Sreinoud 3186e979c658Sreinoud inflen -= size_diff; 3187e979c658Sreinoud objsize -= size_diff; 3188e979c658Sreinoud if (fe) { 3189e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 3190e979c658Sreinoud } else { 3191e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 3192e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 3193e979c658Sreinoud } 3194e979c658Sreinoud error = 0; 3195e979c658Sreinoud 3196e979c658Sreinoud /* set new size for uvm */ 3197e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 3198e979c658Sreinoud 3199e979c658Sreinoud errorout: 3200e979c658Sreinoud free(node_ad_cpy, M_UDFMNT); 3201e979c658Sreinoud 32024d5c88faSreinoud udf_count_alloc_exts(udf_node); 32034d5c88faSreinoud 3204e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 32055eeb4f69Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 32065eeb4f69Sreinoud 3207e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 3208e979c658Sreinoud 3209e979c658Sreinoud return error; 3210e979c658Sreinoud } 3211e979c658Sreinoud 3212