1*e5ee8341Sreinoud /* $NetBSD: udf_allocation.c,v 1.4 2008/06/25 10:46:35 reinoud Exp $ */ 2e979c658Sreinoud 3e979c658Sreinoud /* 4e979c658Sreinoud * Copyright (c) 2006, 2008 Reinoud Zandijk 5e979c658Sreinoud * All rights reserved. 6e979c658Sreinoud * 7e979c658Sreinoud * Redistribution and use in source and binary forms, with or without 8e979c658Sreinoud * modification, are permitted provided that the following conditions 9e979c658Sreinoud * are met: 10e979c658Sreinoud * 1. Redistributions of source code must retain the above copyright 11e979c658Sreinoud * notice, this list of conditions and the following disclaimer. 12e979c658Sreinoud * 2. Redistributions in binary form must reproduce the above copyright 13e979c658Sreinoud * notice, this list of conditions and the following disclaimer in the 14e979c658Sreinoud * documentation and/or other materials provided with the distribution. 15e979c658Sreinoud * 16e979c658Sreinoud * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17e979c658Sreinoud * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18e979c658Sreinoud * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19e979c658Sreinoud * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20e979c658Sreinoud * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21e979c658Sreinoud * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22e979c658Sreinoud * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23e979c658Sreinoud * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24e979c658Sreinoud * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25e979c658Sreinoud * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26e979c658Sreinoud * 27e979c658Sreinoud */ 28e979c658Sreinoud 29e979c658Sreinoud #include <sys/cdefs.h> 30e979c658Sreinoud #ifndef lint 31*e5ee8341Sreinoud __KERNEL_RCSID(0, "$NetBSD: udf_allocation.c,v 1.4 2008/06/25 10:46:35 reinoud Exp $"); 32e979c658Sreinoud #endif /* not lint */ 33e979c658Sreinoud 34e979c658Sreinoud 35e979c658Sreinoud #if defined(_KERNEL_OPT) 36e979c658Sreinoud #include "opt_quota.h" 37e979c658Sreinoud #include "opt_compat_netbsd.h" 38e979c658Sreinoud #endif 39e979c658Sreinoud 40e979c658Sreinoud /* TODO strip */ 41e979c658Sreinoud #include <sys/param.h> 42e979c658Sreinoud #include <sys/systm.h> 43e979c658Sreinoud #include <sys/sysctl.h> 44e979c658Sreinoud #include <sys/namei.h> 45e979c658Sreinoud #include <sys/proc.h> 46e979c658Sreinoud #include <sys/kernel.h> 47e979c658Sreinoud #include <sys/vnode.h> 48e979c658Sreinoud #include <miscfs/genfs/genfs_node.h> 49e979c658Sreinoud #include <sys/mount.h> 50e979c658Sreinoud #include <sys/buf.h> 51e979c658Sreinoud #include <sys/file.h> 52e979c658Sreinoud #include <sys/device.h> 53e979c658Sreinoud #include <sys/disklabel.h> 54e979c658Sreinoud #include <sys/ioctl.h> 55e979c658Sreinoud #include <sys/malloc.h> 56e979c658Sreinoud #include <sys/dirent.h> 57e979c658Sreinoud #include <sys/stat.h> 58e979c658Sreinoud #include <sys/conf.h> 59e979c658Sreinoud #include <sys/kauth.h> 60e979c658Sreinoud #include <sys/kthread.h> 61e979c658Sreinoud #include <dev/clock_subr.h> 62e979c658Sreinoud 63e979c658Sreinoud #include <fs/udf/ecma167-udf.h> 64e979c658Sreinoud #include <fs/udf/udf_mount.h> 65e979c658Sreinoud 66e979c658Sreinoud #if defined(_KERNEL_OPT) 67e979c658Sreinoud #include "opt_udf.h" 68e979c658Sreinoud #endif 69e979c658Sreinoud 70e979c658Sreinoud #include "udf.h" 71e979c658Sreinoud #include "udf_subr.h" 72e979c658Sreinoud #include "udf_bswap.h" 73e979c658Sreinoud 74e979c658Sreinoud 75e979c658Sreinoud #define VTOI(vnode) ((struct udf_node *) vnode->v_data) 76e979c658Sreinoud 77e979c658Sreinoud static void udf_record_allocation_in_node(struct udf_mount *ump, 78e979c658Sreinoud struct buf *buf, uint16_t vpart_num, uint64_t *mapping, 79e979c658Sreinoud struct long_ad *node_ad_cpy); 80e979c658Sreinoud 81e979c658Sreinoud /* 82e979c658Sreinoud * IDEA/BUSY: Each udf_node gets its own extentwalker state for all operations; 83e979c658Sreinoud * this will hopefully/likely reduce O(nlog(n)) to O(1) for most functionality 84e979c658Sreinoud * since actions are most likely sequencial and thus seeking doesn't need 85e979c658Sreinoud * searching for the same or adjacent position again. 86e979c658Sreinoud */ 87e979c658Sreinoud 88e979c658Sreinoud /* --------------------------------------------------------------------- */ 89e979c658Sreinoud //#ifdef DEBUG 90e979c658Sreinoud #if 1 91e979c658Sreinoud #if 1 92e979c658Sreinoud static void 93e979c658Sreinoud udf_node_dump(struct udf_node *udf_node) { 94e979c658Sreinoud struct file_entry *fe; 95e979c658Sreinoud struct extfile_entry *efe; 96e979c658Sreinoud struct icb_tag *icbtag; 97e979c658Sreinoud struct short_ad *short_ad; 98e979c658Sreinoud struct long_ad *long_ad; 99e979c658Sreinoud uint64_t inflen; 100e979c658Sreinoud uint32_t icbflags, addr_type, max_l_ad; 101e979c658Sreinoud uint32_t len, lb_num; 102e979c658Sreinoud uint8_t *data_pos; 103e979c658Sreinoud int part_num; 104e979c658Sreinoud int adlen, ad_off, dscr_size, l_ea, l_ad, lb_size, flags; 105e979c658Sreinoud 106e979c658Sreinoud if ((udf_verbose & UDF_DEBUG_ADWLK) == 0) 107e979c658Sreinoud return; 108e979c658Sreinoud 109e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 110e979c658Sreinoud 111e979c658Sreinoud fe = udf_node->fe; 112e979c658Sreinoud efe = udf_node->efe; 113e979c658Sreinoud if (fe) { 114e979c658Sreinoud icbtag = &fe->icbtag; 115e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 116e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 117e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 118e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 119e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 120e979c658Sreinoud } else { 121e979c658Sreinoud icbtag = &efe->icbtag; 122e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 123e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 124e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 125e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 126e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 127e979c658Sreinoud } 128e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 129e979c658Sreinoud 130e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 131e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 132e979c658Sreinoud 133e979c658Sreinoud printf("udf_node_dump:\n"); 134e979c658Sreinoud printf("\tudf_node %p\n", udf_node); 135e979c658Sreinoud 136e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 137e979c658Sreinoud printf("\t\tIntern alloc, len = %"PRIu64"\n", inflen); 138e979c658Sreinoud return; 139e979c658Sreinoud } 140e979c658Sreinoud 141e979c658Sreinoud printf("\t\tInflen = %"PRIu64"\n", inflen); 142e979c658Sreinoud printf("\t\tl_ad = %d\n", l_ad); 143e979c658Sreinoud 144e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 145e979c658Sreinoud adlen = sizeof(struct short_ad); 146e979c658Sreinoud } else { 147e979c658Sreinoud adlen = sizeof(struct long_ad); 148e979c658Sreinoud } 149e979c658Sreinoud 150e979c658Sreinoud printf("\t\t"); 151e979c658Sreinoud for (ad_off = 0; ad_off < max_l_ad-adlen; ad_off += adlen) { 152e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 153e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + ad_off); 154e979c658Sreinoud len = udf_rw32(short_ad->len); 155e979c658Sreinoud lb_num = udf_rw32(short_ad->lb_num); 156e979c658Sreinoud part_num = -1; 157e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 158e979c658Sreinoud len = UDF_EXT_LEN(len); 159e979c658Sreinoud } else { 160e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + ad_off); 161e979c658Sreinoud len = udf_rw32(long_ad->len); 162e979c658Sreinoud lb_num = udf_rw32(long_ad->loc.lb_num); 163e979c658Sreinoud part_num = udf_rw16(long_ad->loc.part_num); 164e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 165e979c658Sreinoud len = UDF_EXT_LEN(len); 166e979c658Sreinoud } 167e979c658Sreinoud printf("["); 168e979c658Sreinoud if (part_num >= 0) 169e979c658Sreinoud printf("part %d, ", part_num); 170e979c658Sreinoud printf("lb_num %d, len %d", lb_num, len); 171e979c658Sreinoud if (flags) 172e979c658Sreinoud printf(", flags %d", flags); 173e979c658Sreinoud printf("] "); 174e979c658Sreinoud if (ad_off + adlen == l_ad) 175e979c658Sreinoud printf("\n\t\tl_ad END\n\t\t"); 176e979c658Sreinoud } 177e979c658Sreinoud printf("\n"); 178e979c658Sreinoud } 179e979c658Sreinoud #else 180e979c658Sreinoud #define udf_node_dump(a) 181e979c658Sreinoud #endif 182e979c658Sreinoud 183e979c658Sreinoud static void 184e979c658Sreinoud udf_node_sanity_check(struct udf_node *udf_node, 185e979c658Sreinoud uint64_t *cnt_inflen, uint64_t *cnt_logblksrec) { 186e979c658Sreinoud struct file_entry *fe; 187e979c658Sreinoud struct extfile_entry *efe; 188e979c658Sreinoud struct icb_tag *icbtag; 189e979c658Sreinoud struct short_ad *short_ad; 190e979c658Sreinoud struct long_ad *long_ad; 191e979c658Sreinoud uint64_t inflen, logblksrec; 192e979c658Sreinoud uint32_t icbflags, addr_type, max_l_ad; 193e979c658Sreinoud uint32_t len, lb_num; 194e979c658Sreinoud uint8_t *data_pos; 195e979c658Sreinoud int part_num; 196e979c658Sreinoud int adlen, ad_off, dscr_size, l_ea, l_ad, lb_size, flags, whole_lb; 197e979c658Sreinoud 198e979c658Sreinoud /* only lock mutex; we're not changing and its a debug checking func */ 199e979c658Sreinoud mutex_enter(&udf_node->node_mutex); 200e979c658Sreinoud 201e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 202e979c658Sreinoud 203e979c658Sreinoud fe = udf_node->fe; 204e979c658Sreinoud efe = udf_node->efe; 205e979c658Sreinoud if (fe) { 206e979c658Sreinoud icbtag = &fe->icbtag; 207e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 208e979c658Sreinoud logblksrec = udf_rw64(fe->logblks_rec); 209e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 210e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 211e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 212e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 213e979c658Sreinoud } else { 214e979c658Sreinoud icbtag = &efe->icbtag; 215e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 216e979c658Sreinoud logblksrec = udf_rw64(efe->logblks_rec); 217e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 218e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 219e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 220e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 221e979c658Sreinoud } 222e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 223e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 224e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 225e979c658Sreinoud 226e979c658Sreinoud /* reset counters */ 227e979c658Sreinoud *cnt_inflen = 0; 228e979c658Sreinoud *cnt_logblksrec = 0; 229e979c658Sreinoud 230e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 231e979c658Sreinoud KASSERT(l_ad <= max_l_ad); 232e979c658Sreinoud KASSERT(l_ad == inflen); 233e979c658Sreinoud *cnt_inflen = inflen; 234e979c658Sreinoud mutex_exit(&udf_node->node_mutex); 235e979c658Sreinoud return; 236e979c658Sreinoud } 237e979c658Sreinoud 238e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 239e979c658Sreinoud adlen = sizeof(struct short_ad); 240e979c658Sreinoud } else { 241e979c658Sreinoud adlen = sizeof(struct long_ad); 242e979c658Sreinoud } 243e979c658Sreinoud 244e979c658Sreinoud /* start counting */ 245e979c658Sreinoud whole_lb = 1; 246e979c658Sreinoud for (ad_off = 0; ad_off < l_ad; ad_off += adlen) { 247e979c658Sreinoud KASSERT(whole_lb == 1); 248e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 249e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + ad_off); 250e979c658Sreinoud len = udf_rw32(short_ad->len); 251e979c658Sreinoud lb_num = udf_rw32(short_ad->lb_num); 252e979c658Sreinoud part_num = -1; 253e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 254e979c658Sreinoud len = UDF_EXT_LEN(len); 255e979c658Sreinoud } else { 256e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + ad_off); 257e979c658Sreinoud len = udf_rw32(long_ad->len); 258e979c658Sreinoud lb_num = udf_rw32(long_ad->loc.lb_num); 259e979c658Sreinoud part_num = udf_rw16(long_ad->loc.part_num); 260e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 261e979c658Sreinoud len = UDF_EXT_LEN(len); 262e979c658Sreinoud } 263e979c658Sreinoud KASSERT(flags != UDF_EXT_REDIRECT); /* not implemented yet */ 264e979c658Sreinoud *cnt_inflen += len; 265e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 266e979c658Sreinoud *cnt_logblksrec += (len + lb_size -1) / lb_size; 267e979c658Sreinoud } 268e979c658Sreinoud whole_lb = ((len % lb_size) == 0); 269e979c658Sreinoud } 270e979c658Sreinoud /* rest should be zero (ad_off > l_ad < max_l_ad - adlen) */ 271e979c658Sreinoud 272e979c658Sreinoud KASSERT(*cnt_inflen == inflen); 273e979c658Sreinoud KASSERT(*cnt_logblksrec == logblksrec); 274e979c658Sreinoud 275e979c658Sreinoud mutex_exit(&udf_node->node_mutex); 276e979c658Sreinoud if (0) 277e979c658Sreinoud udf_node_dump(udf_node); 278e979c658Sreinoud } 279e979c658Sreinoud #else 280e979c658Sreinoud #define udf_node_sanity_check(a, b, c) 281e979c658Sreinoud #endif 282e979c658Sreinoud 283e979c658Sreinoud /* --------------------------------------------------------------------- */ 284e979c658Sreinoud 285e979c658Sreinoud int 286e979c658Sreinoud udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, 287e979c658Sreinoud uint32_t *lb_numres, uint32_t *extres) 288e979c658Sreinoud { 289e979c658Sreinoud struct part_desc *pdesc; 290e979c658Sreinoud struct spare_map_entry *sme; 291e979c658Sreinoud struct long_ad s_icb_loc; 292e979c658Sreinoud uint64_t foffset, end_foffset; 293e979c658Sreinoud uint32_t lb_size, len; 294e979c658Sreinoud uint32_t lb_num, lb_rel, lb_packet; 295e979c658Sreinoud uint32_t udf_rw32_lbmap, ext_offset; 296e979c658Sreinoud uint16_t vpart; 297e979c658Sreinoud int rel, part, error, eof, slot, flags; 298e979c658Sreinoud 299e979c658Sreinoud assert(ump && icb_loc && lb_numres); 300e979c658Sreinoud 301e979c658Sreinoud vpart = udf_rw16(icb_loc->loc.part_num); 302e979c658Sreinoud lb_num = udf_rw32(icb_loc->loc.lb_num); 303e979c658Sreinoud if (vpart > UDF_VTOP_RAWPART) 304e979c658Sreinoud return EINVAL; 305e979c658Sreinoud 306e979c658Sreinoud translate_again: 307e979c658Sreinoud part = ump->vtop[vpart]; 308e979c658Sreinoud pdesc = ump->partitions[part]; 309e979c658Sreinoud 310e979c658Sreinoud switch (ump->vtop_tp[vpart]) { 311e979c658Sreinoud case UDF_VTOP_TYPE_RAW : 312e979c658Sreinoud /* 1:1 to the end of the device */ 313e979c658Sreinoud *lb_numres = lb_num; 314e979c658Sreinoud *extres = INT_MAX; 315e979c658Sreinoud return 0; 316e979c658Sreinoud case UDF_VTOP_TYPE_PHYS : 317e979c658Sreinoud /* transform into its disc logical block */ 318e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 319e979c658Sreinoud return EINVAL; 320e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 321e979c658Sreinoud 322e979c658Sreinoud /* extent from here to the end of the partition */ 323e979c658Sreinoud *extres = udf_rw32(pdesc->part_len) - lb_num; 324e979c658Sreinoud return 0; 325e979c658Sreinoud case UDF_VTOP_TYPE_VIRT : 326e979c658Sreinoud /* only maps one logical block, lookup in VAT */ 327e979c658Sreinoud if (lb_num >= ump->vat_entries) /* XXX > or >= ? */ 328e979c658Sreinoud return EINVAL; 329e979c658Sreinoud 330e979c658Sreinoud /* lookup in virtual allocation table file */ 331e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 332e979c658Sreinoud error = udf_vat_read(ump->vat_node, 333e979c658Sreinoud (uint8_t *) &udf_rw32_lbmap, 4, 334e979c658Sreinoud ump->vat_offset + lb_num * 4); 335e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 336e979c658Sreinoud 337e979c658Sreinoud if (error) 338e979c658Sreinoud return error; 339e979c658Sreinoud 340e979c658Sreinoud lb_num = udf_rw32(udf_rw32_lbmap); 341e979c658Sreinoud 342e979c658Sreinoud /* transform into its disc logical block */ 343e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 344e979c658Sreinoud return EINVAL; 345e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 346e979c658Sreinoud 347e979c658Sreinoud /* just one logical block */ 348e979c658Sreinoud *extres = 1; 349e979c658Sreinoud return 0; 350e979c658Sreinoud case UDF_VTOP_TYPE_SPARABLE : 351e979c658Sreinoud /* check if the packet containing the lb_num is remapped */ 352e979c658Sreinoud lb_packet = lb_num / ump->sparable_packet_size; 353e979c658Sreinoud lb_rel = lb_num % ump->sparable_packet_size; 354e979c658Sreinoud 355e979c658Sreinoud for (rel = 0; rel < udf_rw16(ump->sparing_table->rt_l); rel++) { 356e979c658Sreinoud sme = &ump->sparing_table->entries[rel]; 357e979c658Sreinoud if (lb_packet == udf_rw32(sme->org)) { 358e979c658Sreinoud /* NOTE maps to absolute disc logical block! */ 359e979c658Sreinoud *lb_numres = udf_rw32(sme->map) + lb_rel; 360e979c658Sreinoud *extres = ump->sparable_packet_size - lb_rel; 361e979c658Sreinoud return 0; 362e979c658Sreinoud } 363e979c658Sreinoud } 364e979c658Sreinoud 365e979c658Sreinoud /* transform into its disc logical block */ 366e979c658Sreinoud if (lb_num > udf_rw32(pdesc->part_len)) 367e979c658Sreinoud return EINVAL; 368e979c658Sreinoud *lb_numres = lb_num + udf_rw32(pdesc->start_loc); 369e979c658Sreinoud 370e979c658Sreinoud /* rest of block */ 371e979c658Sreinoud *extres = ump->sparable_packet_size - lb_rel; 372e979c658Sreinoud return 0; 373e979c658Sreinoud case UDF_VTOP_TYPE_META : 374e979c658Sreinoud /* we have to look into the file's allocation descriptors */ 375e979c658Sreinoud 376e979c658Sreinoud /* use metadatafile allocation mutex */ 377e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 378e979c658Sreinoud 379e979c658Sreinoud UDF_LOCK_NODE(ump->metadata_node, 0); 380e979c658Sreinoud 381e979c658Sreinoud /* get first overlapping extent */ 382e979c658Sreinoud foffset = 0; 383e979c658Sreinoud slot = 0; 384e979c658Sreinoud for (;;) { 385e979c658Sreinoud udf_get_adslot(ump->metadata_node, 386e979c658Sreinoud slot, &s_icb_loc, &eof); 387e979c658Sreinoud if (eof) { 388e979c658Sreinoud DPRINTF(TRANSLATE, 389e979c658Sreinoud ("Meta partition translation " 390e979c658Sreinoud "failed: can't seek location\n")); 391e979c658Sreinoud UDF_UNLOCK_NODE(ump->metadata_node, 0); 392e979c658Sreinoud return EINVAL; 393e979c658Sreinoud } 394e979c658Sreinoud len = udf_rw32(s_icb_loc.len); 395e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 396e979c658Sreinoud len = UDF_EXT_LEN(len); 397e979c658Sreinoud 398e979c658Sreinoud end_foffset = foffset + len; 399e979c658Sreinoud 400e979c658Sreinoud if (end_foffset > lb_num * lb_size) 401e979c658Sreinoud break; /* found */ 402e979c658Sreinoud if (flags != UDF_EXT_REDIRECT) 403e979c658Sreinoud foffset = end_foffset; 404e979c658Sreinoud slot++; 405e979c658Sreinoud } 406e979c658Sreinoud /* found overlapping slot */ 407e979c658Sreinoud ext_offset = lb_num * lb_size - foffset; 408e979c658Sreinoud 409e979c658Sreinoud /* process extent offset */ 410e979c658Sreinoud lb_num = udf_rw32(s_icb_loc.loc.lb_num); 411e979c658Sreinoud vpart = udf_rw16(s_icb_loc.loc.part_num); 412e979c658Sreinoud lb_num += (ext_offset + lb_size -1) / lb_size; 413e979c658Sreinoud len -= ext_offset; 414e979c658Sreinoud ext_offset = 0; 415e979c658Sreinoud 416e979c658Sreinoud flags = UDF_EXT_FLAGS(s_icb_loc.len); 417e979c658Sreinoud 418e979c658Sreinoud UDF_UNLOCK_NODE(ump->metadata_node, 0); 419e979c658Sreinoud if (flags != UDF_EXT_ALLOCATED) { 420e979c658Sreinoud DPRINTF(TRANSLATE, ("Metadata partition translation " 421e979c658Sreinoud "failed: not allocated\n")); 422e979c658Sreinoud return EINVAL; 423e979c658Sreinoud } 424e979c658Sreinoud 425e979c658Sreinoud /* 426e979c658Sreinoud * vpart and lb_num are updated, translate again since we 427e979c658Sreinoud * might be mapped on sparable media 428e979c658Sreinoud */ 429e979c658Sreinoud goto translate_again; 430e979c658Sreinoud default: 431e979c658Sreinoud printf("UDF vtop translation scheme %d unimplemented yet\n", 432e979c658Sreinoud ump->vtop_tp[vpart]); 433e979c658Sreinoud } 434e979c658Sreinoud 435e979c658Sreinoud return EINVAL; 436e979c658Sreinoud } 437e979c658Sreinoud 438e979c658Sreinoud /* --------------------------------------------------------------------- */ 439e979c658Sreinoud 440e979c658Sreinoud /* 441e979c658Sreinoud * Translate an extent (in logical_blocks) into logical block numbers; used 442e979c658Sreinoud * for read and write operations. DOESNT't check extents. 443e979c658Sreinoud */ 444e979c658Sreinoud 445e979c658Sreinoud int 446e979c658Sreinoud udf_translate_file_extent(struct udf_node *udf_node, 447e979c658Sreinoud uint32_t from, uint32_t num_lb, 448e979c658Sreinoud uint64_t *map) 449e979c658Sreinoud { 450e979c658Sreinoud struct udf_mount *ump; 451e979c658Sreinoud struct icb_tag *icbtag; 452e979c658Sreinoud struct long_ad t_ad, s_ad; 453e979c658Sreinoud uint64_t transsec; 454e979c658Sreinoud uint64_t foffset, end_foffset; 455e979c658Sreinoud uint32_t transsec32; 456e979c658Sreinoud uint32_t lb_size; 457e979c658Sreinoud uint32_t ext_offset; 458e979c658Sreinoud uint32_t lb_num, len; 459e979c658Sreinoud uint32_t overlap, translen; 460e979c658Sreinoud uint16_t vpart_num; 461e979c658Sreinoud int eof, error, flags; 462e979c658Sreinoud int slot, addr_type, icbflags; 463e979c658Sreinoud 464e979c658Sreinoud if (!udf_node) 465e979c658Sreinoud return ENOENT; 466e979c658Sreinoud 467e979c658Sreinoud KASSERT(num_lb > 0); 468e979c658Sreinoud 469e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 470e979c658Sreinoud 471e979c658Sreinoud /* initialise derivative vars */ 472e979c658Sreinoud ump = udf_node->ump; 473e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 474e979c658Sreinoud 475e979c658Sreinoud if (udf_node->fe) { 476e979c658Sreinoud icbtag = &udf_node->fe->icbtag; 477e979c658Sreinoud } else { 478e979c658Sreinoud icbtag = &udf_node->efe->icbtag; 479e979c658Sreinoud } 480e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 481e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 482e979c658Sreinoud 483e979c658Sreinoud /* do the work */ 484e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 485e979c658Sreinoud *map = UDF_TRANS_INTERN; 486e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 487e979c658Sreinoud return 0; 488e979c658Sreinoud } 489e979c658Sreinoud 490e979c658Sreinoud /* find first overlapping extent */ 491e979c658Sreinoud foffset = 0; 492e979c658Sreinoud slot = 0; 493e979c658Sreinoud for (;;) { 494e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 495*e5ee8341Sreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, len = %d, " 496*e5ee8341Sreinoud "lb_num = %d, part = %d\n", slot, eof, 497*e5ee8341Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)), 498*e5ee8341Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 499*e5ee8341Sreinoud udf_rw32(s_ad.loc.lb_num), 500*e5ee8341Sreinoud udf_rw16(s_ad.loc.part_num))); 501e979c658Sreinoud if (eof) { 502e979c658Sreinoud DPRINTF(TRANSLATE, 503e979c658Sreinoud ("Translate file extent " 504e979c658Sreinoud "failed: can't seek location\n")); 505e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 506e979c658Sreinoud return EINVAL; 507e979c658Sreinoud } 508e979c658Sreinoud len = udf_rw32(s_ad.len); 509e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 510e979c658Sreinoud len = UDF_EXT_LEN(len); 511e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 512e979c658Sreinoud 513e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 514e979c658Sreinoud slot++; 515e979c658Sreinoud continue; 516e979c658Sreinoud } 517e979c658Sreinoud 518e979c658Sreinoud end_foffset = foffset + len; 519e979c658Sreinoud 520e979c658Sreinoud if (end_foffset > from * lb_size) 521e979c658Sreinoud break; /* found */ 522e979c658Sreinoud foffset = end_foffset; 523e979c658Sreinoud slot++; 524e979c658Sreinoud } 525e979c658Sreinoud /* found overlapping slot */ 526e979c658Sreinoud ext_offset = from * lb_size - foffset; 527e979c658Sreinoud 528e979c658Sreinoud for (;;) { 529e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 530*e5ee8341Sreinoud DPRINTF(ADWLK, ("slot %d, eof = %d, flags = %d, len = %d, " 531*e5ee8341Sreinoud "lb_num = %d, part = %d\n", slot, eof, 532*e5ee8341Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)), 533*e5ee8341Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 534*e5ee8341Sreinoud udf_rw32(s_ad.loc.lb_num), 535*e5ee8341Sreinoud udf_rw16(s_ad.loc.part_num))); 536e979c658Sreinoud if (eof) { 537e979c658Sreinoud DPRINTF(TRANSLATE, 538e979c658Sreinoud ("Translate file extent " 539e979c658Sreinoud "failed: past eof\n")); 540e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 541e979c658Sreinoud return EINVAL; 542e979c658Sreinoud } 543e979c658Sreinoud 544e979c658Sreinoud len = udf_rw32(s_ad.len); 545e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 546e979c658Sreinoud len = UDF_EXT_LEN(len); 547e979c658Sreinoud 548e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 549e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 550e979c658Sreinoud 551e979c658Sreinoud end_foffset = foffset + len; 552e979c658Sreinoud 553e979c658Sreinoud /* process extent, don't forget to advance on ext_offset! */ 554e979c658Sreinoud lb_num += (ext_offset + lb_size -1) / lb_size; 555e979c658Sreinoud overlap = (len - ext_offset + lb_size -1) / lb_size; 556e979c658Sreinoud ext_offset = 0; 557e979c658Sreinoud 558e979c658Sreinoud /* 559e979c658Sreinoud * note that the while(){} is nessisary for the extent that 560e979c658Sreinoud * the udf_translate_vtop() returns doens't have to span the 561e979c658Sreinoud * whole extent. 562e979c658Sreinoud */ 563e979c658Sreinoud 564e979c658Sreinoud overlap = MIN(overlap, num_lb); 565*e5ee8341Sreinoud while (overlap && (flags != UDF_EXT_REDIRECT)) { 566e979c658Sreinoud switch (flags) { 567e979c658Sreinoud case UDF_EXT_FREE : 568e979c658Sreinoud case UDF_EXT_ALLOCATED_BUT_NOT_USED : 569e979c658Sreinoud transsec = UDF_TRANS_ZERO; 570e979c658Sreinoud translen = overlap; 571e979c658Sreinoud while (overlap && num_lb && translen) { 572e979c658Sreinoud *map++ = transsec; 573e979c658Sreinoud lb_num++; 574e979c658Sreinoud overlap--; num_lb--; translen--; 575e979c658Sreinoud } 576e979c658Sreinoud break; 577e979c658Sreinoud case UDF_EXT_ALLOCATED : 578e979c658Sreinoud t_ad.loc.lb_num = udf_rw32(lb_num); 579e979c658Sreinoud t_ad.loc.part_num = udf_rw16(vpart_num); 580e979c658Sreinoud error = udf_translate_vtop(ump, 581e979c658Sreinoud &t_ad, &transsec32, &translen); 582e979c658Sreinoud transsec = transsec32; 583e979c658Sreinoud if (error) { 584e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 585e979c658Sreinoud return error; 586e979c658Sreinoud } 587e979c658Sreinoud while (overlap && num_lb && translen) { 588e979c658Sreinoud *map++ = transsec; 589e979c658Sreinoud lb_num++; transsec++; 590e979c658Sreinoud overlap--; num_lb--; translen--; 591e979c658Sreinoud } 592e979c658Sreinoud break; 593*e5ee8341Sreinoud default: 594*e5ee8341Sreinoud DPRINTF(TRANSLATE, 595*e5ee8341Sreinoud ("Translate file extent " 596*e5ee8341Sreinoud "failed: bad flags %x\n", flags)); 597*e5ee8341Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 598*e5ee8341Sreinoud return EINVAL; 599e979c658Sreinoud } 600e979c658Sreinoud } 601e979c658Sreinoud if (num_lb == 0) 602e979c658Sreinoud break; 603e979c658Sreinoud 604e979c658Sreinoud if (flags != UDF_EXT_REDIRECT) 605e979c658Sreinoud foffset = end_foffset; 606e979c658Sreinoud slot++; 607e979c658Sreinoud } 608e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 609e979c658Sreinoud 610e979c658Sreinoud return 0; 611e979c658Sreinoud } 612e979c658Sreinoud 613e979c658Sreinoud /* --------------------------------------------------------------------- */ 614e979c658Sreinoud 615e979c658Sreinoud static int 616e979c658Sreinoud udf_search_free_vatloc(struct udf_mount *ump, uint32_t *lbnumres) 617e979c658Sreinoud { 618e979c658Sreinoud uint32_t lb_size, lb_num, lb_map, udf_rw32_lbmap; 619e979c658Sreinoud uint8_t *blob; 620e979c658Sreinoud int entry, chunk, found, error; 621e979c658Sreinoud 622e979c658Sreinoud KASSERT(ump); 623e979c658Sreinoud KASSERT(ump->logical_vol); 624e979c658Sreinoud 625e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 626e979c658Sreinoud blob = malloc(lb_size, M_UDFTEMP, M_WAITOK); 627e979c658Sreinoud 628e979c658Sreinoud /* TODO static allocation of search chunk */ 629e979c658Sreinoud 630e979c658Sreinoud lb_num = MIN(ump->vat_entries, ump->vat_last_free_lb); 631e979c658Sreinoud found = 0; 632e979c658Sreinoud error = 0; 633e979c658Sreinoud entry = 0; 634e979c658Sreinoud do { 635e979c658Sreinoud chunk = MIN(lb_size, (ump->vat_entries - lb_num) * 4); 636e979c658Sreinoud if (chunk <= 0) 637e979c658Sreinoud break; 638e979c658Sreinoud /* load in chunk */ 639e979c658Sreinoud error = udf_vat_read(ump->vat_node, blob, chunk, 640e979c658Sreinoud ump->vat_offset + lb_num * 4); 641e979c658Sreinoud 642e979c658Sreinoud if (error) 643e979c658Sreinoud break; 644e979c658Sreinoud 645e979c658Sreinoud /* search this chunk */ 646e979c658Sreinoud for (entry=0; entry < chunk /4; entry++, lb_num++) { 647e979c658Sreinoud udf_rw32_lbmap = *((uint32_t *) (blob + entry * 4)); 648e979c658Sreinoud lb_map = udf_rw32(udf_rw32_lbmap); 649e979c658Sreinoud if (lb_map == 0xffffffff) { 650e979c658Sreinoud found = 1; 651e979c658Sreinoud break; 652e979c658Sreinoud } 653e979c658Sreinoud } 654e979c658Sreinoud } while (!found); 655e979c658Sreinoud if (error) { 656e979c658Sreinoud printf("udf_search_free_vatloc: error reading in vat chunk " 657e979c658Sreinoud "(lb %d, size %d)\n", lb_num, chunk); 658e979c658Sreinoud } 659e979c658Sreinoud 660e979c658Sreinoud if (!found) { 661e979c658Sreinoud /* extend VAT */ 662e979c658Sreinoud DPRINTF(WRITE, ("udf_search_free_vatloc: extending\n")); 663e979c658Sreinoud lb_num = ump->vat_entries; 664e979c658Sreinoud ump->vat_entries++; 665e979c658Sreinoud } 666e979c658Sreinoud 667e979c658Sreinoud /* mark entry with initialiser just in case */ 668e979c658Sreinoud lb_map = udf_rw32(0xfffffffe); 669e979c658Sreinoud udf_vat_write(ump->vat_node, (uint8_t *) &lb_map, 4, 670e979c658Sreinoud ump->vat_offset + lb_num *4); 671e979c658Sreinoud ump->vat_last_free_lb = lb_num; 672e979c658Sreinoud 673e979c658Sreinoud free(blob, M_UDFTEMP); 674e979c658Sreinoud *lbnumres = lb_num; 675e979c658Sreinoud return 0; 676e979c658Sreinoud } 677e979c658Sreinoud 678e979c658Sreinoud 679e979c658Sreinoud static void 680e979c658Sreinoud udf_bitmap_allocate(struct udf_bitmap *bitmap, int ismetadata, 681e979c658Sreinoud uint32_t ptov, uint32_t *num_lb, uint64_t *pmappos, uint64_t *lmappos) 682e979c658Sreinoud { 683e979c658Sreinoud uint32_t offset, lb_num, bit; 684e979c658Sreinoud int32_t diff; 685e979c658Sreinoud uint8_t *bpos; 686e979c658Sreinoud int pass; 687e979c658Sreinoud 688e979c658Sreinoud if (!ismetadata) { 689e979c658Sreinoud /* heuristic to keep the two pointers not too close */ 690e979c658Sreinoud diff = bitmap->data_pos - bitmap->metadata_pos; 691e979c658Sreinoud if ((diff >= 0) && (diff < 1024)) 692e979c658Sreinoud bitmap->data_pos = bitmap->metadata_pos + 1024; 693e979c658Sreinoud } 694e979c658Sreinoud offset = ismetadata ? bitmap->metadata_pos : bitmap->data_pos; 695e979c658Sreinoud offset &= ~7; 696e979c658Sreinoud for (pass = 0; pass < 2; pass++) { 697e979c658Sreinoud if (offset >= bitmap->max_offset) 698e979c658Sreinoud offset = 0; 699e979c658Sreinoud 700e979c658Sreinoud while (offset < bitmap->max_offset) { 701e979c658Sreinoud if (*num_lb == 0) 702e979c658Sreinoud break; 703e979c658Sreinoud 704e979c658Sreinoud /* use first bit not set */ 705e979c658Sreinoud bpos = bitmap->bits + offset/8; 706e979c658Sreinoud bit = ffs(*bpos); 707e979c658Sreinoud if (bit == 0) { 708e979c658Sreinoud offset += 8; 709e979c658Sreinoud continue; 710e979c658Sreinoud } 711e979c658Sreinoud *bpos &= ~(1 << (bit-1)); 712e979c658Sreinoud lb_num = offset + bit-1; 713e979c658Sreinoud *lmappos++ = lb_num; 714e979c658Sreinoud *pmappos++ = lb_num + ptov; 715e979c658Sreinoud *num_lb = *num_lb - 1; 716e979c658Sreinoud // offset = (offset & ~7); 717e979c658Sreinoud } 718e979c658Sreinoud } 719e979c658Sreinoud 720e979c658Sreinoud if (ismetadata) { 721e979c658Sreinoud bitmap->metadata_pos = offset; 722e979c658Sreinoud } else { 723e979c658Sreinoud bitmap->data_pos = offset; 724e979c658Sreinoud } 725e979c658Sreinoud } 726e979c658Sreinoud 727e979c658Sreinoud 728e979c658Sreinoud static void 729e979c658Sreinoud udf_bitmap_free(struct udf_bitmap *bitmap, uint32_t lb_num, uint32_t num_lb) 730e979c658Sreinoud { 731e979c658Sreinoud uint32_t offset; 732e979c658Sreinoud uint32_t bit, bitval; 733e979c658Sreinoud uint8_t *bpos; 734e979c658Sreinoud 735e979c658Sreinoud offset = lb_num; 736e979c658Sreinoud 737e979c658Sreinoud /* starter bits */ 738e979c658Sreinoud bpos = bitmap->bits + offset/8; 739e979c658Sreinoud bit = offset % 8; 740e979c658Sreinoud while ((bit != 0) && (num_lb > 0)) { 741e979c658Sreinoud bitval = (1 << bit); 742e979c658Sreinoud KASSERT((*bpos & bitval) == 0); 743e979c658Sreinoud *bpos |= bitval; 744e979c658Sreinoud offset++; num_lb--; 745e979c658Sreinoud bit = (bit + 1) % 8; 746e979c658Sreinoud } 747e979c658Sreinoud if (num_lb == 0) 748e979c658Sreinoud return; 749e979c658Sreinoud 750e979c658Sreinoud /* whole bytes */ 751e979c658Sreinoud KASSERT(bit == 0); 752e979c658Sreinoud bpos = bitmap->bits + offset / 8; 753e979c658Sreinoud while (num_lb >= 8) { 754e979c658Sreinoud KASSERT((*bpos == 0)); 755e979c658Sreinoud *bpos = 255; 756e979c658Sreinoud offset += 8; num_lb -= 8; 757e979c658Sreinoud bpos++; 758e979c658Sreinoud } 759e979c658Sreinoud 760e979c658Sreinoud /* stop bits */ 761e979c658Sreinoud KASSERT(num_lb < 8); 762e979c658Sreinoud bit = 0; 763e979c658Sreinoud while (num_lb > 0) { 764e979c658Sreinoud bitval = (1 << bit); 765e979c658Sreinoud KASSERT((*bpos & bitval) == 0); 766e979c658Sreinoud *bpos |= bitval; 767e979c658Sreinoud offset++; num_lb--; 768e979c658Sreinoud bit = (bit + 1) % 8; 769e979c658Sreinoud } 770e979c658Sreinoud } 771e979c658Sreinoud 772e979c658Sreinoud 773e979c658Sreinoud /* allocate a contiguous sequence of sectornumbers */ 774e979c658Sreinoud static int 775e979c658Sreinoud udf_allocate_space(struct udf_mount *ump, int ismetadata, int alloc_type, 776e979c658Sreinoud int num_lb, uint16_t *alloc_partp, 777e979c658Sreinoud uint64_t *lmapping, uint64_t *pmapping) 778e979c658Sreinoud { 779e979c658Sreinoud struct mmc_trackinfo *alloc_track, *other_track; 780e979c658Sreinoud struct udf_bitmap *bitmap; 781e979c658Sreinoud struct part_desc *pdesc; 782e979c658Sreinoud struct logvol_int_desc *lvid; 783e979c658Sreinoud uint64_t *lmappos, *pmappos; 784e979c658Sreinoud uint32_t ptov, lb_num, *freepos, free_lbs; 785e979c658Sreinoud int lb_size, alloc_num_lb; 786e979c658Sreinoud int alloc_part; 787e979c658Sreinoud int error; 788e979c658Sreinoud 789e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 790e979c658Sreinoud 791e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 792e979c658Sreinoud KASSERT(lb_size == ump->discinfo.sector_size); 793e979c658Sreinoud 794e979c658Sreinoud if (ismetadata) { 795e979c658Sreinoud alloc_part = ump->metadata_part; 796e979c658Sreinoud alloc_track = &ump->metadata_track; 797e979c658Sreinoud other_track = &ump->data_track; 798e979c658Sreinoud } else { 799e979c658Sreinoud alloc_part = ump->data_part; 800e979c658Sreinoud alloc_track = &ump->data_track; 801e979c658Sreinoud other_track = &ump->metadata_track; 802e979c658Sreinoud } 803e979c658Sreinoud 804e979c658Sreinoud *alloc_partp = alloc_part; 805e979c658Sreinoud 806e979c658Sreinoud error = 0; 807e979c658Sreinoud /* XXX check disc space */ 808e979c658Sreinoud 809e979c658Sreinoud pdesc = ump->partitions[ump->vtop[alloc_part]]; 810e979c658Sreinoud lmappos = lmapping; 811e979c658Sreinoud pmappos = pmapping; 812e979c658Sreinoud 813e979c658Sreinoud switch (alloc_type) { 814e979c658Sreinoud case UDF_ALLOC_VAT : 815e979c658Sreinoud /* search empty slot in VAT file */ 816e979c658Sreinoud KASSERT(num_lb == 1); 817e979c658Sreinoud error = udf_search_free_vatloc(ump, &lb_num); 818e979c658Sreinoud if (!error) { 819e979c658Sreinoud *lmappos = lb_num; 820e979c658Sreinoud *pmappos = 0; /* will get late-allocated */ 821e979c658Sreinoud } 822e979c658Sreinoud break; 823e979c658Sreinoud case UDF_ALLOC_SEQUENTIAL : 824e979c658Sreinoud /* sequential allocation on recordable media */ 825e979c658Sreinoud /* calculate offset from physical base partition */ 826e979c658Sreinoud ptov = udf_rw32(pdesc->start_loc); 827e979c658Sreinoud 828e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 829e979c658Sreinoud *pmappos++ = alloc_track->next_writable; 830e979c658Sreinoud *lmappos++ = alloc_track->next_writable - ptov; 831e979c658Sreinoud alloc_track->next_writable++; 832e979c658Sreinoud alloc_track->free_blocks--; 833e979c658Sreinoud } 834e979c658Sreinoud if (alloc_track->tracknr == other_track->tracknr) 835e979c658Sreinoud memcpy(other_track, alloc_track, 836e979c658Sreinoud sizeof(struct mmc_trackinfo)); 837e979c658Sreinoud break; 838e979c658Sreinoud case UDF_ALLOC_SPACEMAP : 839e979c658Sreinoud ptov = udf_rw32(pdesc->start_loc); 840e979c658Sreinoud 841e979c658Sreinoud /* allocate on unallocated bits page */ 842e979c658Sreinoud alloc_num_lb = num_lb; 843e979c658Sreinoud bitmap = &ump->part_unalloc_bits[alloc_part]; 844e979c658Sreinoud udf_bitmap_allocate(bitmap, ismetadata, ptov, &alloc_num_lb, 845e979c658Sreinoud pmappos, lmappos); 846e979c658Sreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 847e979c658Sreinoud if (alloc_num_lb) { 848e979c658Sreinoud /* TODO convert freed to unalloc and try again */ 849e979c658Sreinoud /* free allocated piece for now */ 850e979c658Sreinoud lmappos = lmapping; 851e979c658Sreinoud for (lb_num=0; lb_num < num_lb-alloc_num_lb; lb_num++) { 852e979c658Sreinoud udf_bitmap_free(bitmap, *lmappos++, 1); 853e979c658Sreinoud } 854e979c658Sreinoud error = ENOSPC; 855e979c658Sreinoud } 856e979c658Sreinoud if (!error) { 857e979c658Sreinoud /* adjust freecount */ 858e979c658Sreinoud lvid = ump->logvol_integrity; 859e979c658Sreinoud freepos = &lvid->tables[0] + alloc_part; 860e979c658Sreinoud free_lbs = udf_rw32(*freepos); 861e979c658Sreinoud *freepos = udf_rw32(free_lbs - num_lb); 862e979c658Sreinoud } 863e979c658Sreinoud break; 864e979c658Sreinoud case UDF_ALLOC_METABITMAP : 865e979c658Sreinoud case UDF_ALLOC_METASEQUENTIAL : 866e979c658Sreinoud case UDF_ALLOC_RELAXEDSEQUENTIAL : 867e979c658Sreinoud printf("ALERT: udf_allocate_space : allocation %d " 868e979c658Sreinoud "not implemented yet!\n", alloc_type); 869e979c658Sreinoud /* TODO implement, doesn't have to be contiguous */ 870e979c658Sreinoud error = ENOSPC; 871e979c658Sreinoud break; 872e979c658Sreinoud } 873e979c658Sreinoud 874e979c658Sreinoud #ifdef DEBUG 875e979c658Sreinoud if (udf_verbose & UDF_DEBUG_ALLOC) { 876e979c658Sreinoud lmappos = lmapping; 877e979c658Sreinoud pmappos = pmapping; 878e979c658Sreinoud printf("udf_allocate_space, mapping l->p:\n"); 879e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 880e979c658Sreinoud printf("\t%"PRIu64" -> %"PRIu64"\n", 881e979c658Sreinoud *lmappos++, *pmappos++); 882e979c658Sreinoud } 883e979c658Sreinoud } 884e979c658Sreinoud #endif 885e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 886e979c658Sreinoud 887e979c658Sreinoud return error; 888e979c658Sreinoud } 889e979c658Sreinoud 890e979c658Sreinoud /* --------------------------------------------------------------------- */ 891e979c658Sreinoud 892e979c658Sreinoud void 893e979c658Sreinoud udf_free_allocated_space(struct udf_mount *ump, uint32_t lb_num, 894e979c658Sreinoud uint16_t vpart_num, uint32_t num_lb) 895e979c658Sreinoud { 896e979c658Sreinoud struct udf_bitmap *bitmap; 897e979c658Sreinoud struct part_desc *pdesc; 898e979c658Sreinoud struct logvol_int_desc *lvid; 899e979c658Sreinoud uint32_t ptov, lb_map, udf_rw32_lbmap; 900e979c658Sreinoud uint32_t *freepos, free_lbs; 901e979c658Sreinoud int phys_part; 902e979c658Sreinoud int error; 903e979c658Sreinoud 904e979c658Sreinoud DPRINTF(ALLOC, ("udf_free_allocated_space: freeing virt lbnum %d " 905e979c658Sreinoud "part %d + %d sect\n", lb_num, vpart_num, num_lb)); 906e979c658Sreinoud 907e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 908e979c658Sreinoud 909e979c658Sreinoud /* get partition backing up this vpart_num */ 910e979c658Sreinoud pdesc = ump->partitions[ump->vtop[vpart_num]]; 911e979c658Sreinoud 912e979c658Sreinoud switch (ump->vtop_tp[vpart_num]) { 913e979c658Sreinoud case UDF_VTOP_TYPE_PHYS : 914e979c658Sreinoud case UDF_VTOP_TYPE_SPARABLE : 915e979c658Sreinoud /* free space to freed or unallocated space bitmap */ 916e979c658Sreinoud ptov = udf_rw32(pdesc->start_loc); 917e979c658Sreinoud phys_part = ump->vtop[vpart_num]; 918e979c658Sreinoud 919e979c658Sreinoud /* first try freed space bitmap */ 920e979c658Sreinoud bitmap = &ump->part_freed_bits[phys_part]; 921e979c658Sreinoud 922e979c658Sreinoud /* if not defined, use unallocated bitmap */ 923e979c658Sreinoud if (bitmap->bits == NULL) 924e979c658Sreinoud bitmap = &ump->part_unalloc_bits[phys_part]; 925e979c658Sreinoud 926e979c658Sreinoud /* if no bitmaps are defined, bail out */ 927e979c658Sreinoud if (bitmap->bits == NULL) 928e979c658Sreinoud break; 929e979c658Sreinoud 930e979c658Sreinoud /* free bits if its defined */ 931e979c658Sreinoud KASSERT(bitmap->bits); 932e979c658Sreinoud ump->lvclose |= UDF_WRITE_PART_BITMAPS; 933e979c658Sreinoud udf_bitmap_free(bitmap, lb_num, num_lb); 934e979c658Sreinoud 935e979c658Sreinoud /* adjust freecount */ 936e979c658Sreinoud lvid = ump->logvol_integrity; 937e979c658Sreinoud freepos = &lvid->tables[0] + vpart_num; 938e979c658Sreinoud free_lbs = udf_rw32(*freepos); 939e979c658Sreinoud *freepos = udf_rw32(free_lbs + num_lb); 940e979c658Sreinoud break; 941e979c658Sreinoud case UDF_VTOP_TYPE_VIRT : 942e979c658Sreinoud /* free this VAT entry */ 943e979c658Sreinoud KASSERT(num_lb == 1); 944e979c658Sreinoud 945e979c658Sreinoud lb_map = 0xffffffff; 946e979c658Sreinoud udf_rw32_lbmap = udf_rw32(lb_map); 947e979c658Sreinoud error = udf_vat_write(ump->vat_node, 948e979c658Sreinoud (uint8_t *) &udf_rw32_lbmap, 4, 949e979c658Sreinoud ump->vat_offset + lb_num * 4); 950e979c658Sreinoud KASSERT(error == 0); 951e979c658Sreinoud ump->vat_last_free_lb = MIN(ump->vat_last_free_lb, lb_num); 952e979c658Sreinoud break; 953e979c658Sreinoud case UDF_VTOP_TYPE_META : 954e979c658Sreinoud /* free space in the metadata bitmap */ 955e979c658Sreinoud default: 956e979c658Sreinoud printf("ALERT: udf_free_allocated_space : allocation %d " 957e979c658Sreinoud "not implemented yet!\n", ump->vtop_tp[vpart_num]); 958e979c658Sreinoud break; 959e979c658Sreinoud } 960e979c658Sreinoud 961e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 962e979c658Sreinoud } 963e979c658Sreinoud 964e979c658Sreinoud /* --------------------------------------------------------------------- */ 965e979c658Sreinoud 966e979c658Sreinoud int 967e979c658Sreinoud udf_pre_allocate_space(struct udf_mount *ump, int udf_c_type, int num_lb, 968e979c658Sreinoud uint16_t *alloc_partp, uint64_t *lmapping, uint64_t *pmapping) 969e979c658Sreinoud { 970e979c658Sreinoud int ismetadata, alloc_type; 971e979c658Sreinoud 972e979c658Sreinoud ismetadata = (udf_c_type == UDF_C_NODE); 973e979c658Sreinoud alloc_type = ismetadata? ump->meta_alloc : ump->data_alloc; 974e979c658Sreinoud 975e979c658Sreinoud #ifdef DIAGNOSTIC 976e979c658Sreinoud if ((alloc_type == UDF_ALLOC_VAT) && (udf_c_type != UDF_C_NODE)) { 977e979c658Sreinoud panic("udf_pre_allocate_space: bad c_type on VAT!\n"); 978e979c658Sreinoud } 979e979c658Sreinoud #endif 980e979c658Sreinoud 981e979c658Sreinoud /* reserve size for VAT allocated data */ 982e979c658Sreinoud if (alloc_type == UDF_ALLOC_VAT) { 983e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 984e979c658Sreinoud ump->uncomitted_lb += num_lb; 985e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 986e979c658Sreinoud } 987e979c658Sreinoud 988e979c658Sreinoud return udf_allocate_space(ump, ismetadata, alloc_type, 989e979c658Sreinoud num_lb, alloc_partp, lmapping, pmapping); 990e979c658Sreinoud } 991e979c658Sreinoud 992e979c658Sreinoud /* --------------------------------------------------------------------- */ 993e979c658Sreinoud 994e979c658Sreinoud /* 995e979c658Sreinoud * Allocate a buf on disc for direct write out. The space doesn't have to be 996e979c658Sreinoud * contiguous as the caller takes care of this. 997e979c658Sreinoud */ 998e979c658Sreinoud 999e979c658Sreinoud void 1000e979c658Sreinoud udf_late_allocate_buf(struct udf_mount *ump, struct buf *buf, 1001e979c658Sreinoud uint64_t *lmapping, uint64_t *pmapping, struct long_ad *node_ad_cpy) 1002e979c658Sreinoud { 1003e979c658Sreinoud struct udf_node *udf_node = VTOI(buf->b_vp); 1004e979c658Sreinoud uint16_t vpart_num; 1005e979c658Sreinoud int lb_size, blks, udf_c_type; 1006e979c658Sreinoud int ismetadata, alloc_type; 1007e979c658Sreinoud int num_lb; 1008e979c658Sreinoud int error, s; 1009e979c658Sreinoud 1010e979c658Sreinoud /* 1011e979c658Sreinoud * for each sector in the buf, allocate a sector on disc and record 1012e979c658Sreinoud * its position in the provided mapping array. 1013e979c658Sreinoud * 1014e979c658Sreinoud * If its userdata or FIDs, record its location in its node. 1015e979c658Sreinoud */ 1016e979c658Sreinoud 1017e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 1018e979c658Sreinoud num_lb = (buf->b_bcount + lb_size -1) / lb_size; 1019e979c658Sreinoud blks = lb_size / DEV_BSIZE; 1020e979c658Sreinoud udf_c_type = buf->b_udf_c_type; 1021e979c658Sreinoud 1022e979c658Sreinoud KASSERT(lb_size == ump->discinfo.sector_size); 1023e979c658Sreinoud 1024e979c658Sreinoud ismetadata = (udf_c_type == UDF_C_NODE); 1025e979c658Sreinoud alloc_type = ismetadata? ump->meta_alloc : ump->data_alloc; 1026e979c658Sreinoud 1027e979c658Sreinoud #ifdef DIAGNOSTIC 1028e979c658Sreinoud if ((alloc_type == UDF_ALLOC_VAT) && (udf_c_type != UDF_C_NODE)) { 1029e979c658Sreinoud panic("udf_late_allocate_buf: bad c_type on VAT!\n"); 1030e979c658Sreinoud } 1031e979c658Sreinoud #endif 1032e979c658Sreinoud 1033e979c658Sreinoud if (udf_c_type == UDF_C_NODE) { 1034e979c658Sreinoud /* if not VAT, its allready allocated */ 1035e979c658Sreinoud if (alloc_type != UDF_ALLOC_VAT) 1036e979c658Sreinoud return; 1037e979c658Sreinoud 1038e979c658Sreinoud /* allocate sequential */ 1039e979c658Sreinoud alloc_type = UDF_ALLOC_SEQUENTIAL; 1040e979c658Sreinoud } 1041e979c658Sreinoud 1042e979c658Sreinoud error = udf_allocate_space(ump, ismetadata, alloc_type, 1043e979c658Sreinoud num_lb, &vpart_num, lmapping, pmapping); 1044e979c658Sreinoud if (error) { 1045e979c658Sreinoud /* ARGH! we've not done our accounting right! */ 1046e979c658Sreinoud panic("UDF disc allocation accounting gone wrong"); 1047e979c658Sreinoud } 1048e979c658Sreinoud 1049e979c658Sreinoud /* commit our sector count */ 1050e979c658Sreinoud mutex_enter(&ump->allocate_mutex); 1051e979c658Sreinoud if (num_lb > ump->uncomitted_lb) { 1052e979c658Sreinoud ump->uncomitted_lb = 0; 1053e979c658Sreinoud } else { 1054e979c658Sreinoud ump->uncomitted_lb -= num_lb; 1055e979c658Sreinoud } 1056e979c658Sreinoud mutex_exit(&ump->allocate_mutex); 1057e979c658Sreinoud 1058e979c658Sreinoud buf->b_blkno = (*pmapping) * blks; 1059e979c658Sreinoud 1060e979c658Sreinoud /* If its userdata or FIDs, record its allocation in its node. */ 1061e979c658Sreinoud if ((udf_c_type == UDF_C_USERDATA) || (udf_c_type == UDF_C_FIDS)) { 1062e979c658Sreinoud udf_record_allocation_in_node(ump, buf, vpart_num, lmapping, 1063e979c658Sreinoud node_ad_cpy); 1064e979c658Sreinoud /* decrement our outstanding bufs counter */ 1065e979c658Sreinoud s = splbio(); 1066e979c658Sreinoud udf_node->outstanding_bufs--; 1067e979c658Sreinoud splx(s); 1068e979c658Sreinoud } 1069e979c658Sreinoud } 1070e979c658Sreinoud 1071e979c658Sreinoud /* --------------------------------------------------------------------- */ 1072e979c658Sreinoud 1073e979c658Sreinoud /* 1074e979c658Sreinoud * Try to merge a1 with the new piece a2. udf_ads_merge returns error when not 1075e979c658Sreinoud * possible (anymore); a2 returns the rest piece. 1076e979c658Sreinoud */ 1077e979c658Sreinoud 1078e979c658Sreinoud static int 1079e979c658Sreinoud udf_ads_merge(uint32_t lb_size, struct long_ad *a1, struct long_ad *a2) 1080e979c658Sreinoud { 1081e979c658Sreinoud uint32_t max_len, merge_len; 1082e979c658Sreinoud uint32_t a1_len, a2_len; 1083e979c658Sreinoud uint32_t a1_flags, a2_flags; 1084e979c658Sreinoud uint32_t a1_lbnum, a2_lbnum; 1085e979c658Sreinoud uint16_t a1_part, a2_part; 1086e979c658Sreinoud 1087e979c658Sreinoud max_len = ((UDF_EXT_MAXLEN / lb_size) * lb_size); 1088e979c658Sreinoud 1089e979c658Sreinoud a1_flags = UDF_EXT_FLAGS(udf_rw32(a1->len)); 1090e979c658Sreinoud a1_len = UDF_EXT_LEN(udf_rw32(a1->len)); 1091e979c658Sreinoud a1_lbnum = udf_rw32(a1->loc.lb_num); 1092e979c658Sreinoud a1_part = udf_rw16(a1->loc.part_num); 1093e979c658Sreinoud 1094e979c658Sreinoud a2_flags = UDF_EXT_FLAGS(udf_rw32(a2->len)); 1095e979c658Sreinoud a2_len = UDF_EXT_LEN(udf_rw32(a2->len)); 1096e979c658Sreinoud a2_lbnum = udf_rw32(a2->loc.lb_num); 1097e979c658Sreinoud a2_part = udf_rw16(a2->loc.part_num); 1098e979c658Sreinoud 1099e979c658Sreinoud /* defines same space */ 1100e979c658Sreinoud if (a1_flags != a2_flags) 1101e979c658Sreinoud return 1; 1102e979c658Sreinoud 1103e979c658Sreinoud if (a1_flags != UDF_EXT_FREE) { 1104e979c658Sreinoud /* the same partition */ 1105e979c658Sreinoud if (a1_part != a2_part) 1106e979c658Sreinoud return 1; 1107e979c658Sreinoud 1108e979c658Sreinoud /* a2 is successor of a1 */ 1109e979c658Sreinoud if (a1_lbnum * lb_size + a1_len != a2_lbnum * lb_size) 1110e979c658Sreinoud return 1; 1111e979c658Sreinoud } 1112e979c658Sreinoud 1113e979c658Sreinoud /* merge as most from a2 if possible */ 1114e979c658Sreinoud merge_len = MIN(a2_len, max_len - a1_len); 1115e979c658Sreinoud a1_len += merge_len; 1116e979c658Sreinoud a2_len -= merge_len; 1117e979c658Sreinoud a2_lbnum += merge_len/lb_size; 1118e979c658Sreinoud 1119e979c658Sreinoud a1->len = udf_rw32(a1_len | a1_flags); 1120e979c658Sreinoud a2->len = udf_rw32(a2_len | a2_flags); 1121e979c658Sreinoud a2->loc.lb_num = udf_rw32(a2_lbnum); 1122e979c658Sreinoud 1123e979c658Sreinoud if (a2_len > 0) 1124e979c658Sreinoud return 1; 1125e979c658Sreinoud 1126e979c658Sreinoud /* there is space over to merge */ 1127e979c658Sreinoud return 0; 1128e979c658Sreinoud } 1129e979c658Sreinoud 1130e979c658Sreinoud /* --------------------------------------------------------------------- */ 1131e979c658Sreinoud 1132e979c658Sreinoud static void 1133e979c658Sreinoud udf_wipe_adslots(struct udf_node *udf_node) 1134e979c658Sreinoud { 1135e979c658Sreinoud struct file_entry *fe; 1136e979c658Sreinoud struct extfile_entry *efe; 1137e979c658Sreinoud struct alloc_ext_entry *ext; 1138e979c658Sreinoud uint64_t inflen, objsize; 1139e979c658Sreinoud uint32_t lb_size, dscr_size, l_ea, l_ad, max_l_ad, crclen; 1140e979c658Sreinoud uint8_t *data_pos; 1141e979c658Sreinoud int extnr; 1142e979c658Sreinoud 1143e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1144e979c658Sreinoud 1145e979c658Sreinoud fe = udf_node->fe; 1146e979c658Sreinoud efe = udf_node->efe; 1147e979c658Sreinoud if (fe) { 1148e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 1149e979c658Sreinoud objsize = inflen; 1150e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1151e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1152e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 1153e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 1154e979c658Sreinoud } else { 1155e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 1156e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 1157e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1158e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1159e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 1160e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 1161e979c658Sreinoud } 1162e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1163e979c658Sreinoud 1164e979c658Sreinoud /* wipe fe/efe */ 1165e979c658Sreinoud memset(data_pos, 0, max_l_ad); 1166e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea; 1167e979c658Sreinoud if (fe) { 1168e979c658Sreinoud fe->l_ad = udf_rw32(0); 1169e979c658Sreinoud fe->logblks_rec = udf_rw64(0); 1170e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 1171e979c658Sreinoud } else { 1172e979c658Sreinoud efe->l_ad = udf_rw32(0); 1173e979c658Sreinoud efe->logblks_rec = udf_rw64(0); 1174e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 1175e979c658Sreinoud } 1176e979c658Sreinoud 1177e979c658Sreinoud /* wipe all allocation extent entries */ 1178e979c658Sreinoud for (extnr = 0; extnr < udf_node->num_extensions; extnr++) { 1179e979c658Sreinoud ext = udf_node->ext[extnr]; 1180e979c658Sreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 1181e979c658Sreinoud max_l_ad = lb_size - dscr_size; 1182e979c658Sreinoud memset(data_pos, 0, max_l_ad); 1183e979c658Sreinoud ext->l_ad = udf_rw32(0); 1184e979c658Sreinoud 1185e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH; 1186e979c658Sreinoud ext->tag.desc_crc_len = udf_rw32(crclen); 1187e979c658Sreinoud } 1188e979c658Sreinoud } 1189e979c658Sreinoud 1190e979c658Sreinoud /* --------------------------------------------------------------------- */ 1191e979c658Sreinoud 1192e979c658Sreinoud void 1193e979c658Sreinoud udf_get_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb, 1194e979c658Sreinoud int *eof) { 1195e979c658Sreinoud struct file_entry *fe; 1196e979c658Sreinoud struct extfile_entry *efe; 1197e979c658Sreinoud struct alloc_ext_entry *ext; 1198e979c658Sreinoud struct icb_tag *icbtag; 1199e979c658Sreinoud struct short_ad *short_ad; 1200e979c658Sreinoud struct long_ad *long_ad; 1201e979c658Sreinoud uint32_t offset; 1202e979c658Sreinoud uint32_t lb_size, dscr_size, l_ea, l_ad, max_l_ad; 1203e979c658Sreinoud uint8_t *data_pos; 1204e979c658Sreinoud int icbflags, addr_type, adlen, extnr; 1205e979c658Sreinoud 1206e979c658Sreinoud /* determine what descriptor we are in */ 1207e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1208e979c658Sreinoud 1209e979c658Sreinoud fe = udf_node->fe; 1210e979c658Sreinoud efe = udf_node->efe; 1211e979c658Sreinoud if (fe) { 1212e979c658Sreinoud icbtag = &fe->icbtag; 1213e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1214e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1215e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 1216e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 1217e979c658Sreinoud } else { 1218e979c658Sreinoud icbtag = &efe->icbtag; 1219e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1220e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1221e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 1222e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 1223e979c658Sreinoud } 1224e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1225e979c658Sreinoud 1226e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1227e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1228e979c658Sreinoud 1229e979c658Sreinoud /* just in case we're called on an intern, its EOF */ 1230e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1231e979c658Sreinoud memset(icb, 0, sizeof(struct long_ad)); 1232e979c658Sreinoud *eof = 1; 1233e979c658Sreinoud return; 1234e979c658Sreinoud } 1235e979c658Sreinoud 1236e979c658Sreinoud adlen = 0; 1237e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1238e979c658Sreinoud adlen = sizeof(struct short_ad); 1239e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1240e979c658Sreinoud adlen = sizeof(struct long_ad); 1241e979c658Sreinoud } 1242e979c658Sreinoud 1243e979c658Sreinoud /* if offset too big, we go to the allocation extensions */ 1244e979c658Sreinoud offset = slot * adlen; 124535d8dddaSreinoud extnr = -1; 124635d8dddaSreinoud while (offset >= max_l_ad) { 124735d8dddaSreinoud extnr++; 1248e979c658Sreinoud offset -= max_l_ad; 1249e979c658Sreinoud ext = udf_node->ext[extnr]; 1250e979c658Sreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 1251e979c658Sreinoud l_ad = udf_rw32(ext->l_ad); 1252e979c658Sreinoud max_l_ad = lb_size - dscr_size; 125335d8dddaSreinoud data_pos = (uint8_t *) ext + dscr_size; 1254e979c658Sreinoud if (extnr > udf_node->num_extensions) { 1255e979c658Sreinoud l_ad = 0; /* force EOF */ 1256e979c658Sreinoud break; 1257e979c658Sreinoud } 1258e979c658Sreinoud } 1259e979c658Sreinoud 1260e979c658Sreinoud *eof = (offset >= l_ad) || (l_ad == 0); 1261e979c658Sreinoud if (*eof) { 1262e979c658Sreinoud memset(icb, 0, sizeof(struct long_ad)); 1263e979c658Sreinoud return; 1264e979c658Sreinoud } 1265e979c658Sreinoud 1266e979c658Sreinoud /* get the element */ 1267e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1268e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 1269e979c658Sreinoud icb->len = short_ad->len; 1270e979c658Sreinoud icb->loc.part_num = udf_rw16(0); /* ignore */ 1271e979c658Sreinoud icb->loc.lb_num = short_ad->lb_num; 1272e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1273e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 1274e979c658Sreinoud *icb = *long_ad; 1275e979c658Sreinoud } 1276e979c658Sreinoud } 1277e979c658Sreinoud 1278e979c658Sreinoud /* --------------------------------------------------------------------- */ 1279e979c658Sreinoud 1280e979c658Sreinoud int 1281e979c658Sreinoud udf_append_adslot(struct udf_node *udf_node, int slot, struct long_ad *icb) { 1282e979c658Sreinoud union dscrptr *dscr; 1283e979c658Sreinoud struct file_entry *fe; 1284e979c658Sreinoud struct extfile_entry *efe; 1285e979c658Sreinoud struct alloc_ext_entry *ext; 1286e979c658Sreinoud struct icb_tag *icbtag; 1287e979c658Sreinoud struct short_ad *short_ad; 1288e979c658Sreinoud struct long_ad *long_ad, o_icb; 1289e979c658Sreinoud uint64_t logblks_rec, *logblks_rec_p; 1290e979c658Sreinoud uint32_t offset, rest, len; 1291e979c658Sreinoud uint32_t lb_size, dscr_size, l_ea, l_ad, *l_ad_p, max_l_ad, crclen; 1292e979c658Sreinoud uint8_t *data_pos; 1293e979c658Sreinoud int icbflags, addr_type, adlen, extnr; 1294e979c658Sreinoud 1295e979c658Sreinoud /* determine what descriptor we are in */ 1296e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1297e979c658Sreinoud 1298e979c658Sreinoud fe = udf_node->fe; 1299e979c658Sreinoud efe = udf_node->efe; 1300e979c658Sreinoud if (fe) { 1301e979c658Sreinoud icbtag = &fe->icbtag; 1302e979c658Sreinoud dscr = (union dscrptr *) fe; 1303e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1304e979c658Sreinoud 1305e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1306e979c658Sreinoud l_ad_p = &fe->l_ad; 1307e979c658Sreinoud logblks_rec_p = &fe->logblks_rec; 1308e979c658Sreinoud } else { 1309e979c658Sreinoud icbtag = &efe->icbtag; 1310e979c658Sreinoud dscr = (union dscrptr *) efe; 1311e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1312e979c658Sreinoud 1313e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1314e979c658Sreinoud l_ad_p = &efe->l_ad; 1315e979c658Sreinoud logblks_rec_p = &efe->logblks_rec; 1316e979c658Sreinoud } 1317e979c658Sreinoud data_pos = (uint8_t *) dscr + dscr_size + l_ea; 1318e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1319e979c658Sreinoud 1320e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1321e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1322e979c658Sreinoud 1323e979c658Sreinoud /* just in case we're called on an intern, its EOF */ 1324e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1325e979c658Sreinoud panic("udf_append_adslot on UDF_ICB_INTERN_ALLOC\n"); 1326e979c658Sreinoud } 1327e979c658Sreinoud 1328e979c658Sreinoud adlen = 0; 1329e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1330e979c658Sreinoud adlen = sizeof(struct short_ad); 1331e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1332e979c658Sreinoud adlen = sizeof(struct long_ad); 1333e979c658Sreinoud } 1334e979c658Sreinoud 1335e979c658Sreinoud /* if offset too big, we go to the allocation extensions */ 1336e979c658Sreinoud offset = slot * adlen; 1337e979c658Sreinoud extnr = 0; 1338e979c658Sreinoud while (offset > max_l_ad) { 1339e979c658Sreinoud offset -= max_l_ad; 1340e979c658Sreinoud ext = udf_node->ext[extnr]; 1341e979c658Sreinoud dscr = (union dscrptr *) ext; 1342e979c658Sreinoud dscr_size = sizeof(struct alloc_ext_entry) -1; 1343e979c658Sreinoud 1344e979c658Sreinoud KASSERT(ext != NULL); 1345e979c658Sreinoud l_ad_p = &ext->l_ad; 1346e979c658Sreinoud max_l_ad = lb_size - dscr_size; 1347e979c658Sreinoud data_pos = (uint8_t *) dscr + dscr_size; 1348e979c658Sreinoud 1349e979c658Sreinoud extnr++; 1350e979c658Sreinoud } 1351e979c658Sreinoud /* offset is offset within the current (E)FE/AED */ 1352e979c658Sreinoud l_ad = udf_rw32(*l_ad_p); 1353e979c658Sreinoud crclen = udf_rw32(dscr->tag.desc_crc_len); 1354e979c658Sreinoud logblks_rec = udf_rw64(*logblks_rec_p); 1355e979c658Sreinoud 1356e979c658Sreinoud if (extnr > udf_node->num_extensions) 1357e979c658Sreinoud return EFBIG; /* too fragmented */ 1358e979c658Sreinoud 1359e979c658Sreinoud /* overwriting old piece? */ 1360e979c658Sreinoud if (offset < l_ad) { 1361e979c658Sreinoud /* overwrite entry; compensate for the old element */ 1362e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1363e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 1364e979c658Sreinoud o_icb.len = short_ad->len; 1365e979c658Sreinoud o_icb.loc.part_num = udf_rw16(0); /* ignore */ 1366e979c658Sreinoud o_icb.loc.lb_num = short_ad->lb_num; 1367e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1368e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 1369e979c658Sreinoud o_icb = *long_ad; 1370e979c658Sreinoud } else { 1371e979c658Sreinoud panic("Invalid address type in udf_append_adslot\n"); 1372e979c658Sreinoud } 1373e979c658Sreinoud 1374e979c658Sreinoud len = udf_rw32(o_icb.len); 1375e979c658Sreinoud if (UDF_EXT_FLAGS(len) == UDF_EXT_ALLOCATED) { 1376e979c658Sreinoud /* adjust counts */ 1377e979c658Sreinoud len = UDF_EXT_LEN(len); 1378e979c658Sreinoud logblks_rec -= (len + lb_size -1) / lb_size; 1379e979c658Sreinoud } 1380e979c658Sreinoud } 1381e979c658Sreinoud 1382e979c658Sreinoud /* calculate rest space in this descriptor */ 1383e979c658Sreinoud rest = max_l_ad - offset; 1384e979c658Sreinoud if (rest <= adlen) { 1385e979c658Sreinoud /* create redirect and link new allocation extension */ 1386e979c658Sreinoud printf("udf_append_to_adslot: can't create allocation extention yet\n"); 1387e979c658Sreinoud return EFBIG; 1388e979c658Sreinoud } 1389e979c658Sreinoud 1390e979c658Sreinoud /* write out the element */ 1391e979c658Sreinoud if (addr_type == UDF_ICB_SHORT_ALLOC) { 1392e979c658Sreinoud short_ad = (struct short_ad *) (data_pos + offset); 1393e979c658Sreinoud short_ad->len = icb->len; 1394e979c658Sreinoud short_ad->lb_num = icb->loc.lb_num; 1395e979c658Sreinoud } else if (addr_type == UDF_ICB_LONG_ALLOC) { 1396e979c658Sreinoud long_ad = (struct long_ad *) (data_pos + offset); 1397e979c658Sreinoud *long_ad = *icb; 1398e979c658Sreinoud } 1399e979c658Sreinoud 1400e979c658Sreinoud /* adjust logblks recorded count */ 1401e979c658Sreinoud if (UDF_EXT_FLAGS(icb->len) == UDF_EXT_ALLOCATED) 1402e979c658Sreinoud logblks_rec += (UDF_EXT_LEN(icb->len) + lb_size -1) / lb_size; 1403e979c658Sreinoud *logblks_rec_p = udf_rw64(logblks_rec); 1404e979c658Sreinoud 1405e979c658Sreinoud /* adjust l_ad and crclen when needed */ 1406e979c658Sreinoud if (offset >= l_ad) { 1407e979c658Sreinoud l_ad += adlen; 1408e979c658Sreinoud crclen += adlen; 1409e979c658Sreinoud dscr->tag.desc_crc_len = udf_rw32(crclen); 1410e979c658Sreinoud *l_ad_p = udf_rw32(l_ad); 1411e979c658Sreinoud } 1412e979c658Sreinoud 1413e979c658Sreinoud return 0; 1414e979c658Sreinoud } 1415e979c658Sreinoud 1416e979c658Sreinoud /* --------------------------------------------------------------------- */ 1417e979c658Sreinoud 1418e979c658Sreinoud /* 1419e979c658Sreinoud * Adjust the node's allocation descriptors to reflect the new mapping; do 1420e979c658Sreinoud * take note that we might glue to existing allocation descriptors. 1421e979c658Sreinoud * 1422e979c658Sreinoud * XXX Note there can only be one allocation being recorded/mount; maybe 1423e979c658Sreinoud * explicit allocation in shedule thread? 1424e979c658Sreinoud */ 1425e979c658Sreinoud 1426e979c658Sreinoud static void 1427e979c658Sreinoud udf_record_allocation_in_node(struct udf_mount *ump, struct buf *buf, 1428e979c658Sreinoud uint16_t vpart_num, uint64_t *mapping, struct long_ad *node_ad_cpy) 1429e979c658Sreinoud { 1430e979c658Sreinoud struct vnode *vp = buf->b_vp; 1431e979c658Sreinoud struct udf_node *udf_node = VTOI(vp); 1432e979c658Sreinoud struct file_entry *fe; 1433e979c658Sreinoud struct extfile_entry *efe; 1434e979c658Sreinoud struct icb_tag *icbtag; 1435e979c658Sreinoud struct long_ad s_ad, c_ad; 1436e979c658Sreinoud uint64_t inflen, from, till; 1437e979c658Sreinoud uint64_t foffset, end_foffset, restart_foffset; 1438e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 1439e979c658Sreinoud uint32_t num_lb, len, flags, lb_num; 1440e979c658Sreinoud uint32_t run_start; 1441e979c658Sreinoud uint32_t slot_offset; 1442e979c658Sreinoud uint32_t skip_len, skipped; 1443e979c658Sreinoud int addr_type, icbflags; 1444e979c658Sreinoud int udf_c_type = buf->b_udf_c_type; 1445e979c658Sreinoud int lb_size, run_length, eof; 1446e979c658Sreinoud int slot, cpy_slot, cpy_slots, restart_slot; 1447e979c658Sreinoud int error; 1448e979c658Sreinoud 1449e979c658Sreinoud DPRINTF(ALLOC, ("udf_record_allocation_in_node\n")); 1450e979c658Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 1451e979c658Sreinoud 1452e979c658Sreinoud /* sanity check ... should be panic ? */ 1453e979c658Sreinoud if ((udf_c_type != UDF_C_USERDATA) && (udf_c_type != UDF_C_FIDS)) 1454e979c658Sreinoud return; 1455e979c658Sreinoud 1456e979c658Sreinoud lb_size = udf_rw32(udf_node->ump->logical_vol->lb_size); 1457e979c658Sreinoud 1458e979c658Sreinoud /* do the job */ 1459e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); /* XXX can deadlock ? */ 1460e979c658Sreinoud 1461e979c658Sreinoud fe = udf_node->fe; 1462e979c658Sreinoud efe = udf_node->efe; 1463e979c658Sreinoud if (fe) { 1464e979c658Sreinoud icbtag = &fe->icbtag; 1465e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 1466e979c658Sreinoud } else { 1467e979c658Sreinoud icbtag = &efe->icbtag; 1468e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 1469e979c658Sreinoud } 1470e979c658Sreinoud 1471e979c658Sreinoud /* do check if `till' is not past file information length */ 1472e979c658Sreinoud from = buf->b_lblkno * lb_size; 1473e979c658Sreinoud till = MIN(inflen, from + buf->b_resid); 1474e979c658Sreinoud 1475e979c658Sreinoud num_lb = (till - from + lb_size -1) / lb_size; 1476e979c658Sreinoud 1477e979c658Sreinoud DPRINTF(ALLOC, ("record allocation from = %"PRIu64" + %d\n", from, buf->b_bcount)); 1478e979c658Sreinoud 1479e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1480e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1481e979c658Sreinoud 1482e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1483e979c658Sreinoud /* nothing to do */ 1484e979c658Sreinoud /* XXX clean up rest of node? just in case? */ 1485e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1486e979c658Sreinoud return; 1487e979c658Sreinoud } 1488e979c658Sreinoud 1489e979c658Sreinoud slot = 0; 1490e979c658Sreinoud cpy_slot = 0; 1491e979c658Sreinoud foffset = 0; 1492e979c658Sreinoud 1493e979c658Sreinoud /* 1) copy till first overlap piece to the rewrite buffer */ 1494e979c658Sreinoud for (;;) { 1495e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1496e979c658Sreinoud if (eof) { 1497e979c658Sreinoud DPRINTF(WRITE, 1498e979c658Sreinoud ("Record allocation in node " 1499e979c658Sreinoud "failed: encountered EOF\n")); 1500e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1501e979c658Sreinoud buf->b_error = EINVAL; 1502e979c658Sreinoud return; 1503e979c658Sreinoud } 1504e979c658Sreinoud len = udf_rw32(s_ad.len); 1505e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1506e979c658Sreinoud len = UDF_EXT_LEN(len); 1507e979c658Sreinoud 1508e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 1509e979c658Sreinoud slot++; 1510e979c658Sreinoud continue; 1511e979c658Sreinoud } 1512e979c658Sreinoud 1513e979c658Sreinoud end_foffset = foffset + len; 1514e979c658Sreinoud if (end_foffset > from) 1515e979c658Sreinoud break; /* found */ 1516e979c658Sreinoud 1517e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1518e979c658Sreinoud 1519e979c658Sreinoud DPRINTF(ALLOC, ("\t1: vp %d, lb %d, len %d, flags %d " 1520e979c658Sreinoud "-> stack\n", 1521e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1522e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1523e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1524e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1525e979c658Sreinoud 1526e979c658Sreinoud foffset = end_foffset; 1527e979c658Sreinoud slot++; 1528e979c658Sreinoud } 1529e979c658Sreinoud restart_slot = slot; 1530e979c658Sreinoud restart_foffset = foffset; 1531e979c658Sreinoud 1532e979c658Sreinoud /* 2) trunc overlapping slot at overlap and copy it */ 1533e979c658Sreinoud slot_offset = from - foffset; 1534e979c658Sreinoud if (slot_offset > 0) { 1535e979c658Sreinoud DPRINTF(ALLOC, ("\tslot_offset = %d, flags = %d (%d)\n", 1536e979c658Sreinoud slot_offset, flags >> 30, flags)); 1537e979c658Sreinoud 1538e979c658Sreinoud s_ad.len = udf_rw32(slot_offset | flags); 1539e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1540e979c658Sreinoud 1541e979c658Sreinoud DPRINTF(ALLOC, ("\t2: vp %d, lb %d, len %d, flags %d " 1542e979c658Sreinoud "-> stack\n", 1543e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1544e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1545e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1546e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1547e979c658Sreinoud } 1548e979c658Sreinoud foffset += slot_offset; 1549e979c658Sreinoud 1550e979c658Sreinoud /* 3) insert new mappings */ 1551e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 1552e979c658Sreinoud lb_num = 0; 1553e979c658Sreinoud for (lb_num = 0; lb_num < num_lb; lb_num++) { 1554e979c658Sreinoud run_start = mapping[lb_num]; 1555e979c658Sreinoud run_length = 1; 1556e979c658Sreinoud while (lb_num < num_lb-1) { 1557e979c658Sreinoud if (mapping[lb_num+1] != mapping[lb_num]+1) 1558e979c658Sreinoud if (mapping[lb_num+1] != mapping[lb_num]) 1559e979c658Sreinoud break; 1560e979c658Sreinoud run_length++; 1561e979c658Sreinoud lb_num++; 1562e979c658Sreinoud } 1563e979c658Sreinoud /* insert slot for this mapping */ 1564e979c658Sreinoud len = run_length * lb_size; 1565e979c658Sreinoud 1566e979c658Sreinoud /* bounds checking */ 1567e979c658Sreinoud if (foffset + len > till) 1568e979c658Sreinoud len = till - foffset; 1569e979c658Sreinoud KASSERT(foffset + len <= inflen); 1570e979c658Sreinoud 1571e979c658Sreinoud s_ad.len = udf_rw32(len | UDF_EXT_ALLOCATED); 1572e979c658Sreinoud s_ad.loc.part_num = udf_rw16(vpart_num); 1573e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(run_start); 1574e979c658Sreinoud 1575e979c658Sreinoud foffset += len; 1576e979c658Sreinoud 1577e979c658Sreinoud /* paranoia */ 1578e979c658Sreinoud if (len == 0) { 1579e979c658Sreinoud DPRINTF(WRITE, 1580e979c658Sreinoud ("Record allocation in node " 1581e979c658Sreinoud "failed: insert failed\n")); 1582e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1583e979c658Sreinoud buf->b_error = EINVAL; 1584e979c658Sreinoud return; 1585e979c658Sreinoud } 1586e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1587e979c658Sreinoud 1588e979c658Sreinoud DPRINTF(ALLOC, ("\t3: insert new mapping vp %d lb %d, len %d, " 1589e979c658Sreinoud "flags %d -> stack\n", 1590e979c658Sreinoud udf_rw16(s_ad.loc.part_num), udf_rw32(s_ad.loc.lb_num), 1591e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1592e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1593e979c658Sreinoud } 1594e979c658Sreinoud 1595e979c658Sreinoud /* 4) pop replaced length */ 1596e979c658Sreinoud slot = restart_slot; 1597e979c658Sreinoud foffset = restart_foffset; 1598e979c658Sreinoud 1599e979c658Sreinoud skip_len = till - foffset; /* relative to start of slot */ 1600e979c658Sreinoud slot_offset = from - foffset; 1601e979c658Sreinoud for (;;) { 1602e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1603e979c658Sreinoud if (eof) 1604e979c658Sreinoud break; 1605e979c658Sreinoud 1606e979c658Sreinoud len = udf_rw32(s_ad.len); 1607e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1608e979c658Sreinoud len = UDF_EXT_LEN(len); 1609e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 1610e979c658Sreinoud 1611e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 1612e979c658Sreinoud slot++; 1613e979c658Sreinoud continue; 1614e979c658Sreinoud } 1615e979c658Sreinoud 1616e979c658Sreinoud DPRINTF(ALLOC, ("\t4i: got slot %d, skip_len %d, vp %d, " 1617e979c658Sreinoud "lb %d, len %d, flags %d\n", 1618e979c658Sreinoud slot, skip_len, udf_rw16(s_ad.loc.part_num), 1619e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1620e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1621e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1622e979c658Sreinoud 1623e979c658Sreinoud skipped = MIN(len, skip_len); 1624e979c658Sreinoud if (flags != UDF_EXT_FREE) { 1625e979c658Sreinoud if (slot_offset) { 1626e979c658Sreinoud /* skip these blocks first */ 1627e979c658Sreinoud num_lb = (slot_offset + lb_size-1) / lb_size; 1628e979c658Sreinoud len -= slot_offset; 1629e979c658Sreinoud skip_len -= slot_offset; 1630e979c658Sreinoud foffset += slot_offset; 1631e979c658Sreinoud lb_num += num_lb; 1632e979c658Sreinoud skipped -= slot_offset; 1633e979c658Sreinoud slot_offset = 0; 1634e979c658Sreinoud } 1635e979c658Sreinoud /* free space from current position till `skipped' */ 1636e979c658Sreinoud num_lb = (skipped + lb_size-1) / lb_size; 1637e979c658Sreinoud udf_free_allocated_space(ump, lb_num, 1638e979c658Sreinoud udf_rw16(s_ad.loc.part_num), num_lb); 1639e979c658Sreinoud lb_num += num_lb; 1640e979c658Sreinoud } 1641e979c658Sreinoud len -= skipped; 1642e979c658Sreinoud skip_len -= skipped; 1643e979c658Sreinoud foffset += skipped; 1644e979c658Sreinoud 1645e979c658Sreinoud if (len) { 1646e979c658Sreinoud KASSERT(skipped % lb_size == 0); 1647e979c658Sreinoud 1648e979c658Sreinoud /* we arrived at our point, push remainder */ 1649e979c658Sreinoud s_ad.len = udf_rw32(len | flags); 1650e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(lb_num); 1651e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1652e979c658Sreinoud foffset += len; 1653e979c658Sreinoud slot++; 1654e979c658Sreinoud 1655e979c658Sreinoud DPRINTF(ALLOC, ("\t4: vp %d, lb %d, len %d, flags %d " 1656e979c658Sreinoud "-> stack\n", 1657e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1658e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1659e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1660e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1661e979c658Sreinoud break; 1662e979c658Sreinoud } 1663e979c658Sreinoud slot++; 1664e979c658Sreinoud } 1665e979c658Sreinoud 1666e979c658Sreinoud /* 5) copy remainder */ 1667e979c658Sreinoud for (;;) { 1668e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 1669e979c658Sreinoud if (eof) 1670e979c658Sreinoud break; 1671e979c658Sreinoud 1672e979c658Sreinoud len = udf_rw32(s_ad.len); 1673e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1674e979c658Sreinoud len = UDF_EXT_LEN(len); 1675e979c658Sreinoud 1676e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 1677e979c658Sreinoud slot++; 1678e979c658Sreinoud continue; 1679e979c658Sreinoud } 1680e979c658Sreinoud 1681e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 1682e979c658Sreinoud 1683e979c658Sreinoud DPRINTF(ALLOC, ("\t5: insert new mapping " 1684e979c658Sreinoud "vp %d lb %d, len %d, flags %d " 1685e979c658Sreinoud "-> stack\n", 1686e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1687e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1688e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1689e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1690e979c658Sreinoud 1691e979c658Sreinoud slot++; 1692e979c658Sreinoud } 1693e979c658Sreinoud 1694e979c658Sreinoud /* 6) reset node descriptors */ 1695e979c658Sreinoud udf_wipe_adslots(udf_node); 1696e979c658Sreinoud 1697e979c658Sreinoud /* 7) copy back extents; merge when possible. Recounting on the fly */ 1698e979c658Sreinoud cpy_slots = cpy_slot; 1699e979c658Sreinoud 1700e979c658Sreinoud c_ad = node_ad_cpy[0]; 1701e979c658Sreinoud slot = 0; 1702e979c658Sreinoud DPRINTF(ALLOC, ("\t7s: stack -> got mapping vp %d " 1703e979c658Sreinoud "lb %d, len %d, flags %d\n", 1704e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 1705e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 1706e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 1707e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 1708e979c658Sreinoud 1709e979c658Sreinoud for (cpy_slot = 1; cpy_slot < cpy_slots; cpy_slot++) { 1710e979c658Sreinoud s_ad = node_ad_cpy[cpy_slot]; 1711e979c658Sreinoud 1712e979c658Sreinoud DPRINTF(ALLOC, ("\t7i: stack -> got mapping vp %d " 1713e979c658Sreinoud "lb %d, len %d, flags %d\n", 1714e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 1715e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 1716e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 1717e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 1718e979c658Sreinoud 1719e979c658Sreinoud /* see if we can merge */ 1720e979c658Sreinoud if (udf_ads_merge(lb_size, &c_ad, &s_ad)) { 1721e979c658Sreinoud /* not mergable (anymore) */ 1722e979c658Sreinoud DPRINTF(ALLOC, ("\t7: appending vp %d lb %d, " 1723e979c658Sreinoud "len %d, flags %d\n", 1724e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 1725e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 1726e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 1727e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 1728e979c658Sreinoud 1729e979c658Sreinoud error = udf_append_adslot(udf_node, slot, &c_ad); 1730e979c658Sreinoud if (error) { 1731e979c658Sreinoud buf->b_error = error; 1732e979c658Sreinoud goto out; 1733e979c658Sreinoud } 1734e979c658Sreinoud c_ad = s_ad; 1735e979c658Sreinoud slot++; 1736e979c658Sreinoud } 1737e979c658Sreinoud } 1738e979c658Sreinoud 1739e979c658Sreinoud /* 8) push rest slot (if any) */ 1740e979c658Sreinoud if (UDF_EXT_LEN(c_ad.len) > 0) { 1741e979c658Sreinoud DPRINTF(ALLOC, ("\t8: last append vp %d lb %d, " 1742e979c658Sreinoud "len %d, flags %d\n", 1743e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 1744e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 1745e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 1746e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 1747e979c658Sreinoud 1748e979c658Sreinoud error = udf_append_adslot(udf_node, slot, &c_ad); 1749e979c658Sreinoud if (error) { 1750e979c658Sreinoud buf->b_error = error; 1751e979c658Sreinoud goto out; 1752e979c658Sreinoud } 1753e979c658Sreinoud } 1754e979c658Sreinoud 1755e979c658Sreinoud out: 1756e979c658Sreinoud /* the node's descriptors should now be sane */ 1757e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1758e979c658Sreinoud 1759e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 1760e979c658Sreinoud 1761e979c658Sreinoud KASSERT(orig_inflen == new_inflen); 1762e979c658Sreinoud KASSERT(new_lbrec >= orig_lbrec); 1763e979c658Sreinoud 1764e979c658Sreinoud return; 1765e979c658Sreinoud } 1766e979c658Sreinoud 1767e979c658Sreinoud /* --------------------------------------------------------------------- */ 1768e979c658Sreinoud 1769e979c658Sreinoud int 1770e979c658Sreinoud udf_grow_node(struct udf_node *udf_node, uint64_t new_size) 1771e979c658Sreinoud { 1772e979c658Sreinoud union dscrptr *dscr; 1773e979c658Sreinoud struct vnode *vp = udf_node->vnode; 1774e979c658Sreinoud struct udf_mount *ump = udf_node->ump; 1775e979c658Sreinoud struct file_entry *fe; 1776e979c658Sreinoud struct extfile_entry *efe; 1777e979c658Sreinoud struct icb_tag *icbtag; 1778e979c658Sreinoud struct long_ad c_ad, s_ad; 1779e979c658Sreinoud uint64_t size_diff, old_size, inflen, objsize, chunk, append_len; 1780e979c658Sreinoud uint64_t foffset, end_foffset; 1781e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 1782e979c658Sreinoud uint32_t lb_size, dscr_size, crclen, lastblock_grow; 1783e979c658Sreinoud uint32_t len, flags, max_len; 1784e979c658Sreinoud uint32_t max_l_ad, l_ad, l_ea; 1785e979c658Sreinoud uint8_t *data_pos, *evacuated_data; 1786e979c658Sreinoud int icbflags, addr_type; 1787e979c658Sreinoud int slot, cpy_slot; 1788e979c658Sreinoud int eof, error; 1789e979c658Sreinoud 1790e979c658Sreinoud DPRINTF(ALLOC, ("udf_grow_node\n")); 1791e979c658Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 1792e979c658Sreinoud 1793e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 1794e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 1795e979c658Sreinoud max_len = ((UDF_EXT_MAXLEN / lb_size) * lb_size); 1796e979c658Sreinoud 1797e979c658Sreinoud fe = udf_node->fe; 1798e979c658Sreinoud efe = udf_node->efe; 1799e979c658Sreinoud if (fe) { 1800e979c658Sreinoud dscr = (union dscrptr *) fe; 1801e979c658Sreinoud icbtag = &fe->icbtag; 1802e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 1803e979c658Sreinoud objsize = inflen; 1804e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 1805e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 1806e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 1807e979c658Sreinoud } else { 1808e979c658Sreinoud dscr = (union dscrptr *) efe; 1809e979c658Sreinoud icbtag = &efe->icbtag; 1810e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 1811e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 1812e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 1813e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 1814e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 1815e979c658Sreinoud } 1816e979c658Sreinoud data_pos = (uint8_t *) dscr + dscr_size + l_ea; 1817e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 1818e979c658Sreinoud 1819e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 1820e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1821e979c658Sreinoud 1822e979c658Sreinoud old_size = inflen; 1823e979c658Sreinoud size_diff = new_size - old_size; 1824e979c658Sreinoud 1825e979c658Sreinoud DPRINTF(ALLOC, ("\tfrom %"PRIu64" to %"PRIu64"\n", old_size, new_size)); 1826e979c658Sreinoud 1827e979c658Sreinoud evacuated_data = NULL; 1828e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 1829e979c658Sreinoud if (l_ad + size_diff <= max_l_ad) { 1830e979c658Sreinoud /* only reflect size change directly in the node */ 1831e979c658Sreinoud inflen += size_diff; 1832e979c658Sreinoud objsize += size_diff; 1833e979c658Sreinoud l_ad += size_diff; 1834e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 1835e979c658Sreinoud if (fe) { 1836e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 1837e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 1838e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 1839e979c658Sreinoud } else { 1840e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 1841e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 1842e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 1843e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 1844e979c658Sreinoud } 1845e979c658Sreinoud error = 0; 1846e979c658Sreinoud 1847e979c658Sreinoud /* set new size for uvm */ 1848e979c658Sreinoud uvm_vnp_setsize(vp, old_size); 1849e979c658Sreinoud uvm_vnp_setwritesize(vp, new_size); 1850e979c658Sreinoud 1851e979c658Sreinoud #if 0 1852e979c658Sreinoud /* zero append space in buffer */ 1853e979c658Sreinoud uvm_vnp_zerorange(vp, old_size, new_size - old_size); 1854e979c658Sreinoud #endif 1855e979c658Sreinoud 1856e979c658Sreinoud /* unlock */ 1857e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1858e979c658Sreinoud 1859e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 1860e979c658Sreinoud KASSERT(new_inflen == orig_inflen + size_diff); 1861e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 1862e979c658Sreinoud KASSERT(new_lbrec == 0); 1863e979c658Sreinoud return 0; 1864e979c658Sreinoud } 1865e979c658Sreinoud 1866e979c658Sreinoud DPRINTF(ALLOC, ("\tCONVERT from internal\n")); 1867e979c658Sreinoud 1868e979c658Sreinoud if (old_size > 0) { 1869e979c658Sreinoud /* allocate some space and copy in the stuff to keep */ 1870e979c658Sreinoud evacuated_data = malloc(lb_size, M_UDFTEMP, M_WAITOK); 1871e979c658Sreinoud memset(evacuated_data, 0, lb_size); 1872e979c658Sreinoud 1873e979c658Sreinoud /* node is locked, so safe to exit mutex */ 1874e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 1875e979c658Sreinoud 1876e979c658Sreinoud /* read in using the `normal' vn_rdwr() */ 1877e979c658Sreinoud error = vn_rdwr(UIO_READ, udf_node->vnode, 1878e979c658Sreinoud evacuated_data, old_size, 0, 1879e979c658Sreinoud UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED, 1880e979c658Sreinoud FSCRED, NULL, NULL); 1881e979c658Sreinoud 1882e979c658Sreinoud /* enter again */ 1883e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 1884e979c658Sreinoud } 1885e979c658Sreinoud 1886e979c658Sreinoud /* convert to a normal alloc */ 1887e979c658Sreinoud /* XXX HOWTO selecting allocation method ? */ 1888e979c658Sreinoud icbflags &= ~UDF_ICB_TAG_FLAGS_ALLOC_MASK; 1889e979c658Sreinoud icbflags |= UDF_ICB_LONG_ALLOC; /* XXX or SHORT_ALLOC */ 1890e979c658Sreinoud icbtag->flags = udf_rw16(icbflags); 1891e979c658Sreinoud 1892e979c658Sreinoud /* wipe old descriptor space */ 1893e979c658Sreinoud udf_wipe_adslots(udf_node); 1894e979c658Sreinoud 1895e979c658Sreinoud memset(&c_ad, 0, sizeof(struct long_ad)); 1896e979c658Sreinoud c_ad.len = udf_rw32(old_size | UDF_EXT_FREE); 1897e979c658Sreinoud c_ad.loc.part_num = udf_rw16(0); /* not relevant */ 1898e979c658Sreinoud c_ad.loc.lb_num = udf_rw32(0); /* not relevant */ 1899e979c658Sreinoud 1900e979c658Sreinoud slot = 0; 1901e979c658Sreinoud } else { 1902e979c658Sreinoud /* goto the last entry (if any) */ 1903e979c658Sreinoud slot = 0; 1904e979c658Sreinoud cpy_slot = 0; 1905e979c658Sreinoud foffset = 0; 1906e979c658Sreinoud memset(&c_ad, 0, sizeof(struct long_ad)); 1907e979c658Sreinoud for (;;) { 1908e979c658Sreinoud udf_get_adslot(udf_node, slot, &c_ad, &eof); 1909e979c658Sreinoud if (eof) 1910e979c658Sreinoud break; 1911e979c658Sreinoud 1912e979c658Sreinoud len = udf_rw32(c_ad.len); 1913e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1914e979c658Sreinoud len = UDF_EXT_LEN(len); 1915e979c658Sreinoud 1916e979c658Sreinoud end_foffset = foffset + len; 1917e979c658Sreinoud if (flags != UDF_EXT_REDIRECT) 1918e979c658Sreinoud foffset = end_foffset; 1919e979c658Sreinoud 1920e979c658Sreinoud slot++; 1921e979c658Sreinoud } 1922e979c658Sreinoud /* at end of adslots */ 1923e979c658Sreinoud 1924e979c658Sreinoud /* special case if the old size was zero, then there is no last slot */ 1925e979c658Sreinoud if (old_size == 0) { 1926e979c658Sreinoud c_ad.len = udf_rw32(0 | UDF_EXT_FREE); 1927e979c658Sreinoud c_ad.loc.part_num = udf_rw16(0); /* not relevant */ 1928e979c658Sreinoud c_ad.loc.lb_num = udf_rw32(0); /* not relevant */ 1929e979c658Sreinoud } else { 1930e979c658Sreinoud /* refetch last slot */ 1931e979c658Sreinoud slot--; 1932e979c658Sreinoud udf_get_adslot(udf_node, slot, &c_ad, &eof); 1933e979c658Sreinoud } 1934e979c658Sreinoud } 1935e979c658Sreinoud 1936e979c658Sreinoud /* 1937e979c658Sreinoud * If the length of the last slot is not a multiple of lb_size, adjust 1938e979c658Sreinoud * length so that it is; don't forget to adjust `append_len'! relevant for 1939e979c658Sreinoud * extending existing files 1940e979c658Sreinoud */ 1941e979c658Sreinoud len = udf_rw32(c_ad.len); 1942e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 1943e979c658Sreinoud len = UDF_EXT_LEN(len); 1944e979c658Sreinoud 1945e979c658Sreinoud lastblock_grow = 0; 1946e979c658Sreinoud if (len % lb_size > 0) { 1947e979c658Sreinoud lastblock_grow = lb_size - (len % lb_size); 1948e979c658Sreinoud lastblock_grow = MIN(size_diff, lastblock_grow); 1949e979c658Sreinoud len += lastblock_grow; 1950e979c658Sreinoud c_ad.len = udf_rw32(len | flags); 1951e979c658Sreinoud 1952e979c658Sreinoud /* TODO zero appened space in buffer! */ 1953e979c658Sreinoud /* using uvm_vnp_zerorange(vp, old_size, new_size - old_size); ? */ 1954e979c658Sreinoud } 1955e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 1956e979c658Sreinoud 1957e979c658Sreinoud /* size_diff can be bigger than allowed, so grow in chunks */ 1958e979c658Sreinoud append_len = size_diff - lastblock_grow; 1959e979c658Sreinoud while (append_len > 0) { 1960e979c658Sreinoud chunk = MIN(append_len, max_len); 1961e979c658Sreinoud s_ad.len = udf_rw32(chunk | UDF_EXT_FREE); 1962e979c658Sreinoud s_ad.loc.part_num = udf_rw16(0); 1963e979c658Sreinoud s_ad.loc.lb_num = udf_rw32(0); 1964e979c658Sreinoud 1965e979c658Sreinoud if (udf_ads_merge(lb_size, &c_ad, &s_ad)) { 1966e979c658Sreinoud /* not mergable (anymore) */ 1967e979c658Sreinoud error = udf_append_adslot(udf_node, slot, &c_ad); 1968e979c658Sreinoud if (error) 1969e979c658Sreinoud goto errorout; 1970e979c658Sreinoud slot++; 1971e979c658Sreinoud c_ad = s_ad; 1972e979c658Sreinoud memset(&s_ad, 0, sizeof(struct long_ad)); 1973e979c658Sreinoud } 1974e979c658Sreinoud append_len -= chunk; 1975e979c658Sreinoud } 1976e979c658Sreinoud 1977e979c658Sreinoud /* if there is a rest piece in the accumulator, append it */ 1978e979c658Sreinoud if (UDF_EXT_LEN(c_ad.len) > 0) { 1979e979c658Sreinoud error = udf_append_adslot(udf_node, slot, &c_ad); 1980e979c658Sreinoud if (error) 1981e979c658Sreinoud goto errorout; 1982e979c658Sreinoud slot++; 1983e979c658Sreinoud } 1984e979c658Sreinoud 1985e979c658Sreinoud /* if there is a rest piece that didn't fit, append it */ 1986e979c658Sreinoud if (UDF_EXT_LEN(s_ad.len) > 0) { 1987e979c658Sreinoud error = udf_append_adslot(udf_node, slot, &s_ad); 1988e979c658Sreinoud if (error) 1989e979c658Sreinoud goto errorout; 1990e979c658Sreinoud slot++; 1991e979c658Sreinoud } 1992e979c658Sreinoud 1993e979c658Sreinoud inflen += size_diff; 1994e979c658Sreinoud objsize += size_diff; 1995e979c658Sreinoud if (fe) { 1996e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 1997e979c658Sreinoud } else { 1998e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 1999e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2000e979c658Sreinoud } 2001e979c658Sreinoud error = 0; 2002e979c658Sreinoud 2003e979c658Sreinoud if (evacuated_data) { 2004e979c658Sreinoud /* set new write size for uvm */ 2005e979c658Sreinoud uvm_vnp_setwritesize(vp, old_size); 2006e979c658Sreinoud 2007e979c658Sreinoud /* write out evacuated data */ 2008e979c658Sreinoud error = vn_rdwr(UIO_WRITE, udf_node->vnode, 2009e979c658Sreinoud evacuated_data, old_size, 0, 2010e979c658Sreinoud UIO_SYSSPACE, IO_ALTSEMANTICS | IO_NODELOCKED, 2011e979c658Sreinoud FSCRED, NULL, NULL); 2012e979c658Sreinoud uvm_vnp_setsize(vp, old_size); 2013e979c658Sreinoud } 2014e979c658Sreinoud 2015e979c658Sreinoud errorout: 2016e979c658Sreinoud if (evacuated_data) 2017e979c658Sreinoud free(evacuated_data, M_UDFTEMP); 2018e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2019e979c658Sreinoud 2020e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 2021e979c658Sreinoud KASSERT(new_inflen == orig_inflen + size_diff); 2022e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2023e979c658Sreinoud 2024e979c658Sreinoud return error; 2025e979c658Sreinoud } 2026e979c658Sreinoud 2027e979c658Sreinoud /* --------------------------------------------------------------------- */ 2028e979c658Sreinoud 2029e979c658Sreinoud int 2030e979c658Sreinoud udf_shrink_node(struct udf_node *udf_node, uint64_t new_size) 2031e979c658Sreinoud { 2032e979c658Sreinoud struct vnode *vp = udf_node->vnode; 2033e979c658Sreinoud struct udf_mount *ump = udf_node->ump; 2034e979c658Sreinoud struct file_entry *fe; 2035e979c658Sreinoud struct extfile_entry *efe; 2036e979c658Sreinoud struct icb_tag *icbtag; 2037e979c658Sreinoud struct long_ad c_ad, s_ad, *node_ad_cpy; 2038e979c658Sreinoud uint64_t size_diff, old_size, inflen, objsize; 2039e979c658Sreinoud uint64_t foffset, end_foffset; 2040e979c658Sreinoud uint64_t orig_inflen, orig_lbrec, new_inflen, new_lbrec; 2041e979c658Sreinoud uint32_t lb_size, dscr_size, crclen; 2042e979c658Sreinoud uint32_t slot_offset; 2043e979c658Sreinoud uint32_t len, flags, max_len; 2044e979c658Sreinoud uint32_t num_lb, lb_num; 2045e979c658Sreinoud uint32_t max_l_ad, l_ad, l_ea; 2046e979c658Sreinoud uint16_t vpart_num; 2047e979c658Sreinoud uint8_t *data_pos; 2048e979c658Sreinoud int icbflags, addr_type; 2049e979c658Sreinoud int slot, cpy_slot, cpy_slots; 2050e979c658Sreinoud int eof, error; 2051e979c658Sreinoud 2052e979c658Sreinoud DPRINTF(ALLOC, ("udf_shrink_node\n")); 2053e979c658Sreinoud udf_node_sanity_check(udf_node, &orig_inflen, &orig_lbrec); 2054e979c658Sreinoud 2055e979c658Sreinoud UDF_LOCK_NODE(udf_node, 0); 2056e979c658Sreinoud lb_size = udf_rw32(ump->logical_vol->lb_size); 2057e979c658Sreinoud max_len = ((UDF_EXT_MAXLEN / lb_size) * lb_size); 2058e979c658Sreinoud 2059e979c658Sreinoud /* do the work */ 2060e979c658Sreinoud fe = udf_node->fe; 2061e979c658Sreinoud efe = udf_node->efe; 2062e979c658Sreinoud if (fe) { 2063e979c658Sreinoud icbtag = &fe->icbtag; 2064e979c658Sreinoud inflen = udf_rw64(fe->inf_len); 2065e979c658Sreinoud objsize = inflen; 2066e979c658Sreinoud dscr_size = sizeof(struct file_entry) -1; 2067e979c658Sreinoud l_ea = udf_rw32(fe->l_ea); 2068e979c658Sreinoud l_ad = udf_rw32(fe->l_ad); 2069e979c658Sreinoud data_pos = (uint8_t *) fe + dscr_size + l_ea; 2070e979c658Sreinoud } else { 2071e979c658Sreinoud icbtag = &efe->icbtag; 2072e979c658Sreinoud inflen = udf_rw64(efe->inf_len); 2073e979c658Sreinoud objsize = udf_rw64(efe->obj_size); 2074e979c658Sreinoud dscr_size = sizeof(struct extfile_entry) -1; 2075e979c658Sreinoud l_ea = udf_rw32(efe->l_ea); 2076e979c658Sreinoud l_ad = udf_rw32(efe->l_ad); 2077e979c658Sreinoud data_pos = (uint8_t *) efe + dscr_size + l_ea; 2078e979c658Sreinoud } 2079e979c658Sreinoud max_l_ad = lb_size - dscr_size - l_ea; 2080e979c658Sreinoud 2081e979c658Sreinoud icbflags = udf_rw16(icbtag->flags); 2082e979c658Sreinoud addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2083e979c658Sreinoud 2084e979c658Sreinoud old_size = inflen; 2085e979c658Sreinoud size_diff = old_size - new_size; 2086e979c658Sreinoud 2087e979c658Sreinoud DPRINTF(ALLOC, ("\tfrom %"PRIu64" to %"PRIu64"\n", old_size, new_size)); 2088e979c658Sreinoud 2089e979c658Sreinoud /* shrink the node to its new size */ 2090e979c658Sreinoud if (addr_type == UDF_ICB_INTERN_ALLOC) { 2091e979c658Sreinoud /* only reflect size change directly in the node */ 2092e979c658Sreinoud KASSERT(new_size <= max_l_ad); 2093e979c658Sreinoud inflen -= size_diff; 2094e979c658Sreinoud objsize -= size_diff; 2095e979c658Sreinoud l_ad -= size_diff; 2096e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 2097e979c658Sreinoud if (fe) { 2098e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2099e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 2100e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 2101e979c658Sreinoud } else { 2102e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2103e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2104e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 2105e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 2106e979c658Sreinoud } 2107e979c658Sreinoud error = 0; 2108e979c658Sreinoud /* TODO zero appened space in buffer! */ 2109e979c658Sreinoud /* using uvm_vnp_zerorange(vp, old_size, old_size - new_size); ? */ 2110e979c658Sreinoud 2111e979c658Sreinoud /* set new size for uvm */ 2112e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 2113e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2114e979c658Sreinoud 2115e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 2116e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 2117e979c658Sreinoud KASSERT(new_lbrec == orig_lbrec); 2118e979c658Sreinoud KASSERT(new_lbrec == 0); 2119e979c658Sreinoud 2120e979c658Sreinoud return 0; 2121e979c658Sreinoud } 2122e979c658Sreinoud 2123e979c658Sreinoud /* setup node cleanup extents copy space */ 2124e979c658Sreinoud node_ad_cpy = malloc(lb_size * UDF_MAX_ALLOC_EXTENTS, 2125e979c658Sreinoud M_UDFMNT, M_WAITOK); 2126e979c658Sreinoud memset(node_ad_cpy, 0, lb_size * UDF_MAX_ALLOC_EXTENTS); 2127e979c658Sreinoud 2128e979c658Sreinoud /* 2129e979c658Sreinoud * Shrink the node by releasing the allocations and truncate the last 2130e979c658Sreinoud * allocation to the new size. If the new size fits into the 2131e979c658Sreinoud * allocation descriptor itself, transform it into an 2132e979c658Sreinoud * UDF_ICB_INTERN_ALLOC. 2133e979c658Sreinoud */ 2134e979c658Sreinoud slot = 0; 2135e979c658Sreinoud cpy_slot = 0; 2136e979c658Sreinoud foffset = 0; 2137e979c658Sreinoud 2138e979c658Sreinoud /* 1) copy till first overlap piece to the rewrite buffer */ 2139e979c658Sreinoud for (;;) { 2140e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2141e979c658Sreinoud if (eof) { 2142e979c658Sreinoud DPRINTF(WRITE, 2143e979c658Sreinoud ("Shrink node failed: " 2144e979c658Sreinoud "encountered EOF\n")); 2145e979c658Sreinoud error = EINVAL; 2146e979c658Sreinoud goto errorout; /* panic? */ 2147e979c658Sreinoud } 2148e979c658Sreinoud len = udf_rw32(s_ad.len); 2149e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2150e979c658Sreinoud len = UDF_EXT_LEN(len); 2151e979c658Sreinoud 2152e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 2153e979c658Sreinoud slot++; 2154e979c658Sreinoud continue; 2155e979c658Sreinoud } 2156e979c658Sreinoud 2157e979c658Sreinoud end_foffset = foffset + len; 2158e979c658Sreinoud if (end_foffset > new_size) 2159e979c658Sreinoud break; /* found */ 2160e979c658Sreinoud 2161e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2162e979c658Sreinoud 2163e979c658Sreinoud DPRINTF(ALLOC, ("\t1: vp %d, lb %d, len %d, flags %d " 2164e979c658Sreinoud "-> stack\n", 2165e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2166e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2167e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2168e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2169e979c658Sreinoud 2170e979c658Sreinoud foffset = end_foffset; 2171e979c658Sreinoud slot++; 2172e979c658Sreinoud } 2173e979c658Sreinoud slot_offset = new_size - foffset; 2174e979c658Sreinoud 2175e979c658Sreinoud /* 2) trunc overlapping slot at overlap and copy it */ 2176e979c658Sreinoud if (slot_offset > 0) { 2177e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 2178e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 2179e979c658Sreinoud 2180e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 2181e979c658Sreinoud lb_num += (slot_offset + lb_size -1) / lb_size; 2182e979c658Sreinoud num_lb = (len - slot_offset + lb_size - 1) / lb_size; 2183e979c658Sreinoud 2184e979c658Sreinoud udf_free_allocated_space(ump, lb_num, vpart_num, num_lb); 2185e979c658Sreinoud } 2186e979c658Sreinoud 2187e979c658Sreinoud s_ad.len = udf_rw32(slot_offset | flags); 2188e979c658Sreinoud node_ad_cpy[cpy_slot++] = s_ad; 2189e979c658Sreinoud slot++; 2190e979c658Sreinoud 2191e979c658Sreinoud DPRINTF(ALLOC, ("\t2: vp %d, lb %d, len %d, flags %d " 2192e979c658Sreinoud "-> stack\n", 2193e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2194e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2195e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2196e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2197e979c658Sreinoud } 2198e979c658Sreinoud 2199e979c658Sreinoud /* 3) delete remainder */ 2200e979c658Sreinoud for (;;) { 2201e979c658Sreinoud udf_get_adslot(udf_node, slot, &s_ad, &eof); 2202e979c658Sreinoud if (eof) 2203e979c658Sreinoud break; 2204e979c658Sreinoud 2205e979c658Sreinoud len = udf_rw32(s_ad.len); 2206e979c658Sreinoud flags = UDF_EXT_FLAGS(len); 2207e979c658Sreinoud len = UDF_EXT_LEN(len); 2208e979c658Sreinoud 2209e979c658Sreinoud if (flags == UDF_EXT_REDIRECT) { 2210e979c658Sreinoud slot++; 2211e979c658Sreinoud continue; 2212e979c658Sreinoud } 2213e979c658Sreinoud 2214e979c658Sreinoud DPRINTF(ALLOC, ("\t3: delete remainder " 2215e979c658Sreinoud "vp %d lb %d, len %d, flags %d\n", 2216e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2217e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2218e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2219e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2220e979c658Sreinoud 2221e979c658Sreinoud if (flags == UDF_EXT_ALLOCATED) { 2222e979c658Sreinoud lb_num = udf_rw32(s_ad.loc.lb_num); 2223e979c658Sreinoud vpart_num = udf_rw16(s_ad.loc.part_num); 2224e979c658Sreinoud num_lb = (len + lb_size - 1) / lb_size; 2225e979c658Sreinoud 2226e979c658Sreinoud udf_free_allocated_space(ump, lb_num, vpart_num, 2227e979c658Sreinoud num_lb); 2228e979c658Sreinoud } 2229e979c658Sreinoud 2230e979c658Sreinoud slot++; 2231e979c658Sreinoud } 2232e979c658Sreinoud 2233e979c658Sreinoud /* 4) if it will fit into the descriptor then convert */ 2234e979c658Sreinoud if (new_size < max_l_ad) { 2235e979c658Sreinoud /* 2236e979c658Sreinoud * resque/evacuate old piece by reading it in, and convert it 2237e979c658Sreinoud * to internal alloc. 2238e979c658Sreinoud */ 2239e979c658Sreinoud if (new_size == 0) { 2240e979c658Sreinoud /* XXX/TODO only for zero sizing now */ 2241e979c658Sreinoud udf_wipe_adslots(udf_node); 2242e979c658Sreinoud 2243e979c658Sreinoud icbflags &= ~UDF_ICB_TAG_FLAGS_ALLOC_MASK; 2244e979c658Sreinoud icbflags |= UDF_ICB_INTERN_ALLOC; 2245e979c658Sreinoud icbtag->flags = udf_rw16(icbflags); 2246e979c658Sreinoud 2247e979c658Sreinoud inflen -= size_diff; KASSERT(inflen == 0); 2248e979c658Sreinoud objsize -= size_diff; 2249e979c658Sreinoud l_ad = new_size; 2250e979c658Sreinoud crclen = dscr_size - UDF_DESC_TAG_LENGTH + l_ea + l_ad; 2251e979c658Sreinoud if (fe) { 2252e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2253e979c658Sreinoud fe->l_ad = udf_rw32(l_ad); 2254e979c658Sreinoud fe->tag.desc_crc_len = udf_rw32(crclen); 2255e979c658Sreinoud } else { 2256e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2257e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2258e979c658Sreinoud efe->l_ad = udf_rw32(l_ad); 2259e979c658Sreinoud efe->tag.desc_crc_len = udf_rw32(crclen); 2260e979c658Sreinoud } 2261e979c658Sreinoud /* eventually copy in evacuated piece */ 2262e979c658Sreinoud /* set new size for uvm */ 2263e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 2264e979c658Sreinoud 2265e979c658Sreinoud free(node_ad_cpy, M_UDFMNT); 2266e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2267e979c658Sreinoud 2268e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 2269e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 2270e979c658Sreinoud KASSERT(new_inflen == 0); 2271e979c658Sreinoud KASSERT(new_lbrec == 0); 2272e979c658Sreinoud 2273e979c658Sreinoud return 0; 2274e979c658Sreinoud } 2275e979c658Sreinoud 2276e979c658Sreinoud printf("UDF_SHRINK_NODE: could convert to internal alloc!\n"); 2277e979c658Sreinoud } 2278e979c658Sreinoud 2279e979c658Sreinoud /* 5) reset node descriptors */ 2280e979c658Sreinoud udf_wipe_adslots(udf_node); 2281e979c658Sreinoud 2282e979c658Sreinoud /* 6) copy back extents; merge when possible. Recounting on the fly */ 2283e979c658Sreinoud cpy_slots = cpy_slot; 2284e979c658Sreinoud 2285e979c658Sreinoud c_ad = node_ad_cpy[0]; 2286e979c658Sreinoud slot = 0; 2287e979c658Sreinoud for (cpy_slot = 1; cpy_slot < cpy_slots; cpy_slot++) { 2288e979c658Sreinoud s_ad = node_ad_cpy[cpy_slot]; 2289e979c658Sreinoud 2290e979c658Sreinoud DPRINTF(ALLOC, ("\t6: stack -> got mapping vp %d " 2291e979c658Sreinoud "lb %d, len %d, flags %d\n", 2292e979c658Sreinoud udf_rw16(s_ad.loc.part_num), 2293e979c658Sreinoud udf_rw32(s_ad.loc.lb_num), 2294e979c658Sreinoud UDF_EXT_LEN(udf_rw32(s_ad.len)), 2295e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(s_ad.len)) >> 30)); 2296e979c658Sreinoud 2297e979c658Sreinoud /* see if we can merge */ 2298e979c658Sreinoud if (udf_ads_merge(lb_size, &c_ad, &s_ad)) { 2299e979c658Sreinoud /* not mergable (anymore) */ 2300e979c658Sreinoud DPRINTF(ALLOC, ("\t6: appending vp %d lb %d, " 2301e979c658Sreinoud "len %d, flags %d\n", 2302e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2303e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2304e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2305e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2306e979c658Sreinoud 2307e979c658Sreinoud error = udf_append_adslot(udf_node, slot, &c_ad); 2308e979c658Sreinoud if (error) 2309e979c658Sreinoud goto errorout; /* panic? */ 2310e979c658Sreinoud c_ad = s_ad; 2311e979c658Sreinoud slot++; 2312e979c658Sreinoud } 2313e979c658Sreinoud } 2314e979c658Sreinoud 2315e979c658Sreinoud /* 7) push rest slot (if any) */ 2316e979c658Sreinoud if (UDF_EXT_LEN(c_ad.len) > 0) { 2317e979c658Sreinoud DPRINTF(ALLOC, ("\t7: last append vp %d lb %d, " 2318e979c658Sreinoud "len %d, flags %d\n", 2319e979c658Sreinoud udf_rw16(c_ad.loc.part_num), 2320e979c658Sreinoud udf_rw32(c_ad.loc.lb_num), 2321e979c658Sreinoud UDF_EXT_LEN(udf_rw32(c_ad.len)), 2322e979c658Sreinoud UDF_EXT_FLAGS(udf_rw32(c_ad.len)) >> 30)); 2323e979c658Sreinoud 2324e979c658Sreinoud error = udf_append_adslot(udf_node, slot, &c_ad); 2325e979c658Sreinoud if (error) 2326e979c658Sreinoud goto errorout; /* panic? */ 2327e979c658Sreinoud ; 2328e979c658Sreinoud } 2329e979c658Sreinoud 2330e979c658Sreinoud inflen -= size_diff; 2331e979c658Sreinoud objsize -= size_diff; 2332e979c658Sreinoud if (fe) { 2333e979c658Sreinoud fe->inf_len = udf_rw64(inflen); 2334e979c658Sreinoud } else { 2335e979c658Sreinoud efe->inf_len = udf_rw64(inflen); 2336e979c658Sreinoud efe->obj_size = udf_rw64(objsize); 2337e979c658Sreinoud } 2338e979c658Sreinoud error = 0; 2339e979c658Sreinoud 2340e979c658Sreinoud /* set new size for uvm */ 2341e979c658Sreinoud uvm_vnp_setsize(vp, new_size); 2342e979c658Sreinoud 2343e979c658Sreinoud errorout: 2344e979c658Sreinoud free(node_ad_cpy, M_UDFMNT); 2345e979c658Sreinoud UDF_UNLOCK_NODE(udf_node, 0); 2346e979c658Sreinoud 2347e979c658Sreinoud udf_node_sanity_check(udf_node, &new_inflen, &new_lbrec); 2348e979c658Sreinoud KASSERT(new_inflen == orig_inflen - size_diff); 2349e979c658Sreinoud 2350e979c658Sreinoud return error; 2351e979c658Sreinoud } 2352e979c658Sreinoud 2353