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