xref: /netbsd-src/sys/fs/udf/udf_readwrite.c (revision a10c2cec390bbc4a870ed981c04dc105e6820ccf)
1*a10c2cecSandvar /* $NetBSD: udf_readwrite.c,v 1.14 2024/02/10 09:21:53 andvar Exp $ */
2e979c658Sreinoud 
3e979c658Sreinoud /*
4e979c658Sreinoud  * Copyright (c) 2007, 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*a10c2cecSandvar __KERNEL_RCSID(0, "$NetBSD: udf_readwrite.c,v 1.14 2024/02/10 09:21:53 andvar Exp $");
32e979c658Sreinoud #endif /* not lint */
33e979c658Sreinoud 
34e979c658Sreinoud 
35e979c658Sreinoud #if defined(_KERNEL_OPT)
36e979c658Sreinoud #include "opt_compat_netbsd.h"
37e979c658Sreinoud #endif
38e979c658Sreinoud 
39e979c658Sreinoud #include <sys/param.h>
40e979c658Sreinoud #include <sys/systm.h>
41e979c658Sreinoud #include <sys/sysctl.h>
42e979c658Sreinoud #include <sys/namei.h>
43e979c658Sreinoud #include <sys/proc.h>
44e979c658Sreinoud #include <sys/kernel.h>
45e979c658Sreinoud #include <sys/vnode.h>
46e979c658Sreinoud #include <miscfs/genfs/genfs_node.h>
47e979c658Sreinoud #include <sys/mount.h>
48e979c658Sreinoud #include <sys/buf.h>
49e979c658Sreinoud #include <sys/file.h>
50e979c658Sreinoud #include <sys/device.h>
51e979c658Sreinoud #include <sys/disklabel.h>
52e979c658Sreinoud #include <sys/ioctl.h>
53e979c658Sreinoud #include <sys/malloc.h>
54e979c658Sreinoud #include <sys/dirent.h>
55e979c658Sreinoud #include <sys/stat.h>
56e979c658Sreinoud #include <sys/conf.h>
57e979c658Sreinoud #include <sys/kauth.h>
58e979c658Sreinoud #include <sys/kthread.h>
59e979c658Sreinoud #include <dev/clock_subr.h>
60e979c658Sreinoud 
61e979c658Sreinoud #include <fs/udf/ecma167-udf.h>
62e979c658Sreinoud #include <fs/udf/udf_mount.h>
63e979c658Sreinoud 
64e979c658Sreinoud #include "udf.h"
65e979c658Sreinoud #include "udf_subr.h"
66e979c658Sreinoud #include "udf_bswap.h"
67e979c658Sreinoud 
68e979c658Sreinoud 
69e979c658Sreinoud #define VTOI(vnode) ((struct udf_node *) vnode->v_data)
70e979c658Sreinoud 
71e979c658Sreinoud /* --------------------------------------------------------------------- */
72e979c658Sreinoud 
73e979c658Sreinoud void
udf_fixup_fid_block(uint8_t * blob,int lb_size,int rfix_pos,int max_rfix_pos,uint32_t lb_num)74e979c658Sreinoud udf_fixup_fid_block(uint8_t *blob, int lb_size,
75e979c658Sreinoud 	int rfix_pos, int max_rfix_pos, uint32_t lb_num)
76e979c658Sreinoud {
77e979c658Sreinoud 	struct fileid_desc *fid;
78e979c658Sreinoud 	uint8_t *fid_pos;
79e979c658Sreinoud 	int fid_len, found;
80e979c658Sreinoud 
81e979c658Sreinoud 	/* needs to be word aligned */
82e979c658Sreinoud 	KASSERT(rfix_pos % 4 == 0);
83e979c658Sreinoud 
84e979c658Sreinoud 	/* first resync with the FID stream !!! */
85e979c658Sreinoud 	found = 0;
86e979c658Sreinoud 	while (rfix_pos + sizeof(struct desc_tag) <= max_rfix_pos) {
87e979c658Sreinoud 		fid_pos = blob + rfix_pos;
88e979c658Sreinoud 		fid = (struct fileid_desc *) fid_pos;
89e979c658Sreinoud 		if (udf_rw16(fid->tag.id) == TAGID_FID) {
90e979c658Sreinoud 			if (udf_check_tag((union dscrptr *) fid) == 0)
91e979c658Sreinoud 				found = 1;
92e979c658Sreinoud 		}
93e979c658Sreinoud 		if (found)
94e979c658Sreinoud 			break;
95e979c658Sreinoud 		/* try next location; can only be 4 bytes aligned */
96e979c658Sreinoud 		rfix_pos += 4;
97e979c658Sreinoud 	}
98e979c658Sreinoud 
99e979c658Sreinoud 	/* walk over the fids */
100e979c658Sreinoud 	fid_pos = blob + rfix_pos;
101e979c658Sreinoud 	while (rfix_pos + sizeof(struct desc_tag) <= max_rfix_pos) {
102e979c658Sreinoud 		fid = (struct fileid_desc *) fid_pos;
103e979c658Sreinoud 		if (udf_rw16(fid->tag.id) != TAGID_FID) {
104e979c658Sreinoud 			/* end of FID stream; end of directory or currupted */
105e979c658Sreinoud 			break;
106e979c658Sreinoud 		}
107e979c658Sreinoud 
108b707f360Smsaitoh 		/* update sector number and recalculate checksum */
109e979c658Sreinoud 		fid->tag.tag_loc = udf_rw32(lb_num);
110e979c658Sreinoud 		udf_validate_tag_sum((union dscrptr *) fid);
111e979c658Sreinoud 
112e979c658Sreinoud 		/* if the FID crosses the memory, we're done! */
113e979c658Sreinoud 		if (rfix_pos + UDF_FID_SIZE >= max_rfix_pos)
114e979c658Sreinoud 			break;
115e979c658Sreinoud 
116e979c658Sreinoud 		fid_len = udf_fidsize(fid);
117e979c658Sreinoud 		fid_pos  += fid_len;
118e979c658Sreinoud 		rfix_pos += fid_len;
119e979c658Sreinoud 	}
120e979c658Sreinoud }
121e979c658Sreinoud 
122e979c658Sreinoud 
123e979c658Sreinoud void
udf_fixup_internal_extattr(uint8_t * blob,uint32_t lb_num)124e979c658Sreinoud udf_fixup_internal_extattr(uint8_t *blob, uint32_t lb_num)
125e979c658Sreinoud {
126e979c658Sreinoud 	struct desc_tag        *tag;
127e979c658Sreinoud 	struct file_entry      *fe;
128e979c658Sreinoud 	struct extfile_entry   *efe;
129e979c658Sreinoud 	struct extattrhdr_desc *eahdr;
13031c0e74bSreinoud 	int l_ea;
131e979c658Sreinoud 
132e979c658Sreinoud 	/* get information from fe/efe */
133e979c658Sreinoud 	tag = (struct desc_tag *) blob;
134e979c658Sreinoud 	switch (udf_rw16(tag->id)) {
135e979c658Sreinoud 	case TAGID_FENTRY :
136e979c658Sreinoud 		fe = (struct file_entry *) blob;
137e979c658Sreinoud 		l_ea  = udf_rw32(fe->l_ea);
138e979c658Sreinoud 		eahdr = (struct extattrhdr_desc *) fe->data;
139e979c658Sreinoud 		break;
140e979c658Sreinoud 	case TAGID_EXTFENTRY :
141e979c658Sreinoud 		efe = (struct extfile_entry *) blob;
142e979c658Sreinoud 		l_ea  = udf_rw32(efe->l_ea);
143e979c658Sreinoud 		eahdr = (struct extattrhdr_desc *) efe->data;
144e979c658Sreinoud 		break;
145e979c658Sreinoud 	case TAGID_INDIRECTENTRY :
146e979c658Sreinoud 	case TAGID_ALLOCEXTENT :
147e979c658Sreinoud 	case TAGID_EXTATTR_HDR :
148e979c658Sreinoud 		return;
149e979c658Sreinoud 	default:
15010cfc49bSperry 		panic("%s: passed bad tag\n", __func__);
151e979c658Sreinoud 	}
152e979c658Sreinoud 
153e979c658Sreinoud 	/* something recorded here? (why am i called?) */
154e979c658Sreinoud 	if (l_ea == 0)
155e979c658Sreinoud 		return;
156e979c658Sreinoud 
15731c0e74bSreinoud #if 0
158e979c658Sreinoud 	/* check extended attribute tag */
159e979c658Sreinoud 	/* TODO XXX what to do when we encounter an error here? */
160e979c658Sreinoud 	error = udf_check_tag(eahdr);
161e979c658Sreinoud 	if (error)
162e979c658Sreinoud 		return;	/* for now */
163e979c658Sreinoud 	if (udf_rw16(eahdr->tag.id) != TAGID_EXTATTR_HDR)
164e979c658Sreinoud 		return;	/* for now */
165e979c658Sreinoud 	error = udf_check_tag_payload(eahdr, sizeof(struct extattrhdr_desc));
166e979c658Sreinoud 	if (error)
167e979c658Sreinoud 		return; /* for now */
16831c0e74bSreinoud #endif
169e979c658Sreinoud 
170e979c658Sreinoud 	DPRINTF(EXTATTR, ("node fixup: found %d bytes of extended attributes\n",
171e979c658Sreinoud 		l_ea));
172e979c658Sreinoud 
173e979c658Sreinoud 	/* fixup eahdr tag */
174e979c658Sreinoud 	eahdr->tag.tag_loc = udf_rw32(lb_num);
17531c0e74bSreinoud 	udf_validate_tag_and_crc_sums((union dscrptr *) eahdr);
176e979c658Sreinoud }
177e979c658Sreinoud 
178e979c658Sreinoud 
179e979c658Sreinoud void
udf_fixup_node_internals(struct udf_mount * ump,uint8_t * blob,int udf_c_type)180e979c658Sreinoud udf_fixup_node_internals(struct udf_mount *ump, uint8_t *blob, int udf_c_type)
181e979c658Sreinoud {
18271c9aa33Sreinoud 	struct desc_tag *tag, *sbm_tag;
183e979c658Sreinoud 	struct file_entry *fe;
184e979c658Sreinoud 	struct extfile_entry *efe;
185e367a2e8Sreinoud 	struct alloc_ext_entry *ext;
186e979c658Sreinoud 	uint32_t lb_size, lb_num;
1875e89a5a8Sreinoud 	uint32_t intern_pos, max_intern_pos;
1885e89a5a8Sreinoud 	int icbflags, addr_type, file_type, intern, has_fids, has_sbm, l_ea;
189e979c658Sreinoud 
190e979c658Sreinoud 	lb_size = udf_rw32(ump->logical_vol->lb_size);
191e979c658Sreinoud 	/* if its not a node we're done */
192e979c658Sreinoud 	if (udf_c_type != UDF_C_NODE)
193e979c658Sreinoud 		return;
194e979c658Sreinoud 
195e979c658Sreinoud 	/* NOTE this could also be done in write_internal */
196e979c658Sreinoud 	/* start of a descriptor */
197e367a2e8Sreinoud 	l_ea      = 0;
198e979c658Sreinoud 	has_fids  = 0;
19971c9aa33Sreinoud 	has_sbm   = 0;
2005e89a5a8Sreinoud 	intern    = 0;
2015e89a5a8Sreinoud 	file_type = 0;
2025e89a5a8Sreinoud 	max_intern_pos = intern_pos = lb_num = 0;	/* shut up gcc! */
203e979c658Sreinoud 
204e979c658Sreinoud 	tag = (struct desc_tag *) blob;
205e979c658Sreinoud 	switch (udf_rw16(tag->id)) {
206e979c658Sreinoud 	case TAGID_FENTRY :
207e979c658Sreinoud 		fe = (struct file_entry *) tag;
208e979c658Sreinoud 		l_ea = udf_rw32(fe->l_ea);
209e979c658Sreinoud 		icbflags  = udf_rw16(fe->icbtag.flags);
210e979c658Sreinoud 		addr_type = (icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK);
21171c9aa33Sreinoud 		file_type = fe->icbtag.file_type;
2125e89a5a8Sreinoud 		intern = (addr_type == UDF_ICB_INTERN_ALLOC);
2135e89a5a8Sreinoud 		intern_pos  = UDF_FENTRY_SIZE + l_ea;
2145e89a5a8Sreinoud 		max_intern_pos = intern_pos + udf_rw64(fe->inf_len);
215e979c658Sreinoud 		lb_num = udf_rw32(fe->tag.tag_loc);
216e979c658Sreinoud 		break;
217e979c658Sreinoud 	case TAGID_EXTFENTRY :
218e979c658Sreinoud 		efe = (struct extfile_entry *) tag;
219e979c658Sreinoud 		l_ea = udf_rw32(efe->l_ea);
220e979c658Sreinoud 		icbflags  = udf_rw16(efe->icbtag.flags);
221e979c658Sreinoud 		addr_type = (icbflags & UDF_ICB_TAG_FLAGS_ALLOC_MASK);
22271c9aa33Sreinoud 		file_type = efe->icbtag.file_type;
2235e89a5a8Sreinoud 		intern = (addr_type == UDF_ICB_INTERN_ALLOC);
2245e89a5a8Sreinoud 		intern_pos  = UDF_EXTFENTRY_SIZE + l_ea;
2255e89a5a8Sreinoud 		max_intern_pos = intern_pos + udf_rw64(efe->inf_len);
226e979c658Sreinoud 		lb_num = udf_rw32(efe->tag.tag_loc);
227e979c658Sreinoud 		break;
228e979c658Sreinoud 	case TAGID_INDIRECTENTRY :
229e979c658Sreinoud 	case TAGID_EXTATTR_HDR :
230e367a2e8Sreinoud 		break;
231e367a2e8Sreinoud 	case TAGID_ALLOCEXTENT :
232e367a2e8Sreinoud 		/* force crclen to 8 for UDF version < 2.01 */
233e367a2e8Sreinoud 		ext = (struct alloc_ext_entry *) tag;
234e367a2e8Sreinoud 		if (udf_rw16(ump->logvol_info->min_udf_readver) <= 0x200)
235e367a2e8Sreinoud 			ext->tag.desc_crc_len = udf_rw16(8);
236e979c658Sreinoud 		break;
237e979c658Sreinoud 	default:
23810cfc49bSperry 		panic("%s: passed bad tag\n", __func__);
239e979c658Sreinoud 		break;
240e979c658Sreinoud 	}
241e979c658Sreinoud 
2425e89a5a8Sreinoud 	/* determine what to fix if its internally recorded */
2435e89a5a8Sreinoud 	if (intern) {
2445e89a5a8Sreinoud 		has_fids = (file_type == UDF_ICB_FILETYPE_DIRECTORY) ||
2455e89a5a8Sreinoud 			   (file_type == UDF_ICB_FILETYPE_STREAMDIR);
2465e89a5a8Sreinoud 		has_sbm  = (file_type == UDF_ICB_FILETYPE_META_BITMAP);
2475e89a5a8Sreinoud 	}
2485e89a5a8Sreinoud 
249e979c658Sreinoud 	/* fixup internal extended attributes if present */
250e979c658Sreinoud 	if (l_ea)
251e979c658Sreinoud 		udf_fixup_internal_extattr(blob, lb_num);
252e979c658Sreinoud 
2535e89a5a8Sreinoud 	/* fixup fids lb numbers */
25471c9aa33Sreinoud 	if (has_fids)
2555e89a5a8Sreinoud 		udf_fixup_fid_block(blob, lb_size, intern_pos,
2565e89a5a8Sreinoud 			max_intern_pos, lb_num);
25771c9aa33Sreinoud 
2585e89a5a8Sreinoud 	/* fixup space bitmap descriptor */
25971c9aa33Sreinoud 	if (has_sbm) {
2605e89a5a8Sreinoud 		sbm_tag = (struct desc_tag *) (blob + intern_pos);
26171c9aa33Sreinoud 		sbm_tag->tag_loc = tag->tag_loc;
26271c9aa33Sreinoud 		udf_validate_tag_and_crc_sums((uint8_t *) sbm_tag);
263e979c658Sreinoud 	}
26471c9aa33Sreinoud 
265e979c658Sreinoud 	udf_validate_tag_and_crc_sums(blob);
266e979c658Sreinoud }
267e979c658Sreinoud 
268e979c658Sreinoud /* --------------------------------------------------------------------- */
269e979c658Sreinoud 
270e979c658Sreinoud /*
271e979c658Sreinoud  * Set of generic descriptor readers and writers and their helper functions.
272e979c658Sreinoud  * Descriptors inside `logical space' i.e. inside logically mapped partitions
273e979c658Sreinoud  * can never be longer than one logical sector.
274e979c658Sreinoud  *
275*a10c2cecSandvar  * NOTE that these functions *can* be used by the scheduler backends to read
276e979c658Sreinoud  * node descriptors too.
277e979c658Sreinoud  *
278e979c658Sreinoud  * For reading, the size of allocated piece is returned in multiple of sector
279e979c658Sreinoud  * size due to udf_calc_udf_malloc_size().
280e979c658Sreinoud  */
281e979c658Sreinoud 
282e979c658Sreinoud 
283e979c658Sreinoud /* SYNC reading of n blocks from specified sector */
2849609b0edSreinoud int
udf_read_phys_sectors(struct udf_mount * ump,int what,void * blob,uint32_t start,uint32_t sectors)285e979c658Sreinoud udf_read_phys_sectors(struct udf_mount *ump, int what, void *blob,
286e979c658Sreinoud 	uint32_t start, uint32_t sectors)
287e979c658Sreinoud {
288e979c658Sreinoud 	struct buf *buf, *nestbuf;
289e979c658Sreinoud 	uint32_t buf_offset;
290e979c658Sreinoud 	off_t lblkno, rblkno;
291e979c658Sreinoud 	int sector_size = ump->discinfo.sector_size;
292e979c658Sreinoud 	int blks = sector_size / DEV_BSIZE;
293e979c658Sreinoud 	int piece;
294e979c658Sreinoud 	int error;
295e979c658Sreinoud 
296e979c658Sreinoud 	DPRINTF(READ, ("udf_intbreadn() : sectors = %d, sector_size = %d\n",
297e979c658Sreinoud 		sectors, sector_size));
298e979c658Sreinoud 	buf = getiobuf(ump->devvp, true);
299e979c658Sreinoud 	buf->b_flags    = B_READ;
300e979c658Sreinoud 	buf->b_cflags   = BC_BUSY;	/* needed? */
301e979c658Sreinoud 	buf->b_iodone   = NULL;
302e979c658Sreinoud 	buf->b_data     = blob;
303e979c658Sreinoud 	buf->b_bcount   = sectors * sector_size;
304e979c658Sreinoud 	buf->b_resid    = buf->b_bcount;
305e979c658Sreinoud 	buf->b_bufsize  = buf->b_bcount;
306e979c658Sreinoud 	buf->b_private  = NULL;	/* not needed yet */
307e979c658Sreinoud 	BIO_SETPRIO(buf, BPRIO_DEFAULT);
308e979c658Sreinoud 	buf->b_lblkno   = buf->b_blkno = buf->b_rawblkno = start * blks;
309e979c658Sreinoud 	buf->b_proc     = NULL;
310e979c658Sreinoud 
311e979c658Sreinoud 	error = 0;
312e979c658Sreinoud 	buf_offset = 0;
313e979c658Sreinoud 	rblkno = start;
314e979c658Sreinoud 	lblkno = 0;
315e979c658Sreinoud 	while ((sectors > 0) && (error == 0)) {
316e979c658Sreinoud 		piece = MIN(MAXPHYS/sector_size, sectors);
317e979c658Sreinoud 		DPRINTF(READ, ("read in %d + %d\n", (uint32_t) rblkno, piece));
318e979c658Sreinoud 
319e979c658Sreinoud 		nestbuf = getiobuf(NULL, true);
320e979c658Sreinoud 		nestiobuf_setup(buf, nestbuf, buf_offset, piece * sector_size);
321e979c658Sreinoud 		/* nestbuf is B_ASYNC */
322e979c658Sreinoud 
323e979c658Sreinoud 		/* identify this nestbuf */
324e979c658Sreinoud 		nestbuf->b_lblkno   = lblkno;
325e979c658Sreinoud 
326*a10c2cecSandvar 		/* CD schedules on raw blkno */
327e979c658Sreinoud 		nestbuf->b_blkno      = rblkno * blks;
328e979c658Sreinoud 		nestbuf->b_proc       = NULL;
329e979c658Sreinoud 		nestbuf->b_rawblkno   = rblkno * blks;
330e979c658Sreinoud 		nestbuf->b_udf_c_type = what;
331e979c658Sreinoud 
332e979c658Sreinoud 		udf_discstrat_queuebuf(ump, nestbuf);
333e979c658Sreinoud 
334e979c658Sreinoud 		lblkno     += piece;
335e979c658Sreinoud 		rblkno     += piece;
336e979c658Sreinoud 		buf_offset += piece * sector_size;
337e979c658Sreinoud 		sectors    -= piece;
338e979c658Sreinoud 	}
339e979c658Sreinoud 	error = biowait(buf);
340e979c658Sreinoud 	putiobuf(buf);
341e979c658Sreinoud 
342e979c658Sreinoud 	return error;
343e979c658Sreinoud }
344e979c658Sreinoud 
345e979c658Sreinoud 
346e979c658Sreinoud /* synchronous generic descriptor read */
347e979c658Sreinoud int
udf_read_phys_dscr(struct udf_mount * ump,uint32_t sector,struct malloc_type * mtype,union dscrptr ** dstp)348e979c658Sreinoud udf_read_phys_dscr(struct udf_mount *ump, uint32_t sector,
349e979c658Sreinoud 		    struct malloc_type *mtype, union dscrptr **dstp)
350e979c658Sreinoud {
351e979c658Sreinoud 	union dscrptr *dst, *new_dst;
352e979c658Sreinoud 	uint8_t *pos;
353e979c658Sreinoud 	int sectors, dscrlen;
354e979c658Sreinoud 	int i, error, sector_size;
355e979c658Sreinoud 
356e979c658Sreinoud 	sector_size = ump->discinfo.sector_size;
357e979c658Sreinoud 
358e979c658Sreinoud 	*dstp = dst = NULL;
359e979c658Sreinoud 	dscrlen = sector_size;
360e979c658Sreinoud 
361e979c658Sreinoud 	/* read initial piece */
362e979c658Sreinoud 	dst = malloc(sector_size, mtype, M_WAITOK);
363e979c658Sreinoud 	error = udf_read_phys_sectors(ump, UDF_C_DSCR, dst, sector, 1);
364e979c658Sreinoud 	DPRINTFIF(DESCRIPTOR, error, ("read error (%d)\n", error));
365e979c658Sreinoud 
366e979c658Sreinoud 	if (!error) {
367e979c658Sreinoud 		/* check if its a valid tag */
368e979c658Sreinoud 		error = udf_check_tag(dst);
369e979c658Sreinoud 		if (error) {
370e979c658Sreinoud 			/* check if its an empty block */
371e979c658Sreinoud 			pos = (uint8_t *) dst;
372e979c658Sreinoud 			for (i = 0; i < sector_size; i++, pos++) {
373e979c658Sreinoud 				if (*pos) break;
374e979c658Sreinoud 			}
375e979c658Sreinoud 			if (i == sector_size) {
376e979c658Sreinoud 				/* return no error but with no dscrptr */
377e979c658Sreinoud 				/* dispose first block */
378e979c658Sreinoud 				free(dst, mtype);
379e979c658Sreinoud 				return 0;
380e979c658Sreinoud 			}
381e979c658Sreinoud 		}
382e979c658Sreinoud 		/* calculate descriptor size */
383e979c658Sreinoud 		dscrlen = udf_tagsize(dst, sector_size);
384e979c658Sreinoud 	}
385e979c658Sreinoud 	DPRINTFIF(DESCRIPTOR, error, ("bad tag checksum\n"));
386e979c658Sreinoud 
387e979c658Sreinoud 	if (!error && (dscrlen > sector_size)) {
388e979c658Sreinoud 		DPRINTF(DESCRIPTOR, ("multi block descriptor read\n"));
389e979c658Sreinoud 		/*
390e979c658Sreinoud 		 * Read the rest of descriptor. Since it is only used at mount
391e979c658Sreinoud 		 * time its overdone to define and use a specific udf_intbreadn
392e979c658Sreinoud 		 * for this alone.
393e979c658Sreinoud 		 */
394e979c658Sreinoud 
395e979c658Sreinoud 		new_dst = realloc(dst, dscrlen, mtype, M_WAITOK);
396e979c658Sreinoud 		if (new_dst == NULL) {
397e979c658Sreinoud 			free(dst, mtype);
398e979c658Sreinoud 			return ENOMEM;
399e979c658Sreinoud 		}
400e979c658Sreinoud 		dst = new_dst;
401e979c658Sreinoud 
402e979c658Sreinoud 		sectors = (dscrlen + sector_size -1) / sector_size;
403e979c658Sreinoud 		DPRINTF(DESCRIPTOR, ("dscrlen = %d (%d blk)\n", dscrlen, sectors));
404e979c658Sreinoud 
405e979c658Sreinoud 		pos = (uint8_t *) dst + sector_size;
406e979c658Sreinoud 		error = udf_read_phys_sectors(ump, UDF_C_DSCR, pos,
407e979c658Sreinoud 				sector + 1, sectors-1);
408e979c658Sreinoud 
409e979c658Sreinoud 		DPRINTFIF(DESCRIPTOR, error, ("read error on multi (%d)\n",
410e979c658Sreinoud 		    error));
411e979c658Sreinoud 	}
412e979c658Sreinoud 	if (!error) {
413e979c658Sreinoud 		error = udf_check_tag_payload(dst, dscrlen);
414e979c658Sreinoud 		DPRINTFIF(DESCRIPTOR, error, ("bad payload check sum\n"));
415e979c658Sreinoud 	}
416e979c658Sreinoud 	if (error && dst) {
417e979c658Sreinoud 		free(dst, mtype);
418e979c658Sreinoud 		dst = NULL;
419e979c658Sreinoud 	}
420e979c658Sreinoud 	*dstp = dst;
421e979c658Sreinoud 
422e979c658Sreinoud 	return error;
423e979c658Sreinoud }
424e979c658Sreinoud 
425e979c658Sreinoud 
426e979c658Sreinoud static void
udf_write_phys_buf(struct udf_mount * ump,int what,struct buf * buf)427e979c658Sreinoud udf_write_phys_buf(struct udf_mount *ump, int what, struct buf *buf)
428e979c658Sreinoud {
429e979c658Sreinoud 	struct buf *nestbuf;
430e979c658Sreinoud 	uint32_t buf_offset;
431e979c658Sreinoud 	off_t lblkno, rblkno;
432e979c658Sreinoud 	int sector_size = ump->discinfo.sector_size;
433e979c658Sreinoud 	int blks = sector_size / DEV_BSIZE;
434e979c658Sreinoud 	uint32_t sectors;
435e979c658Sreinoud 	int piece;
436e979c658Sreinoud 	int error;
437e979c658Sreinoud 
438e979c658Sreinoud 	sectors = buf->b_bcount / sector_size;
439e979c658Sreinoud 	DPRINTF(WRITE, ("udf_intbwriten() : sectors = %d, sector_size = %d\n",
440e979c658Sreinoud 		sectors, sector_size));
441e979c658Sreinoud 
442e979c658Sreinoud 	/* don't forget to increase pending count for the bwrite itself */
443e979c658Sreinoud /* panic("NO WRITING\n"); */
444e979c658Sreinoud 	if (buf->b_vp) {
445e225b7bdSrmind 		mutex_enter(buf->b_vp->v_interlock);
446e979c658Sreinoud 		buf->b_vp->v_numoutput++;
447e225b7bdSrmind 		mutex_exit(buf->b_vp->v_interlock);
448e979c658Sreinoud 	}
449e979c658Sreinoud 
450e979c658Sreinoud 	error = 0;
451e979c658Sreinoud 	buf_offset = 0;
452e979c658Sreinoud 	rblkno = buf->b_blkno / blks;
453e979c658Sreinoud 	lblkno = 0;
454e979c658Sreinoud 	while ((sectors > 0) && (error == 0)) {
455e979c658Sreinoud 		piece = MIN(MAXPHYS/sector_size, sectors);
456e979c658Sreinoud 		DPRINTF(WRITE, ("write out %d + %d\n",
457e979c658Sreinoud 		    (uint32_t) rblkno, piece));
458e979c658Sreinoud 
459e979c658Sreinoud 		nestbuf = getiobuf(NULL, true);
460e979c658Sreinoud 		nestiobuf_setup(buf, nestbuf, buf_offset, piece * sector_size);
461e979c658Sreinoud 		/* nestbuf is B_ASYNC */
462e979c658Sreinoud 
463e979c658Sreinoud 		/* identify this nestbuf */
464e979c658Sreinoud 		nestbuf->b_lblkno   = lblkno;
465e979c658Sreinoud 
466*a10c2cecSandvar 		/* CD schedules on raw blkno */
467e979c658Sreinoud 		nestbuf->b_blkno      = rblkno * blks;
468e979c658Sreinoud 		nestbuf->b_proc       = NULL;
469e979c658Sreinoud 		nestbuf->b_rawblkno   = rblkno * blks;
470e979c658Sreinoud 		nestbuf->b_udf_c_type = what;
471e979c658Sreinoud 
472e979c658Sreinoud 		udf_discstrat_queuebuf(ump, nestbuf);
473e979c658Sreinoud 
474e979c658Sreinoud 		lblkno     += piece;
475e979c658Sreinoud 		rblkno     += piece;
476e979c658Sreinoud 		buf_offset += piece * sector_size;
477e979c658Sreinoud 		sectors    -= piece;
478e979c658Sreinoud 	}
479e979c658Sreinoud }
480e979c658Sreinoud 
481e979c658Sreinoud 
4829609b0edSreinoud /* SYNC writing of n blocks from specified sector */
4839609b0edSreinoud int
udf_write_phys_sectors(struct udf_mount * ump,int what,void * blob,uint32_t start,uint32_t sectors)4849609b0edSreinoud udf_write_phys_sectors(struct udf_mount *ump, int what, void *blob,
4859609b0edSreinoud 	uint32_t start, uint32_t sectors)
4869609b0edSreinoud {
4879609b0edSreinoud 	struct vnode *vp;
4889609b0edSreinoud 	struct buf *buf;
4899609b0edSreinoud 	int sector_size = ump->discinfo.sector_size;
4909609b0edSreinoud 	int blks = sector_size / DEV_BSIZE;
4919609b0edSreinoud 	int error;
4929609b0edSreinoud 
4939609b0edSreinoud 	/* get transfer buffer */
4949609b0edSreinoud 	vp = ump->devvp;
4959609b0edSreinoud 	buf = getiobuf(vp, true);
4969609b0edSreinoud 	buf->b_flags    = B_WRITE;
4979609b0edSreinoud 	buf->b_cflags   = BC_BUSY;	/* needed? */
4989609b0edSreinoud 	buf->b_iodone   = NULL;
4999609b0edSreinoud 	buf->b_data     = blob;
5009609b0edSreinoud 	buf->b_bcount   = sectors * sector_size;
5019609b0edSreinoud 	buf->b_resid    = buf->b_bcount;
5029609b0edSreinoud 	buf->b_bufsize  = buf->b_bcount;
5039609b0edSreinoud 	buf->b_private  = NULL;	/* not needed yet */
5049609b0edSreinoud 	BIO_SETPRIO(buf, BPRIO_DEFAULT);
5059609b0edSreinoud 	buf->b_lblkno   = buf->b_blkno = buf->b_rawblkno = start * blks;
5069609b0edSreinoud 	buf->b_proc     = NULL;
5079609b0edSreinoud 
5089609b0edSreinoud 	/* do the write, wait and return error */
5099609b0edSreinoud 	udf_write_phys_buf(ump, what, buf);
5109609b0edSreinoud 	error = biowait(buf);
5119609b0edSreinoud 	putiobuf(buf);
5129609b0edSreinoud 
5139609b0edSreinoud 	return error;
5149609b0edSreinoud }
5159609b0edSreinoud 
5169609b0edSreinoud 
517e979c658Sreinoud /* synchronous generic descriptor write */
518e979c658Sreinoud int
udf_write_phys_dscr_sync(struct udf_mount * ump,struct udf_node * udf_node,int what,union dscrptr * dscr,uint32_t sector,uint32_t logsector)519e979c658Sreinoud udf_write_phys_dscr_sync(struct udf_mount *ump, struct udf_node *udf_node, int what,
520e979c658Sreinoud 		     union dscrptr *dscr, uint32_t sector, uint32_t logsector)
521e979c658Sreinoud {
522e979c658Sreinoud 	struct vnode *vp;
523e979c658Sreinoud 	struct buf *buf;
524e979c658Sreinoud 	int sector_size = ump->discinfo.sector_size;
525e979c658Sreinoud 	int blks = sector_size / DEV_BSIZE;
526e979c658Sreinoud 	int dscrlen;
527e979c658Sreinoud 	int error;
528e979c658Sreinoud 
529e979c658Sreinoud 	/* set sector number in the descriptor and validate */
530e979c658Sreinoud 	dscr->tag.tag_loc = udf_rw32(logsector);
531e979c658Sreinoud 	udf_validate_tag_and_crc_sums(dscr);
532e979c658Sreinoud 
533e979c658Sreinoud 	/* calculate descriptor size */
534e979c658Sreinoud 	dscrlen = udf_tagsize(dscr, sector_size);
535e979c658Sreinoud 
536e979c658Sreinoud 	/* get transfer buffer */
537e979c658Sreinoud 	vp = udf_node ? udf_node->vnode : ump->devvp;
538e979c658Sreinoud 	buf = getiobuf(vp, true);
539e979c658Sreinoud 	buf->b_flags    = B_WRITE;
540e979c658Sreinoud 	buf->b_cflags   = BC_BUSY;	/* needed? */
541e979c658Sreinoud 	buf->b_iodone   = NULL;
542e979c658Sreinoud 	buf->b_data     = (void *) dscr;
543e979c658Sreinoud 	buf->b_bcount   = dscrlen;
544e979c658Sreinoud 	buf->b_resid    = buf->b_bcount;
545e979c658Sreinoud 	buf->b_bufsize  = buf->b_bcount;
546e979c658Sreinoud 	buf->b_private  = NULL;	/* not needed yet */
547e979c658Sreinoud 	BIO_SETPRIO(buf, BPRIO_DEFAULT);
548e979c658Sreinoud 	buf->b_lblkno   = buf->b_blkno = buf->b_rawblkno = sector * blks;
549e979c658Sreinoud 	buf->b_proc     = NULL;
550e979c658Sreinoud 
551e979c658Sreinoud 	/* do the write, wait and return error */
552e979c658Sreinoud 	udf_write_phys_buf(ump, what, buf);
553e979c658Sreinoud 	error = biowait(buf);
554e979c658Sreinoud 	putiobuf(buf);
555e979c658Sreinoud 
556e979c658Sreinoud 	return error;
557e979c658Sreinoud }
558e979c658Sreinoud 
559e979c658Sreinoud 
560e979c658Sreinoud /* asynchronous generic descriptor write */
561e979c658Sreinoud int
udf_write_phys_dscr_async(struct udf_mount * ump,struct udf_node * udf_node,int what,union dscrptr * dscr,uint32_t sector,uint32_t logsector,void (* dscrwr_callback)(struct buf *))562e979c658Sreinoud udf_write_phys_dscr_async(struct udf_mount *ump, struct udf_node *udf_node,
563e979c658Sreinoud 		      int what, union dscrptr *dscr,
564e979c658Sreinoud 		      uint32_t sector, uint32_t logsector,
565e979c658Sreinoud 		      void (*dscrwr_callback)(struct buf *))
566e979c658Sreinoud {
567e979c658Sreinoud 	struct vnode *vp;
568e979c658Sreinoud 	struct buf *buf;
569e979c658Sreinoud 	int dscrlen;
570e979c658Sreinoud 	int sector_size = ump->discinfo.sector_size;
571e979c658Sreinoud 	int blks = sector_size / DEV_BSIZE;
572e979c658Sreinoud 
573e979c658Sreinoud 	KASSERT(dscrwr_callback);
574e979c658Sreinoud 	DPRINTF(NODE, ("udf_write_phys_dscr_async() called\n"));
575e979c658Sreinoud 
576e979c658Sreinoud 	/* set sector number in the descriptor and validate */
577e979c658Sreinoud 	dscr->tag.tag_loc = udf_rw32(logsector);
578e979c658Sreinoud 	udf_validate_tag_and_crc_sums(dscr);
579e979c658Sreinoud 
580e979c658Sreinoud 	/* calculate descriptor size */
581e979c658Sreinoud 	dscrlen = udf_tagsize(dscr, sector_size);
582e979c658Sreinoud 
583e979c658Sreinoud 	/* get transfer buffer */
584e979c658Sreinoud 	vp = udf_node ? udf_node->vnode : ump->devvp;
585e979c658Sreinoud 	buf = getiobuf(vp, true);
586e979c658Sreinoud 	buf->b_flags    = B_WRITE; // | B_ASYNC;
587e979c658Sreinoud 	buf->b_cflags   = BC_BUSY;
588e979c658Sreinoud 	buf->b_iodone	= dscrwr_callback;
589e979c658Sreinoud 	buf->b_data     = dscr;
590e979c658Sreinoud 	buf->b_bcount   = dscrlen;
591e979c658Sreinoud 	buf->b_resid    = buf->b_bcount;
592e979c658Sreinoud 	buf->b_bufsize  = buf->b_bcount;
593e979c658Sreinoud 	buf->b_private  = NULL;	/* not needed yet */
594e979c658Sreinoud 	BIO_SETPRIO(buf, BPRIO_DEFAULT);
595e979c658Sreinoud 	buf->b_lblkno   = buf->b_blkno = buf->b_rawblkno = sector * blks;
596e979c658Sreinoud 	buf->b_proc     = NULL;
597e979c658Sreinoud 
598e979c658Sreinoud 	/* do the write and return no error */
599e979c658Sreinoud 	udf_write_phys_buf(ump, what, buf);
600e979c658Sreinoud 	return 0;
601e979c658Sreinoud }
602e979c658Sreinoud 
603e979c658Sreinoud /* --------------------------------------------------------------------- */
604e979c658Sreinoud 
605e979c658Sreinoud /* disc strategy dispatchers */
606e979c658Sreinoud 
607e979c658Sreinoud int
udf_create_logvol_dscr(struct udf_mount * ump,struct udf_node * udf_node,struct long_ad * icb,union dscrptr ** dscrptr)608e979c658Sreinoud udf_create_logvol_dscr(struct udf_mount *ump, struct udf_node *udf_node, struct long_ad *icb,
609e979c658Sreinoud 	union dscrptr **dscrptr)
610e979c658Sreinoud {
611e979c658Sreinoud 	struct udf_strategy *strategy = ump->strategy;
612e979c658Sreinoud 	struct udf_strat_args args;
613e979c658Sreinoud 	int error;
614e979c658Sreinoud 
6150687ceb2Sreinoud 	KASSERT(strategy);
616e979c658Sreinoud 	args.ump  = ump;
617e979c658Sreinoud 	args.udf_node = udf_node;
618e979c658Sreinoud 	args.icb  = icb;
619e979c658Sreinoud 	args.dscr = NULL;
620e979c658Sreinoud 
621e979c658Sreinoud 	error = (strategy->create_logvol_dscr)(&args);
622e979c658Sreinoud 	*dscrptr = args.dscr;
623e979c658Sreinoud 
624e979c658Sreinoud 	return error;
625e979c658Sreinoud }
626e979c658Sreinoud 
627e979c658Sreinoud 
628e979c658Sreinoud void
udf_free_logvol_dscr(struct udf_mount * ump,struct long_ad * icb,void * dscr)629e979c658Sreinoud udf_free_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
630e979c658Sreinoud 	void *dscr)
631e979c658Sreinoud {
632e979c658Sreinoud 	struct udf_strategy *strategy = ump->strategy;
633e979c658Sreinoud 	struct udf_strat_args args;
634e979c658Sreinoud 
6350687ceb2Sreinoud 	KASSERT(strategy);
636e979c658Sreinoud 	args.ump  = ump;
637e979c658Sreinoud 	args.icb  = icb;
638e979c658Sreinoud 	args.dscr = dscr;
639e979c658Sreinoud 
640e979c658Sreinoud 	(strategy->free_logvol_dscr)(&args);
641e979c658Sreinoud }
642e979c658Sreinoud 
643e979c658Sreinoud 
644e979c658Sreinoud int
udf_read_logvol_dscr(struct udf_mount * ump,struct long_ad * icb,union dscrptr ** dscrptr)645e979c658Sreinoud udf_read_logvol_dscr(struct udf_mount *ump, struct long_ad *icb,
646e979c658Sreinoud 	union dscrptr **dscrptr)
647e979c658Sreinoud {
648e979c658Sreinoud 	struct udf_strategy *strategy = ump->strategy;
649e979c658Sreinoud 	struct udf_strat_args args;
650e979c658Sreinoud 	int error;
651e979c658Sreinoud 
6520687ceb2Sreinoud 	KASSERT(strategy);
653e979c658Sreinoud 	args.ump  = ump;
654e979c658Sreinoud 	args.icb  = icb;
655e979c658Sreinoud 	args.dscr = NULL;
656e979c658Sreinoud 
657e979c658Sreinoud 	error = (strategy->read_logvol_dscr)(&args);
658e979c658Sreinoud 	*dscrptr = args.dscr;
659e979c658Sreinoud 
660e979c658Sreinoud 	return error;
661e979c658Sreinoud }
662e979c658Sreinoud 
663e979c658Sreinoud 
664e979c658Sreinoud int
udf_write_logvol_dscr(struct udf_node * udf_node,union dscrptr * dscr,struct long_ad * icb,int waitfor)665e979c658Sreinoud udf_write_logvol_dscr(struct udf_node *udf_node, union dscrptr *dscr,
666e979c658Sreinoud 	struct long_ad *icb, int waitfor)
667e979c658Sreinoud {
668e979c658Sreinoud 	struct udf_strategy *strategy = udf_node->ump->strategy;
669e979c658Sreinoud 	struct udf_strat_args args;
670e979c658Sreinoud 	int error;
671e979c658Sreinoud 
6720687ceb2Sreinoud 	KASSERT(strategy);
673e979c658Sreinoud 	args.ump      = udf_node->ump;
674e979c658Sreinoud 	args.udf_node = udf_node;
675e979c658Sreinoud 	args.icb      = icb;
676e979c658Sreinoud 	args.dscr     = dscr;
677e979c658Sreinoud 	args.waitfor  = waitfor;
678e979c658Sreinoud 
679e979c658Sreinoud 	error = (strategy->write_logvol_dscr)(&args);
680e979c658Sreinoud 	return error;
681e979c658Sreinoud }
682e979c658Sreinoud 
683e979c658Sreinoud 
684e979c658Sreinoud void
udf_discstrat_queuebuf(struct udf_mount * ump,struct buf * nestbuf)685e979c658Sreinoud udf_discstrat_queuebuf(struct udf_mount *ump, struct buf *nestbuf)
686e979c658Sreinoud {
687e979c658Sreinoud 	struct udf_strategy *strategy = ump->strategy;
688e979c658Sreinoud 	struct udf_strat_args args;
689e979c658Sreinoud 
6900687ceb2Sreinoud 	KASSERT(strategy);
691e979c658Sreinoud 	args.ump = ump;
692e979c658Sreinoud 	args.nestbuf = nestbuf;
693e979c658Sreinoud 
694e979c658Sreinoud 	(strategy->queuebuf)(&args);
695e979c658Sreinoud }
696e979c658Sreinoud 
697e979c658Sreinoud 
698e979c658Sreinoud void
udf_synchronise_caches(struct udf_mount * ump)69942866dd2Sreinoud udf_synchronise_caches(struct udf_mount *ump)
70042866dd2Sreinoud {
70142866dd2Sreinoud 	struct udf_strategy *strategy = ump->strategy;
70242866dd2Sreinoud 	struct udf_strat_args args;
70342866dd2Sreinoud 
70442866dd2Sreinoud 	KASSERT(strategy);
70542866dd2Sreinoud 	args.ump = ump;
70642866dd2Sreinoud 
70742866dd2Sreinoud 	(strategy->sync_caches)(&args);
70842866dd2Sreinoud }
70942866dd2Sreinoud 
71042866dd2Sreinoud 
71142866dd2Sreinoud void
udf_discstrat_init(struct udf_mount * ump)712e979c658Sreinoud udf_discstrat_init(struct udf_mount *ump)
713e979c658Sreinoud {
714e979c658Sreinoud 	struct udf_strategy *strategy = ump->strategy;
715e979c658Sreinoud 	struct udf_strat_args args;
716e979c658Sreinoud 
7170687ceb2Sreinoud 	KASSERT(strategy);
718e979c658Sreinoud 	args.ump = ump;
719e979c658Sreinoud 	(strategy->discstrat_init)(&args);
720e979c658Sreinoud }
721e979c658Sreinoud 
722e979c658Sreinoud 
udf_discstrat_finish(struct udf_mount * ump)723e979c658Sreinoud void udf_discstrat_finish(struct udf_mount *ump)
724e979c658Sreinoud {
725e979c658Sreinoud 	struct udf_strategy *strategy = ump->strategy;
726e979c658Sreinoud 	struct udf_strat_args args;
727e979c658Sreinoud 
7280687ceb2Sreinoud 	/* strategy might not have been set, so ignore if not set */
7290687ceb2Sreinoud 	if (strategy) {
730e979c658Sreinoud 		args.ump = ump;
731e979c658Sreinoud 		(strategy->discstrat_finish)(&args);
732e979c658Sreinoud 	}
7330687ceb2Sreinoud }
734e979c658Sreinoud 
735e979c658Sreinoud /* --------------------------------------------------------------------- */
736e979c658Sreinoud 
737