xref: /illumos-gate/usr/src/uts/common/fs/udfs/udf_vfsops.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/t_lock.h>
30 #include <sys/param.h>
31 #include <sys/time.h>
32 #include <sys/systm.h>
33 #include <sys/sysmacros.h>
34 #include <sys/resource.h>
35 #include <sys/signal.h>
36 #include <sys/cred.h>
37 #include <sys/user.h>
38 #include <sys/buf.h>
39 #include <sys/vfs.h>
40 #include <sys/vfs_opreg.h>
41 #include <sys/stat.h>
42 #include <sys/vnode.h>
43 #include <sys/mode.h>
44 #include <sys/proc.h>
45 #include <sys/disp.h>
46 #include <sys/file.h>
47 #include <sys/fcntl.h>
48 #include <sys/flock.h>
49 #include <sys/kmem.h>
50 #include <sys/uio.h>
51 #include <sys/dnlc.h>
52 #include <sys/conf.h>
53 #include <sys/errno.h>
54 #include <sys/mman.h>
55 #include <sys/fbuf.h>
56 #include <sys/pathname.h>
57 #include <sys/debug.h>
58 #include <sys/vmsystm.h>
59 #include <sys/cmn_err.h>
60 #include <sys/dirent.h>
61 #include <sys/errno.h>
62 #include <sys/modctl.h>
63 #include <sys/statvfs.h>
64 #include <sys/mount.h>
65 #include <sys/sunddi.h>
66 #include <sys/bootconf.h>
67 #include <sys/policy.h>
68 
69 #include <vm/hat.h>
70 #include <vm/page.h>
71 #include <vm/pvn.h>
72 #include <vm/as.h>
73 #include <vm/seg.h>
74 #include <vm/seg_map.h>
75 #include <vm/seg_kmem.h>
76 #include <vm/seg_vn.h>
77 #include <vm/rm.h>
78 #include <vm/page.h>
79 #include <sys/swap.h>
80 #include <sys/mntent.h>
81 
82 
83 #include <fs/fs_subr.h>
84 
85 
86 #include <sys/fs/udf_volume.h>
87 #include <sys/fs/udf_inode.h>
88 
89 
90 extern struct vnode *common_specvp(struct vnode *vp);
91 
92 extern kmutex_t ud_sync_busy;
93 static int32_t ud_mountfs(struct vfs *,
94     enum whymountroot, dev_t, char *, struct cred *, int32_t);
95 static struct udf_vfs *ud_validate_and_fill_superblock(dev_t,
96     int32_t, uint32_t);
97 void ud_destroy_fsp(struct udf_vfs *);
98 void ud_convert_to_superblock(struct udf_vfs *,
99     struct log_vol_int_desc *);
100 void ud_update_superblock(struct vfs *);
101 int32_t ud_get_last_block(dev_t, daddr_t *);
102 static int32_t ud_val_get_vat(struct udf_vfs *,
103     dev_t, daddr_t, struct ud_map *);
104 int32_t ud_read_sparing_tbls(struct udf_vfs *,
105     dev_t, struct ud_map *, struct pmap_typ2 *);
106 uint32_t ud_get_lbsize(dev_t, uint32_t *);
107 
108 static int32_t udf_mount(struct vfs *,
109     struct vnode *, struct mounta *, struct cred *);
110 static int32_t udf_unmount(struct vfs *, int, struct cred *);
111 static int32_t udf_root(struct vfs *, struct vnode **);
112 static int32_t udf_statvfs(struct vfs *, struct statvfs64 *);
113 static int32_t udf_sync(struct vfs *, int16_t, struct cred *);
114 static int32_t udf_vget(struct vfs *, struct vnode **, struct fid *);
115 static int32_t udf_mountroot(struct vfs *vfsp, enum whymountroot);
116 
117 static int udfinit(int, char *);
118 
119 static mntopts_t udfs_mntopts;
120 
121 static vfsdef_t vfw = {
122 	VFSDEF_VERSION,
123 	"udfs",
124 	udfinit,
125 	VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_CANLOFI,
126 	&udfs_mntopts
127 };
128 
129 static mntopts_t udfs_mntopts = {
130 	0,
131 	NULL
132 };
133 
134 /*
135  * Module linkage information for the kernel.
136  */
137 extern struct mod_ops mod_fsops;
138 
139 static struct modlfs modlfs = {
140 	&mod_fsops, "filesystem for UDFS", &vfw
141 };
142 
143 static struct modlinkage modlinkage = {
144 	MODREV_1, (void *)&modlfs, NULL
145 };
146 
147 char _depends_on[] = "fs/specfs";
148 
149 int32_t udf_fstype = -1;
150 
151 int
152 _init()
153 {
154 	return (mod_install(&modlinkage));
155 }
156 
157 int
158 _fini()
159 {
160 	return (EBUSY);
161 }
162 
163 int
164 _info(struct modinfo *modinfop)
165 {
166 	return (mod_info(&modlinkage, modinfop));
167 }
168 
169 
170 /* -------------------- vfs routines -------------------- */
171 
172 /*
173  * XXX - this appears only to be used by the VM code to handle the case where
174  * UNIX is running off the mini-root.  That probably wants to be done
175  * differently.
176  */
177 struct vnode *rootvp;
178 #ifndef	__lint
179 _NOTE(SCHEME_PROTECTS_DATA("safe sharing", rootvp))
180 #endif
181 static int32_t
182 udf_mount(struct vfs *vfsp, struct vnode *mvp,
183 	struct mounta *uap, struct cred *cr)
184 {
185 	dev_t dev;
186 	struct vnode *lvp = NULL;
187 	struct vnode *svp = NULL;
188 	struct pathname dpn;
189 	int32_t error;
190 	enum whymountroot why;
191 	int oflag, aflag;
192 
193 	ud_printf("udf_mount\n");
194 
195 	if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) {
196 		return (error);
197 	}
198 
199 	if (mvp->v_type != VDIR) {
200 		return (ENOTDIR);
201 	}
202 
203 	mutex_enter(&mvp->v_lock);
204 	if ((uap->flags & MS_REMOUNT) == 0 &&
205 	    (uap->flags & MS_OVERLAY) == 0 &&
206 	    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
207 		mutex_exit(&mvp->v_lock);
208 		return (EBUSY);
209 	}
210 	mutex_exit(&mvp->v_lock);
211 
212 	if (error = pn_get(uap->dir, UIO_USERSPACE, &dpn)) {
213 		return (error);
214 	}
215 
216 	/*
217 	 * Resolve path name of the file being mounted.
218 	 */
219 	if (error = lookupname(uap->spec, UIO_USERSPACE, FOLLOW, NULLVPP,
220 	    &svp)) {
221 		pn_free(&dpn);
222 		return (error);
223 	}
224 
225 	error = vfs_get_lofi(vfsp, &lvp);
226 
227 	if (error > 0) {
228 		if (error == ENOENT)
229 			error = ENODEV;
230 		goto out;
231 	} else if (error == 0) {
232 		dev = lvp->v_rdev;
233 	} else {
234 		dev = svp->v_rdev;
235 
236 		if (svp->v_type != VBLK) {
237 			error = ENOTBLK;
238 			goto out;
239 		}
240 	}
241 
242 	/*
243 	 * Ensure that this device isn't already mounted,
244 	 * unless this is a REMOUNT request
245 	 */
246 	if (vfs_devmounting(dev, vfsp)) {
247 		error = EBUSY;
248 		goto out;
249 	}
250 	if (vfs_devismounted(dev)) {
251 		if (uap->flags & MS_REMOUNT) {
252 			why = ROOT_REMOUNT;
253 		} else {
254 			error = EBUSY;
255 			goto out;
256 		}
257 	} else {
258 		why = ROOT_INIT;
259 	}
260 	if (getmajor(dev) >= devcnt) {
261 		error = ENXIO;
262 		goto out;
263 	}
264 
265 	/*
266 	 * If the device is a tape, mount it read only
267 	 */
268 	if (devopsp[getmajor(dev)]->devo_cb_ops->cb_flag & D_TAPE) {
269 		vfsp->vfs_flag |= VFS_RDONLY;
270 	}
271 
272 	if (uap->flags & MS_RDONLY) {
273 		vfsp->vfs_flag |= VFS_RDONLY;
274 	}
275 
276 	/*
277 	 * Set mount options.
278 	 */
279 	if (uap->flags & MS_RDONLY) {
280 		vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
281 	}
282 	if (uap->flags & MS_NOSUID) {
283 		vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
284 	}
285 
286 	/*
287 	 * Verify that the caller can open the device special file as
288 	 * required.  It is not until this moment that we know whether
289 	 * we're mounting "ro" or not.
290 	 */
291 	if ((vfsp->vfs_flag & VFS_RDONLY) != 0) {
292 		oflag = FREAD;
293 		aflag = VREAD;
294 	} else {
295 		oflag = FREAD | FWRITE;
296 		aflag = VREAD | VWRITE;
297 	}
298 
299 	if (lvp == NULL &&
300 	    (error = secpolicy_spec_open(cr, svp, oflag)) != 0)
301 		goto out;
302 
303 	if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0)
304 		goto out;
305 
306 	/*
307 	 * Mount the filesystem.
308 	 */
309 	error = ud_mountfs(vfsp, why, dev, dpn.pn_path, cr, 0);
310 out:
311 	VN_RELE(svp);
312 	if (lvp != NULL)
313 		VN_RELE(lvp);
314 	pn_free(&dpn);
315 	return (error);
316 }
317 
318 
319 
320 /*
321  * unmount the file system pointed
322  * by vfsp
323  */
324 /* ARGSUSED */
325 static int32_t
326 udf_unmount(struct vfs *vfsp, int fflag, struct cred *cr)
327 {
328 	struct udf_vfs *udf_vfsp;
329 	struct vnode *bvp, *rvp;
330 	struct ud_inode *rip;
331 	int32_t flag;
332 
333 	ud_printf("udf_unmount\n");
334 
335 	if (secpolicy_fs_unmount(cr, vfsp) != 0) {
336 		return (EPERM);
337 	}
338 
339 	/*
340 	 * forced unmount is not supported by this file system
341 	 * and thus, ENOTSUP, is being returned.
342 	 */
343 	if (fflag & MS_FORCE)
344 		return (ENOTSUP);
345 
346 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
347 	flag = !(udf_vfsp->udf_flags & UDF_FL_RDONLY);
348 	bvp = udf_vfsp->udf_devvp;
349 
350 	rvp = udf_vfsp->udf_root;
351 	ASSERT(rvp != NULL);
352 	rip = VTOI(rvp);
353 
354 	(void) ud_release_cache(udf_vfsp);
355 
356 
357 	/* Flush all inodes except root */
358 	if (ud_iflush(vfsp) < 0) {
359 		return (EBUSY);
360 	}
361 
362 	rw_enter(&rip->i_contents, RW_WRITER);
363 	(void) ud_syncip(rip, B_INVAL, I_SYNC);
364 	rw_exit(&rip->i_contents);
365 
366 	mutex_enter(&ud_sync_busy);
367 	if ((udf_vfsp->udf_flags & UDF_FL_RDONLY) == 0) {
368 		bflush(vfsp->vfs_dev);
369 		mutex_enter(&udf_vfsp->udf_lock);
370 		udf_vfsp->udf_clean = UDF_CLEAN;
371 		mutex_exit(&udf_vfsp->udf_lock);
372 		ud_update_superblock(vfsp);
373 	}
374 	mutex_exit(&ud_sync_busy);
375 
376 	mutex_destroy(&udf_vfsp->udf_lock);
377 	mutex_destroy(&udf_vfsp->udf_rename_lck);
378 
379 	ud_delcache(rip);
380 	ITIMES(rip);
381 	VN_RELE(rvp);
382 
383 	ud_destroy_fsp(udf_vfsp);
384 
385 	(void) VOP_PUTPAGE(bvp, (offset_t)0, (uint32_t)0, B_INVAL, cr, NULL);
386 	(void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr, NULL);
387 
388 	(void) bfinval(vfsp->vfs_dev, 1);
389 	VN_RELE(bvp);
390 
391 
392 	return (0);
393 }
394 
395 
396 /*
397  * Get the root vp for the
398  * file system
399  */
400 static int32_t
401 udf_root(struct vfs *vfsp, struct vnode **vpp)
402 {
403 	struct udf_vfs *udf_vfsp;
404 	struct vnode *vp;
405 
406 	ud_printf("udf_root\n");
407 
408 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
409 
410 	ASSERT(udf_vfsp != NULL);
411 	ASSERT(udf_vfsp->udf_root != NULL);
412 
413 	vp = udf_vfsp->udf_root;
414 	VN_HOLD(vp);
415 	*vpp = vp;
416 	return (0);
417 }
418 
419 
420 /*
421  * Get file system statistics.
422  */
423 static int32_t
424 udf_statvfs(struct vfs *vfsp, struct statvfs64 *sp)
425 {
426 	struct udf_vfs *udf_vfsp;
427 	struct ud_part *parts;
428 	dev32_t d32;
429 	int32_t index;
430 
431 	ud_printf("udf_statvfs\n");
432 
433 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
434 	(void) bzero(sp, sizeof (struct statvfs64));
435 
436 	mutex_enter(&udf_vfsp->udf_lock);
437 	sp->f_bsize = udf_vfsp->udf_lbsize;
438 	sp->f_frsize = udf_vfsp->udf_lbsize;
439 	sp->f_blocks = 0;
440 	sp->f_bfree = 0;
441 	parts = udf_vfsp->udf_parts;
442 	for (index = 0; index < udf_vfsp->udf_npart; index++) {
443 		sp->f_blocks += parts->udp_nblocks;
444 		sp->f_bfree += parts->udp_nfree;
445 		parts++;
446 	}
447 	sp->f_bavail = sp->f_bfree;
448 
449 	/*
450 	 * Since there are no real inodes allocated
451 	 * we will approximate
452 	 * each new file will occupy :
453 	 * 38(over head each dent) + MAXNAMLEN / 2 + inode_size(==block size)
454 	 */
455 	sp->f_ffree = sp->f_favail =
456 	    (sp->f_bavail * sp->f_bsize) / (146 + sp->f_bsize);
457 
458 	/*
459 	 * The total number of inodes is
460 	 * the sum of files + directories + free inodes
461 	 */
462 	sp->f_files = sp->f_ffree + udf_vfsp->udf_nfiles + udf_vfsp->udf_ndirs;
463 	(void) cmpldev(&d32, vfsp->vfs_dev);
464 	sp->f_fsid = d32;
465 	(void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
466 	sp->f_flag = vf_to_stf(vfsp->vfs_flag);
467 	sp->f_namemax = MAXNAMLEN;
468 	(void) strcpy(sp->f_fstr, udf_vfsp->udf_volid);
469 
470 	mutex_exit(&udf_vfsp->udf_lock);
471 
472 	return (0);
473 }
474 
475 
476 /*
477  * Flush any pending I/O to file system vfsp.
478  * The ud_update() routine will only flush *all* udf files.
479  */
480 /*ARGSUSED*/
481 /* ARGSUSED */
482 static int32_t
483 udf_sync(struct vfs *vfsp, int16_t flag, struct cred *cr)
484 {
485 	ud_printf("udf_sync\n");
486 
487 	ud_update(flag);
488 	return (0);
489 }
490 
491 
492 
493 /* ARGSUSED */
494 static int32_t
495 udf_vget(struct vfs *vfsp,
496 	struct vnode **vpp, struct fid *fidp)
497 {
498 	int32_t error = 0;
499 	struct udf_fid *udfid;
500 	struct udf_vfs *udf_vfsp;
501 	struct ud_inode *ip;
502 
503 	ud_printf("udf_vget\n");
504 
505 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
506 	if (udf_vfsp == NULL) {
507 		*vpp = NULL;
508 		return (0);
509 	}
510 
511 	udfid = (struct udf_fid *)fidp;
512 	if ((error = ud_iget(vfsp, udfid->udfid_prn,
513 	    udfid->udfid_icb_lbn, &ip, NULL, CRED())) != 0) {
514 		*vpp = NULL;
515 		return (error);
516 	}
517 
518 	rw_enter(&ip->i_contents, RW_READER);
519 	if ((udfid->udfid_uinq_lo != (ip->i_uniqid & 0xffffffff)) ||
520 	    (udfid->udfid_prn != ip->i_icb_prn)) {
521 		rw_exit(&ip->i_contents);
522 		VN_RELE(ITOV(ip));
523 		*vpp = NULL;
524 		return (EINVAL);
525 	}
526 	rw_exit(&ip->i_contents);
527 
528 	*vpp = ITOV(ip);
529 	return (0);
530 }
531 
532 
533 /*
534  * Mount root file system.
535  * "why" is ROOT_INIT on initial call, ROOT_REMOUNT if called to
536  * remount the root file system, and ROOT_UNMOUNT if called to
537  * unmount the root (e.g., as part of a system shutdown).
538  *
539  * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
540  * operation, goes along with auto-configuration.  A mechanism should be
541  * provided by which machine-INdependent code in the kernel can say "get me the
542  * right root file system" and "get me the right initial swap area", and have
543  * that done in what may well be a machine-dependent fashion.
544  * Unfortunately, it is also file-system-type dependent (NFS gets it via
545  * bootparams calls, UFS gets it from various and sundry machine-dependent
546  * mechanisms, as SPECFS does for swap).
547  */
548 /* ARGSUSED */
549 static int32_t
550 udf_mountroot(struct vfs *vfsp, enum whymountroot why)
551 {
552 	dev_t rootdev;
553 	static int32_t udf_rootdone = 0;
554 	struct vnode *vp = NULL;
555 	int32_t ovflags, error;
556 	ud_printf("udf_mountroot\n");
557 
558 	if (why == ROOT_INIT) {
559 		if (udf_rootdone++) {
560 			return (EBUSY);
561 		}
562 		rootdev = getrootdev();
563 		if (rootdev == (dev_t)NODEV) {
564 			return (ENODEV);
565 		}
566 		vfsp->vfs_dev = rootdev;
567 		vfsp->vfs_flag |= VFS_RDONLY;
568 	} else if (why == ROOT_REMOUNT) {
569 		vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
570 		(void) dnlc_purge_vfsp(vfsp, 0);
571 		vp = common_specvp(vp);
572 		(void) VOP_PUTPAGE(vp, (offset_t)0,
573 		    (uint32_t)0, B_INVAL, CRED(), NULL);
574 		binval(vfsp->vfs_dev);
575 
576 		ovflags = vfsp->vfs_flag;
577 		vfsp->vfs_flag &= ~VFS_RDONLY;
578 		vfsp->vfs_flag |= VFS_REMOUNT;
579 		rootdev = vfsp->vfs_dev;
580 	} else if (why == ROOT_UNMOUNT) {
581 		ud_update(0);
582 		vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
583 		(void) VOP_CLOSE(vp, FREAD|FWRITE, 1,
584 		    (offset_t)0, CRED(), NULL);
585 		return (0);
586 	}
587 
588 	if ((error = vfs_lock(vfsp)) != 0) {
589 		return (error);
590 	}
591 
592 	error = ud_mountfs(vfsp, why, rootdev, "/", CRED(), 1);
593 	if (error) {
594 		vfs_unlock(vfsp);
595 		if (why == ROOT_REMOUNT) {
596 			vfsp->vfs_flag = ovflags;
597 		}
598 		if (rootvp) {
599 			VN_RELE(rootvp);
600 			rootvp = (struct vnode *)0;
601 		}
602 		return (error);
603 	}
604 
605 	if (why == ROOT_INIT) {
606 		vfs_add((struct vnode *)0, vfsp,
607 		    (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0);
608 	}
609 	vfs_unlock(vfsp);
610 	return (0);
611 }
612 
613 
614 /* ------------------------- local routines ------------------------- */
615 
616 
617 static int32_t
618 ud_mountfs(struct vfs *vfsp,
619 	enum whymountroot why, dev_t dev, char *name,
620 	struct cred *cr, int32_t isroot)
621 {
622 	struct vnode *devvp = NULL;
623 	int32_t error = 0;
624 	int32_t needclose = 0;
625 	struct udf_vfs *udf_vfsp = NULL;
626 	struct log_vol_int_desc *lvid;
627 	struct ud_inode *rip = NULL;
628 	struct vnode *rvp = NULL;
629 	int32_t i, lbsize;
630 	uint32_t avd_loc;
631 	struct ud_map *map;
632 	int32_t	desc_len;
633 
634 	ud_printf("ud_mountfs\n");
635 
636 	if (why == ROOT_INIT) {
637 		/*
638 		 * Open the device.
639 		 */
640 		devvp = makespecvp(dev, VBLK);
641 
642 		/*
643 		 * Open block device mounted on.
644 		 * When bio is fixed for vnodes this can all be vnode
645 		 * operations.
646 		 */
647 		error = VOP_OPEN(&devvp,
648 		    (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
649 		    cr, NULL);
650 		if (error) {
651 			goto out;
652 		}
653 		needclose = 1;
654 
655 		/*
656 		 * Refuse to go any further if this
657 		 * device is being used for swapping.
658 		 */
659 		if (IS_SWAPVP(devvp)) {
660 			error = EBUSY;
661 			goto out;
662 		}
663 	}
664 
665 	/*
666 	 * check for dev already mounted on
667 	 */
668 	if (vfsp->vfs_flag & VFS_REMOUNT) {
669 		struct tag *ttag;
670 		int32_t index, count;
671 		struct buf *tpt = 0;
672 		caddr_t addr;
673 
674 
675 		/* cannot remount to RDONLY */
676 		if (vfsp->vfs_flag & VFS_RDONLY) {
677 			return (EINVAL);
678 		}
679 
680 		if (vfsp->vfs_dev != dev) {
681 			return (EINVAL);
682 		}
683 
684 		udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
685 		devvp = udf_vfsp->udf_devvp;
686 
687 		/*
688 		 * fsck may have altered the file system; discard
689 		 * as much incore data as possible.  Don't flush
690 		 * if this is a rw to rw remount; it's just resetting
691 		 * the options.
692 		 */
693 		if (udf_vfsp->udf_flags & UDF_FL_RDONLY) {
694 			(void) dnlc_purge_vfsp(vfsp, 0);
695 			(void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0,
696 			    B_INVAL, CRED(), NULL);
697 			(void) ud_iflush(vfsp);
698 			bflush(dev);
699 			binval(dev);
700 		}
701 
702 		/*
703 		 * We could read UDF1.50 and write UDF1.50 only
704 		 * disallow mount of any highier version
705 		 */
706 		if ((udf_vfsp->udf_miread > UDF_150) ||
707 		    (udf_vfsp->udf_miwrite > UDF_150)) {
708 			error = EINVAL;
709 			goto remountout;
710 		}
711 
712 		/*
713 		 * read/write to read/write; all done
714 		 */
715 		if (udf_vfsp->udf_flags & UDF_FL_RW) {
716 			goto remountout;
717 		}
718 
719 		/*
720 		 * Does the media type allow a writable mount
721 		 */
722 		if (udf_vfsp->udf_mtype != UDF_MT_OW) {
723 			error = EINVAL;
724 			goto remountout;
725 		}
726 
727 		/*
728 		 * Read the metadata
729 		 * and check if it is possible to
730 		 * mount in rw mode
731 		 */
732 		tpt = ud_bread(vfsp->vfs_dev,
733 		    udf_vfsp->udf_iseq_loc << udf_vfsp->udf_l2d_shift,
734 		    udf_vfsp->udf_iseq_len);
735 		if (tpt->b_flags & B_ERROR) {
736 			error = EIO;
737 			goto remountout;
738 		}
739 		count = udf_vfsp->udf_iseq_len / DEV_BSIZE;
740 		addr = tpt->b_un.b_addr;
741 		for (index = 0; index < count; index ++) {
742 			ttag = (struct tag *)(addr + index * DEV_BSIZE);
743 			desc_len = udf_vfsp->udf_iseq_len - (index * DEV_BSIZE);
744 			if (ud_verify_tag_and_desc(ttag, UD_LOG_VOL_INT,
745 			    udf_vfsp->udf_iseq_loc +
746 			    (index >> udf_vfsp->udf_l2d_shift),
747 			    1, desc_len) == 0) {
748 				struct log_vol_int_desc *lvid;
749 
750 				lvid = (struct log_vol_int_desc *)ttag;
751 
752 				if (SWAP_32(lvid->lvid_int_type) !=
753 				    LOG_VOL_CLOSE_INT) {
754 					error = EINVAL;
755 					goto remountout;
756 				}
757 
758 				/*
759 				 * Copy new data to old data
760 				 */
761 				bcopy(udf_vfsp->udf_iseq->b_un.b_addr,
762 				    tpt->b_un.b_addr, udf_vfsp->udf_iseq_len);
763 				break;
764 			}
765 		}
766 
767 		udf_vfsp->udf_flags = UDF_FL_RW;
768 
769 		mutex_enter(&udf_vfsp->udf_lock);
770 		ud_sbwrite(udf_vfsp);
771 		mutex_exit(&udf_vfsp->udf_lock);
772 remountout:
773 		if (tpt != NULL) {
774 			tpt->b_flags = B_AGE | B_STALE;
775 			brelse(tpt);
776 		}
777 		return (error);
778 	}
779 
780 	ASSERT(devvp != 0);
781 	/*
782 	 * Flush back any dirty pages on the block device to
783 	 * try and keep the buffer cache in sync with the page
784 	 * cache if someone is trying to use block devices when
785 	 * they really should be using the raw device.
786 	 */
787 	(void) VOP_PUTPAGE(common_specvp(devvp), (offset_t)0,
788 	    (uint32_t)0, B_INVAL, cr, NULL);
789 
790 
791 	/*
792 	 * Check if the file system
793 	 * is a valid udfs and fill
794 	 * the required fields in udf_vfs
795 	 */
796 #ifndef	__lint
797 	_NOTE(NO_COMPETING_THREADS_NOW);
798 #endif
799 
800 	if ((lbsize = ud_get_lbsize(dev, &avd_loc)) == 0) {
801 		error = EINVAL;
802 		goto out;
803 	}
804 
805 	udf_vfsp = ud_validate_and_fill_superblock(dev, lbsize, avd_loc);
806 	if (udf_vfsp == NULL) {
807 		error = EINVAL;
808 		goto out;
809 	}
810 
811 	/*
812 	 * Fill in vfs private data
813 	 */
814 	vfsp->vfs_fstype = udf_fstype;
815 	vfs_make_fsid(&vfsp->vfs_fsid, dev, udf_fstype);
816 	vfsp->vfs_data = (caddr_t)udf_vfsp;
817 	vfsp->vfs_dev = dev;
818 	vfsp->vfs_flag |= VFS_NOTRUNC;
819 	udf_vfsp->udf_devvp = devvp;
820 
821 	udf_vfsp->udf_fsmnt = kmem_zalloc(strlen(name) + 1, KM_SLEEP);
822 	(void) strcpy(udf_vfsp->udf_fsmnt, name);
823 
824 	udf_vfsp->udf_vfs = vfsp;
825 	udf_vfsp->udf_rdclustsz = udf_vfsp->udf_wrclustsz = maxphys;
826 
827 	udf_vfsp->udf_mod = 0;
828 
829 
830 	lvid = udf_vfsp->udf_lvid;
831 	if (vfsp->vfs_flag & VFS_RDONLY) {
832 		/*
833 		 * We could read only UDF1.50
834 		 * disallow mount of any highier version
835 		 */
836 		if (udf_vfsp->udf_miread > UDF_150) {
837 			error = EINVAL;
838 			goto out;
839 		}
840 		udf_vfsp->udf_flags = UDF_FL_RDONLY;
841 		if (SWAP_32(lvid->lvid_int_type) == LOG_VOL_CLOSE_INT) {
842 			udf_vfsp->udf_clean = UDF_CLEAN;
843 		} else {
844 			/* Do we have a VAT at the end of the recorded media */
845 			map = udf_vfsp->udf_maps;
846 			for (i = 0; i < udf_vfsp->udf_nmaps; i++) {
847 				if (map->udm_flags & UDM_MAP_VPM) {
848 					break;
849 				}
850 				map++;
851 			}
852 			if (i == udf_vfsp->udf_nmaps) {
853 				error = ENOSPC;
854 				goto out;
855 			}
856 			udf_vfsp->udf_clean = UDF_CLEAN;
857 		}
858 	} else {
859 		/*
860 		 * We could read UDF1.50 and write UDF1.50 only
861 		 * disallow mount of any highier version
862 		 */
863 		if ((udf_vfsp->udf_miread > UDF_150) ||
864 		    (udf_vfsp->udf_miwrite > UDF_150)) {
865 			error = EINVAL;
866 			goto out;
867 		}
868 		/*
869 		 * Check if the media allows
870 		 * us to mount read/write
871 		 */
872 		if (udf_vfsp->udf_mtype != UDF_MT_OW) {
873 			error = EACCES;
874 			goto out;
875 		}
876 
877 		/*
878 		 * Check if we have VAT on a writable media
879 		 * we cannot use the media in presence of VAT
880 		 * Dent RW mount.
881 		 */
882 		map = udf_vfsp->udf_maps;
883 		ASSERT(map != NULL);
884 		for (i = 0; i < udf_vfsp->udf_nmaps; i++) {
885 			if (map->udm_flags & UDM_MAP_VPM) {
886 				error = EACCES;
887 				goto out;
888 			}
889 			map++;
890 		}
891 
892 		/*
893 		 * Check if the domain Id allows
894 		 * us to write
895 		 */
896 		if (udf_vfsp->udf_lvd->lvd_dom_id.reg_ids[2] & 0x3) {
897 			error = EACCES;
898 			goto out;
899 		}
900 		udf_vfsp->udf_flags = UDF_FL_RW;
901 
902 		if (SWAP_32(lvid->lvid_int_type) == LOG_VOL_CLOSE_INT) {
903 			udf_vfsp->udf_clean = UDF_CLEAN;
904 		} else {
905 			if (isroot) {
906 				udf_vfsp->udf_clean = UDF_DIRTY;
907 			} else {
908 				error = ENOSPC;
909 				goto out;
910 			}
911 		}
912 	}
913 
914 	mutex_init(&udf_vfsp->udf_lock, NULL, MUTEX_DEFAULT, NULL);
915 
916 	mutex_init(&udf_vfsp->udf_rename_lck, NULL, MUTEX_DEFAULT, NULL);
917 
918 #ifndef	__lint
919 	_NOTE(COMPETING_THREADS_NOW);
920 #endif
921 	if (error = ud_iget(vfsp, udf_vfsp->udf_ricb_prn,
922 	    udf_vfsp->udf_ricb_loc, &rip, NULL, cr)) {
923 		mutex_destroy(&udf_vfsp->udf_lock);
924 		goto out;
925 	}
926 
927 
928 	/*
929 	 * Get the root inode and
930 	 * initialize the root vnode
931 	 */
932 	rvp = ITOV(rip);
933 	mutex_enter(&rvp->v_lock);
934 	rvp->v_flag |= VROOT;
935 	mutex_exit(&rvp->v_lock);
936 	udf_vfsp->udf_root = rvp;
937 
938 
939 	if (why == ROOT_INIT && isroot)
940 		rootvp = devvp;
941 
942 	ud_vfs_add(udf_vfsp);
943 
944 	if (udf_vfsp->udf_flags == UDF_FL_RW) {
945 		udf_vfsp->udf_clean = UDF_DIRTY;
946 		ud_update_superblock(vfsp);
947 	}
948 
949 	return (0);
950 
951 out:
952 	ud_destroy_fsp(udf_vfsp);
953 	if (needclose) {
954 		(void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
955 		    FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
956 		bflush(dev);
957 		binval(dev);
958 	}
959 	VN_RELE(devvp);
960 
961 	return (error);
962 }
963 
964 
965 static struct udf_vfs *
966 ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
967 {
968 	int32_t error, count, index, shift;
969 	uint32_t dummy, vds_loc;
970 	caddr_t addr;
971 	daddr_t blkno, lblkno;
972 	struct buf *secbp, *bp;
973 	struct tag *ttag;
974 	struct anch_vol_desc_ptr *avdp;
975 	struct file_set_desc *fsd;
976 	struct udf_vfs *udf_vfsp = NULL;
977 	struct pmap_hdr *hdr;
978 	struct pmap_typ1 *typ1;
979 	struct pmap_typ2 *typ2;
980 	struct ud_map *map;
981 	int32_t	desc_len;
982 
983 	ud_printf("ud_validate_and_fill_superblock\n");
984 
985 	if (bsize < DEV_BSIZE) {
986 		return (NULL);
987 	}
988 	shift = 0;
989 	while ((bsize >> shift) > DEV_BSIZE) {
990 		shift++;
991 	}
992 
993 	/*
994 	 * Read Anchor Volume Descriptor
995 	 * Verify it and get the location of
996 	 * Main Volume Descriptor Sequence
997 	 */
998 	secbp = ud_bread(dev, avd_loc << shift, ANCHOR_VOL_DESC_LEN);
999 	if ((error = geterror(secbp)) != 0) {
1000 		cmn_err(CE_NOTE, "udfs : Could not read Anchor Volume Desc %x",
1001 		    error);
1002 		brelse(secbp);
1003 		return (NULL);
1004 	}
1005 	avdp = (struct anch_vol_desc_ptr *)secbp->b_un.b_addr;
1006 	if (ud_verify_tag_and_desc(&avdp->avd_tag, UD_ANCH_VOL_DESC,
1007 	    avd_loc, 1, ANCHOR_VOL_DESC_LEN) != 0) {
1008 		brelse(secbp);
1009 		return (NULL);
1010 	}
1011 	udf_vfsp = (struct udf_vfs *)
1012 	    kmem_zalloc(sizeof (struct udf_vfs), KM_SLEEP);
1013 	udf_vfsp->udf_mvds_loc = SWAP_32(avdp->avd_main_vdse.ext_loc);
1014 	udf_vfsp->udf_mvds_len = SWAP_32(avdp->avd_main_vdse.ext_len);
1015 	udf_vfsp->udf_rvds_loc = SWAP_32(avdp->avd_res_vdse.ext_loc);
1016 	udf_vfsp->udf_rvds_len = SWAP_32(avdp->avd_res_vdse.ext_len);
1017 	secbp->b_flags = B_AGE | B_STALE;
1018 	brelse(secbp);
1019 
1020 	/*
1021 	 * Read Main Volume Descriptor Sequence
1022 	 * and process it
1023 	 */
1024 	vds_loc = udf_vfsp->udf_mvds_loc;
1025 	secbp = ud_bread(dev, vds_loc << shift,
1026 	    udf_vfsp->udf_mvds_len);
1027 	if ((error = geterror(secbp)) != 0) {
1028 		brelse(secbp);
1029 		cmn_err(CE_NOTE, "udfs : Could not read Main Volume Desc %x",
1030 		    error);
1031 
1032 		vds_loc = udf_vfsp->udf_rvds_loc;
1033 		secbp = ud_bread(dev, vds_loc << shift,
1034 		    udf_vfsp->udf_rvds_len);
1035 		if ((error = geterror(secbp)) != 0) {
1036 			brelse(secbp);
1037 			cmn_err(CE_NOTE,
1038 			"udfs : Could not read Res Volume Desc %x", error);
1039 			return (NULL);
1040 		}
1041 	}
1042 
1043 	udf_vfsp->udf_vds = ngeteblk(udf_vfsp->udf_mvds_len);
1044 	bp = udf_vfsp->udf_vds;
1045 	bp->b_edev = dev;
1046 	bp->b_dev = cmpdev(dev);
1047 	bp->b_blkno = vds_loc << shift;
1048 	bp->b_bcount = udf_vfsp->udf_mvds_len;
1049 	bcopy(secbp->b_un.b_addr, bp->b_un.b_addr, udf_vfsp->udf_mvds_len);
1050 	secbp->b_flags |= B_STALE | B_AGE;
1051 	brelse(secbp);
1052 
1053 
1054 	count = udf_vfsp->udf_mvds_len / DEV_BSIZE;
1055 	addr = bp->b_un.b_addr;
1056 	for (index = 0; index < count; index ++) {
1057 		ttag = (struct tag *)(addr + index * DEV_BSIZE);
1058 		desc_len = udf_vfsp->udf_mvds_len - (index * DEV_BSIZE);
1059 		if (ud_verify_tag_and_desc(ttag, UD_PRI_VOL_DESC,
1060 		    vds_loc + (index >> shift),
1061 		    1, desc_len) == 0) {
1062 			if (udf_vfsp->udf_pvd == NULL) {
1063 				udf_vfsp->udf_pvd =
1064 				    (struct pri_vol_desc *)ttag;
1065 			} else {
1066 				struct pri_vol_desc *opvd, *npvd;
1067 
1068 				opvd = udf_vfsp->udf_pvd;
1069 				npvd = (struct pri_vol_desc *)ttag;
1070 
1071 				if ((strncmp(opvd->pvd_vsi,
1072 				    npvd->pvd_vsi, 128) == 0) &&
1073 				    (strncmp(opvd->pvd_vol_id,
1074 				    npvd->pvd_vol_id, 32) == 0) &&
1075 				    (strncmp((caddr_t)&opvd->pvd_desc_cs,
1076 				    (caddr_t)&npvd->pvd_desc_cs,
1077 				    sizeof (charspec_t)) == 0)) {
1078 
1079 					if (SWAP_32(opvd->pvd_vdsn) <
1080 					    SWAP_32(npvd->pvd_vdsn)) {
1081 						udf_vfsp->udf_pvd = npvd;
1082 					}
1083 				} else {
1084 					goto out;
1085 				}
1086 			}
1087 		} else if (ud_verify_tag_and_desc(ttag, UD_LOG_VOL_DESC,
1088 		    vds_loc + (index >> shift),
1089 		    1, desc_len) == 0) {
1090 			struct log_vol_desc *lvd;
1091 
1092 			lvd = (struct log_vol_desc *)ttag;
1093 			if (strncmp(lvd->lvd_dom_id.reg_id,
1094 			    UDF_DOMAIN_NAME, 23) != 0) {
1095 				printf("Domain ID in lvd is not valid\n");
1096 				goto out;
1097 			}
1098 
1099 			if (udf_vfsp->udf_lvd == NULL) {
1100 				udf_vfsp->udf_lvd = lvd;
1101 			} else {
1102 				struct log_vol_desc *olvd;
1103 
1104 				olvd = udf_vfsp->udf_lvd;
1105 				if ((strncmp((caddr_t)&olvd->lvd_desc_cs,
1106 				    (caddr_t)&lvd->lvd_desc_cs,
1107 				    sizeof (charspec_t)) == 0) &&
1108 				    (strncmp(olvd->lvd_lvid,
1109 				    lvd->lvd_lvid, 128) == 0)) {
1110 					if (SWAP_32(olvd->lvd_vdsn) <
1111 					    SWAP_32(lvd->lvd_vdsn)) {
1112 						udf_vfsp->udf_lvd = lvd;
1113 					}
1114 				} else {
1115 					goto out;
1116 				}
1117 			}
1118 		} else if (ud_verify_tag_and_desc(ttag, UD_PART_DESC,
1119 		    vds_loc + (index >> shift),
1120 		    1, desc_len) == 0) {
1121 			int32_t i;
1122 			struct phdr_desc *hdr;
1123 			struct part_desc *pdesc;
1124 			struct ud_part *pnew, *pold, *part;
1125 
1126 			pdesc = (struct part_desc *)ttag;
1127 			pold = udf_vfsp->udf_parts;
1128 			for (i = 0; i < udf_vfsp->udf_npart; i++) {
1129 				if (pold->udp_number !=
1130 				    SWAP_16(pdesc->pd_pnum)) {
1131 					pold++;
1132 					continue;
1133 				}
1134 
1135 				if (SWAP_32(pdesc->pd_vdsn) >
1136 				    pold->udp_seqno) {
1137 					pold->udp_seqno =
1138 					    SWAP_32(pdesc->pd_vdsn);
1139 					pold->udp_access =
1140 					    SWAP_32(pdesc->pd_acc_type);
1141 					pold->udp_start =
1142 					    SWAP_32(pdesc->pd_part_start);
1143 					pold->udp_length =
1144 					    SWAP_32(pdesc->pd_part_length);
1145 				}
1146 				goto loop_end;
1147 			}
1148 			pold = udf_vfsp->udf_parts;
1149 			udf_vfsp->udf_npart++;
1150 			pnew = kmem_zalloc(udf_vfsp->udf_npart *
1151 			    sizeof (struct ud_part), KM_SLEEP);
1152 			udf_vfsp->udf_parts = pnew;
1153 			if (pold) {
1154 				bcopy(pold, pnew,
1155 				    sizeof (struct ud_part) *
1156 				    (udf_vfsp->udf_npart - 1));
1157 				kmem_free(pold,
1158 				    sizeof (struct ud_part) *
1159 				    (udf_vfsp->udf_npart - 1));
1160 			}
1161 			part = pnew + (udf_vfsp->udf_npart - 1);
1162 			part->udp_number = SWAP_16(pdesc->pd_pnum);
1163 			part->udp_seqno = SWAP_32(pdesc->pd_vdsn);
1164 			part->udp_access = SWAP_32(pdesc->pd_acc_type);
1165 			part->udp_start = SWAP_32(pdesc->pd_part_start);
1166 			part->udp_length = SWAP_32(pdesc->pd_part_length);
1167 			part->udp_last_alloc = 0;
1168 
1169 			/*
1170 			 * Figure out space bitmaps
1171 			 * or space tables
1172 			 */
1173 			hdr = (struct phdr_desc *)pdesc->pd_pc_use;
1174 			if (hdr->phdr_ust.sad_ext_len) {
1175 				part->udp_flags = UDP_SPACETBLS;
1176 				part->udp_unall_loc =
1177 				    SWAP_32(hdr->phdr_ust.sad_ext_loc);
1178 				part->udp_unall_len =
1179 				    SWAP_32(hdr->phdr_ust.sad_ext_len);
1180 				part->udp_freed_loc =
1181 				    SWAP_32(hdr->phdr_fst.sad_ext_loc);
1182 				part->udp_freed_len =
1183 				    SWAP_32(hdr->phdr_fst.sad_ext_len);
1184 			} else {
1185 				part->udp_flags = UDP_BITMAPS;
1186 				part->udp_unall_loc =
1187 				    SWAP_32(hdr->phdr_usb.sad_ext_loc);
1188 				part->udp_unall_len =
1189 				    SWAP_32(hdr->phdr_usb.sad_ext_len);
1190 				part->udp_freed_loc =
1191 				    SWAP_32(hdr->phdr_fsb.sad_ext_loc);
1192 				part->udp_freed_len =
1193 				    SWAP_32(hdr->phdr_fsb.sad_ext_len);
1194 			}
1195 		} else if (ud_verify_tag_and_desc(ttag, UD_TERM_DESC,
1196 		    vds_loc + (index >> shift),
1197 		    1, desc_len) == 0) {
1198 
1199 			break;
1200 		}
1201 loop_end:
1202 		;
1203 	}
1204 	if ((udf_vfsp->udf_pvd == NULL) ||
1205 	    (udf_vfsp->udf_lvd == NULL) ||
1206 	    (udf_vfsp->udf_parts == NULL)) {
1207 		goto out;
1208 	}
1209 
1210 	/*
1211 	 * Process Primary Volume Descriptor
1212 	 */
1213 	(void) strncpy(udf_vfsp->udf_volid, udf_vfsp->udf_pvd->pvd_vol_id, 32);
1214 	udf_vfsp->udf_volid[31] = '\0';
1215 	udf_vfsp->udf_tsno = SWAP_16(udf_vfsp->udf_pvd->pvd_tag.tag_sno);
1216 
1217 	/*
1218 	 * Process Logical Volume Descriptor
1219 	 */
1220 	udf_vfsp->udf_lbsize =
1221 	    SWAP_32(udf_vfsp->udf_lvd->lvd_log_bsize);
1222 	udf_vfsp->udf_lbmask = udf_vfsp->udf_lbsize - 1;
1223 	udf_vfsp->udf_l2d_shift = shift;
1224 	udf_vfsp->udf_l2b_shift = shift + DEV_BSHIFT;
1225 
1226 	/*
1227 	 * Check if the media is in
1228 	 * proper domain.
1229 	 */
1230 	if (strcmp(udf_vfsp->udf_lvd->lvd_dom_id.reg_id,
1231 	    UDF_DOMAIN_NAME) != 0) {
1232 		goto out;
1233 	}
1234 
1235 	/*
1236 	 * AVDS offset does not match with the lbsize
1237 	 * in the lvd
1238 	 */
1239 	if (udf_vfsp->udf_lbsize != bsize) {
1240 		goto out;
1241 	}
1242 
1243 	udf_vfsp->udf_iseq_loc =
1244 	    SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_loc);
1245 	udf_vfsp->udf_iseq_len =
1246 	    SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_len);
1247 
1248 	udf_vfsp->udf_fsd_prn =
1249 	    SWAP_16(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_prn);
1250 	udf_vfsp->udf_fsd_loc =
1251 	    SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_loc);
1252 	udf_vfsp->udf_fsd_len =
1253 	    SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_len);
1254 
1255 
1256 	/*
1257 	 * process paritions
1258 	 */
1259 	udf_vfsp->udf_mtype = udf_vfsp->udf_parts[0].udp_access;
1260 	for (index = 0; index < udf_vfsp->udf_npart; index ++) {
1261 		if (udf_vfsp->udf_parts[index].udp_access <
1262 		    udf_vfsp->udf_mtype) {
1263 			udf_vfsp->udf_mtype =
1264 			    udf_vfsp->udf_parts[index].udp_access;
1265 		}
1266 	}
1267 	if ((udf_vfsp->udf_mtype < UDF_MT_RO) ||
1268 	    (udf_vfsp->udf_mtype > UDF_MT_OW)) {
1269 		udf_vfsp->udf_mtype = UDF_MT_RO;
1270 	}
1271 
1272 	udf_vfsp->udf_nmaps = 0;
1273 	hdr = (struct pmap_hdr *)udf_vfsp->udf_lvd->lvd_pmaps;
1274 	count = SWAP_32(udf_vfsp->udf_lvd->lvd_num_pmaps);
1275 	for (index = 0; index < count; index++) {
1276 
1277 		if ((hdr->maph_type == MAP_TYPE1) &&
1278 		    (hdr->maph_length == MAP_TYPE1_LEN)) {
1279 			typ1 = (struct pmap_typ1 *)hdr;
1280 
1281 			map = udf_vfsp->udf_maps;
1282 			udf_vfsp->udf_maps =
1283 			    kmem_zalloc(sizeof (struct ud_map) *
1284 			    (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
1285 			if (map != NULL) {
1286 				bcopy(map, udf_vfsp->udf_maps,
1287 				    sizeof (struct ud_map) *
1288 				    udf_vfsp->udf_nmaps);
1289 				kmem_free(map, sizeof (struct ud_map) *
1290 				    udf_vfsp->udf_nmaps);
1291 			}
1292 			map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
1293 			map->udm_flags = UDM_MAP_NORM;
1294 			map->udm_vsn = SWAP_16(typ1->map1_vsn);
1295 			map->udm_pn = SWAP_16(typ1->map1_pn);
1296 			udf_vfsp->udf_nmaps ++;
1297 		} else if ((hdr->maph_type == MAP_TYPE2) &&
1298 		    (hdr->maph_length == MAP_TYPE2_LEN)) {
1299 			typ2 = (struct pmap_typ2 *)hdr;
1300 
1301 			if (strncmp(typ2->map2_pti.reg_id,
1302 			    UDF_VIRT_PART, 23) == 0) {
1303 				/*
1304 				 * Add this to the normal
1305 				 * partition table so that
1306 				 * we donot
1307 				 */
1308 				map = udf_vfsp->udf_maps;
1309 				udf_vfsp->udf_maps =
1310 				    kmem_zalloc(sizeof (struct ud_map) *
1311 				    (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
1312 				if (map != NULL) {
1313 					bcopy(map, udf_vfsp->udf_maps,
1314 					    sizeof (struct ud_map) *
1315 					    udf_vfsp->udf_nmaps);
1316 					kmem_free(map,
1317 					    sizeof (struct ud_map) *
1318 					    udf_vfsp->udf_nmaps);
1319 				}
1320 				map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
1321 				map->udm_flags = UDM_MAP_VPM;
1322 				map->udm_vsn = SWAP_16(typ2->map2_vsn);
1323 				map->udm_pn = SWAP_16(typ2->map2_pn);
1324 				udf_vfsp->udf_nmaps ++;
1325 				if (error = ud_get_last_block(dev, &lblkno)) {
1326 					goto out;
1327 				}
1328 				if (error = ud_val_get_vat(udf_vfsp, dev,
1329 				    lblkno, map)) {
1330 					goto out;
1331 				}
1332 			} else if (strncmp(typ2->map2_pti.reg_id,
1333 			    UDF_SPAR_PART, 23) == 0) {
1334 
1335 				if (SWAP_16(typ2->map2_pl) != 32) {
1336 					printf(
1337 					    "Packet Length is not valid %x\n",
1338 					    SWAP_16(typ2->map2_pl));
1339 					goto out;
1340 				}
1341 				if ((typ2->map2_nst < 1) ||
1342 				    (typ2->map2_nst > 4)) {
1343 					goto out;
1344 				}
1345 				map = udf_vfsp->udf_maps;
1346 				udf_vfsp->udf_maps =
1347 				    kmem_zalloc(sizeof (struct ud_map) *
1348 				    (udf_vfsp->udf_nmaps + 1),
1349 				    KM_SLEEP);
1350 				if (map != NULL) {
1351 					bcopy(map, udf_vfsp->udf_maps,
1352 					    sizeof (struct ud_map) *
1353 					    udf_vfsp->udf_nmaps);
1354 					kmem_free(map,
1355 					    sizeof (struct ud_map) *
1356 					    udf_vfsp->udf_nmaps);
1357 				}
1358 				map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
1359 				map->udm_flags = UDM_MAP_SPM;
1360 				map->udm_vsn = SWAP_16(typ2->map2_vsn);
1361 				map->udm_pn = SWAP_16(typ2->map2_pn);
1362 
1363 				udf_vfsp->udf_nmaps ++;
1364 
1365 				if (error = ud_read_sparing_tbls(udf_vfsp,
1366 				    dev, map, typ2)) {
1367 					goto out;
1368 				}
1369 			} else {
1370 				/*
1371 				 * Unknown type of partition
1372 				 * Bail out
1373 				 */
1374 				goto out;
1375 			}
1376 		} else {
1377 			/*
1378 			 * Unknown type of partition
1379 			 * Bail out
1380 			 */
1381 			goto out;
1382 		}
1383 		hdr = (struct pmap_hdr *)(((uint8_t *)hdr) + hdr->maph_length);
1384 	}
1385 
1386 
1387 	/*
1388 	 * Read Logical Volume Integrity Sequence
1389 	 * and process it
1390 	 */
1391 	secbp = ud_bread(dev, udf_vfsp->udf_iseq_loc << shift,
1392 	    udf_vfsp->udf_iseq_len);
1393 	if ((error = geterror(secbp)) != 0) {
1394 		cmn_err(CE_NOTE,
1395 		"udfs : Could not read Logical Volume Integrity Sequence %x",
1396 		    error);
1397 		brelse(secbp);
1398 		goto out;
1399 	}
1400 	udf_vfsp->udf_iseq = ngeteblk(udf_vfsp->udf_iseq_len);
1401 	bp = udf_vfsp->udf_iseq;
1402 	bp->b_edev = dev;
1403 	bp->b_dev = cmpdev(dev);
1404 	bp->b_blkno = udf_vfsp->udf_iseq_loc << shift;
1405 	bp->b_bcount = udf_vfsp->udf_iseq_len;
1406 	bcopy(secbp->b_un.b_addr, bp->b_un.b_addr, udf_vfsp->udf_iseq_len);
1407 	secbp->b_flags |= B_STALE | B_AGE;
1408 	brelse(secbp);
1409 
1410 	count = udf_vfsp->udf_iseq_len / DEV_BSIZE;
1411 	addr = bp->b_un.b_addr;
1412 	for (index = 0; index < count; index ++) {
1413 		ttag = (struct tag *)(addr + index * DEV_BSIZE);
1414 		desc_len = udf_vfsp->udf_iseq_len - (index * DEV_BSIZE);
1415 		if (ud_verify_tag_and_desc(ttag, UD_LOG_VOL_INT,
1416 		    udf_vfsp->udf_iseq_loc + (index >> shift),
1417 		    1, desc_len) == 0) {
1418 
1419 			struct log_vol_int_desc *lvid;
1420 
1421 			lvid = (struct log_vol_int_desc *)ttag;
1422 			udf_vfsp->udf_lvid = lvid;
1423 
1424 			if (SWAP_32(lvid->lvid_int_type) == LOG_VOL_CLOSE_INT) {
1425 				udf_vfsp->udf_clean = UDF_CLEAN;
1426 			} else {
1427 				udf_vfsp->udf_clean = UDF_DIRTY;
1428 			}
1429 
1430 			/*
1431 			 * update superblock with the metadata
1432 			 */
1433 			ud_convert_to_superblock(udf_vfsp, lvid);
1434 			break;
1435 		}
1436 	}
1437 
1438 	if (udf_vfsp->udf_lvid == NULL) {
1439 		goto out;
1440 	}
1441 
1442 	if ((blkno = ud_xlate_to_daddr(udf_vfsp,
1443 	    udf_vfsp->udf_fsd_prn, udf_vfsp->udf_fsd_loc,
1444 	    1, &dummy)) == 0) {
1445 		goto out;
1446 	}
1447 	secbp = ud_bread(dev, blkno << shift, udf_vfsp->udf_fsd_len);
1448 	if ((error = geterror(secbp)) != 0) {
1449 		cmn_err(CE_NOTE,
1450 		"udfs : Could not read File Set Descriptor %x", error);
1451 		brelse(secbp);
1452 		goto out;
1453 	}
1454 	fsd = (struct file_set_desc *)secbp->b_un.b_addr;
1455 	if (ud_verify_tag_and_desc(&fsd->fsd_tag, UD_FILE_SET_DESC,
1456 	    udf_vfsp->udf_fsd_loc,
1457 	    1, udf_vfsp->udf_fsd_len) != 0) {
1458 		secbp->b_flags = B_AGE | B_STALE;
1459 		brelse(secbp);
1460 		goto out;
1461 	}
1462 	udf_vfsp->udf_ricb_prn = SWAP_16(fsd->fsd_root_icb.lad_ext_prn);
1463 	udf_vfsp->udf_ricb_loc = SWAP_32(fsd->fsd_root_icb.lad_ext_loc);
1464 	udf_vfsp->udf_ricb_len = SWAP_32(fsd->fsd_root_icb.lad_ext_len);
1465 	secbp->b_flags = B_AGE | B_STALE;
1466 	brelse(secbp);
1467 	udf_vfsp->udf_root_blkno = ud_xlate_to_daddr(udf_vfsp,
1468 	    udf_vfsp->udf_ricb_prn, udf_vfsp->udf_ricb_loc,
1469 	    1, &dummy);
1470 
1471 	return (udf_vfsp);
1472 out:
1473 	ud_destroy_fsp(udf_vfsp);
1474 
1475 	return (NULL);
1476 }
1477 
1478 /*
1479  * release/free resources from one ud_map; map data was zalloc'd in
1480  * ud_validate_and_fill_superblock() and fields may later point to
1481  * valid data
1482  */
1483 static void
1484 ud_free_map(struct ud_map *map)
1485 {
1486 	uint32_t n;
1487 
1488 	if (map->udm_flags & UDM_MAP_VPM) {
1489 		if (map->udm_count) {
1490 			kmem_free(map->udm_count,
1491 			    map->udm_nent * sizeof (*map->udm_count));
1492 			map->udm_count = NULL;
1493 		}
1494 		if (map->udm_bp) {
1495 			for (n = 0; n < map->udm_nent; n++) {
1496 				if (map->udm_bp[n])
1497 					brelse(map->udm_bp[n]);
1498 			}
1499 			kmem_free(map->udm_bp,
1500 			    map->udm_nent * sizeof (*map->udm_bp));
1501 			map->udm_bp = NULL;
1502 		}
1503 		if (map->udm_addr) {
1504 			kmem_free(map->udm_addr,
1505 			    map->udm_nent * sizeof (*map->udm_addr));
1506 			map->udm_addr = NULL;
1507 		}
1508 	}
1509 	if (map->udm_flags & UDM_MAP_SPM) {
1510 		for (n = 0; n < MAX_SPM; n++) {
1511 			if (map->udm_sbp[n]) {
1512 				brelse(map->udm_sbp[n]);
1513 				map->udm_sbp[n] = NULL;
1514 				map->udm_spaddr[n] = NULL;
1515 			}
1516 		}
1517 	}
1518 }
1519 
1520 void
1521 ud_destroy_fsp(struct udf_vfs *udf_vfsp)
1522 {
1523 	int32_t i;
1524 
1525 	ud_printf("ud_destroy_fsp\n");
1526 	if (udf_vfsp == NULL)
1527 		return;
1528 
1529 	if (udf_vfsp->udf_maps) {
1530 		for (i = 0; i < udf_vfsp->udf_nmaps; i++)
1531 			ud_free_map(&udf_vfsp->udf_maps[i]);
1532 
1533 		kmem_free(udf_vfsp->udf_maps,
1534 		    udf_vfsp->udf_nmaps * sizeof (*udf_vfsp->udf_maps));
1535 	}
1536 
1537 	if (udf_vfsp->udf_parts) {
1538 		kmem_free(udf_vfsp->udf_parts,
1539 		    udf_vfsp->udf_npart * sizeof (*udf_vfsp->udf_parts));
1540 	}
1541 	if (udf_vfsp->udf_iseq) {
1542 		udf_vfsp->udf_iseq->b_flags |= (B_STALE|B_AGE);
1543 		brelse(udf_vfsp->udf_iseq);
1544 	}
1545 	if (udf_vfsp->udf_vds) {
1546 		udf_vfsp->udf_vds->b_flags |= (B_STALE|B_AGE);
1547 		brelse(udf_vfsp->udf_vds);
1548 	}
1549 	if (udf_vfsp->udf_vfs)
1550 		ud_vfs_remove(udf_vfsp);
1551 	if (udf_vfsp->udf_fsmnt) {
1552 		kmem_free(udf_vfsp->udf_fsmnt,
1553 		    strlen(udf_vfsp->udf_fsmnt) + 1);
1554 	}
1555 	kmem_free(udf_vfsp, sizeof (*udf_vfsp));
1556 }
1557 
1558 void
1559 ud_convert_to_superblock(struct udf_vfs *udf_vfsp,
1560 	struct log_vol_int_desc *lvid)
1561 {
1562 	int32_t i, c;
1563 	uint32_t *temp;
1564 	struct ud_part *ud_part;
1565 	struct lvid_iu *iu;
1566 
1567 	udf_vfsp->udf_maxuniq = SWAP_64(lvid->lvid_uniqid);
1568 	temp = lvid->lvid_fst;
1569 	c = SWAP_32(lvid->lvid_npart);
1570 	ud_part = udf_vfsp->udf_parts;
1571 	for (i = 0; i < c; i++) {
1572 		if (i >= udf_vfsp->udf_npart) {
1573 			continue;
1574 		}
1575 		ud_part->udp_nfree =  SWAP_32(temp[i]);
1576 		ud_part->udp_nblocks =  SWAP_32(temp[c + i]);
1577 		udf_vfsp->udf_freeblks += SWAP_32(temp[i]);
1578 		udf_vfsp->udf_totalblks += SWAP_32(temp[c + i]);
1579 		ud_part++;
1580 	}
1581 
1582 	iu = (struct lvid_iu *)(temp + c * 2);
1583 	udf_vfsp->udf_nfiles = SWAP_32(iu->lvidiu_nfiles);
1584 	udf_vfsp->udf_ndirs = SWAP_32(iu->lvidiu_ndirs);
1585 	udf_vfsp->udf_miread = BCD2HEX_16(SWAP_16(iu->lvidiu_mread));
1586 	udf_vfsp->udf_miwrite = BCD2HEX_16(SWAP_16(iu->lvidiu_mwrite));
1587 	udf_vfsp->udf_mawrite = BCD2HEX_16(SWAP_16(iu->lvidiu_maxwr));
1588 }
1589 
1590 void
1591 ud_update_superblock(struct vfs *vfsp)
1592 {
1593 	struct udf_vfs *udf_vfsp;
1594 
1595 	ud_printf("ud_update_superblock\n");
1596 
1597 	udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
1598 
1599 	mutex_enter(&udf_vfsp->udf_lock);
1600 	ud_sbwrite(udf_vfsp);
1601 	mutex_exit(&udf_vfsp->udf_lock);
1602 }
1603 
1604 
1605 #include <sys/dkio.h>
1606 #include <sys/cdio.h>
1607 #include <sys/vtoc.h>
1608 
1609 /*
1610  * This part of the code is known
1611  * to work with only sparc. It needs
1612  * to be evluated before using it with x86
1613  */
1614 int32_t
1615 ud_get_last_block(dev_t dev, daddr_t *blkno)
1616 {
1617 	struct vtoc vtoc;
1618 	struct dk_cinfo dki_info;
1619 	int32_t rval, error;
1620 
1621 	if ((error = cdev_ioctl(dev, DKIOCGVTOC, (intptr_t)&vtoc,
1622 	    FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
1623 		cmn_err(CE_NOTE, "Could not get the vtoc information");
1624 		return (error);
1625 	}
1626 
1627 	if (vtoc.v_sanity != VTOC_SANE) {
1628 		return (EINVAL);
1629 	}
1630 	if ((error = cdev_ioctl(dev, DKIOCINFO, (intptr_t)&dki_info,
1631 	    FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
1632 		cmn_err(CE_NOTE, "Could not get the slice information");
1633 		return (error);
1634 	}
1635 
1636 	if (dki_info.dki_partition > V_NUMPAR) {
1637 		return (EINVAL);
1638 	}
1639 
1640 
1641 	*blkno = vtoc.v_part[dki_info.dki_partition].p_size;
1642 
1643 	return (0);
1644 }
1645 
1646 /* Search sequentially N - 2, N, N - 152, N - 150 for vat icb */
1647 /*
1648  * int32_t ud_sub_blks[] = {2, 0, 152, 150};
1649  */
1650 int32_t ud_sub_blks[] = {152, 150, 2, 0};
1651 int32_t ud_sub_count = 4;
1652 
1653 /*
1654  * Validate the VAT ICB
1655  */
1656 static int32_t
1657 ud_val_get_vat(struct udf_vfs *udf_vfsp, dev_t dev,
1658 	daddr_t blkno, struct ud_map *udm)
1659 {
1660 	struct buf *secbp;
1661 	struct file_entry *fe;
1662 	int32_t end_loc, i, j, ad_type;
1663 	struct short_ad *sad;
1664 	struct long_ad *lad;
1665 	uint32_t count, blk;
1666 	struct ud_part *ud_part;
1667 	int err = 0;
1668 
1669 	end_loc = (blkno >> udf_vfsp->udf_l2d_shift) - 1;
1670 
1671 	for (i = 0; i < ud_sub_count; i++) {
1672 		udm->udm_vat_icb = end_loc - ud_sub_blks[i];
1673 
1674 		secbp = ud_bread(dev,
1675 		    udm->udm_vat_icb << udf_vfsp->udf_l2d_shift,
1676 		    udf_vfsp->udf_lbsize);
1677 		ASSERT(secbp->b_un.b_addr);
1678 
1679 		fe = (struct file_entry *)secbp->b_un.b_addr;
1680 		if (ud_verify_tag_and_desc(&fe->fe_tag, UD_FILE_ENTRY, 0,
1681 		    0, 0) == 0) {
1682 			if (ud_verify_tag_and_desc(&fe->fe_tag, UD_FILE_ENTRY,
1683 			    SWAP_32(fe->fe_tag.tag_loc),
1684 			    1, udf_vfsp->udf_lbsize) == 0) {
1685 				if (fe->fe_icb_tag.itag_ftype == 0) {
1686 					break;
1687 				}
1688 			}
1689 		}
1690 		secbp->b_flags |= B_AGE | B_STALE;
1691 		brelse(secbp);
1692 	}
1693 	if (i == ud_sub_count) {
1694 		return (EINVAL);
1695 	}
1696 
1697 	ad_type = SWAP_16(fe->fe_icb_tag.itag_flags) & 0x3;
1698 	if (ad_type == ICB_FLAG_ONE_AD) {
1699 		udm->udm_nent = 1;
1700 	} else if (ad_type == ICB_FLAG_SHORT_AD) {
1701 		udm->udm_nent =
1702 		    SWAP_32(fe->fe_len_adesc) / sizeof (struct short_ad);
1703 	} else if (ad_type == ICB_FLAG_LONG_AD) {
1704 		udm->udm_nent =
1705 		    SWAP_32(fe->fe_len_adesc) / sizeof (struct long_ad);
1706 	} else {
1707 		err = EINVAL;
1708 		goto end;
1709 	}
1710 
1711 	udm->udm_count = kmem_zalloc(udm->udm_nent * sizeof (*udm->udm_count),
1712 	    KM_SLEEP);
1713 	udm->udm_bp = kmem_zalloc(udm->udm_nent * sizeof (*udm->udm_bp),
1714 	    KM_SLEEP);
1715 	udm->udm_addr = kmem_zalloc(udm->udm_nent * sizeof (*udm->udm_addr),
1716 	    KM_SLEEP);
1717 
1718 	if (ad_type == ICB_FLAG_ONE_AD) {
1719 			udm->udm_count[0] = (SWAP_64(fe->fe_info_len) - 36) /
1720 			    sizeof (uint32_t);
1721 			udm->udm_bp[0] = secbp;
1722 			udm->udm_addr[0] = (uint32_t *)
1723 			    &fe->fe_spec[SWAP_32(fe->fe_len_ear)];
1724 			return (0);
1725 	}
1726 	for (i = 0; i < udm->udm_nent; i++) {
1727 		if (ad_type == ICB_FLAG_SHORT_AD) {
1728 			sad = (struct short_ad *)
1729 			    (fe->fe_spec + SWAP_32(fe->fe_len_ear));
1730 			sad += i;
1731 			count = SWAP_32(sad->sad_ext_len);
1732 			blk = SWAP_32(sad->sad_ext_loc);
1733 		} else {
1734 			lad = (struct long_ad *)
1735 			    (fe->fe_spec + SWAP_32(fe->fe_len_ear));
1736 			lad += i;
1737 			count = SWAP_32(lad->lad_ext_len);
1738 			blk = SWAP_32(lad->lad_ext_loc);
1739 			ASSERT(SWAP_16(lad->lad_ext_prn) == udm->udm_pn);
1740 		}
1741 		if ((count & 0x3FFFFFFF) == 0) {
1742 			break;
1743 		}
1744 		if (i < udm->udm_nent - 1) {
1745 			udm->udm_count[i] = count / 4;
1746 		} else {
1747 			udm->udm_count[i] = (count - 36) / 4;
1748 		}
1749 		ud_part = udf_vfsp->udf_parts;
1750 		for (j = 0; j < udf_vfsp->udf_npart; j++) {
1751 			if (udm->udm_pn == ud_part->udp_number) {
1752 				blk = ud_part->udp_start + blk;
1753 				break;
1754 			}
1755 		}
1756 		if (j == udf_vfsp->udf_npart) {
1757 			err = EINVAL;
1758 			break;
1759 		}
1760 
1761 		count = (count + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
1762 		udm->udm_bp[i] = ud_bread(dev,
1763 		    blk << udf_vfsp->udf_l2d_shift, count);
1764 		if ((udm->udm_bp[i]->b_error != 0) ||
1765 		    (udm->udm_bp[i]->b_resid)) {
1766 			err = EINVAL;
1767 			break;
1768 		}
1769 		udm->udm_addr[i] = (uint32_t *)udm->udm_bp[i]->b_un.b_addr;
1770 	}
1771 
1772 end:
1773 	if (err)
1774 		ud_free_map(udm);
1775 	secbp->b_flags |= B_AGE | B_STALE;
1776 	brelse(secbp);
1777 	return (err);
1778 }
1779 
1780 int32_t
1781 ud_read_sparing_tbls(struct udf_vfs *udf_vfsp,
1782 	dev_t dev, struct ud_map *map, struct pmap_typ2 *typ2)
1783 {
1784 	int32_t index, valid = 0;
1785 	uint32_t sz;
1786 	struct buf *bp;
1787 	struct stbl *stbl;
1788 
1789 	map->udm_plen = SWAP_16(typ2->map2_pl);
1790 	map->udm_nspm = typ2->map2_nst;
1791 	map->udm_spsz = SWAP_32(typ2->map2_sest);
1792 	sz = (map->udm_spsz + udf_vfsp->udf_lbmask) & ~udf_vfsp->udf_lbmask;
1793 	if (sz == 0) {
1794 		return (0);
1795 	}
1796 
1797 	for (index = 0; index < map->udm_nspm; index++) {
1798 		map->udm_loc[index] = SWAP_32(typ2->map2_st[index]);
1799 
1800 		bp = ud_bread(dev,
1801 		    map->udm_loc[index] << udf_vfsp->udf_l2d_shift, sz);
1802 		if ((bp->b_error != 0) || (bp->b_resid)) {
1803 			brelse(bp);
1804 			continue;
1805 		}
1806 		stbl = (struct stbl *)bp->b_un.b_addr;
1807 		if (strncmp(stbl->stbl_si.reg_id, UDF_SPAR_TBL, 23) != 0) {
1808 			printf("Sparing Identifier does not match\n");
1809 			bp->b_flags |= B_AGE | B_STALE;
1810 			brelse(bp);
1811 			continue;
1812 		}
1813 		map->udm_sbp[index] = bp;
1814 		map->udm_spaddr[index] = bp->b_un.b_addr;
1815 #ifdef	UNDEF
1816 {
1817 	struct stbl_entry *te;
1818 	int32_t i, tbl_len;
1819 
1820 	te = (struct stbl_entry *)&stbl->stbl_entry;
1821 	tbl_len = SWAP_16(stbl->stbl_len);
1822 
1823 	printf("%x %x\n", tbl_len, SWAP_32(stbl->stbl_seqno));
1824 	printf("%x %x\n", bp->b_un.b_addr, te);
1825 
1826 	for (i = 0; i < tbl_len; i++) {
1827 		printf("%x %x\n", SWAP_32(te->sent_ol), SWAP_32(te->sent_ml));
1828 		te ++;
1829 	}
1830 }
1831 #endif
1832 		valid ++;
1833 	}
1834 
1835 	if (valid) {
1836 		return (0);
1837 	}
1838 	return (EINVAL);
1839 }
1840 
1841 uint32_t
1842 ud_get_lbsize(dev_t dev, uint32_t *loc)
1843 {
1844 	int32_t bsize, shift, index, end_index;
1845 	daddr_t last_block;
1846 	uint32_t avd_loc;
1847 	struct buf *bp;
1848 	struct anch_vol_desc_ptr *avdp;
1849 	uint32_t session_offset = 0;
1850 	int32_t rval;
1851 
1852 	if (ud_get_last_block(dev, &last_block) != 0) {
1853 		end_index = 1;
1854 	} else {
1855 		end_index = 3;
1856 	}
1857 
1858 	if (cdev_ioctl(dev, CDROMREADOFFSET, (intptr_t)&session_offset,
1859 	    FKIOCTL|FREAD|FNATIVE, CRED(), &rval) != 0) {
1860 		session_offset = 0;
1861 	}
1862 
1863 	for (index = 0; index < end_index; index++) {
1864 
1865 		for (bsize = DEV_BSIZE, shift = 0;
1866 		    bsize <= MAXBSIZE; bsize <<= 1, shift++) {
1867 
1868 			if (index == 0) {
1869 				avd_loc = 256;
1870 				if (bsize <= 2048) {
1871 					avd_loc +=
1872 					    session_offset * 2048 / bsize;
1873 				} else {
1874 					avd_loc +=
1875 					    session_offset / (bsize / 2048);
1876 				}
1877 			} else if (index == 1) {
1878 				avd_loc = last_block - (1 << shift);
1879 			} else {
1880 				avd_loc = last_block - (256 << shift);
1881 			}
1882 
1883 			bp = ud_bread(dev, avd_loc << shift,
1884 			    ANCHOR_VOL_DESC_LEN);
1885 			if (geterror(bp) != 0) {
1886 				brelse(bp);
1887 				continue;
1888 			}
1889 
1890 			/*
1891 			 * Verify if we have avdp here
1892 			 */
1893 			avdp = (struct anch_vol_desc_ptr *)bp->b_un.b_addr;
1894 			if (ud_verify_tag_and_desc(&avdp->avd_tag,
1895 			    UD_ANCH_VOL_DESC, avd_loc,
1896 			    1, ANCHOR_VOL_DESC_LEN) != 0) {
1897 				bp->b_flags |= B_AGE | B_STALE;
1898 				brelse(bp);
1899 				continue;
1900 			}
1901 			bp->b_flags |= B_AGE | B_STALE;
1902 			brelse(bp);
1903 			*loc = avd_loc;
1904 			return (bsize);
1905 		}
1906 	}
1907 
1908 	/*
1909 	 * Did not find AVD at all the locations
1910 	 */
1911 	return (0);
1912 }
1913 
1914 static int
1915 udfinit(int fstype, char *name)
1916 {
1917 	static const fs_operation_def_t udf_vfsops_template[] = {
1918 		VFSNAME_MOUNT,		{ .vfs_mount = udf_mount },
1919 		VFSNAME_UNMOUNT,	{ .vfs_unmount = udf_unmount },
1920 		VFSNAME_ROOT,		{ .vfs_root = udf_root },
1921 		VFSNAME_STATVFS,	{ .vfs_statvfs = udf_statvfs },
1922 		VFSNAME_SYNC,		{ .vfs_sync = udf_sync },
1923 		VFSNAME_VGET,		{ .vfs_vget = udf_vget },
1924 		VFSNAME_MOUNTROOT,	{ .vfs_mountroot = udf_mountroot },
1925 		NULL,			NULL
1926 	};
1927 	extern struct vnodeops *udf_vnodeops;
1928 	extern const fs_operation_def_t udf_vnodeops_template[];
1929 	int error;
1930 
1931 	ud_printf("udfinit\n");
1932 
1933 	error = vfs_setfsops(fstype, udf_vfsops_template, NULL);
1934 	if (error != 0) {
1935 		cmn_err(CE_WARN, "udfinit: bad vfs ops template");
1936 		return (error);
1937 	}
1938 
1939 	error = vn_make_ops(name, udf_vnodeops_template, &udf_vnodeops);
1940 	if (error != 0) {
1941 		(void) vfs_freevfsops_by_type(fstype);
1942 		cmn_err(CE_WARN, "udfinit: bad vnode ops template");
1943 		return (error);
1944 	}
1945 
1946 	udf_fstype = fstype;
1947 
1948 	ud_init_inodes();
1949 
1950 	return (0);
1951 }
1952