static int udf_write_logvol_dscr_seq(struct udf_strat_args *args) { union dscrptr *dscr = args->dscr; struct udf_mount *ump = args->ump; struct udf_node *udf_node = args->udf_node; struct long_ad *icb = args->icb; int waitfor = args->waitfor; uint32_t logsectornr, sectornr, dummy; int error, vpart; /* * we have to decide if we write it out sequential or at its fixed * position by examining the partition its (to be) written on. */ vpart = udf_rw16(udf_node->loc.loc.part_num); logsectornr = udf_rw32(icb->loc.lb_num); sectornr = 0; if (ump->vtop_tp[vpart] != UDF_VTOP_TYPE_VIRT) { error = udf_translate_vtop(ump, icb, §ornr, &dummy); if (error) goto out; } /* add reference to the vnode to prevent recycling */ vhold(udf_node->vnode); if (waitfor) { DPRINTF(WRITE, ("udf_write_logvol_dscr: sync write\n")); error = udf_write_phys_dscr_sync(ump, udf_node, UDF_C_NODE, dscr, sectornr, logsectornr); } else { DPRINTF(WRITE, ("udf_write_logvol_dscr: no wait, async write\n")); error = udf_write_phys_dscr_async(ump, udf_node, UDF_C_NODE, dscr, sectornr, logsectornr, udf_wr_nodedscr_callback); /* will be UNLOCKED in call back */ return error; } holdrele(udf_node->vnode); out: udf_node->outstanding_nodedscr--; if (udf_node->outstanding_nodedscr == 0) { UDF_UNLOCK_NODE(udf_node, 0); wakeup(&udf_node->outstanding_nodedscr); } return error; }
static void udf_wr_nodedscr_callback(struct buf *buf) { struct udf_node *udf_node; KASSERT(buf); KASSERT(buf->b_data); /* called when write action is done */ DPRINTF(WRITE, ("udf_wr_nodedscr_callback(): node written out\n")); udf_node = VTOI(buf->b_vp); if (udf_node == NULL) { putiobuf(buf); printf("udf_wr_node_callback: NULL node?\n"); return; } /* XXX right flags to mark dirty again on error? */ if (buf->b_error) { udf_node->i_flags |= IN_MODIFIED | IN_ACCESSED; /* XXX TODO reshedule on error */ } /* decrement outstanding_nodedscr */ KASSERT(udf_node->outstanding_nodedscr >= 1); udf_node->outstanding_nodedscr--; if (udf_node->outstanding_nodedscr == 0) { /* first unlock the node */ UDF_UNLOCK_NODE(udf_node, 0); wakeup(&udf_node->outstanding_nodedscr); } /* unreference the vnode so it can be recycled */ holdrele(udf_node->vnode); putiobuf(buf); }
int udf_translate_vtop(struct udf_mount *ump, struct long_ad *icb_loc, uint32_t *lb_numres, uint32_t *extres) { struct part_desc *pdesc; struct spare_map_entry *sme; struct long_ad s_icb_loc; uint64_t end_foffset, foffset; int eof, error, flags, part, rel, slot; uint32_t lb_num, lb_packet, lb_rel, lb_size, len; uint32_t ext_offset, udf_rw32_lbmap; uint16_t vpart; KASSERT(ump && icb_loc && lb_numres,("ump && icb_loc && lb_numres")); vpart = le16toh(icb_loc->loc.part_num); lb_num = le32toh(icb_loc->loc.lb_num); if (vpart > UDF_VTOP_RAWPART) return (EINVAL); translate_again: part = ump->vtop[vpart]; pdesc = ump->partitions[part]; switch (ump->vtop_tp[vpart]) { case UDF_VTOP_TYPE_RAW: /* 1:1 to the end of the device */ *lb_numres = lb_num; *extres = INT_MAX; return (0); case UDF_VTOP_TYPE_PHYS: /* transform into its disc logical block */ if (lb_num > le32toh(pdesc->part_len)) return (EINVAL); *lb_numres = lb_num + le32toh(pdesc->start_loc); /* extent from here to the end of the partition */ *extres = le32toh(pdesc->part_len) - lb_num; return (0); case UDF_VTOP_TYPE_VIRT: /* only maps one logical block, lookup in VAT */ if (lb_num >= ump->vat_entries) /* XXX > or >= ? */ return (EINVAL); /* lookup in virtual allocation table file */ error = udf_vat_read(ump, (uint8_t *)&udf_rw32_lbmap, 4, ump->vat_offset + lb_num * 4); if (error != 0) return (error); lb_num = le32toh(udf_rw32_lbmap); /* transform into its disc logical block */ if (lb_num > le32toh(pdesc->part_len)) return (EINVAL); *lb_numres = lb_num + le32toh(pdesc->start_loc); /* just one logical block */ *extres = 1; return (0); case UDF_VTOP_TYPE_SPARABLE: /* check if the packet containing the lb_num is remapped */ lb_packet = lb_num / ump->sparable_packet_size; lb_rel = lb_num % ump->sparable_packet_size; for (rel = 0; rel < le16toh(ump->sparing_table->rt_l); rel++) { sme = &ump->sparing_table->entries[rel]; if (lb_packet == le32toh(sme->org)) { /* NOTE maps to absolute disc logical block! */ *lb_numres = le32toh(sme->map) + lb_rel; *extres = ump->sparable_packet_size - lb_rel; return (0); } } /* transform into its disc logical block */ if (lb_num > le32toh(pdesc->part_len)) return (EINVAL); *lb_numres = lb_num + le32toh(pdesc->start_loc); /* rest of block */ *extres = ump->sparable_packet_size - lb_rel; return (0); case UDF_VTOP_TYPE_META: /* we have to look into the file's allocation descriptors */ /* use metadatafile allocation mutex */ lb_size = le32toh(ump->logical_vol->lb_size); UDF_LOCK_NODE(ump->metadata_node, 0); /* get first overlapping extent */ foffset = 0; slot = 0; for (;;) { udf_get_adslot(ump->metadata_node, slot, &s_icb_loc, &eof); if (eof) { UDF_UNLOCK_NODE(ump->metadata_node, 0); return (EINVAL); } len = le32toh(s_icb_loc.len); flags = UDF_EXT_FLAGS(len); len = UDF_EXT_LEN(len); if (flags == UDF_EXT_REDIRECT) { slot++; continue; } end_foffset = foffset + len; if (end_foffset > lb_num * lb_size) break; /* found */ foffset = end_foffset; slot++; } /* found overlapping slot */ ext_offset = lb_num * lb_size - foffset; /* process extent offset */ lb_num = le32toh(s_icb_loc.loc.lb_num); vpart = le16toh(s_icb_loc.loc.part_num); lb_num += (ext_offset + lb_size -1) / lb_size; ext_offset = 0; UDF_UNLOCK_NODE(ump->metadata_node, 0); if (flags != UDF_EXT_ALLOCATED) return (EINVAL); /* * vpart and lb_num are updated, translate again since we * might be mapped on sparable media */ goto translate_again; default: printf("UDF vtop translation scheme %d unimplemented yet\n", ump->vtop_tp[vpart]); } return (EINVAL); }
/* * This is a simplified version of the udf_translate_file_extent function. */ int udf_bmap_translate(struct udf_node *udf_node, uint32_t block, int *exttype, uint64_t *lsector, uint32_t *maxblks) { struct udf_mount *ump; struct icb_tag *icbtag; struct long_ad s_ad, t_ad; uint64_t foffset, new_foffset; int addr_type, eof, error, flags, icbflags, slot; uint32_t ext_offset, ext_remain, lb_num, lb_size, len, transsec32; uint32_t translen; uint16_t vpart_num; if (udf_node == NULL) return (ENOENT); KASSERT(num_lb > 0,("num_lb > 0")); UDF_LOCK_NODE(udf_node, 0); /* initialise derivative vars */ ump = udf_node->ump; lb_size = le32toh(ump->logical_vol->lb_size); if (udf_node->fe != NULL) icbtag = &udf_node->fe->icbtag; else icbtag = &udf_node->efe->icbtag; icbflags = le16toh(icbtag->flags); addr_type = icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK; /* do the work */ if (addr_type == UDF_ICB_INTERN_ALLOC) { *exttype = UDF_TRAN_INTERN; *maxblks = 1; UDF_UNLOCK_NODE(udf_node, 0); return (0); } /* find first overlapping extent */ foffset = 0; slot = 0; for (;;) { udf_get_adslot(udf_node, slot, &s_ad, &eof); if (eof) { UDF_UNLOCK_NODE(udf_node, 0); return (EINVAL); } len = le32toh(s_ad.len); flags = UDF_EXT_FLAGS(len); len = UDF_EXT_LEN(len); if (flags == UDF_EXT_REDIRECT) { slot++; continue; } new_foffset = foffset + len; if (new_foffset > block * lb_size) break; /* found */ foffset = new_foffset; slot++; } /* found overlapping slot */ lb_num = le32toh(s_ad.loc.lb_num); vpart_num = le16toh(s_ad.loc.part_num); ext_offset = block * lb_size - foffset; lb_num += (ext_offset + lb_size - 1) / lb_size; ext_remain = (len - ext_offset + lb_size - 1) / lb_size; /* * note that the while(){} is nessisary for the extent that * the udf_translate_vtop() returns doens't have to span the * whole extent. */ switch (flags) { case UDF_EXT_FREE: case UDF_EXT_ALLOCATED_BUT_NOT_USED: *exttype = UDF_TRAN_ZERO; *maxblks = ext_remain; break; case UDF_EXT_ALLOCATED: *exttype = UDF_TRAN_EXTERNAL; t_ad.loc.lb_num = htole32(lb_num); t_ad.loc.part_num = htole16(vpart_num); error = udf_translate_vtop(ump, &t_ad, &transsec32, &translen); if (error != 0) { UDF_UNLOCK_NODE(udf_node, 0); return (error); } *lsector = transsec32; *maxblks = MIN(ext_remain, translen); break; default: UDF_UNLOCK_NODE(udf_node, 0); return (EINVAL); } UDF_UNLOCK_NODE(udf_node, 0); return (0); }