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, &sectornr, &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);
}
Exemple #3
0
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);
}
Exemple #4
0
/* 
 * 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);
}