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