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