xref: /dflybsd-src/sys/vfs/udf/udf_vfsops.c (revision 2b3f93ea6d1f70880f3e87f3c2cbe0dc0bfc9332)
103998195SJoerg Sonnenberger /*-
203998195SJoerg Sonnenberger  * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
303998195SJoerg Sonnenberger  * All rights reserved.
403998195SJoerg Sonnenberger  *
503998195SJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
603998195SJoerg Sonnenberger  * modification, are permitted provided that the following conditions
703998195SJoerg Sonnenberger  * are met:
803998195SJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
903998195SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
1003998195SJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
1103998195SJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
1203998195SJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
1303998195SJoerg Sonnenberger  *
1403998195SJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1503998195SJoerg Sonnenberger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1603998195SJoerg Sonnenberger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1703998195SJoerg Sonnenberger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1803998195SJoerg Sonnenberger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1903998195SJoerg Sonnenberger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2003998195SJoerg Sonnenberger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2103998195SJoerg Sonnenberger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2203998195SJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2303998195SJoerg Sonnenberger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2403998195SJoerg Sonnenberger  * SUCH DAMAGE.
2503998195SJoerg Sonnenberger  *
2603998195SJoerg Sonnenberger  * $FreeBSD: src/sys/fs/udf/udf_vfsops.c,v 1.16 2003/11/05 06:56:08 scottl Exp $
2703998195SJoerg Sonnenberger  */
2803998195SJoerg Sonnenberger 
2903998195SJoerg Sonnenberger /* udf_vfsops.c */
3003998195SJoerg Sonnenberger /* Implement the VFS side of things */
3103998195SJoerg Sonnenberger 
3203998195SJoerg Sonnenberger /*
3303998195SJoerg Sonnenberger  * Ok, here's how it goes.  The UDF specs are pretty clear on how each data
3403998195SJoerg Sonnenberger  * structure is made up, but not very clear on how they relate to each other.
3503998195SJoerg Sonnenberger  * Here is the skinny... This demostrates a filesystem with one file in the
3603998195SJoerg Sonnenberger  * root directory.  Subdirectories are treated just as normal files, but they
3703998195SJoerg Sonnenberger  * have File Id Descriptors of their children as their file data.  As for the
3803998195SJoerg Sonnenberger  * Anchor Volume Descriptor Pointer, it can exist in two of the following three
3903998195SJoerg Sonnenberger  * places: sector 256, sector n (the max sector of the disk), or sector
4003998195SJoerg Sonnenberger  * n - 256.  It's a pretty good bet that one will exist at sector 256 though.
4103998195SJoerg Sonnenberger  * One caveat is unclosed CD media.  For that, sector 256 cannot be written,
4203998195SJoerg Sonnenberger  * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the
4303998195SJoerg Sonnenberger  * media is closed.
4403998195SJoerg Sonnenberger  *
4503998195SJoerg Sonnenberger  *  Sector:
4603998195SJoerg Sonnenberger  *     256:
4703998195SJoerg Sonnenberger  *       n: Anchor Volume Descriptor Pointer
4803998195SJoerg Sonnenberger  * n - 256:	|
4903998195SJoerg Sonnenberger  *		|
5003998195SJoerg Sonnenberger  *		|-->Main Volume Descriptor Sequence
5103998195SJoerg Sonnenberger  *			|	|
5203998195SJoerg Sonnenberger  *			|	|
5303998195SJoerg Sonnenberger  *			|	|-->Logical Volume Descriptor
5403998195SJoerg Sonnenberger  *			|			  |
5503998195SJoerg Sonnenberger  *			|-->Partition Descriptor  |
5603998195SJoerg Sonnenberger  *				|		  |
5703998195SJoerg Sonnenberger  *				|		  |
5803998195SJoerg Sonnenberger  *				|-->Fileset Descriptor
5903998195SJoerg Sonnenberger  *					|
6003998195SJoerg Sonnenberger  *					|
6103998195SJoerg Sonnenberger  *					|-->Root Dir File Entry
6203998195SJoerg Sonnenberger  *						|
6303998195SJoerg Sonnenberger  *						|
6403998195SJoerg Sonnenberger  *						|-->File data:
6503998195SJoerg Sonnenberger  *						    File Id Descriptor
6603998195SJoerg Sonnenberger  *							|
6703998195SJoerg Sonnenberger  *							|
6803998195SJoerg Sonnenberger  *							|-->File Entry
6903998195SJoerg Sonnenberger  *								|
7003998195SJoerg Sonnenberger  *								|
7103998195SJoerg Sonnenberger  *								|-->File data
7203998195SJoerg Sonnenberger  */
7303998195SJoerg Sonnenberger 
7403998195SJoerg Sonnenberger #include <sys/types.h>
7503998195SJoerg Sonnenberger #include <sys/param.h>
7603998195SJoerg Sonnenberger #include <sys/systm.h>
7703998195SJoerg Sonnenberger #include <sys/uio.h>
7803998195SJoerg Sonnenberger #include <sys/buf.h>
7903998195SJoerg Sonnenberger #include <sys/conf.h>
8003998195SJoerg Sonnenberger #include <sys/fcntl.h>
8103998195SJoerg Sonnenberger #include <sys/module.h>
8203998195SJoerg Sonnenberger #include <sys/kernel.h>
8303998195SJoerg Sonnenberger #include <sys/malloc.h>
8403998195SJoerg Sonnenberger #include <sys/mount.h>
85fad57d0eSMatthew Dillon #include <sys/nlookup.h>
8603998195SJoerg Sonnenberger #include <sys/proc.h>
87*2b3f93eaSMatthew Dillon #include <sys/caps.h>
8803998195SJoerg Sonnenberger #include <sys/queue.h>
8903998195SJoerg Sonnenberger #include <sys/vnode.h>
9003998195SJoerg Sonnenberger 
9154341a3bSMatthew Dillon #include <sys/buf2.h>
9254341a3bSMatthew Dillon 
9303998195SJoerg Sonnenberger #include <vfs/udf/ecma167-udf.h>
9403998195SJoerg Sonnenberger #include <vfs/udf/osta.h>
9503998195SJoerg Sonnenberger #include <vfs/udf/udf.h>
9603998195SJoerg Sonnenberger #include <vfs/udf/udf_mount.h>
9703998195SJoerg Sonnenberger 
9866a1ddf5SMatthew Dillon extern struct vop_ops udf_vnode_vops;
990961aa92SMatthew Dillon 
10003998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFNODE, "UDF node", "UDF node structure");
10103998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFMOUNT, "UDF mount", "UDF mount structure");
10203998195SJoerg Sonnenberger MALLOC_DEFINE(M_UDFFENTRY, "UDF fentry", "UDF file entry structure");
10303998195SJoerg Sonnenberger 
104acde96dbSMatthew Dillon static int udf_mount(struct mount *, char *, caddr_t, struct ucred *);
105acde96dbSMatthew Dillon static int udf_unmount(struct mount *, int);
10603998195SJoerg Sonnenberger static int udf_root(struct mount *, struct vnode **);
107acde96dbSMatthew Dillon static int udf_statfs(struct mount *, struct statfs *, struct ucred *);
10867863d04SMatthew Dillon static int udf_fhtovp(struct mount *, struct vnode *,
10967863d04SMatthew Dillon 				struct fid *, struct vnode **);
11003998195SJoerg Sonnenberger static int udf_vptofh(struct vnode *, struct fid *);
11103998195SJoerg Sonnenberger 
11203998195SJoerg Sonnenberger static int udf_find_partmaps(struct udf_mnt *, struct logvol_desc *);
11303998195SJoerg Sonnenberger 
11403998195SJoerg Sonnenberger static struct vfsops udf_vfsops = {
11500369c4aSMatthew Dillon 	.vfs_flags =		0,
11643c45e8fSHiten Pandya 	.vfs_mount =    	udf_mount,
11743c45e8fSHiten Pandya 	.vfs_unmount =    	udf_unmount,
11843c45e8fSHiten Pandya 	.vfs_root =    		udf_root,
11943c45e8fSHiten Pandya 	.vfs_statfs =    	udf_statfs,
12043c45e8fSHiten Pandya 	.vfs_vget =    		udf_vget,
12143c45e8fSHiten Pandya 	.vfs_fhtovp =    	udf_fhtovp,
12243c45e8fSHiten Pandya 	.vfs_vptofh =    	udf_vptofh
12303998195SJoerg Sonnenberger };
12403998195SJoerg Sonnenberger VFS_SET(udf_vfsops, udf, VFCF_READONLY);
12503998195SJoerg Sonnenberger 
12603998195SJoerg Sonnenberger MODULE_VERSION(udf, 1);
12703998195SJoerg Sonnenberger 
128acde96dbSMatthew Dillon static int udf_mountfs(struct vnode *, struct mount *);
12903998195SJoerg Sonnenberger 
13003998195SJoerg Sonnenberger static int
udf_mount(struct mount * mp,char * path,caddr_t data,struct ucred * cred)131acde96dbSMatthew Dillon udf_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred)
13203998195SJoerg Sonnenberger {
13303998195SJoerg Sonnenberger 	struct vnode *devvp;	/* vnode of the mount device */
13403998195SJoerg Sonnenberger 	struct udf_args args;
1354090d6ffSSascha Wildner 	struct udf_mnt *imp = NULL;
13603998195SJoerg Sonnenberger 	size_t size;
13703998195SJoerg Sonnenberger 	int error;
138fad57d0eSMatthew Dillon 	struct nlookupdata nd;
13903998195SJoerg Sonnenberger 
14003998195SJoerg Sonnenberger 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
14103998195SJoerg Sonnenberger 		return (EROFS);
14203998195SJoerg Sonnenberger 
14303998195SJoerg Sonnenberger 	/*
14403998195SJoerg Sonnenberger 	 * No root filesystem support.  Probably not a big deal, since the
14503998195SJoerg Sonnenberger 	 * bootloader doesn't understand UDF.
14603998195SJoerg Sonnenberger 	 */
14703998195SJoerg Sonnenberger 	if (mp->mnt_flag & MNT_ROOTFS)
14803998195SJoerg Sonnenberger 		return (ENOTSUP);
14903998195SJoerg Sonnenberger 
15003998195SJoerg Sonnenberger 	if ((error = copyin(data, (caddr_t)&args, sizeof(struct udf_args))))
15103998195SJoerg Sonnenberger 		return(error);
15203998195SJoerg Sonnenberger 
15303998195SJoerg Sonnenberger 	if (mp->mnt_flag & MNT_UPDATE) {
15403998195SJoerg Sonnenberger 		imp = VFSTOUDFFS(mp);
15503998195SJoerg Sonnenberger 		if (args.fspec == NULL)
15603998195SJoerg Sonnenberger 			return(vfs_export(mp, &imp->im_export, &args.export));
15703998195SJoerg Sonnenberger 	}
15803998195SJoerg Sonnenberger 
15903998195SJoerg Sonnenberger 	/* Check that the mount device exists */
160fad57d0eSMatthew Dillon 	devvp = NULL;
161fad57d0eSMatthew Dillon 	error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW);
162fad57d0eSMatthew Dillon 	if (error == 0)
163fad57d0eSMatthew Dillon 		error = nlookup(&nd);
164fad57d0eSMatthew Dillon 	if (error == 0)
16528623bf9SMatthew Dillon 		error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
166fad57d0eSMatthew Dillon 	nlookup_done(&nd);
167fad57d0eSMatthew Dillon 	if (error)
16803998195SJoerg Sonnenberger 		return (error);
16903998195SJoerg Sonnenberger 
17003998195SJoerg Sonnenberger 	if (vn_isdisk(devvp, &error) == 0) {
17103998195SJoerg Sonnenberger 		vrele(devvp);
17203998195SJoerg Sonnenberger 		return(error);
17303998195SJoerg Sonnenberger 	}
17403998195SJoerg Sonnenberger 
17503998195SJoerg Sonnenberger 	/* Check the access rights on the mount device */
176ca466baeSMatthew Dillon 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
177cb66845aSMatthew Dillon 	error = VOP_EACCESS(devvp, VREAD, cred);
17803998195SJoerg Sonnenberger 	if (error)
179*2b3f93eaSMatthew Dillon 		error = caps_priv_check(cred, SYSCAP_RESTRICTEDROOT);
18003998195SJoerg Sonnenberger 	if (error) {
18103998195SJoerg Sonnenberger 		vput(devvp);
18203998195SJoerg Sonnenberger 		return(error);
18303998195SJoerg Sonnenberger 	}
184a11aaa81SMatthew Dillon 	vn_unlock(devvp);
18503998195SJoerg Sonnenberger 
186acde96dbSMatthew Dillon 	if ((error = udf_mountfs(devvp, mp))) {
18703998195SJoerg Sonnenberger 		vrele(devvp);
18803998195SJoerg Sonnenberger 		return(error);
18903998195SJoerg Sonnenberger 	}
19003998195SJoerg Sonnenberger 
19103998195SJoerg Sonnenberger 	imp = VFSTOUDFFS(mp);
19203998195SJoerg Sonnenberger 
19303998195SJoerg Sonnenberger 	imp->im_flags = args.flags;
19403998195SJoerg Sonnenberger 
19503998195SJoerg Sonnenberger 	copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
19603998195SJoerg Sonnenberger 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
197acde96dbSMatthew Dillon 	udf_statfs(mp, &mp->mnt_stat, cred);
19803998195SJoerg Sonnenberger 	return(0);
1994a77c3abSDavid Rhodus }
20003998195SJoerg Sonnenberger 
20103998195SJoerg Sonnenberger /*
20203998195SJoerg Sonnenberger  * Check the descriptor tag for both the correct id and correct checksum.
20303998195SJoerg Sonnenberger  * Return zero if all is good, EINVAL if not.
20403998195SJoerg Sonnenberger  */
20503998195SJoerg Sonnenberger int
udf_checktag(struct desc_tag * tag,uint16_t id)20603998195SJoerg Sonnenberger udf_checktag(struct desc_tag *tag, uint16_t id)
20703998195SJoerg Sonnenberger {
20803998195SJoerg Sonnenberger 	uint8_t *itag;
20903998195SJoerg Sonnenberger 	uint8_t i, cksum = 0;
21003998195SJoerg Sonnenberger 
21103998195SJoerg Sonnenberger 	itag = (uint8_t *)tag;
21203998195SJoerg Sonnenberger 
21303998195SJoerg Sonnenberger 	if (tag->id != id)
21403998195SJoerg Sonnenberger 		return(EINVAL);
21503998195SJoerg Sonnenberger 
21603998195SJoerg Sonnenberger 	for (i = 0; i < 15; i++)
21703998195SJoerg Sonnenberger 		cksum = cksum + itag[i];
21803998195SJoerg Sonnenberger 	cksum = cksum - itag[4];
21903998195SJoerg Sonnenberger 
22003998195SJoerg Sonnenberger 	if (cksum == tag->cksum)
22103998195SJoerg Sonnenberger 		return(0);
22203998195SJoerg Sonnenberger 
22303998195SJoerg Sonnenberger 	return(EINVAL);
22403998195SJoerg Sonnenberger }
22503998195SJoerg Sonnenberger 
22603998195SJoerg Sonnenberger static int
udf_mountfs(struct vnode * devvp,struct mount * mp)227acde96dbSMatthew Dillon udf_mountfs(struct vnode *devvp, struct mount *mp)
228e4c9c0c8SMatthew Dillon {
22903998195SJoerg Sonnenberger 	struct buf *bp = NULL;
23003998195SJoerg Sonnenberger 	struct anchor_vdp avdp;
23103998195SJoerg Sonnenberger 	struct udf_mnt *udfmp = NULL;
23203998195SJoerg Sonnenberger 	struct part_desc *pd;
23303998195SJoerg Sonnenberger 	struct logvol_desc *lvd;
23403998195SJoerg Sonnenberger 	struct fileset_desc *fsd;
23503998195SJoerg Sonnenberger 	struct file_entry *root_fentry;
236b13267a5SMatthew Dillon 	cdev_t dev;
23703998195SJoerg Sonnenberger 	uint32_t sector, size, mvds_start, mvds_end;
23803998195SJoerg Sonnenberger 	uint32_t fsd_offset = 0;
23903998195SJoerg Sonnenberger 	uint16_t part_num = 0, fsd_part = 0;
24003998195SJoerg Sonnenberger 	int error = EINVAL, needclose = 0;
24103998195SJoerg Sonnenberger 	int logvol_found = 0, part_found = 0, fsd_found = 0;
24203998195SJoerg Sonnenberger 	int bsize;
24303998195SJoerg Sonnenberger 
24403998195SJoerg Sonnenberger 	/*
24503998195SJoerg Sonnenberger 	 * Disallow multiple mounts of the same device. Flush the buffer
24603998195SJoerg Sonnenberger 	 * cache for the device.
24703998195SJoerg Sonnenberger 	 */
24803998195SJoerg Sonnenberger 	if ((error = vfs_mountedon(devvp)))
24903998195SJoerg Sonnenberger 		return(error);
2508be7edadSMatthew Dillon 	if (vcount(devvp) > 0)
25103998195SJoerg Sonnenberger 		return(EBUSY);
25287de5057SMatthew Dillon 	if ((error = vinvalbuf(devvp, V_SAVE, 0, 0)))
25303998195SJoerg Sonnenberger 		return(error);
25403998195SJoerg Sonnenberger 
255ca466baeSMatthew Dillon 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
25687de5057SMatthew Dillon 	error = VOP_OPEN(devvp, FREAD, FSCRED, NULL);
257a11aaa81SMatthew Dillon 	vn_unlock(devvp);
25803998195SJoerg Sonnenberger 	if (error)
25903998195SJoerg Sonnenberger 		return(error);
26003998195SJoerg Sonnenberger 	needclose = 1;
261e4c9c0c8SMatthew Dillon 	dev = devvp->v_rdev;
26203998195SJoerg Sonnenberger 
263efda3bd0SMatthew Dillon 	udfmp = kmalloc(sizeof(*udfmp), M_UDFMOUNT, M_WAITOK | M_ZERO);
26403998195SJoerg Sonnenberger 
26503998195SJoerg Sonnenberger 	mp->mnt_data = (qaddr_t)udfmp;
2662ac7d105SSascha Wildner 	mp->mnt_stat.f_fsid.val[0] = devid_from_dev(dev);
26703998195SJoerg Sonnenberger 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
26803998195SJoerg Sonnenberger 	mp->mnt_maxsymlinklen = 0;
26903998195SJoerg Sonnenberger 	mp->mnt_flag |= MNT_LOCAL;
27003998195SJoerg Sonnenberger 	udfmp->im_mountp = mp;
271e4c9c0c8SMatthew Dillon 	udfmp->im_dev = dev;
27203998195SJoerg Sonnenberger 	udfmp->im_devvp = devvp;
27303998195SJoerg Sonnenberger 
27403998195SJoerg Sonnenberger 	bsize = 2048;	/* XXX Should probe the media for it's size */
27503998195SJoerg Sonnenberger 
27603998195SJoerg Sonnenberger 	/*
27703998195SJoerg Sonnenberger 	 * Get the Anchor Volume Descriptor Pointer from sector 256.
27803998195SJoerg Sonnenberger 	 * XXX Should also check sector n - 256, n, and 512.
27903998195SJoerg Sonnenberger 	 */
28003998195SJoerg Sonnenberger 	sector = 256;
28154078292SMatthew Dillon 	if ((error = bread(devvp, (off_t)sector * bsize, bsize, &bp)) != 0)
28203998195SJoerg Sonnenberger 		goto bail;
28303998195SJoerg Sonnenberger 	if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
28403998195SJoerg Sonnenberger 		goto bail;
28503998195SJoerg Sonnenberger 
28603998195SJoerg Sonnenberger 	bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
28703998195SJoerg Sonnenberger 	brelse(bp);
28803998195SJoerg Sonnenberger 	bp = NULL;
28903998195SJoerg Sonnenberger 
29003998195SJoerg Sonnenberger 	/*
29103998195SJoerg Sonnenberger 	 * Extract the Partition Descriptor and Logical Volume Descriptor
29203998195SJoerg Sonnenberger 	 * from the Volume Descriptor Sequence.
29303998195SJoerg Sonnenberger 	 * XXX Should we care about the partition type right now?
29403998195SJoerg Sonnenberger 	 * XXX What about multiple partitions?
29503998195SJoerg Sonnenberger 	 */
29603998195SJoerg Sonnenberger 	mvds_start = avdp.main_vds_ex.loc;
29703998195SJoerg Sonnenberger 	mvds_end = mvds_start + (avdp.main_vds_ex.len - 1) / bsize;
29803998195SJoerg Sonnenberger 	for (sector = mvds_start; sector < mvds_end; sector++) {
29954078292SMatthew Dillon 		if ((error = bread(devvp, (off_t)sector * bsize, bsize,
30003998195SJoerg Sonnenberger 				   &bp)) != 0) {
301086c1d7eSSascha Wildner 			kprintf("Can't read sector %d of VDS\n", sector);
30203998195SJoerg Sonnenberger 			goto bail;
30303998195SJoerg Sonnenberger 		}
30403998195SJoerg Sonnenberger 		lvd = (struct logvol_desc *)bp->b_data;
30503998195SJoerg Sonnenberger 		if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
30603998195SJoerg Sonnenberger 			udfmp->bsize = lvd->lb_size;
30703998195SJoerg Sonnenberger 			udfmp->bmask = udfmp->bsize - 1;
30803998195SJoerg Sonnenberger 			udfmp->bshift = ffs(udfmp->bsize) - 1;
30903998195SJoerg Sonnenberger 			fsd_part = lvd->_lvd_use.fsd_loc.loc.part_num;
31003998195SJoerg Sonnenberger 			fsd_offset = lvd->_lvd_use.fsd_loc.loc.lb_num;
31103998195SJoerg Sonnenberger 			if (udf_find_partmaps(udfmp, lvd))
31203998195SJoerg Sonnenberger 				break;
31303998195SJoerg Sonnenberger 			logvol_found = 1;
31403998195SJoerg Sonnenberger 		}
31503998195SJoerg Sonnenberger 		pd = (struct part_desc *)bp->b_data;
31603998195SJoerg Sonnenberger 		if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
31703998195SJoerg Sonnenberger 			part_found = 1;
31803998195SJoerg Sonnenberger 			part_num = pd->part_num;
31903998195SJoerg Sonnenberger 			udfmp->part_len = pd->part_len;
32003998195SJoerg Sonnenberger 			udfmp->part_start = pd->start_loc;
32103998195SJoerg Sonnenberger 		}
32203998195SJoerg Sonnenberger 
32303998195SJoerg Sonnenberger 		brelse(bp);
32403998195SJoerg Sonnenberger 		bp = NULL;
32503998195SJoerg Sonnenberger 		if ((part_found) && (logvol_found))
32603998195SJoerg Sonnenberger 			break;
32703998195SJoerg Sonnenberger 	}
32803998195SJoerg Sonnenberger 
32903998195SJoerg Sonnenberger 	if (!part_found || !logvol_found) {
33003998195SJoerg Sonnenberger 		error = EINVAL;
33103998195SJoerg Sonnenberger 		goto bail;
33203998195SJoerg Sonnenberger 	}
33303998195SJoerg Sonnenberger 
33403998195SJoerg Sonnenberger 	if (fsd_part != part_num) {
335086c1d7eSSascha Wildner 		kprintf("FSD does not lie within the partition!\n");
33603998195SJoerg Sonnenberger 		error = EINVAL;
33703998195SJoerg Sonnenberger 		goto bail;
33803998195SJoerg Sonnenberger 	}
33903998195SJoerg Sonnenberger 
34003998195SJoerg Sonnenberger 
34103998195SJoerg Sonnenberger 	/*
34203998195SJoerg Sonnenberger 	 * Grab the Fileset Descriptor
34303998195SJoerg Sonnenberger 	 * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing
34403998195SJoerg Sonnenberger 	 * me in the right direction here.
34503998195SJoerg Sonnenberger 	 */
34603998195SJoerg Sonnenberger 	sector = udfmp->part_start + fsd_offset;
34703998195SJoerg Sonnenberger 	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
348086c1d7eSSascha Wildner 		kprintf("Cannot read sector %d of FSD\n", sector);
34903998195SJoerg Sonnenberger 		goto bail;
35003998195SJoerg Sonnenberger 	}
35103998195SJoerg Sonnenberger 	fsd = (struct fileset_desc *)bp->b_data;
35203998195SJoerg Sonnenberger 	if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
35303998195SJoerg Sonnenberger 		fsd_found = 1;
35403998195SJoerg Sonnenberger 		bcopy(&fsd->rootdir_icb, &udfmp->root_icb,
35503998195SJoerg Sonnenberger 		      sizeof(struct long_ad));
35603998195SJoerg Sonnenberger 	}
35703998195SJoerg Sonnenberger 
35803998195SJoerg Sonnenberger 	brelse(bp);
35903998195SJoerg Sonnenberger 	bp = NULL;
36003998195SJoerg Sonnenberger 
36103998195SJoerg Sonnenberger 	if (!fsd_found) {
362086c1d7eSSascha Wildner 		kprintf("Couldn't find the fsd\n");
36303998195SJoerg Sonnenberger 		error = EINVAL;
36403998195SJoerg Sonnenberger 		goto bail;
36503998195SJoerg Sonnenberger 	}
36603998195SJoerg Sonnenberger 
36766a1ddf5SMatthew Dillon 	vfs_add_vnodeops(mp, &udf_vnode_vops, &mp->mnt_vn_norm_ops);
3680961aa92SMatthew Dillon 
36903998195SJoerg Sonnenberger 	/*
37003998195SJoerg Sonnenberger 	 * Find the file entry for the root directory.
37103998195SJoerg Sonnenberger 	 */
37203998195SJoerg Sonnenberger 	sector = udfmp->root_icb.loc.lb_num + udfmp->part_start;
37303998195SJoerg Sonnenberger 	size = udfmp->root_icb.len;
37403998195SJoerg Sonnenberger 	if ((error = udf_readlblks(udfmp, sector, size, &bp)) != 0) {
375086c1d7eSSascha Wildner 		kprintf("Cannot read sector %d\n", sector);
37603998195SJoerg Sonnenberger 		goto bail;
37703998195SJoerg Sonnenberger 	}
37803998195SJoerg Sonnenberger 
37903998195SJoerg Sonnenberger 	root_fentry = (struct file_entry *)bp->b_data;
38003998195SJoerg Sonnenberger 	if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) {
381086c1d7eSSascha Wildner 		kprintf("Invalid root file entry!\n");
38203998195SJoerg Sonnenberger 		goto bail;
38303998195SJoerg Sonnenberger 	}
38403998195SJoerg Sonnenberger 
38503998195SJoerg Sonnenberger 	brelse(bp);
38603998195SJoerg Sonnenberger 	bp = NULL;
38703998195SJoerg Sonnenberger 
388a3c18566SMatthew Dillon 	lwkt_token_init(&udfmp->hash_token, "udfihash");
38903998195SJoerg Sonnenberger 	udfmp->hashtbl = phashinit(UDF_HASHTBLSIZE, M_UDFMOUNT, &udfmp->hashsz);
39003998195SJoerg Sonnenberger 
39103998195SJoerg Sonnenberger 	return(0);
39203998195SJoerg Sonnenberger 
39303998195SJoerg Sonnenberger bail:
39403998195SJoerg Sonnenberger 	if (udfmp != NULL)
395efda3bd0SMatthew Dillon 		kfree(udfmp, M_UDFMOUNT);
39603998195SJoerg Sonnenberger 	if (bp != NULL)
39703998195SJoerg Sonnenberger 		brelse(bp);
39812cdc371SMatthew Dillon 	if (needclose) {
39912cdc371SMatthew Dillon 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
4003596743eSMarkus Pfeiffer 		VOP_CLOSE(devvp, FREAD, NULL);
40112cdc371SMatthew Dillon 		vn_unlock(devvp);
40212cdc371SMatthew Dillon 	}
40303998195SJoerg Sonnenberger 	return(error);
4044a77c3abSDavid Rhodus }
40503998195SJoerg Sonnenberger 
40603998195SJoerg Sonnenberger static int
udf_unmount(struct mount * mp,int mntflags)407acde96dbSMatthew Dillon udf_unmount(struct mount *mp, int mntflags)
40803998195SJoerg Sonnenberger {
40903998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
41003998195SJoerg Sonnenberger 	int error, flags = 0;
41103998195SJoerg Sonnenberger 
41203998195SJoerg Sonnenberger 	udfmp = VFSTOUDFFS(mp);
41303998195SJoerg Sonnenberger 
41403998195SJoerg Sonnenberger 	if (mntflags & MNT_FORCE)
41503998195SJoerg Sonnenberger 		flags |= FORCECLOSE;
41603998195SJoerg Sonnenberger 
41703998195SJoerg Sonnenberger 	if ((error = vflush(mp, 0, flags)))
41803998195SJoerg Sonnenberger 		return (error);
41903998195SJoerg Sonnenberger 
420e4c9c0c8SMatthew Dillon 	udfmp->im_devvp->v_rdev->si_mountpoint = NULL;
42112cdc371SMatthew Dillon 	vn_lock(udfmp->im_devvp, LK_EXCLUSIVE | LK_RETRY);
4223596743eSMarkus Pfeiffer 	error = VOP_CLOSE(udfmp->im_devvp, FREAD, NULL);
42312cdc371SMatthew Dillon 	vn_unlock(udfmp->im_devvp);
42403998195SJoerg Sonnenberger 	vrele(udfmp->im_devvp);
42503998195SJoerg Sonnenberger 
42603998195SJoerg Sonnenberger 	if (udfmp->s_table)
427efda3bd0SMatthew Dillon 		kfree(udfmp->s_table, M_UDFMOUNT);
42803998195SJoerg Sonnenberger 	if (udfmp->hashtbl)
429efda3bd0SMatthew Dillon 		kfree(udfmp->hashtbl, M_UDFMOUNT);
430efda3bd0SMatthew Dillon 	kfree(udfmp, M_UDFMOUNT);
43103998195SJoerg Sonnenberger 
43203998195SJoerg Sonnenberger 	mp->mnt_data = (qaddr_t)0;
43303998195SJoerg Sonnenberger 	mp->mnt_flag &= ~MNT_LOCAL;
43403998195SJoerg Sonnenberger 
43503998195SJoerg Sonnenberger 	return (error);
43603998195SJoerg Sonnenberger }
43703998195SJoerg Sonnenberger 
43803998195SJoerg Sonnenberger static int
udf_root(struct mount * mp,struct vnode ** vpp)43903998195SJoerg Sonnenberger udf_root(struct mount *mp, struct vnode **vpp)
44003998195SJoerg Sonnenberger {
44103998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
44203998195SJoerg Sonnenberger 	struct vnode *vp;
44303998195SJoerg Sonnenberger 	ino_t id;
44403998195SJoerg Sonnenberger 	int error;
44503998195SJoerg Sonnenberger 
44603998195SJoerg Sonnenberger 	udfmp = VFSTOUDFFS(mp);
44703998195SJoerg Sonnenberger 
44803998195SJoerg Sonnenberger 	id = udf_getid(&udfmp->root_icb);
44903998195SJoerg Sonnenberger 
450b9b0a6d0SMatthew Dillon 	error = udf_vget(mp, NULL, id, vpp);
45103998195SJoerg Sonnenberger 	if (error)
45203998195SJoerg Sonnenberger 		return(error);
45303998195SJoerg Sonnenberger 
45403998195SJoerg Sonnenberger 	vp = *vpp;
4552247fe02SMatthew Dillon 	vsetflags(vp, VROOT);
45603998195SJoerg Sonnenberger 	udfmp->root_vp = vp;
45703998195SJoerg Sonnenberger 
45803998195SJoerg Sonnenberger 	return(0);
45903998195SJoerg Sonnenberger }
46003998195SJoerg Sonnenberger 
46103998195SJoerg Sonnenberger static int
udf_statfs(struct mount * mp,struct statfs * sbp,struct ucred * cred)462acde96dbSMatthew Dillon udf_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
46303998195SJoerg Sonnenberger {
46403998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
46503998195SJoerg Sonnenberger 
46603998195SJoerg Sonnenberger 	udfmp = VFSTOUDFFS(mp);
46703998195SJoerg Sonnenberger 
46803998195SJoerg Sonnenberger 	sbp->f_bsize = udfmp->bsize;
46903998195SJoerg Sonnenberger 	sbp->f_iosize = udfmp->bsize;
47003998195SJoerg Sonnenberger 	sbp->f_blocks = udfmp->part_len;
47103998195SJoerg Sonnenberger 	sbp->f_bfree = 0;
47203998195SJoerg Sonnenberger 	sbp->f_bavail = 0;
47303998195SJoerg Sonnenberger 	sbp->f_files = 0;
47403998195SJoerg Sonnenberger 	sbp->f_ffree = 0;
47503998195SJoerg Sonnenberger 	if (sbp != &mp->mnt_stat) {
47603998195SJoerg Sonnenberger 		sbp->f_type = mp->mnt_vfc->vfc_typenum;
47703998195SJoerg Sonnenberger 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
47803998195SJoerg Sonnenberger 	}
47903998195SJoerg Sonnenberger 
48003998195SJoerg Sonnenberger 	return(0);
48103998195SJoerg Sonnenberger }
48203998195SJoerg Sonnenberger 
48303998195SJoerg Sonnenberger int
udf_vget(struct mount * mp,struct vnode * dvp,ino_t ino,struct vnode ** vpp)484b9b0a6d0SMatthew Dillon udf_vget(struct mount *mp, struct vnode *dvp, ino_t ino, struct vnode **vpp)
48503998195SJoerg Sonnenberger {
48603998195SJoerg Sonnenberger 	struct buf *bp;
48703998195SJoerg Sonnenberger 	struct vnode *devvp;
48803998195SJoerg Sonnenberger 	struct udf_mnt *udfmp;
48903998195SJoerg Sonnenberger 	struct vnode *vp;
49003998195SJoerg Sonnenberger 	struct udf_node *unode;
49103998195SJoerg Sonnenberger 	struct file_entry *fe;
49203998195SJoerg Sonnenberger 	int error, sector, size;
49303998195SJoerg Sonnenberger 
49403998195SJoerg Sonnenberger 	udfmp = VFSTOUDFFS(mp);
49503998195SJoerg Sonnenberger 
49603998195SJoerg Sonnenberger 	/* See if we already have this in the cache */
49703998195SJoerg Sonnenberger 	if ((error = udf_hashlookup(udfmp, ino, vpp)) != 0)
49803998195SJoerg Sonnenberger 		return(error);
49903998195SJoerg Sonnenberger 	if (*vpp != NULL) {
50003998195SJoerg Sonnenberger 		return(0);
50103998195SJoerg Sonnenberger 	}
50203998195SJoerg Sonnenberger 
50303998195SJoerg Sonnenberger 	/*
50403998195SJoerg Sonnenberger 	 * Allocate memory and check the tag id's before grabbing a new
50503998195SJoerg Sonnenberger 	 * vnode, since it's hard to roll back if there is a problem.
50603998195SJoerg Sonnenberger 	 */
507efda3bd0SMatthew Dillon 	unode = kmalloc(sizeof(*unode), M_UDFNODE, M_WAITOK | M_ZERO);
50803998195SJoerg Sonnenberger 
50903998195SJoerg Sonnenberger 	/*
51003998195SJoerg Sonnenberger 	 * Copy in the file entry.  Per the spec, the size can only be 1 block.
51103998195SJoerg Sonnenberger 	 */
51203998195SJoerg Sonnenberger 	sector = ino + udfmp->part_start;
51303998195SJoerg Sonnenberger 	devvp = udfmp->im_devvp;
51403998195SJoerg Sonnenberger 	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
515086c1d7eSSascha Wildner 		kprintf("Cannot read sector %d\n", sector);
516efda3bd0SMatthew Dillon 		kfree(unode, M_UDFNODE);
51703998195SJoerg Sonnenberger 		return(error);
51803998195SJoerg Sonnenberger 	}
51903998195SJoerg Sonnenberger 
52003998195SJoerg Sonnenberger 	fe = (struct file_entry *)bp->b_data;
52103998195SJoerg Sonnenberger 	if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
522086c1d7eSSascha Wildner 		kprintf("Invalid file entry!\n");
523efda3bd0SMatthew Dillon 		kfree(unode, M_UDFNODE);
52403998195SJoerg Sonnenberger 		brelse(bp);
52503998195SJoerg Sonnenberger 		return(ENOMEM);
52603998195SJoerg Sonnenberger 	}
52703998195SJoerg Sonnenberger 	size = UDF_FENTRY_SIZE + fe->l_ea + fe->l_ad;
528efda3bd0SMatthew Dillon 	unode->fentry = kmalloc(size, M_UDFFENTRY, M_WAITOK | M_ZERO);
52903998195SJoerg Sonnenberger 
53003998195SJoerg Sonnenberger 	bcopy(bp->b_data, unode->fentry, size);
53103998195SJoerg Sonnenberger 
53203998195SJoerg Sonnenberger 	brelse(bp);
53303998195SJoerg Sonnenberger 	bp = NULL;
53403998195SJoerg Sonnenberger 
53503998195SJoerg Sonnenberger 	if ((error = udf_allocv(mp, &vp))) {
536086c1d7eSSascha Wildner 		kprintf("Error from udf_allocv\n");
537efda3bd0SMatthew Dillon 		kfree(unode, M_UDFNODE);
53803998195SJoerg Sonnenberger 		return(error);
53903998195SJoerg Sonnenberger 	}
54003998195SJoerg Sonnenberger 
54103998195SJoerg Sonnenberger 	unode->i_vnode = vp;
54203998195SJoerg Sonnenberger 	unode->hash_id = ino;
54303998195SJoerg Sonnenberger 	unode->i_devvp = udfmp->im_devvp;
54403998195SJoerg Sonnenberger 	unode->i_dev = udfmp->im_dev;
54503998195SJoerg Sonnenberger 	unode->udfmp = udfmp;
54603998195SJoerg Sonnenberger 	vp->v_data = unode;
547597aea93SDavid Rhodus 	vref(udfmp->im_devvp);
54803998195SJoerg Sonnenberger 	udf_hashins(unode);
54903998195SJoerg Sonnenberger 
55003998195SJoerg Sonnenberger 	switch (unode->fentry->icbtag.file_type) {
55103998195SJoerg Sonnenberger 	default:
55203998195SJoerg Sonnenberger 		vp->v_type = VBAD;
55303998195SJoerg Sonnenberger 		break;
55403998195SJoerg Sonnenberger 	case 4:
55503998195SJoerg Sonnenberger 		vp->v_type = VDIR;
55603998195SJoerg Sonnenberger 		break;
55703998195SJoerg Sonnenberger 	case 5:
55803998195SJoerg Sonnenberger 		vp->v_type = VREG;
55903998195SJoerg Sonnenberger 		break;
56003998195SJoerg Sonnenberger 	case 6:
56103998195SJoerg Sonnenberger 		vp->v_type = VBLK;
56203998195SJoerg Sonnenberger 		break;
56303998195SJoerg Sonnenberger 	case 7:
56403998195SJoerg Sonnenberger 		vp->v_type = VCHR;
56503998195SJoerg Sonnenberger 		break;
56603998195SJoerg Sonnenberger 	case 9:
56703998195SJoerg Sonnenberger 		vp->v_type = VFIFO;
56803998195SJoerg Sonnenberger 		break;
56903998195SJoerg Sonnenberger 	case 10:
57003998195SJoerg Sonnenberger 		vp->v_type = VSOCK;
57103998195SJoerg Sonnenberger 		break;
57203998195SJoerg Sonnenberger 	case 12:
57303998195SJoerg Sonnenberger 		vp->v_type = VLNK;
57403998195SJoerg Sonnenberger 		break;
57503998195SJoerg Sonnenberger 	}
5765fd012e0SMatthew Dillon 	/*
5775fd012e0SMatthew Dillon 	 * Locked and refd vnode returned
5785fd012e0SMatthew Dillon 	 */
57903998195SJoerg Sonnenberger 	*vpp = vp;
58003998195SJoerg Sonnenberger 
58103998195SJoerg Sonnenberger 	return(0);
58203998195SJoerg Sonnenberger }
58303998195SJoerg Sonnenberger 
58403998195SJoerg Sonnenberger struct ifid {
58503998195SJoerg Sonnenberger 	u_short	ifid_len;
58603998195SJoerg Sonnenberger 	u_short	ifid_pad;
58703998195SJoerg Sonnenberger 	int	ifid_ino;
58803998195SJoerg Sonnenberger 	long	ifid_start;
58903998195SJoerg Sonnenberger };
59003998195SJoerg Sonnenberger 
59103998195SJoerg Sonnenberger static int
udf_fhtovp(struct mount * mp,struct vnode * rootvp,struct fid * fhp,struct vnode ** vpp)59267863d04SMatthew Dillon udf_fhtovp(struct mount *mp, struct vnode *rootvp,
59367863d04SMatthew Dillon 	   struct fid *fhp, struct vnode **vpp)
59403998195SJoerg Sonnenberger {
59503998195SJoerg Sonnenberger 	struct ifid *ifhp;
59603998195SJoerg Sonnenberger 	struct vnode *nvp;
59703998195SJoerg Sonnenberger 	int error;
59803998195SJoerg Sonnenberger 
59903998195SJoerg Sonnenberger 	ifhp = (struct ifid *)fhp;
60003998195SJoerg Sonnenberger 
601b9b0a6d0SMatthew Dillon 	if ((error = VFS_VGET(mp, NULL, ifhp->ifid_ino, &nvp)) != 0) {
60203998195SJoerg Sonnenberger 		*vpp = NULLVP;
60303998195SJoerg Sonnenberger 		return(error);
60403998195SJoerg Sonnenberger 	}
60503998195SJoerg Sonnenberger 
60603998195SJoerg Sonnenberger 	*vpp = nvp;
60703998195SJoerg Sonnenberger 	return(0);
60803998195SJoerg Sonnenberger }
60903998195SJoerg Sonnenberger 
61003998195SJoerg Sonnenberger static int
udf_vptofh(struct vnode * vp,struct fid * fhp)61103998195SJoerg Sonnenberger udf_vptofh (struct vnode *vp, struct fid *fhp)
61203998195SJoerg Sonnenberger {
61303998195SJoerg Sonnenberger 	struct udf_node *node;
61403998195SJoerg Sonnenberger 	struct ifid *ifhp;
61503998195SJoerg Sonnenberger 
61603998195SJoerg Sonnenberger 	node = VTON(vp);
61703998195SJoerg Sonnenberger 	ifhp = (struct ifid *)fhp;
61803998195SJoerg Sonnenberger 	ifhp->ifid_len = sizeof(struct ifid);
61903998195SJoerg Sonnenberger 	ifhp->ifid_ino = node->hash_id;
62003998195SJoerg Sonnenberger 
62103998195SJoerg Sonnenberger 	return(0);
62203998195SJoerg Sonnenberger }
62303998195SJoerg Sonnenberger 
62403998195SJoerg Sonnenberger static int
udf_find_partmaps(struct udf_mnt * udfmp,struct logvol_desc * lvd)62503998195SJoerg Sonnenberger udf_find_partmaps(struct udf_mnt *udfmp, struct logvol_desc *lvd)
62603998195SJoerg Sonnenberger {
62703998195SJoerg Sonnenberger 	union udf_pmap *pmap;
62803998195SJoerg Sonnenberger 	struct part_map_spare *pms;
62903998195SJoerg Sonnenberger 	struct regid *pmap_id;
63003998195SJoerg Sonnenberger 	struct buf *bp;
63103998195SJoerg Sonnenberger 	unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
63203998195SJoerg Sonnenberger 	int ptype, psize, error;
63303998195SJoerg Sonnenberger 	unsigned int i;
63403998195SJoerg Sonnenberger 
63503998195SJoerg Sonnenberger 	for (i = 0; i < lvd->n_pm; i++) {
63603998195SJoerg Sonnenberger 		pmap = (union udf_pmap *)&lvd->maps[i * UDF_PMAP_SIZE];
63703998195SJoerg Sonnenberger 		ptype = pmap->data[0];
63803998195SJoerg Sonnenberger 		psize = pmap->data[1];
63903998195SJoerg Sonnenberger 		if (((ptype != 1) && (ptype != 2)) ||
64003998195SJoerg Sonnenberger 		    ((psize != UDF_PMAP_SIZE) && (psize != 6))) {
641086c1d7eSSascha Wildner 			kprintf("Invalid partition map found\n");
64203998195SJoerg Sonnenberger 			return(1);
64303998195SJoerg Sonnenberger 		}
64403998195SJoerg Sonnenberger 
64503998195SJoerg Sonnenberger 		if (ptype == 1) {
64603998195SJoerg Sonnenberger 			/* Type 1 map.  We don't care */
64703998195SJoerg Sonnenberger 			continue;
64803998195SJoerg Sonnenberger 		}
64903998195SJoerg Sonnenberger 
65003998195SJoerg Sonnenberger 		/* Type 2 map.  Gotta find out the details */
65103998195SJoerg Sonnenberger 		pmap_id = (struct regid *)&pmap->data[4];
65203998195SJoerg Sonnenberger 		bzero(&regid_id[0], UDF_REGID_ID_SIZE);
65303998195SJoerg Sonnenberger 		bcopy(&pmap_id->id[0], &regid_id[0], UDF_REGID_ID_SIZE);
65403998195SJoerg Sonnenberger 
65503998195SJoerg Sonnenberger 		if (bcmp(&regid_id[0], "*UDF Sparable Partition",
65603998195SJoerg Sonnenberger 		    UDF_REGID_ID_SIZE)) {
657086c1d7eSSascha Wildner 			kprintf("Unsupported partition map: %s\n", &regid_id[0]);
65803998195SJoerg Sonnenberger 			return(1);
65903998195SJoerg Sonnenberger 		}
66003998195SJoerg Sonnenberger 
66103998195SJoerg Sonnenberger 		pms = &pmap->pms;
662efda3bd0SMatthew Dillon 		udfmp->s_table = kmalloc(pms->st_size, M_UDFMOUNT,
66303998195SJoerg Sonnenberger 					M_WAITOK | M_ZERO);
66403998195SJoerg Sonnenberger 
66503998195SJoerg Sonnenberger 		/* Calculate the number of sectors per packet. */
66603998195SJoerg Sonnenberger 		/* XXX Logical or physical? */
66703998195SJoerg Sonnenberger 		udfmp->p_sectors = pms->packet_len / udfmp->bsize;
66803998195SJoerg Sonnenberger 
66903998195SJoerg Sonnenberger 		/*
67003998195SJoerg Sonnenberger 		 * XXX If reading the first Sparing Table fails, should look
67103998195SJoerg Sonnenberger 		 * for another table.
67203998195SJoerg Sonnenberger 		 */
67303998195SJoerg Sonnenberger 		if ((error = udf_readlblks(udfmp, pms->st_loc[0], pms->st_size,
67403998195SJoerg Sonnenberger 		    &bp)) != 0) {
675ffaa7d78SMatthew Dillon 			if (bp)
676ffaa7d78SMatthew Dillon 				brelse(bp);
677086c1d7eSSascha Wildner 			kprintf("Failed to read Sparing Table at sector %d\n",
67803998195SJoerg Sonnenberger 			    pms->st_loc[0]);
67903998195SJoerg Sonnenberger 			return(error);
68003998195SJoerg Sonnenberger 		}
68103998195SJoerg Sonnenberger 		bcopy(bp->b_data, udfmp->s_table, pms->st_size);
68203998195SJoerg Sonnenberger 		brelse(bp);
68303998195SJoerg Sonnenberger 
68403998195SJoerg Sonnenberger 		if (udf_checktag(&udfmp->s_table->tag, 0)) {
685086c1d7eSSascha Wildner 			kprintf("Invalid sparing table found\n");
68603998195SJoerg Sonnenberger 			return(EINVAL);
68703998195SJoerg Sonnenberger 		}
68803998195SJoerg Sonnenberger 
68903998195SJoerg Sonnenberger 		/* See how many valid entries there are here.  The list is
69003998195SJoerg Sonnenberger 		 * supposed to be sorted. 0xfffffff0 and higher are not valid
69103998195SJoerg Sonnenberger 		 */
69203998195SJoerg Sonnenberger 		for (i = 0; i < udfmp->s_table->rt_l; i++) {
69303998195SJoerg Sonnenberger 			udfmp->s_table_entries = i;
69403998195SJoerg Sonnenberger 			if (udfmp->s_table->entries[i].org >= 0xfffffff0)
69503998195SJoerg Sonnenberger 				break;
69603998195SJoerg Sonnenberger 		}
69703998195SJoerg Sonnenberger 	}
69803998195SJoerg Sonnenberger 
69903998195SJoerg Sonnenberger 	return(0);
70003998195SJoerg Sonnenberger }
701