remove unnecessary uint_t casts of 0
[unleashed.git] / kernel / fs / udfs / udf_vfsops.c
blob2c99f8a58f911b27121e5936472dea27554ad99c
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
27 #include <sys/types.h>
28 #include <sys/t_lock.h>
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/systm.h>
32 #include <sys/sysmacros.h>
33 #include <sys/resource.h>
34 #include <sys/signal.h>
35 #include <sys/cred.h>
36 #include <sys/user.h>
37 #include <sys/buf.h>
38 #include <sys/vfs.h>
39 #include <sys/stat.h>
40 #include <sys/vnode.h>
41 #include <sys/mode.h>
42 #include <sys/proc.h>
43 #include <sys/disp.h>
44 #include <sys/file.h>
45 #include <sys/fcntl.h>
46 #include <sys/flock.h>
47 #include <sys/kmem.h>
48 #include <sys/uio.h>
49 #include <sys/dnlc.h>
50 #include <sys/conf.h>
51 #include <sys/errno.h>
52 #include <sys/mman.h>
53 #include <sys/fbuf.h>
54 #include <sys/pathname.h>
55 #include <sys/debug.h>
56 #include <sys/vmsystm.h>
57 #include <sys/cmn_err.h>
58 #include <sys/dirent.h>
59 #include <sys/errno.h>
60 #include <sys/modctl.h>
61 #include <sys/statvfs.h>
62 #include <sys/mount.h>
63 #include <sys/sunddi.h>
64 #include <sys/bootconf.h>
65 #include <sys/policy.h>
67 #include <vm/hat.h>
68 #include <vm/page.h>
69 #include <vm/pvn.h>
70 #include <vm/as.h>
71 #include <vm/seg.h>
72 #include <vm/seg_map.h>
73 #include <vm/seg_kmem.h>
74 #include <vm/seg_vn.h>
75 #include <vm/rm.h>
76 #include <vm/page.h>
77 #include <sys/swap.h>
78 #include <sys/mntent.h>
81 #include <sys/fs_subr.h>
84 #include <sys/fs/udf_volume.h>
85 #include <sys/fs/udf_inode.h>
88 extern struct vnode *common_specvp(struct vnode *vp);
90 extern kmutex_t ud_sync_busy;
91 static int32_t ud_mountfs(struct vfs *,
92 enum whymountroot, dev_t, char *, struct cred *, int32_t);
93 static struct udf_vfs *ud_validate_and_fill_superblock(dev_t,
94 int32_t, uint32_t);
95 void ud_destroy_fsp(struct udf_vfs *);
96 void ud_convert_to_superblock(struct udf_vfs *,
97 struct log_vol_int_desc *);
98 void ud_update_superblock(struct vfs *);
99 int32_t ud_get_last_block(dev_t, daddr_t *);
100 static int32_t ud_val_get_vat(struct udf_vfs *,
101 dev_t, daddr_t, struct ud_map *);
102 int32_t ud_read_sparing_tbls(struct udf_vfs *,
103 dev_t, struct ud_map *, struct pmap_typ2 *);
104 uint32_t ud_get_lbsize(dev_t, uint32_t *);
106 static int32_t udf_mount(struct vfs *,
107 struct vnode *, struct mounta *, struct cred *);
108 static int32_t udf_unmount(struct vfs *, int, struct cred *);
109 static int32_t udf_root(struct vfs *, struct vnode **);
110 static int32_t udf_statvfs(struct vfs *, struct statvfs64 *);
111 static int32_t udf_sync(struct vfs *, int16_t, struct cred *);
112 static int32_t udf_vget(struct vfs *, struct vnode **, struct fid *);
113 static int32_t udf_mountroot(struct vfs *vfsp, enum whymountroot);
115 static int udfinit(int, char *);
117 static mntopts_t udfs_mntopts;
119 static vfsdef_t vfw = {
120 VFSDEF_VERSION,
121 "udfs",
122 udfinit,
123 VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_CANLOFI,
124 &udfs_mntopts
127 static mntopts_t udfs_mntopts = {
129 NULL
133 * Module linkage information for the kernel.
135 extern struct mod_ops mod_fsops;
137 static struct modlfs modlfs = {
138 &mod_fsops, "filesystem for UDFS", &vfw
141 static struct modlinkage modlinkage = {
142 MODREV_1, (void *)&modlfs, NULL
145 int32_t udf_fstype = -1;
148 _init()
150 return (mod_install(&modlinkage));
154 _fini()
156 return (EBUSY);
160 _info(struct modinfo *modinfop)
162 return (mod_info(&modlinkage, modinfop));
166 /* -------------------- vfs routines -------------------- */
169 * XXX - this appears only to be used by the VM code to handle the case where
170 * UNIX is running off the mini-root. That probably wants to be done
171 * differently.
173 struct vnode *rootvp;
174 _NOTE(SCHEME_PROTECTS_DATA("safe sharing", rootvp))
175 static int32_t
176 udf_mount(struct vfs *vfsp, struct vnode *mvp,
177 struct mounta *uap, struct cred *cr)
179 dev_t dev;
180 struct vnode *lvp = NULL;
181 struct vnode *svp = NULL;
182 struct pathname dpn;
183 int32_t error;
184 enum whymountroot why;
185 int oflag, aflag;
187 ud_printf("udf_mount\n");
189 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) {
190 return (error);
193 if (mvp->v_type != VDIR) {
194 return (ENOTDIR);
197 mutex_enter(&mvp->v_lock);
198 if ((uap->flags & MS_REMOUNT) == 0 &&
199 (uap->flags & MS_OVERLAY) == 0 &&
200 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
201 mutex_exit(&mvp->v_lock);
202 return (EBUSY);
204 mutex_exit(&mvp->v_lock);
206 if (error = pn_get(uap->dir, UIO_USERSPACE, &dpn)) {
207 return (error);
211 * Resolve path name of the file being mounted.
213 if (error = lookupname(uap->spec, UIO_USERSPACE, FOLLOW, NULLVPP,
214 &svp)) {
215 pn_free(&dpn);
216 return (error);
219 error = vfs_get_lofi(vfsp, &lvp);
221 if (error > 0) {
222 if (error == ENOENT)
223 error = ENODEV;
224 goto out;
225 } else if (error == 0) {
226 dev = lvp->v_rdev;
227 } else {
228 dev = svp->v_rdev;
230 if (svp->v_type != VBLK) {
231 error = ENOTBLK;
232 goto out;
237 * Ensure that this device isn't already mounted,
238 * unless this is a REMOUNT request
240 if (vfs_devmounting(dev, vfsp)) {
241 error = EBUSY;
242 goto out;
244 if (vfs_devismounted(dev)) {
245 if (uap->flags & MS_REMOUNT) {
246 why = ROOT_REMOUNT;
247 } else {
248 error = EBUSY;
249 goto out;
251 } else {
252 why = ROOT_INIT;
254 if (getmajor(dev) >= devcnt) {
255 error = ENXIO;
256 goto out;
260 * If the device is a tape, mount it read only
262 if (devopsp[getmajor(dev)]->devo_cb_ops->cb_flag & D_TAPE) {
263 vfsp->vfs_flag |= VFS_RDONLY;
266 if (uap->flags & MS_RDONLY) {
267 vfsp->vfs_flag |= VFS_RDONLY;
271 * Set mount options.
273 if (uap->flags & MS_RDONLY) {
274 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
276 if (uap->flags & MS_NOSUID) {
277 vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
281 * Verify that the caller can open the device special file as
282 * required. It is not until this moment that we know whether
283 * we're mounting "ro" or not.
285 if ((vfsp->vfs_flag & VFS_RDONLY) != 0) {
286 oflag = FREAD;
287 aflag = VREAD;
288 } else {
289 oflag = FREAD | FWRITE;
290 aflag = VREAD | VWRITE;
293 if (lvp == NULL &&
294 (error = secpolicy_spec_open(cr, svp, oflag)) != 0)
295 goto out;
297 if ((error = fop_access(svp, aflag, 0, cr, NULL)) != 0)
298 goto out;
301 * Mount the filesystem.
303 error = ud_mountfs(vfsp, why, dev, dpn.pn_path, cr, 0);
304 out:
305 VN_RELE(svp);
306 if (lvp != NULL)
307 VN_RELE(lvp);
308 pn_free(&dpn);
309 return (error);
315 * unmount the file system pointed
316 * by vfsp
318 /* ARGSUSED */
319 static int32_t
320 udf_unmount(struct vfs *vfsp, int fflag, struct cred *cr)
322 struct udf_vfs *udf_vfsp;
323 struct vnode *bvp, *rvp;
324 struct ud_inode *rip;
325 int32_t flag;
327 ud_printf("udf_unmount\n");
329 if (secpolicy_fs_unmount(cr, vfsp) != 0) {
330 return (EPERM);
334 * forced unmount is not supported by this file system
335 * and thus, ENOTSUP, is being returned.
337 if (fflag & MS_FORCE)
338 return (ENOTSUP);
340 udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
341 flag = !(udf_vfsp->udf_flags & UDF_FL_RDONLY);
342 bvp = udf_vfsp->udf_devvp;
344 rvp = udf_vfsp->udf_root;
345 ASSERT(rvp != NULL);
346 rip = VTOI(rvp);
348 (void) ud_release_cache(udf_vfsp);
351 /* Flush all inodes except root */
352 if (ud_iflush(vfsp) < 0) {
353 return (EBUSY);
356 rw_enter(&rip->i_contents, RW_WRITER);
357 (void) ud_syncip(rip, B_INVAL, I_SYNC);
358 rw_exit(&rip->i_contents);
360 mutex_enter(&ud_sync_busy);
361 if ((udf_vfsp->udf_flags & UDF_FL_RDONLY) == 0) {
362 bflush(vfsp->vfs_dev);
363 mutex_enter(&udf_vfsp->udf_lock);
364 udf_vfsp->udf_clean = UDF_CLEAN;
365 mutex_exit(&udf_vfsp->udf_lock);
366 ud_update_superblock(vfsp);
368 mutex_exit(&ud_sync_busy);
370 mutex_destroy(&udf_vfsp->udf_lock);
371 mutex_destroy(&udf_vfsp->udf_rename_lck);
373 ud_delcache(rip);
374 ITIMES(rip);
375 VN_RELE(rvp);
377 ud_destroy_fsp(udf_vfsp);
379 (void) fop_putpage(bvp, 0, (uint32_t)0, B_INVAL, cr, NULL);
380 (void) fop_close(bvp, flag, 1, 0, cr, NULL);
382 (void) bfinval(vfsp->vfs_dev, 1);
383 VN_RELE(bvp);
386 return (0);
391 * Get the root vp for the
392 * file system
394 static int32_t
395 udf_root(struct vfs *vfsp, struct vnode **vpp)
397 struct udf_vfs *udf_vfsp;
398 struct vnode *vp;
400 ud_printf("udf_root\n");
402 udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
404 ASSERT(udf_vfsp != NULL);
405 ASSERT(udf_vfsp->udf_root != NULL);
407 vp = udf_vfsp->udf_root;
408 VN_HOLD(vp);
409 *vpp = vp;
410 return (0);
415 * Get file system statistics.
417 static int32_t
418 udf_statvfs(struct vfs *vfsp, struct statvfs64 *sp)
420 struct udf_vfs *udf_vfsp;
421 struct ud_part *parts;
422 dev32_t d32;
423 int32_t index;
425 ud_printf("udf_statvfs\n");
427 udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
428 (void) bzero(sp, sizeof (struct statvfs64));
430 mutex_enter(&udf_vfsp->udf_lock);
431 sp->f_bsize = udf_vfsp->udf_lbsize;
432 sp->f_frsize = udf_vfsp->udf_lbsize;
433 sp->f_blocks = 0;
434 sp->f_bfree = 0;
435 parts = udf_vfsp->udf_parts;
436 for (index = 0; index < udf_vfsp->udf_npart; index++) {
437 sp->f_blocks += parts->udp_nblocks;
438 sp->f_bfree += parts->udp_nfree;
439 parts++;
441 sp->f_bavail = sp->f_bfree;
444 * Since there are no real inodes allocated
445 * we will approximate
446 * each new file will occupy :
447 * 38(over head each dent) + MAXNAMLEN / 2 + inode_size(==block size)
449 sp->f_ffree = sp->f_favail =
450 (sp->f_bavail * sp->f_bsize) / (146 + sp->f_bsize);
453 * The total number of inodes is
454 * the sum of files + directories + free inodes
456 sp->f_files = sp->f_ffree + udf_vfsp->udf_nfiles + udf_vfsp->udf_ndirs;
457 (void) cmpldev(&d32, vfsp->vfs_dev);
458 sp->f_fsid = d32;
459 (void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
460 sp->f_flag = vf_to_stf(vfsp->vfs_flag);
461 sp->f_namemax = MAXNAMLEN;
462 (void) strcpy(sp->f_fstr, udf_vfsp->udf_volid);
464 mutex_exit(&udf_vfsp->udf_lock);
466 return (0);
471 * Flush any pending I/O to file system vfsp.
472 * The ud_update() routine will only flush *all* udf files.
474 /*ARGSUSED*/
475 /* ARGSUSED */
476 static int32_t
477 udf_sync(struct vfs *vfsp, int16_t flag, struct cred *cr)
479 ud_printf("udf_sync\n");
481 ud_update(flag);
482 return (0);
487 /* ARGSUSED */
488 static int32_t
489 udf_vget(struct vfs *vfsp,
490 struct vnode **vpp, struct fid *fidp)
492 int32_t error = 0;
493 struct udf_fid *udfid;
494 struct udf_vfs *udf_vfsp;
495 struct ud_inode *ip;
497 ud_printf("udf_vget\n");
499 udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
500 if (udf_vfsp == NULL) {
501 *vpp = NULL;
502 return (0);
505 udfid = (struct udf_fid *)fidp;
506 if ((error = ud_iget(vfsp, udfid->udfid_prn,
507 udfid->udfid_icb_lbn, &ip, NULL, CRED())) != 0) {
508 *vpp = NULL;
509 return (error);
512 rw_enter(&ip->i_contents, RW_READER);
513 if ((udfid->udfid_uinq_lo != (ip->i_uniqid & 0xffffffff)) ||
514 (udfid->udfid_prn != ip->i_icb_prn)) {
515 rw_exit(&ip->i_contents);
516 VN_RELE(ITOV(ip));
517 *vpp = NULL;
518 return (EINVAL);
520 rw_exit(&ip->i_contents);
522 *vpp = ITOV(ip);
523 return (0);
528 * Mount root file system.
529 * "why" is ROOT_INIT on initial call, ROOT_REMOUNT if called to
530 * remount the root file system, and ROOT_UNMOUNT if called to
531 * unmount the root (e.g., as part of a system shutdown).
533 * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
534 * operation, goes along with auto-configuration. A mechanism should be
535 * provided by which machine-INdependent code in the kernel can say "get me the
536 * right root file system" and "get me the right initial swap area", and have
537 * that done in what may well be a machine-dependent fashion.
538 * Unfortunately, it is also file-system-type dependent (NFS gets it via
539 * bootparams calls, UFS gets it from various and sundry machine-dependent
540 * mechanisms, as SPECFS does for swap).
542 /* ARGSUSED */
543 static int32_t
544 udf_mountroot(struct vfs *vfsp, enum whymountroot why)
546 dev_t rootdev;
547 static int32_t udf_rootdone = 0;
548 struct vnode *vp = NULL;
549 int32_t ovflags, error;
550 ud_printf("udf_mountroot\n");
552 if (why == ROOT_INIT) {
553 if (udf_rootdone++) {
554 return (EBUSY);
556 rootdev = getrootdev();
557 if (rootdev == (dev_t)NODEV) {
558 return (ENODEV);
560 vfsp->vfs_dev = rootdev;
561 vfsp->vfs_flag |= VFS_RDONLY;
562 } else if (why == ROOT_REMOUNT) {
563 vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
564 (void) dnlc_purge_vfsp(vfsp, 0);
565 vp = common_specvp(vp);
566 (void) fop_putpage(vp, 0,
567 (uint32_t)0, B_INVAL, CRED(), NULL);
568 binval(vfsp->vfs_dev);
570 ovflags = vfsp->vfs_flag;
571 vfsp->vfs_flag &= ~VFS_RDONLY;
572 vfsp->vfs_flag |= VFS_REMOUNT;
573 rootdev = vfsp->vfs_dev;
574 } else if (why == ROOT_UNMOUNT) {
575 ud_update(0);
576 vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
577 (void) fop_close(vp, FREAD|FWRITE, 1,
578 0, CRED(), NULL);
579 return (0);
582 if ((error = vfs_lock(vfsp)) != 0) {
583 return (error);
586 error = ud_mountfs(vfsp, why, rootdev, "/", CRED(), 1);
587 if (error) {
588 vfs_unlock(vfsp);
589 if (why == ROOT_REMOUNT) {
590 vfsp->vfs_flag = ovflags;
592 if (rootvp) {
593 VN_RELE(rootvp);
594 rootvp = NULL;
596 return (error);
599 if (why == ROOT_INIT) {
600 vfs_add(NULL, vfsp,
601 (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0);
603 vfs_unlock(vfsp);
604 return (0);
608 /* ------------------------- local routines ------------------------- */
611 static int32_t
612 ud_mountfs(struct vfs *vfsp,
613 enum whymountroot why, dev_t dev, char *name,
614 struct cred *cr, int32_t isroot)
616 struct vnode *devvp = NULL;
617 int32_t error = 0;
618 int32_t needclose = 0;
619 struct udf_vfs *udf_vfsp = NULL;
620 struct log_vol_int_desc *lvid;
621 struct ud_inode *rip = NULL;
622 struct vnode *rvp = NULL;
623 int32_t i, lbsize;
624 uint32_t avd_loc;
625 struct ud_map *map;
626 int32_t desc_len;
628 ud_printf("ud_mountfs\n");
630 if (why == ROOT_INIT) {
632 * Open the device.
634 devvp = makespecvp(dev, VBLK);
637 * Open block device mounted on.
638 * When bio is fixed for vnodes this can all be vnode
639 * operations.
641 error = fop_open(&devvp,
642 (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE,
643 cr, NULL);
644 if (error) {
645 goto out;
647 needclose = 1;
650 * Refuse to go any further if this
651 * device is being used for swapping.
653 if (IS_SWAPVP(devvp)) {
654 error = EBUSY;
655 goto out;
660 * check for dev already mounted on
662 if (vfsp->vfs_flag & VFS_REMOUNT) {
663 struct tag *ttag;
664 int32_t index, count;
665 struct buf *tpt = 0;
666 caddr_t addr;
669 /* cannot remount to RDONLY */
670 if (vfsp->vfs_flag & VFS_RDONLY) {
671 return (EINVAL);
674 if (vfsp->vfs_dev != dev) {
675 return (EINVAL);
678 udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
679 devvp = udf_vfsp->udf_devvp;
682 * fsck may have altered the file system; discard
683 * as much incore data as possible. Don't flush
684 * if this is a rw to rw remount; it's just resetting
685 * the options.
687 if (udf_vfsp->udf_flags & UDF_FL_RDONLY) {
688 (void) dnlc_purge_vfsp(vfsp, 0);
689 (void) fop_putpage(devvp, 0, 0,
690 B_INVAL, CRED(), NULL);
691 (void) ud_iflush(vfsp);
692 bflush(dev);
693 binval(dev);
697 * We could read UDF1.50 and write UDF1.50 only
698 * disallow mount of any highier version
700 if ((udf_vfsp->udf_miread > UDF_150) ||
701 (udf_vfsp->udf_miwrite > UDF_150)) {
702 error = EINVAL;
703 goto remountout;
707 * read/write to read/write; all done
709 if (udf_vfsp->udf_flags & UDF_FL_RW) {
710 goto remountout;
714 * Does the media type allow a writable mount
716 if (udf_vfsp->udf_mtype != UDF_MT_OW) {
717 error = EINVAL;
718 goto remountout;
722 * Read the metadata
723 * and check if it is possible to
724 * mount in rw mode
726 tpt = ud_bread(vfsp->vfs_dev,
727 udf_vfsp->udf_iseq_loc << udf_vfsp->udf_l2d_shift,
728 udf_vfsp->udf_iseq_len);
729 if (tpt->b_flags & B_ERROR) {
730 error = EIO;
731 goto remountout;
733 count = udf_vfsp->udf_iseq_len / DEV_BSIZE;
734 addr = tpt->b_un.b_addr;
735 for (index = 0; index < count; index ++) {
736 ttag = (struct tag *)(addr + index * DEV_BSIZE);
737 desc_len = udf_vfsp->udf_iseq_len - (index * DEV_BSIZE);
738 if (ud_verify_tag_and_desc(ttag, UD_LOG_VOL_INT,
739 udf_vfsp->udf_iseq_loc +
740 (index >> udf_vfsp->udf_l2d_shift),
741 1, desc_len) == 0) {
742 struct log_vol_int_desc *lvid;
744 lvid = (struct log_vol_int_desc *)ttag;
746 if (SWAP_32(lvid->lvid_int_type) !=
747 LOG_VOL_CLOSE_INT) {
748 error = EINVAL;
749 goto remountout;
753 * Copy new data to old data
755 bcopy(udf_vfsp->udf_iseq->b_un.b_addr,
756 tpt->b_un.b_addr, udf_vfsp->udf_iseq_len);
757 break;
761 udf_vfsp->udf_flags = UDF_FL_RW;
763 mutex_enter(&udf_vfsp->udf_lock);
764 ud_sbwrite(udf_vfsp);
765 mutex_exit(&udf_vfsp->udf_lock);
766 remountout:
767 if (tpt != NULL) {
768 tpt->b_flags = B_AGE | B_STALE;
769 brelse(tpt);
771 return (error);
774 ASSERT(devvp != 0);
776 * Flush back any dirty pages on the block device to
777 * try and keep the buffer cache in sync with the page
778 * cache if someone is trying to use block devices when
779 * they really should be using the raw device.
781 (void) fop_putpage(common_specvp(devvp), 0,
782 (uint32_t)0, B_INVAL, cr, NULL);
786 * Check if the file system
787 * is a valid udfs and fill
788 * the required fields in udf_vfs
790 _NOTE(NO_COMPETING_THREADS_NOW);
792 if ((lbsize = ud_get_lbsize(dev, &avd_loc)) == 0) {
793 error = EINVAL;
794 goto out;
797 udf_vfsp = ud_validate_and_fill_superblock(dev, lbsize, avd_loc);
798 if (udf_vfsp == NULL) {
799 error = EINVAL;
800 goto out;
804 * Fill in vfs private data
806 vfsp->vfs_fstype = udf_fstype;
807 vfs_make_fsid(&vfsp->vfs_fsid, dev, udf_fstype);
808 vfsp->vfs_data = (caddr_t)udf_vfsp;
809 vfsp->vfs_dev = dev;
810 vfsp->vfs_flag |= VFS_NOTRUNC;
811 udf_vfsp->udf_devvp = devvp;
813 udf_vfsp->udf_fsmnt = kmem_zalloc(strlen(name) + 1, KM_SLEEP);
814 (void) strcpy(udf_vfsp->udf_fsmnt, name);
816 udf_vfsp->udf_vfs = vfsp;
817 udf_vfsp->udf_rdclustsz = udf_vfsp->udf_wrclustsz = maxphys;
819 udf_vfsp->udf_mod = 0;
822 lvid = udf_vfsp->udf_lvid;
823 if (vfsp->vfs_flag & VFS_RDONLY) {
825 * We could read only UDF1.50
826 * disallow mount of any highier version
828 if (udf_vfsp->udf_miread > UDF_150) {
829 error = EINVAL;
830 goto out;
832 udf_vfsp->udf_flags = UDF_FL_RDONLY;
833 if (SWAP_32(lvid->lvid_int_type) == LOG_VOL_CLOSE_INT) {
834 udf_vfsp->udf_clean = UDF_CLEAN;
835 } else {
836 /* Do we have a VAT at the end of the recorded media */
837 map = udf_vfsp->udf_maps;
838 for (i = 0; i < udf_vfsp->udf_nmaps; i++) {
839 if (map->udm_flags & UDM_MAP_VPM) {
840 break;
842 map++;
844 if (i == udf_vfsp->udf_nmaps) {
845 error = ENOSPC;
846 goto out;
848 udf_vfsp->udf_clean = UDF_CLEAN;
850 } else {
852 * We could read UDF1.50 and write UDF1.50 only
853 * disallow mount of any highier version
855 if ((udf_vfsp->udf_miread > UDF_150) ||
856 (udf_vfsp->udf_miwrite > UDF_150)) {
857 error = EINVAL;
858 goto out;
861 * Check if the media allows
862 * us to mount read/write
864 if (udf_vfsp->udf_mtype != UDF_MT_OW) {
865 error = EACCES;
866 goto out;
870 * Check if we have VAT on a writable media
871 * we cannot use the media in presence of VAT
872 * Dent RW mount.
874 map = udf_vfsp->udf_maps;
875 ASSERT(map != NULL);
876 for (i = 0; i < udf_vfsp->udf_nmaps; i++) {
877 if (map->udm_flags & UDM_MAP_VPM) {
878 error = EACCES;
879 goto out;
881 map++;
885 * Check if the domain Id allows
886 * us to write
888 if (udf_vfsp->udf_lvd->lvd_dom_id.reg_ids[2] & 0x3) {
889 error = EACCES;
890 goto out;
892 udf_vfsp->udf_flags = UDF_FL_RW;
894 if (SWAP_32(lvid->lvid_int_type) == LOG_VOL_CLOSE_INT) {
895 udf_vfsp->udf_clean = UDF_CLEAN;
896 } else {
897 if (isroot) {
898 udf_vfsp->udf_clean = UDF_DIRTY;
899 } else {
900 error = ENOSPC;
901 goto out;
906 mutex_init(&udf_vfsp->udf_lock, NULL, MUTEX_DEFAULT, NULL);
908 mutex_init(&udf_vfsp->udf_rename_lck, NULL, MUTEX_DEFAULT, NULL);
910 _NOTE(COMPETING_THREADS_NOW);
911 if (error = ud_iget(vfsp, udf_vfsp->udf_ricb_prn,
912 udf_vfsp->udf_ricb_loc, &rip, NULL, cr)) {
913 mutex_destroy(&udf_vfsp->udf_lock);
914 goto out;
919 * Get the root inode and
920 * initialize the root vnode
922 rvp = ITOV(rip);
923 mutex_enter(&rvp->v_lock);
924 rvp->v_flag |= VROOT;
925 mutex_exit(&rvp->v_lock);
926 udf_vfsp->udf_root = rvp;
929 if (why == ROOT_INIT && isroot)
930 rootvp = devvp;
932 ud_vfs_add(udf_vfsp);
934 if (udf_vfsp->udf_flags == UDF_FL_RW) {
935 udf_vfsp->udf_clean = UDF_DIRTY;
936 ud_update_superblock(vfsp);
939 return (0);
941 out:
942 ud_destroy_fsp(udf_vfsp);
943 if (needclose) {
944 (void) fop_close(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
945 FREAD : FREAD|FWRITE, 1, 0, cr, NULL);
946 bflush(dev);
947 binval(dev);
949 VN_RELE(devvp);
951 return (error);
955 static struct udf_vfs *
956 ud_validate_and_fill_superblock(dev_t dev, int32_t bsize, uint32_t avd_loc)
958 int32_t error, count, index, shift;
959 uint32_t dummy, vds_loc;
960 caddr_t addr;
961 daddr_t blkno, lblkno;
962 struct buf *secbp, *bp;
963 struct tag *ttag;
964 struct anch_vol_desc_ptr *avdp;
965 struct file_set_desc *fsd;
966 struct udf_vfs *udf_vfsp = NULL;
967 struct pmap_hdr *hdr;
968 struct pmap_typ1 *typ1;
969 struct pmap_typ2 *typ2;
970 struct ud_map *map;
971 int32_t desc_len;
973 ud_printf("ud_validate_and_fill_superblock\n");
975 if (bsize < DEV_BSIZE) {
976 return (NULL);
978 shift = 0;
979 while ((bsize >> shift) > DEV_BSIZE) {
980 shift++;
984 * Read Anchor Volume Descriptor
985 * Verify it and get the location of
986 * Main Volume Descriptor Sequence
988 secbp = ud_bread(dev, avd_loc << shift, ANCHOR_VOL_DESC_LEN);
989 if ((error = geterror(secbp)) != 0) {
990 cmn_err(CE_NOTE, "udfs : Could not read Anchor Volume Desc %x",
991 error);
992 brelse(secbp);
993 return (NULL);
995 avdp = (struct anch_vol_desc_ptr *)secbp->b_un.b_addr;
996 if (ud_verify_tag_and_desc(&avdp->avd_tag, UD_ANCH_VOL_DESC,
997 avd_loc, 1, ANCHOR_VOL_DESC_LEN) != 0) {
998 brelse(secbp);
999 return (NULL);
1001 udf_vfsp = (struct udf_vfs *)
1002 kmem_zalloc(sizeof (struct udf_vfs), KM_SLEEP);
1003 udf_vfsp->udf_mvds_loc = SWAP_32(avdp->avd_main_vdse.ext_loc);
1004 udf_vfsp->udf_mvds_len = SWAP_32(avdp->avd_main_vdse.ext_len);
1005 udf_vfsp->udf_rvds_loc = SWAP_32(avdp->avd_res_vdse.ext_loc);
1006 udf_vfsp->udf_rvds_len = SWAP_32(avdp->avd_res_vdse.ext_len);
1007 secbp->b_flags = B_AGE | B_STALE;
1008 brelse(secbp);
1011 * Read Main Volume Descriptor Sequence
1012 * and process it
1014 vds_loc = udf_vfsp->udf_mvds_loc;
1015 secbp = ud_bread(dev, vds_loc << shift,
1016 udf_vfsp->udf_mvds_len);
1017 if ((error = geterror(secbp)) != 0) {
1018 brelse(secbp);
1019 cmn_err(CE_NOTE, "udfs : Could not read Main Volume Desc %x",
1020 error);
1022 vds_loc = udf_vfsp->udf_rvds_loc;
1023 secbp = ud_bread(dev, vds_loc << shift,
1024 udf_vfsp->udf_rvds_len);
1025 if ((error = geterror(secbp)) != 0) {
1026 brelse(secbp);
1027 cmn_err(CE_NOTE,
1028 "udfs : Could not read Res Volume Desc %x", error);
1029 return (NULL);
1033 udf_vfsp->udf_vds = ngeteblk(udf_vfsp->udf_mvds_len);
1034 bp = udf_vfsp->udf_vds;
1035 bp->b_edev = dev;
1036 bp->b_dev = cmpdev(dev);
1037 bp->b_blkno = vds_loc << shift;
1038 bp->b_bcount = udf_vfsp->udf_mvds_len;
1039 bcopy(secbp->b_un.b_addr, bp->b_un.b_addr, udf_vfsp->udf_mvds_len);
1040 secbp->b_flags |= B_STALE | B_AGE;
1041 brelse(secbp);
1044 count = udf_vfsp->udf_mvds_len / DEV_BSIZE;
1045 addr = bp->b_un.b_addr;
1046 for (index = 0; index < count; index ++) {
1047 ttag = (struct tag *)(addr + index * DEV_BSIZE);
1048 desc_len = udf_vfsp->udf_mvds_len - (index * DEV_BSIZE);
1049 if (ud_verify_tag_and_desc(ttag, UD_PRI_VOL_DESC,
1050 vds_loc + (index >> shift),
1051 1, desc_len) == 0) {
1052 if (udf_vfsp->udf_pvd == NULL) {
1053 udf_vfsp->udf_pvd =
1054 (struct pri_vol_desc *)ttag;
1055 } else {
1056 struct pri_vol_desc *opvd, *npvd;
1058 opvd = udf_vfsp->udf_pvd;
1059 npvd = (struct pri_vol_desc *)ttag;
1061 if ((strncmp(opvd->pvd_vsi,
1062 npvd->pvd_vsi, 128) == 0) &&
1063 (strncmp(opvd->pvd_vol_id,
1064 npvd->pvd_vol_id, 32) == 0) &&
1065 (strncmp((caddr_t)&opvd->pvd_desc_cs,
1066 (caddr_t)&npvd->pvd_desc_cs,
1067 sizeof (charspec_t)) == 0)) {
1069 if (SWAP_32(opvd->pvd_vdsn) <
1070 SWAP_32(npvd->pvd_vdsn)) {
1071 udf_vfsp->udf_pvd = npvd;
1073 } else {
1074 goto out;
1077 } else if (ud_verify_tag_and_desc(ttag, UD_LOG_VOL_DESC,
1078 vds_loc + (index >> shift),
1079 1, desc_len) == 0) {
1080 struct log_vol_desc *lvd;
1082 lvd = (struct log_vol_desc *)ttag;
1083 if (strncmp(lvd->lvd_dom_id.reg_id,
1084 UDF_DOMAIN_NAME, 23) != 0) {
1085 printf("Domain ID in lvd is not valid\n");
1086 goto out;
1089 if (udf_vfsp->udf_lvd == NULL) {
1090 udf_vfsp->udf_lvd = lvd;
1091 } else {
1092 struct log_vol_desc *olvd;
1094 olvd = udf_vfsp->udf_lvd;
1095 if ((strncmp((caddr_t)&olvd->lvd_desc_cs,
1096 (caddr_t)&lvd->lvd_desc_cs,
1097 sizeof (charspec_t)) == 0) &&
1098 (strncmp(olvd->lvd_lvid,
1099 lvd->lvd_lvid, 128) == 0)) {
1100 if (SWAP_32(olvd->lvd_vdsn) <
1101 SWAP_32(lvd->lvd_vdsn)) {
1102 udf_vfsp->udf_lvd = lvd;
1104 } else {
1105 goto out;
1108 } else if (ud_verify_tag_and_desc(ttag, UD_PART_DESC,
1109 vds_loc + (index >> shift),
1110 1, desc_len) == 0) {
1111 int32_t i;
1112 struct phdr_desc *hdr;
1113 struct part_desc *pdesc;
1114 struct ud_part *pnew, *pold, *part;
1116 pdesc = (struct part_desc *)ttag;
1117 pold = udf_vfsp->udf_parts;
1118 for (i = 0; i < udf_vfsp->udf_npart; i++) {
1119 if (pold->udp_number !=
1120 SWAP_16(pdesc->pd_pnum)) {
1121 pold++;
1122 continue;
1125 if (SWAP_32(pdesc->pd_vdsn) >
1126 pold->udp_seqno) {
1127 pold->udp_seqno =
1128 SWAP_32(pdesc->pd_vdsn);
1129 pold->udp_access =
1130 SWAP_32(pdesc->pd_acc_type);
1131 pold->udp_start =
1132 SWAP_32(pdesc->pd_part_start);
1133 pold->udp_length =
1134 SWAP_32(pdesc->pd_part_length);
1136 goto loop_end;
1138 pold = udf_vfsp->udf_parts;
1139 udf_vfsp->udf_npart++;
1140 pnew = kmem_zalloc(udf_vfsp->udf_npart *
1141 sizeof (struct ud_part), KM_SLEEP);
1142 udf_vfsp->udf_parts = pnew;
1143 if (pold) {
1144 bcopy(pold, pnew,
1145 sizeof (struct ud_part) *
1146 (udf_vfsp->udf_npart - 1));
1147 kmem_free(pold,
1148 sizeof (struct ud_part) *
1149 (udf_vfsp->udf_npart - 1));
1151 part = pnew + (udf_vfsp->udf_npart - 1);
1152 part->udp_number = SWAP_16(pdesc->pd_pnum);
1153 part->udp_seqno = SWAP_32(pdesc->pd_vdsn);
1154 part->udp_access = SWAP_32(pdesc->pd_acc_type);
1155 part->udp_start = SWAP_32(pdesc->pd_part_start);
1156 part->udp_length = SWAP_32(pdesc->pd_part_length);
1157 part->udp_last_alloc = 0;
1160 * Figure out space bitmaps
1161 * or space tables
1163 hdr = (struct phdr_desc *)pdesc->pd_pc_use;
1164 if (hdr->phdr_ust.sad_ext_len) {
1165 part->udp_flags = UDP_SPACETBLS;
1166 part->udp_unall_loc =
1167 SWAP_32(hdr->phdr_ust.sad_ext_loc);
1168 part->udp_unall_len =
1169 SWAP_32(hdr->phdr_ust.sad_ext_len);
1170 part->udp_freed_loc =
1171 SWAP_32(hdr->phdr_fst.sad_ext_loc);
1172 part->udp_freed_len =
1173 SWAP_32(hdr->phdr_fst.sad_ext_len);
1174 } else {
1175 part->udp_flags = UDP_BITMAPS;
1176 part->udp_unall_loc =
1177 SWAP_32(hdr->phdr_usb.sad_ext_loc);
1178 part->udp_unall_len =
1179 SWAP_32(hdr->phdr_usb.sad_ext_len);
1180 part->udp_freed_loc =
1181 SWAP_32(hdr->phdr_fsb.sad_ext_loc);
1182 part->udp_freed_len =
1183 SWAP_32(hdr->phdr_fsb.sad_ext_len);
1185 } else if (ud_verify_tag_and_desc(ttag, UD_TERM_DESC,
1186 vds_loc + (index >> shift),
1187 1, desc_len) == 0) {
1189 break;
1191 loop_end:
1194 if ((udf_vfsp->udf_pvd == NULL) ||
1195 (udf_vfsp->udf_lvd == NULL) ||
1196 (udf_vfsp->udf_parts == NULL)) {
1197 goto out;
1201 * Process Primary Volume Descriptor
1203 (void) strncpy(udf_vfsp->udf_volid, udf_vfsp->udf_pvd->pvd_vol_id, 32);
1204 udf_vfsp->udf_volid[31] = '\0';
1205 udf_vfsp->udf_tsno = SWAP_16(udf_vfsp->udf_pvd->pvd_tag.tag_sno);
1208 * Process Logical Volume Descriptor
1210 udf_vfsp->udf_lbsize =
1211 SWAP_32(udf_vfsp->udf_lvd->lvd_log_bsize);
1212 udf_vfsp->udf_lbmask = udf_vfsp->udf_lbsize - 1;
1213 udf_vfsp->udf_l2d_shift = shift;
1214 udf_vfsp->udf_l2b_shift = shift + DEV_BSHIFT;
1217 * Check if the media is in
1218 * proper domain.
1220 if (strcmp(udf_vfsp->udf_lvd->lvd_dom_id.reg_id,
1221 UDF_DOMAIN_NAME) != 0) {
1222 goto out;
1226 * AVDS offset does not match with the lbsize
1227 * in the lvd
1229 if (udf_vfsp->udf_lbsize != bsize) {
1230 goto out;
1233 udf_vfsp->udf_iseq_loc =
1234 SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_loc);
1235 udf_vfsp->udf_iseq_len =
1236 SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_len);
1238 udf_vfsp->udf_fsd_prn =
1239 SWAP_16(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_prn);
1240 udf_vfsp->udf_fsd_loc =
1241 SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_loc);
1242 udf_vfsp->udf_fsd_len =
1243 SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_len);
1247 * process paritions
1249 udf_vfsp->udf_mtype = udf_vfsp->udf_parts[0].udp_access;
1250 for (index = 0; index < udf_vfsp->udf_npart; index ++) {
1251 if (udf_vfsp->udf_parts[index].udp_access <
1252 udf_vfsp->udf_mtype) {
1253 udf_vfsp->udf_mtype =
1254 udf_vfsp->udf_parts[index].udp_access;
1257 if ((udf_vfsp->udf_mtype < UDF_MT_RO) ||
1258 (udf_vfsp->udf_mtype > UDF_MT_OW)) {
1259 udf_vfsp->udf_mtype = UDF_MT_RO;
1262 udf_vfsp->udf_nmaps = 0;
1263 hdr = (struct pmap_hdr *)udf_vfsp->udf_lvd->lvd_pmaps;
1264 count = SWAP_32(udf_vfsp->udf_lvd->lvd_num_pmaps);
1265 for (index = 0; index < count; index++) {
1267 if ((hdr->maph_type == MAP_TYPE1) &&
1268 (hdr->maph_length == MAP_TYPE1_LEN)) {
1269 typ1 = (struct pmap_typ1 *)hdr;
1271 map = udf_vfsp->udf_maps;
1272 udf_vfsp->udf_maps =
1273 kmem_zalloc(sizeof (struct ud_map) *
1274 (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
1275 if (map != NULL) {
1276 bcopy(map, udf_vfsp->udf_maps,
1277 sizeof (struct ud_map) *
1278 udf_vfsp->udf_nmaps);
1279 kmem_free(map, sizeof (struct ud_map) *
1280 udf_vfsp->udf_nmaps);
1282 map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
1283 map->udm_flags = UDM_MAP_NORM;
1284 map->udm_vsn = SWAP_16(typ1->map1_vsn);
1285 map->udm_pn = SWAP_16(typ1->map1_pn);
1286 udf_vfsp->udf_nmaps ++;
1287 } else if ((hdr->maph_type == MAP_TYPE2) &&
1288 (hdr->maph_length == MAP_TYPE2_LEN)) {
1289 typ2 = (struct pmap_typ2 *)hdr;
1291 if (strncmp(typ2->map2_pti.reg_id,
1292 UDF_VIRT_PART, 23) == 0) {
1294 * Add this to the normal
1295 * partition table so that
1296 * we donot
1298 map = udf_vfsp->udf_maps;
1299 udf_vfsp->udf_maps =
1300 kmem_zalloc(sizeof (struct ud_map) *
1301 (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
1302 if (map != NULL) {
1303 bcopy(map, udf_vfsp->udf_maps,
1304 sizeof (struct ud_map) *
1305 udf_vfsp->udf_nmaps);
1306 kmem_free(map,
1307 sizeof (struct ud_map) *
1308 udf_vfsp->udf_nmaps);
1310 map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
1311 map->udm_flags = UDM_MAP_VPM;
1312 map->udm_vsn = SWAP_16(typ2->map2_vsn);
1313 map->udm_pn = SWAP_16(typ2->map2_pn);
1314 udf_vfsp->udf_nmaps ++;
1315 if (error = ud_get_last_block(dev, &lblkno)) {
1316 goto out;
1318 if (error = ud_val_get_vat(udf_vfsp, dev,
1319 lblkno, map)) {
1320 goto out;
1322 } else if (strncmp(typ2->map2_pti.reg_id,
1323 UDF_SPAR_PART, 23) == 0) {
1325 if (SWAP_16(typ2->map2_pl) != 32) {
1326 printf(
1327 "Packet Length is not valid %x\n",
1328 SWAP_16(typ2->map2_pl));
1329 goto out;
1331 if ((typ2->map2_nst < 1) ||
1332 (typ2->map2_nst > 4)) {
1333 goto out;
1335 map = udf_vfsp->udf_maps;
1336 udf_vfsp->udf_maps =
1337 kmem_zalloc(sizeof (struct ud_map) *
1338 (udf_vfsp->udf_nmaps + 1),
1339 KM_SLEEP);
1340 if (map != NULL) {
1341 bcopy(map, udf_vfsp->udf_maps,
1342 sizeof (struct ud_map) *
1343 udf_vfsp->udf_nmaps);
1344 kmem_free(map,
1345 sizeof (struct ud_map) *
1346 udf_vfsp->udf_nmaps);
1348 map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
1349 map->udm_flags = UDM_MAP_SPM;
1350 map->udm_vsn = SWAP_16(typ2->map2_vsn);
1351 map->udm_pn = SWAP_16(typ2->map2_pn);
1353 udf_vfsp->udf_nmaps ++;
1355 if (error = ud_read_sparing_tbls(udf_vfsp,
1356 dev, map, typ2)) {
1357 goto out;
1359 } else {
1361 * Unknown type of partition
1362 * Bail out
1364 goto out;
1366 } else {
1368 * Unknown type of partition
1369 * Bail out
1371 goto out;
1373 hdr = (struct pmap_hdr *)(((uint8_t *)hdr) + hdr->maph_length);
1378 * Read Logical Volume Integrity Sequence
1379 * and process it
1381 secbp = ud_bread(dev, udf_vfsp->udf_iseq_loc << shift,
1382 udf_vfsp->udf_iseq_len);
1383 if ((error = geterror(secbp)) != 0) {
1384 cmn_err(CE_NOTE,
1385 "udfs : Could not read Logical Volume Integrity Sequence %x",
1386 error);
1387 brelse(secbp);
1388 goto out;
1390 udf_vfsp->udf_iseq = ngeteblk(udf_vfsp->udf_iseq_len);
1391 bp = udf_vfsp->udf_iseq;
1392 bp->b_edev = dev;
1393 bp->b_dev = cmpdev(dev);
1394 bp->b_blkno = udf_vfsp->udf_iseq_loc << shift;
1395 bp->b_bcount = udf_vfsp->udf_iseq_len;
1396 bcopy(secbp->b_un.b_addr, bp->b_un.b_addr, udf_vfsp->udf_iseq_len);
1397 secbp->b_flags |= B_STALE | B_AGE;
1398 brelse(secbp);
1400 count = udf_vfsp->udf_iseq_len / DEV_BSIZE;
1401 addr = bp->b_un.b_addr;
1402 for (index = 0; index < count; index ++) {
1403 ttag = (struct tag *)(addr + index * DEV_BSIZE);
1404 desc_len = udf_vfsp->udf_iseq_len - (index * DEV_BSIZE);
1405 if (ud_verify_tag_and_desc(ttag, UD_LOG_VOL_INT,
1406 udf_vfsp->udf_iseq_loc + (index >> shift),
1407 1, desc_len) == 0) {
1409 struct log_vol_int_desc *lvid;
1411 lvid = (struct log_vol_int_desc *)ttag;
1412 udf_vfsp->udf_lvid = lvid;
1414 if (SWAP_32(lvid->lvid_int_type) == LOG_VOL_CLOSE_INT) {
1415 udf_vfsp->udf_clean = UDF_CLEAN;
1416 } else {
1417 udf_vfsp->udf_clean = UDF_DIRTY;
1421 * update superblock with the metadata
1423 ud_convert_to_superblock(udf_vfsp, lvid);
1424 break;
1428 if (udf_vfsp->udf_lvid == NULL) {
1429 goto out;
1432 if ((blkno = ud_xlate_to_daddr(udf_vfsp,
1433 udf_vfsp->udf_fsd_prn, udf_vfsp->udf_fsd_loc,
1434 1, &dummy)) == 0) {
1435 goto out;
1437 secbp = ud_bread(dev, blkno << shift, udf_vfsp->udf_fsd_len);
1438 if ((error = geterror(secbp)) != 0) {
1439 cmn_err(CE_NOTE,
1440 "udfs : Could not read File Set Descriptor %x", error);
1441 brelse(secbp);
1442 goto out;
1444 fsd = (struct file_set_desc *)secbp->b_un.b_addr;
1445 if (ud_verify_tag_and_desc(&fsd->fsd_tag, UD_FILE_SET_DESC,
1446 udf_vfsp->udf_fsd_loc,
1447 1, udf_vfsp->udf_fsd_len) != 0) {
1448 secbp->b_flags = B_AGE | B_STALE;
1449 brelse(secbp);
1450 goto out;
1452 udf_vfsp->udf_ricb_prn = SWAP_16(fsd->fsd_root_icb.lad_ext_prn);
1453 udf_vfsp->udf_ricb_loc = SWAP_32(fsd->fsd_root_icb.lad_ext_loc);
1454 udf_vfsp->udf_ricb_len = SWAP_32(fsd->fsd_root_icb.lad_ext_len);
1455 secbp->b_flags = B_AGE | B_STALE;
1456 brelse(secbp);
1457 udf_vfsp->udf_root_blkno = ud_xlate_to_daddr(udf_vfsp,
1458 udf_vfsp->udf_ricb_prn, udf_vfsp->udf_ricb_loc,
1459 1, &dummy);
1461 return (udf_vfsp);
1462 out:
1463 ud_destroy_fsp(udf_vfsp);
1465 return (NULL);
1469 * release/free resources from one ud_map; map data was zalloc'd in
1470 * ud_validate_and_fill_superblock() and fields may later point to
1471 * valid data
1473 static void
1474 ud_free_map(struct ud_map *map)
1476 uint32_t n;
1478 if (map->udm_flags & UDM_MAP_VPM) {
1479 if (map->udm_count) {
1480 kmem_free(map->udm_count,
1481 map->udm_nent * sizeof (*map->udm_count));
1482 map->udm_count = NULL;
1484 if (map->udm_bp) {
1485 for (n = 0; n < map->udm_nent; n++) {
1486 if (map->udm_bp[n])
1487 brelse(map->udm_bp[n]);
1489 kmem_free(map->udm_bp,
1490 map->udm_nent * sizeof (*map->udm_bp));
1491 map->udm_bp = NULL;
1493 if (map->udm_addr) {
1494 kmem_free(map->udm_addr,
1495 map->udm_nent * sizeof (*map->udm_addr));
1496 map->udm_addr = NULL;
1499 if (map->udm_flags & UDM_MAP_SPM) {
1500 for (n = 0; n < MAX_SPM; n++) {
1501 if (map->udm_sbp[n]) {
1502 brelse(map->udm_sbp[n]);
1503 map->udm_sbp[n] = NULL;
1504 map->udm_spaddr[n] = NULL;
1510 void
1511 ud_destroy_fsp(struct udf_vfs *udf_vfsp)
1513 int32_t i;
1515 ud_printf("ud_destroy_fsp\n");
1516 if (udf_vfsp == NULL)
1517 return;
1519 if (udf_vfsp->udf_maps) {
1520 for (i = 0; i < udf_vfsp->udf_nmaps; i++)
1521 ud_free_map(&udf_vfsp->udf_maps[i]);
1523 kmem_free(udf_vfsp->udf_maps,
1524 udf_vfsp->udf_nmaps * sizeof (*udf_vfsp->udf_maps));
1527 if (udf_vfsp->udf_parts) {
1528 kmem_free(udf_vfsp->udf_parts,
1529 udf_vfsp->udf_npart * sizeof (*udf_vfsp->udf_parts));
1531 if (udf_vfsp->udf_iseq) {
1532 udf_vfsp->udf_iseq->b_flags |= (B_STALE|B_AGE);
1533 brelse(udf_vfsp->udf_iseq);
1535 if (udf_vfsp->udf_vds) {
1536 udf_vfsp->udf_vds->b_flags |= (B_STALE|B_AGE);
1537 brelse(udf_vfsp->udf_vds);
1539 if (udf_vfsp->udf_vfs)
1540 ud_vfs_remove(udf_vfsp);
1541 if (udf_vfsp->udf_fsmnt) {
1542 kmem_free(udf_vfsp->udf_fsmnt,
1543 strlen(udf_vfsp->udf_fsmnt) + 1);
1545 kmem_free(udf_vfsp, sizeof (*udf_vfsp));
1548 void
1549 ud_convert_to_superblock(struct udf_vfs *udf_vfsp,
1550 struct log_vol_int_desc *lvid)
1552 int32_t i, c;
1553 uint32_t *temp;
1554 struct ud_part *ud_part;
1555 struct lvid_iu *iu;
1557 udf_vfsp->udf_maxuniq = SWAP_64(lvid->lvid_uniqid);
1558 temp = lvid->lvid_fst;
1559 c = SWAP_32(lvid->lvid_npart);
1560 ud_part = udf_vfsp->udf_parts;
1561 for (i = 0; i < c; i++) {
1562 if (i >= udf_vfsp->udf_npart) {
1563 continue;
1565 ud_part->udp_nfree = SWAP_32(temp[i]);
1566 ud_part->udp_nblocks = SWAP_32(temp[c + i]);
1567 udf_vfsp->udf_freeblks += SWAP_32(temp[i]);
1568 udf_vfsp->udf_totalblks += SWAP_32(temp[c + i]);
1569 ud_part++;
1572 iu = (struct lvid_iu *)(temp + c * 2);
1573 udf_vfsp->udf_nfiles = SWAP_32(iu->lvidiu_nfiles);
1574 udf_vfsp->udf_ndirs = SWAP_32(iu->lvidiu_ndirs);
1575 udf_vfsp->udf_miread = BCD2HEX_16(SWAP_16(iu->lvidiu_mread));
1576 udf_vfsp->udf_miwrite = BCD2HEX_16(SWAP_16(iu->lvidiu_mwrite));
1577 udf_vfsp->udf_mawrite = BCD2HEX_16(SWAP_16(iu->lvidiu_maxwr));
1580 void
1581 ud_update_superblock(struct vfs *vfsp)
1583 struct udf_vfs *udf_vfsp;
1585 ud_printf("ud_update_superblock\n");
1587 udf_vfsp = (struct udf_vfs *)vfsp->vfs_data;
1589 mutex_enter(&udf_vfsp->udf_lock);
1590 ud_sbwrite(udf_vfsp);
1591 mutex_exit(&udf_vfsp->udf_lock);
1595 #include <sys/dkio.h>
1596 #include <sys/cdio.h>
1597 #include <sys/vtoc.h>
1600 * This part of the code is known
1601 * to work with only sparc. It needs
1602 * to be evluated before using it with x86
1604 int32_t
1605 ud_get_last_block(dev_t dev, daddr_t *blkno)
1607 struct vtoc vtoc;
1608 struct dk_cinfo dki_info;
1609 int32_t rval, error;
1611 if ((error = cdev_ioctl(dev, DKIOCGVTOC, (intptr_t)&vtoc,
1612 FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
1613 cmn_err(CE_NOTE, "Could not get the vtoc information");
1614 return (error);
1617 if (vtoc.v_sanity != VTOC_SANE) {
1618 return (EINVAL);
1620 if ((error = cdev_ioctl(dev, DKIOCINFO, (intptr_t)&dki_info,
1621 FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
1622 cmn_err(CE_NOTE, "Could not get the slice information");
1623 return (error);
1626 if (dki_info.dki_partition > V_NUMPAR) {
1627 return (EINVAL);
1631 *blkno = vtoc.v_part[dki_info.dki_partition].p_size;
1633 return (0);
1636 /* Search sequentially N - 2, N, N - 152, N - 150 for vat icb */
1638 * int32_t ud_sub_blks[] = {2, 0, 152, 150};
1640 int32_t ud_sub_blks[] = {152, 150, 2, 0};
1641 int32_t ud_sub_count = 4;
1644 * Validate the VAT ICB
1646 static int32_t
1647 ud_val_get_vat(struct udf_vfs *udf_vfsp, dev_t dev,
1648 daddr_t blkno, struct ud_map *udm)
1650 struct buf *secbp;
1651 struct file_entry *fe;
1652 int32_t end_loc, i, j, ad_type;
1653 struct short_ad *sad;
1654 struct long_ad *lad;
1655 uint32_t count, blk;
1656 struct ud_part *ud_part;
1657 int err = 0;
1659 end_loc = (blkno >> udf_vfsp->udf_l2d_shift) - 1;
1661 for (i = 0; i < ud_sub_count; i++) {
1662 udm->udm_vat_icb = end_loc - ud_sub_blks[i];
1664 secbp = ud_bread(dev,
1665 udm->udm_vat_icb << udf_vfsp->udf_l2d_shift,
1666 udf_vfsp->udf_lbsize);
1667 ASSERT(secbp->b_un.b_addr);
1669 fe = (struct file_entry *)secbp->b_un.b_addr;
1670 if (ud_verify_tag_and_desc(&fe->fe_tag, UD_FILE_ENTRY, 0,
1671 0, 0) == 0) {
1672 if (ud_verify_tag_and_desc(&fe->fe_tag, UD_FILE_ENTRY,
1673 SWAP_32(fe->fe_tag.tag_loc),
1674 1, udf_vfsp->udf_lbsize) == 0) {
1675 if (fe->fe_icb_tag.itag_ftype == 0) {
1676 break;
1680 secbp->b_flags |= B_AGE | B_STALE;
1681 brelse(secbp);
1683 if (i == ud_sub_count) {
1684 return (EINVAL);
1687 ad_type = SWAP_16(fe->fe_icb_tag.itag_flags) & 0x3;
1688 if (ad_type == ICB_FLAG_ONE_AD) {
1689 udm->udm_nent = 1;
1690 } else if (ad_type == ICB_FLAG_SHORT_AD) {
1691 udm->udm_nent =
1692 SWAP_32(fe->fe_len_adesc) / sizeof (struct short_ad);
1693 } else if (ad_type == ICB_FLAG_LONG_AD) {
1694 udm->udm_nent =
1695 SWAP_32(fe->fe_len_adesc) / sizeof (struct long_ad);
1696 } else {
1697 err = EINVAL;
1698 goto end;
1701 udm->udm_count = kmem_zalloc(udm->udm_nent * sizeof (*udm->udm_count),
1702 KM_SLEEP);
1703 udm->udm_bp = kmem_zalloc(udm->udm_nent * sizeof (*udm->udm_bp),
1704 KM_SLEEP);
1705 udm->udm_addr = kmem_zalloc(udm->udm_nent * sizeof (*udm->udm_addr),
1706 KM_SLEEP);
1708 if (ad_type == ICB_FLAG_ONE_AD) {
1709 udm->udm_count[0] = (SWAP_64(fe->fe_info_len) - 36) /
1710 sizeof (uint32_t);
1711 udm->udm_bp[0] = secbp;
1712 udm->udm_addr[0] = (uint32_t *)
1713 &fe->fe_spec[SWAP_32(fe->fe_len_ear)];
1714 return (0);
1716 for (i = 0; i < udm->udm_nent; i++) {
1717 if (ad_type == ICB_FLAG_SHORT_AD) {
1718 sad = (struct short_ad *)
1719 (fe->fe_spec + SWAP_32(fe->fe_len_ear));
1720 sad += i;
1721 count = SWAP_32(sad->sad_ext_len);
1722 blk = SWAP_32(sad->sad_ext_loc);
1723 } else {
1724 lad = (struct long_ad *)
1725 (fe->fe_spec + SWAP_32(fe->fe_len_ear));
1726 lad += i;
1727 count = SWAP_32(lad->lad_ext_len);
1728 blk = SWAP_32(lad->lad_ext_loc);
1729 ASSERT(SWAP_16(lad->lad_ext_prn) == udm->udm_pn);
1731 if ((count & 0x3FFFFFFF) == 0) {
1732 break;
1734 if (i < udm->udm_nent - 1) {
1735 udm->udm_count[i] = count / 4;
1736 } else {
1737 udm->udm_count[i] = (count - 36) / 4;
1739 ud_part = udf_vfsp->udf_parts;
1740 for (j = 0; j < udf_vfsp->udf_npart; j++) {
1741 if (udm->udm_pn == ud_part->udp_number) {
1742 blk = ud_part->udp_start + blk;
1743 break;
1746 if (j == udf_vfsp->udf_npart) {
1747 err = EINVAL;
1748 break;
1751 count = (count + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
1752 udm->udm_bp[i] = ud_bread(dev,
1753 blk << udf_vfsp->udf_l2d_shift, count);
1754 if ((udm->udm_bp[i]->b_error != 0) ||
1755 (udm->udm_bp[i]->b_resid)) {
1756 err = EINVAL;
1757 break;
1759 udm->udm_addr[i] = (uint32_t *)udm->udm_bp[i]->b_un.b_addr;
1762 end:
1763 if (err)
1764 ud_free_map(udm);
1765 secbp->b_flags |= B_AGE | B_STALE;
1766 brelse(secbp);
1767 return (err);
1770 int32_t
1771 ud_read_sparing_tbls(struct udf_vfs *udf_vfsp,
1772 dev_t dev, struct ud_map *map, struct pmap_typ2 *typ2)
1774 int32_t index, valid = 0;
1775 uint32_t sz;
1776 struct buf *bp;
1777 struct stbl *stbl;
1779 map->udm_plen = SWAP_16(typ2->map2_pl);
1780 map->udm_nspm = typ2->map2_nst;
1781 map->udm_spsz = SWAP_32(typ2->map2_sest);
1782 sz = (map->udm_spsz + udf_vfsp->udf_lbmask) & ~udf_vfsp->udf_lbmask;
1783 if (sz == 0) {
1784 return (0);
1787 for (index = 0; index < map->udm_nspm; index++) {
1788 map->udm_loc[index] = SWAP_32(typ2->map2_st[index]);
1790 bp = ud_bread(dev,
1791 map->udm_loc[index] << udf_vfsp->udf_l2d_shift, sz);
1792 if ((bp->b_error != 0) || (bp->b_resid)) {
1793 brelse(bp);
1794 continue;
1796 stbl = (struct stbl *)bp->b_un.b_addr;
1797 if (strncmp(stbl->stbl_si.reg_id, UDF_SPAR_TBL, 23) != 0) {
1798 printf("Sparing Identifier does not match\n");
1799 bp->b_flags |= B_AGE | B_STALE;
1800 brelse(bp);
1801 continue;
1803 map->udm_sbp[index] = bp;
1804 map->udm_spaddr[index] = bp->b_un.b_addr;
1805 #ifdef UNDEF
1807 struct stbl_entry *te;
1808 int32_t i, tbl_len;
1810 te = (struct stbl_entry *)&stbl->stbl_entry;
1811 tbl_len = SWAP_16(stbl->stbl_len);
1813 printf("%x %x\n", tbl_len, SWAP_32(stbl->stbl_seqno));
1814 printf("%x %x\n", bp->b_un.b_addr, te);
1816 for (i = 0; i < tbl_len; i++) {
1817 printf("%x %x\n", SWAP_32(te->sent_ol), SWAP_32(te->sent_ml));
1818 te ++;
1821 #endif
1822 valid ++;
1825 if (valid) {
1826 return (0);
1828 return (EINVAL);
1831 uint32_t
1832 ud_get_lbsize(dev_t dev, uint32_t *loc)
1834 int32_t bsize, shift, index, end_index;
1835 daddr_t last_block;
1836 uint32_t avd_loc;
1837 struct buf *bp;
1838 struct anch_vol_desc_ptr *avdp;
1839 uint32_t session_offset = 0;
1840 int32_t rval;
1842 if (ud_get_last_block(dev, &last_block) != 0) {
1843 end_index = 1;
1844 } else {
1845 end_index = 3;
1848 if (cdev_ioctl(dev, CDROMREADOFFSET, (intptr_t)&session_offset,
1849 FKIOCTL|FREAD|FNATIVE, CRED(), &rval) != 0) {
1850 session_offset = 0;
1853 for (index = 0; index < end_index; index++) {
1855 for (bsize = DEV_BSIZE, shift = 0;
1856 bsize <= MAXBSIZE; bsize <<= 1, shift++) {
1858 if (index == 0) {
1859 avd_loc = 256;
1860 if (bsize <= 2048) {
1861 avd_loc +=
1862 session_offset * 2048 / bsize;
1863 } else {
1864 avd_loc +=
1865 session_offset / (bsize / 2048);
1867 } else if (index == 1) {
1868 avd_loc = last_block - (1 << shift);
1869 } else {
1870 avd_loc = last_block - (256 << shift);
1873 bp = ud_bread(dev, avd_loc << shift,
1874 ANCHOR_VOL_DESC_LEN);
1875 if (geterror(bp) != 0) {
1876 brelse(bp);
1877 continue;
1881 * Verify if we have avdp here
1883 avdp = (struct anch_vol_desc_ptr *)bp->b_un.b_addr;
1884 if (ud_verify_tag_and_desc(&avdp->avd_tag,
1885 UD_ANCH_VOL_DESC, avd_loc,
1886 1, ANCHOR_VOL_DESC_LEN) != 0) {
1887 bp->b_flags |= B_AGE | B_STALE;
1888 brelse(bp);
1889 continue;
1891 bp->b_flags |= B_AGE | B_STALE;
1892 brelse(bp);
1893 *loc = avd_loc;
1894 return (bsize);
1899 * Did not find AVD at all the locations
1901 return (0);
1904 static const struct vfsops udf_vfsops = {
1905 .vfs_mount = udf_mount,
1906 .vfs_unmount = udf_unmount,
1907 .vfs_root = udf_root,
1908 .vfs_statvfs = udf_statvfs,
1909 .vfs_sync = udf_sync,
1910 .vfs_vget = udf_vget,
1911 .vfs_mountroot = udf_mountroot,
1914 static int
1915 udfinit(int fstype, char *name)
1917 int error;
1919 ud_printf("udfinit\n");
1921 error = vfs_setfsops(fstype, &udf_vfsops);
1922 if (error != 0) {
1923 cmn_err(CE_WARN, "udfinit: bad fstype");
1924 return (error);
1927 udf_fstype = fstype;
1929 ud_init_inodes();
1931 return (0);