194663Sscottl/*-
294663Sscottl * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
394663Sscottl * All rights reserved.
494663Sscottl *
594663Sscottl * Redistribution and use in source and binary forms, with or without
694663Sscottl * modification, are permitted provided that the following conditions
794663Sscottl * are met:
894663Sscottl * 1. Redistributions of source code must retain the above copyright
994663Sscottl *    notice, this list of conditions and the following disclaimer.
1094663Sscottl * 2. Redistributions in binary form must reproduce the above copyright
1194663Sscottl *    notice, this list of conditions and the following disclaimer in the
1294663Sscottl *    documentation and/or other materials provided with the distribution.
1394663Sscottl *
1494663Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1594663Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1694663Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1794663Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1894663Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1994663Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2094663Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2194663Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2294663Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2394663Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2494663Sscottl * SUCH DAMAGE.
2594663Sscottl *
2694663Sscottl * $FreeBSD: releng/10.3/sys/fs/udf/udf_vfsops.c 242833 2012-11-09 18:02:25Z attilio $
2794663Sscottl */
2894663Sscottl
2994663Sscottl/* udf_vfsops.c */
3094663Sscottl/* Implement the VFS side of things */
3194663Sscottl
3294663Sscottl/*
3394663Sscottl * Ok, here's how it goes.  The UDF specs are pretty clear on how each data
3494663Sscottl * structure is made up, but not very clear on how they relate to each other.
3594663Sscottl * Here is the skinny... This demostrates a filesystem with one file in the
3694663Sscottl * root directory.  Subdirectories are treated just as normal files, but they
3794663Sscottl * have File Id Descriptors of their children as their file data.  As for the
3894663Sscottl * Anchor Volume Descriptor Pointer, it can exist in two of the following three
3994663Sscottl * places: sector 256, sector n (the max sector of the disk), or sector
4094663Sscottl * n - 256.  It's a pretty good bet that one will exist at sector 256 though.
4194663Sscottl * One caveat is unclosed CD media.  For that, sector 256 cannot be written,
4294663Sscottl * so the Anchor Volume Descriptor Pointer can exist at sector 512 until the
4394663Sscottl * media is closed.
4494663Sscottl *
4594663Sscottl *  Sector:
4694663Sscottl *     256:
4794663Sscottl *       n: Anchor Volume Descriptor Pointer
4894663Sscottl * n - 256:	|
4994663Sscottl *		|
5094663Sscottl *		|-->Main Volume Descriptor Sequence
5194663Sscottl *			|	|
5294663Sscottl *			|	|
5394663Sscottl *			|	|-->Logical Volume Descriptor
5494663Sscottl *			|			  |
5594663Sscottl *			|-->Partition Descriptor  |
5694663Sscottl *				|		  |
5794663Sscottl *				|		  |
5894663Sscottl *				|-->Fileset Descriptor
5994663Sscottl *					|
6094663Sscottl *					|
6194663Sscottl *					|-->Root Dir File Entry
6294663Sscottl *						|
6394663Sscottl *						|
6494663Sscottl *						|-->File data:
6594663Sscottl *						    File Id Descriptor
6694663Sscottl *							|
6794663Sscottl *							|
6894663Sscottl *							|-->File Entry
6994663Sscottl *								|
7094663Sscottl *								|
7194663Sscottl *								|-->File data
7294663Sscottl */
7394663Sscottl#include <sys/types.h>
7494663Sscottl#include <sys/param.h>
7594663Sscottl#include <sys/systm.h>
76100164Smarkm#include <sys/uio.h>
7794663Sscottl#include <sys/bio.h>
7894663Sscottl#include <sys/buf.h>
79100164Smarkm#include <sys/conf.h>
80100164Smarkm#include <sys/dirent.h>
81100164Smarkm#include <sys/fcntl.h>
82122102Sscottl#include <sys/iconv.h>
83100164Smarkm#include <sys/kernel.h>
8494663Sscottl#include <sys/malloc.h>
8594663Sscottl#include <sys/mount.h>
86100164Smarkm#include <sys/namei.h>
87164033Srwatson#include <sys/priv.h>
88100164Smarkm#include <sys/proc.h>
8994663Sscottl#include <sys/queue.h>
90100164Smarkm#include <sys/vnode.h>
91130986Sscottl#include <sys/endian.h>
9294663Sscottl
93137037Sphk#include <geom/geom.h>
94137037Sphk#include <geom/geom_vfs.h>
95137037Sphk
9694663Sscottl#include <vm/uma.h>
9794663Sscottl
9894663Sscottl#include <fs/udf/ecma167-udf.h>
99122102Sscottl#include <fs/udf/osta.h>
10094663Sscottl#include <fs/udf/udf.h>
101122102Sscottl#include <fs/udf/udf_mount.h>
10294663Sscottl
103151897Srwatsonstatic MALLOC_DEFINE(M_UDFMOUNT, "udf_mount", "UDF mount structure");
104151897SrwatsonMALLOC_DEFINE(M_UDFFENTRY, "udf_fentry", "UDF file entry structure");
10594663Sscottl
106122102Sscottlstruct iconv_functions *udf_iconv = NULL;
107122102Sscottl
10894663Sscottl/* Zones */
10994663Sscottluma_zone_t udf_zone_trans = NULL;
11094663Sscottluma_zone_t udf_zone_node = NULL;
111101890Sscottluma_zone_t udf_zone_ds = NULL;
11294663Sscottl
113116271Sphkstatic vfs_init_t      udf_init;
114116271Sphkstatic vfs_uninit_t    udf_uninit;
115132902Sphkstatic vfs_mount_t     udf_mount;
116116271Sphkstatic vfs_root_t      udf_root;
117116271Sphkstatic vfs_statfs_t    udf_statfs;
118116271Sphkstatic vfs_unmount_t   udf_unmount;
119116271Sphkstatic vfs_fhtovp_t	udf_fhtovp;
120116271Sphk
12194663Sscottlstatic int udf_find_partmaps(struct udf_mnt *, struct logvol_desc *);
12294663Sscottl
12394663Sscottlstatic struct vfsops udf_vfsops = {
124116271Sphk	.vfs_fhtovp =		udf_fhtovp,
125116271Sphk	.vfs_init =		udf_init,
126132902Sphk	.vfs_mount =		udf_mount,
127116271Sphk	.vfs_root =		udf_root,
128116271Sphk	.vfs_statfs =		udf_statfs,
129116271Sphk	.vfs_uninit =		udf_uninit,
130116271Sphk	.vfs_unmount =		udf_unmount,
131116271Sphk	.vfs_vget =		udf_vget,
13294663Sscottl};
13394663SscottlVFS_SET(udf_vfsops, udf, VFCF_READONLY);
13494663Sscottl
135122102SscottlMODULE_VERSION(udf, 1);
136122102Sscottl
137183754Sattiliostatic int udf_mountfs(struct vnode *, struct mount *);
13894663Sscottl
13994663Sscottlstatic int
14094663Sscottludf_init(struct vfsconf *foo)
14194663Sscottl{
14294663Sscottl
14394663Sscottl	/*
14494663Sscottl	 * This code used to pre-allocate a certain number of pages for each
14594663Sscottl	 * pool, reducing the need to grow the zones later on.  UMA doesn't
14694663Sscottl	 * advertise any such functionality, unfortunately =-<
14794663Sscottl	 */
14894663Sscottl	udf_zone_trans = uma_zcreate("UDF translation buffer, zone", MAXNAMLEN *
14994663Sscottl	    sizeof(unicode_t), NULL, NULL, NULL, NULL, 0, 0);
15094663Sscottl
15194663Sscottl	udf_zone_node = uma_zcreate("UDF Node zone", sizeof(struct udf_node),
15294663Sscottl	    NULL, NULL, NULL, NULL, 0, 0);
15394663Sscottl
154101890Sscottl	udf_zone_ds = uma_zcreate("UDF Dirstream zone",
155101890Sscottl	    sizeof(struct udf_dirstream), NULL, NULL, NULL, NULL, 0, 0);
156101890Sscottl
157101890Sscottl	if ((udf_zone_node == NULL) || (udf_zone_trans == NULL) ||
158101890Sscottl	    (udf_zone_ds == NULL)) {
15994663Sscottl		printf("Cannot create allocation zones.\n");
16094663Sscottl		return (ENOMEM);
16194663Sscottl	}
16294663Sscottl
16394663Sscottl	return 0;
16494663Sscottl}
16594663Sscottl
16694663Sscottlstatic int
16794663Sscottludf_uninit(struct vfsconf *foo)
16894663Sscottl{
16994663Sscottl
17094663Sscottl	if (udf_zone_trans != NULL) {
17194663Sscottl		uma_zdestroy(udf_zone_trans);
17294663Sscottl		udf_zone_trans = NULL;
17394663Sscottl	}
17494663Sscottl
17594663Sscottl	if (udf_zone_node != NULL) {
17694663Sscottl		uma_zdestroy(udf_zone_node);
17794663Sscottl		udf_zone_node = NULL;
17894663Sscottl	}
17994663Sscottl
180101890Sscottl	if (udf_zone_ds != NULL) {
181101890Sscottl		uma_zdestroy(udf_zone_ds);
182101890Sscottl		udf_zone_ds = NULL;
183101890Sscottl	}
184101890Sscottl
18594663Sscottl	return (0);
18694663Sscottl}
18794663Sscottl
18894663Sscottlstatic int
189191990Sattilioudf_mount(struct mount *mp)
19094663Sscottl{
19194663Sscottl	struct vnode *devvp;	/* vnode of the mount device */
192191990Sattilio	struct thread *td;
193238697Skevlo	struct udf_mnt *imp = NULL;
19498265Smux	struct vfsoptlist *opts;
195122102Sscottl	char *fspec, *cs_disk, *cs_local;
196122102Sscottl	int error, len, *udf_flags;
197132902Sphk	struct nameidata nd, *ndp = &nd;
19894663Sscottl
199191990Sattilio	td = curthread;
20098265Smux	opts = mp->mnt_optnew;
20198265Smux
202151405Srodrigc	/*
203151405Srodrigc	 * Unconditionally mount as read-only.
204151405Srodrigc	 */
205162647Stegge	MNT_ILOCK(mp);
206151405Srodrigc	mp->mnt_flag |= MNT_RDONLY;
207162647Stegge	MNT_IUNLOCK(mp);
20894663Sscottl
20994663Sscottl	/*
21094663Sscottl	 * No root filesystem support.  Probably not a big deal, since the
21194663Sscottl	 * bootloader doesn't understand UDF.
21294663Sscottl	 */
21394663Sscottl	if (mp->mnt_flag & MNT_ROOTFS)
21494663Sscottl		return (ENOTSUP);
21594663Sscottl
21698265Smux	fspec = NULL;
21798265Smux	error = vfs_getopt(opts, "from", (void **)&fspec, &len);
21898265Smux	if (!error && fspec[len - 1] != '\0')
21998265Smux		return (EINVAL);
22094663Sscottl
22194663Sscottl	if (mp->mnt_flag & MNT_UPDATE) {
222158927Srodrigc		return (0);
22394663Sscottl	}
22494663Sscottl
22594663Sscottl	/* Check that the mount device exists */
22698265Smux	if (fspec == NULL)
22798265Smux		return (EINVAL);
228149720Sssouhlal	NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td);
22994663Sscottl	if ((error = namei(ndp)))
23094663Sscottl		return (error);
23194663Sscottl	NDFREE(ndp, NDF_ONLY_PNBUF);
23294663Sscottl	devvp = ndp->ni_vp;
23394663Sscottl
23494663Sscottl	if (vn_isdisk(devvp, &error) == 0) {
235149720Sssouhlal		vput(devvp);
23694663Sscottl		return (error);
23794663Sscottl	}
23894663Sscottl
23994663Sscottl	/* Check the access rights on the mount device */
24094663Sscottl	error = VOP_ACCESS(devvp, VREAD, td->td_ucred, td);
24194663Sscottl	if (error)
242164033Srwatson		error = priv_check(td, PRIV_VFS_MOUNT_PERM);
24394663Sscottl	if (error) {
24494663Sscottl		vput(devvp);
24594663Sscottl		return (error);
24694663Sscottl	}
24794663Sscottl
248183754Sattilio	if ((error = udf_mountfs(devvp, mp))) {
24994663Sscottl		vrele(devvp);
25094663Sscottl		return (error);
25194663Sscottl	}
25294663Sscottl
25394663Sscottl	imp = VFSTOUDFFS(mp);
254122102Sscottl
255122102Sscottl	udf_flags = NULL;
256122102Sscottl	error = vfs_getopt(opts, "flags", (void **)&udf_flags, &len);
257122102Sscottl	if (error || len != sizeof(int))
258122102Sscottl		return (EINVAL);
259122102Sscottl	imp->im_flags = *udf_flags;
260122102Sscottl
261122102Sscottl	if (imp->im_flags & UDFMNT_KICONV && udf_iconv) {
262122102Sscottl		cs_disk = NULL;
263122102Sscottl		error = vfs_getopt(opts, "cs_disk", (void **)&cs_disk, &len);
264122102Sscottl		if (!error && cs_disk[len - 1] != '\0')
265122102Sscottl			return (EINVAL);
266122102Sscottl		cs_local = NULL;
267122102Sscottl		error = vfs_getopt(opts, "cs_local", (void **)&cs_local, &len);
268122102Sscottl		if (!error && cs_local[len - 1] != '\0')
269122102Sscottl			return (EINVAL);
270122102Sscottl		udf_iconv->open(cs_local, cs_disk, &imp->im_d2l);
271122102Sscottl#if 0
272122102Sscottl		udf_iconv->open(cs_disk, cs_local, &imp->im_l2d);
273122102Sscottl#endif
274122102Sscottl	}
275122102Sscottl
276138484Sphk	vfs_mountedfrom(mp, fspec);
27794663Sscottl	return 0;
27894663Sscottl};
27994663Sscottl
28094663Sscottl/*
28194663Sscottl * Check the descriptor tag for both the correct id and correct checksum.
28294663Sscottl * Return zero if all is good, EINVAL if not.
28394663Sscottl */
28494663Sscottlint
28594795Sasmodaiudf_checktag(struct desc_tag *tag, uint16_t id)
28694663Sscottl{
28794795Sasmodai	uint8_t *itag;
28894795Sasmodai	uint8_t i, cksum = 0;
28994663Sscottl
29094795Sasmodai	itag = (uint8_t *)tag;
29194663Sscottl
292155256Swill	if (le16toh(tag->id) != id)
29394663Sscottl		return (EINVAL);
29494663Sscottl
295174538Smarkus	for (i = 0; i < 16; i++)
29694663Sscottl		cksum = cksum + itag[i];
29794663Sscottl	cksum = cksum - itag[4];
29894663Sscottl
29994663Sscottl	if (cksum == tag->cksum)
30094663Sscottl		return (0);
30194663Sscottl
30294663Sscottl	return (EINVAL);
30394663Sscottl}
30494663Sscottl
30594663Sscottlstatic int
306188502Sjhbudf_mountfs(struct vnode *devvp, struct mount *mp)
307188502Sjhb{
30894663Sscottl	struct buf *bp = NULL;
309188502Sjhb	struct cdev *dev;
31094663Sscottl	struct anchor_vdp avdp;
31194663Sscottl	struct udf_mnt *udfmp = NULL;
31294663Sscottl	struct part_desc *pd;
31394663Sscottl	struct logvol_desc *lvd;
31494663Sscottl	struct fileset_desc *fsd;
31594663Sscottl	struct file_entry *root_fentry;
31694795Sasmodai	uint32_t sector, size, mvds_start, mvds_end;
317151157Srodrigc	uint32_t logical_secsize;
31894795Sasmodai	uint32_t fsd_offset = 0;
31994795Sasmodai	uint16_t part_num = 0, fsd_part = 0;
320137037Sphk	int error = EINVAL;
32194663Sscottl	int logvol_found = 0, part_found = 0, fsd_found = 0;
32294663Sscottl	int bsize;
323137037Sphk	struct g_consumer *cp;
324137037Sphk	struct bufobj *bo;
32594663Sscottl
326188502Sjhb	dev = devvp->v_rdev;
327188502Sjhb	dev_ref(dev);
328137037Sphk	DROP_GIANT();
329137037Sphk	g_topology_lock();
330137037Sphk	error = g_vfs_open(devvp, &cp, "udf", 0);
331137037Sphk	g_topology_unlock();
332137037Sphk	PICKUP_GIANT();
333175294Sattilio	VOP_UNLOCK(devvp, 0);
33494663Sscottl	if (error)
335188502Sjhb		goto bail;
33694663Sscottl
337137037Sphk	bo = &devvp->v_bufobj;
338137037Sphk
339189070Savg	if (devvp->v_rdev->si_iosize_max != 0)
340189070Savg		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
341189070Savg	if (mp->mnt_iosize_max > MAXPHYS)
342189070Savg		mp->mnt_iosize_max = MAXPHYS;
343189070Savg
344137037Sphk	/* XXX: should be M_WAITOK */
345184205Sdes	udfmp = malloc(sizeof(struct udf_mnt), M_UDFMOUNT,
34694663Sscottl	    M_NOWAIT | M_ZERO);
34794663Sscottl	if (udfmp == NULL) {
34894663Sscottl		printf("Cannot allocate UDF mount struct\n");
34994663Sscottl		error = ENOMEM;
35094663Sscottl		goto bail;
35194663Sscottl	}
35294663Sscottl
353172697Salfred	mp->mnt_data = udfmp;
35494663Sscottl	mp->mnt_stat.f_fsid.val[0] = dev2udev(devvp->v_rdev);
35594663Sscottl	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
356162647Stegge	MNT_ILOCK(mp);
35794663Sscottl	mp->mnt_flag |= MNT_LOCAL;
358242833Sattilio	mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
359162647Stegge	MNT_IUNLOCK(mp);
36094663Sscottl	udfmp->im_mountp = mp;
361188502Sjhb	udfmp->im_dev = dev;
36294663Sscottl	udfmp->im_devvp = devvp;
363122102Sscottl	udfmp->im_d2l = NULL;
364137037Sphk	udfmp->im_cp = cp;
365137037Sphk	udfmp->im_bo = bo;
366137037Sphk
367122102Sscottl#if 0
368122102Sscottl	udfmp->im_l2d = NULL;
369122102Sscottl#endif
370151157Srodrigc	/*
371151157Srodrigc	 * The UDF specification defines a logical sectorsize of 2048
372151157Srodrigc	 * for DVD media.
373151157Srodrigc	 */
374151157Srodrigc	logical_secsize = 2048;
37594663Sscottl
376151157Srodrigc	if (((logical_secsize % cp->provider->sectorsize) != 0) ||
377151157Srodrigc	    (logical_secsize < cp->provider->sectorsize)) {
378188502Sjhb		error = EINVAL;
379188502Sjhb		goto bail;
380151157Srodrigc	}
38194663Sscottl
382151157Srodrigc	bsize = cp->provider->sectorsize;
383151157Srodrigc
38494663Sscottl	/*
38594663Sscottl	 * Get the Anchor Volume Descriptor Pointer from sector 256.
38694663Sscottl	 * XXX Should also check sector n - 256, n, and 512.
38794663Sscottl	 */
38894663Sscottl	sector = 256;
389151157Srodrigc	if ((error = bread(devvp, sector * btodb(logical_secsize), bsize,
390151157Srodrigc			   NOCRED, &bp)) != 0)
39194663Sscottl		goto bail;
39294663Sscottl	if ((error = udf_checktag((struct desc_tag *)bp->b_data, TAGID_ANCHOR)))
39394663Sscottl		goto bail;
39494663Sscottl
39594663Sscottl	bcopy(bp->b_data, &avdp, sizeof(struct anchor_vdp));
39694663Sscottl	brelse(bp);
39794663Sscottl	bp = NULL;
39894663Sscottl
39994663Sscottl	/*
40094663Sscottl	 * Extract the Partition Descriptor and Logical Volume Descriptor
40194663Sscottl	 * from the Volume Descriptor Sequence.
40294663Sscottl	 * XXX Should we care about the partition type right now?
40394663Sscottl	 * XXX What about multiple partitions?
40494663Sscottl	 */
405130986Sscottl	mvds_start = le32toh(avdp.main_vds_ex.loc);
406130986Sscottl	mvds_end = mvds_start + (le32toh(avdp.main_vds_ex.len) - 1) / bsize;
40794663Sscottl	for (sector = mvds_start; sector < mvds_end; sector++) {
408151157Srodrigc		if ((error = bread(devvp, sector * btodb(logical_secsize),
409151157Srodrigc				   bsize, NOCRED, &bp)) != 0) {
41094663Sscottl			printf("Can't read sector %d of VDS\n", sector);
41194663Sscottl			goto bail;
41294663Sscottl		}
41394663Sscottl		lvd = (struct logvol_desc *)bp->b_data;
41494663Sscottl		if (!udf_checktag(&lvd->tag, TAGID_LOGVOL)) {
415130986Sscottl			udfmp->bsize = le32toh(lvd->lb_size);
41694663Sscottl			udfmp->bmask = udfmp->bsize - 1;
41794663Sscottl			udfmp->bshift = ffs(udfmp->bsize) - 1;
418130986Sscottl			fsd_part = le16toh(lvd->_lvd_use.fsd_loc.loc.part_num);
419130986Sscottl			fsd_offset = le32toh(lvd->_lvd_use.fsd_loc.loc.lb_num);
42094663Sscottl			if (udf_find_partmaps(udfmp, lvd))
42194663Sscottl				break;
42294663Sscottl			logvol_found = 1;
42394663Sscottl		}
42494663Sscottl		pd = (struct part_desc *)bp->b_data;
42594663Sscottl		if (!udf_checktag(&pd->tag, TAGID_PARTITION)) {
42694663Sscottl			part_found = 1;
427130986Sscottl			part_num = le16toh(pd->part_num);
428130986Sscottl			udfmp->part_len = le32toh(pd->part_len);
429130986Sscottl			udfmp->part_start = le32toh(pd->start_loc);
43094663Sscottl		}
43194663Sscottl
43294663Sscottl		brelse(bp);
43394663Sscottl		bp = NULL;
43494663Sscottl		if ((part_found) && (logvol_found))
43594663Sscottl			break;
43694663Sscottl	}
43794663Sscottl
43894663Sscottl	if (!part_found || !logvol_found) {
43994663Sscottl		error = EINVAL;
44094663Sscottl		goto bail;
44194663Sscottl	}
44294663Sscottl
44394663Sscottl	if (fsd_part != part_num) {
44494663Sscottl		printf("FSD does not lie within the partition!\n");
44594663Sscottl		error = EINVAL;
44694663Sscottl		goto bail;
44794663Sscottl	}
44894663Sscottl
44994663Sscottl
45094663Sscottl	/*
45194663Sscottl	 * Grab the Fileset Descriptor
45294663Sscottl	 * Thanks to Chuck McCrobie <mccrobie@cablespeed.com> for pointing
45394663Sscottl	 * me in the right direction here.
45494663Sscottl	 */
45594663Sscottl	sector = udfmp->part_start + fsd_offset;
45694663Sscottl	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
45794663Sscottl		printf("Cannot read sector %d of FSD\n", sector);
45894663Sscottl		goto bail;
45994663Sscottl	}
46094663Sscottl	fsd = (struct fileset_desc *)bp->b_data;
46194663Sscottl	if (!udf_checktag(&fsd->tag, TAGID_FSD)) {
46294663Sscottl		fsd_found = 1;
46394663Sscottl		bcopy(&fsd->rootdir_icb, &udfmp->root_icb,
46494663Sscottl		    sizeof(struct long_ad));
46594663Sscottl	}
46694663Sscottl
46794663Sscottl	brelse(bp);
46894663Sscottl	bp = NULL;
46994663Sscottl
47094663Sscottl	if (!fsd_found) {
47194663Sscottl		printf("Couldn't find the fsd\n");
47294663Sscottl		error = EINVAL;
47394663Sscottl		goto bail;
47494663Sscottl	}
47594663Sscottl
47694663Sscottl	/*
47794663Sscottl	 * Find the file entry for the root directory.
47894663Sscottl	 */
479130986Sscottl	sector = le32toh(udfmp->root_icb.loc.lb_num) + udfmp->part_start;
480130986Sscottl	size = le32toh(udfmp->root_icb.len);
481189082Savg	if ((error = udf_readdevblks(udfmp, sector, size, &bp)) != 0) {
48294663Sscottl		printf("Cannot read sector %d\n", sector);
48394663Sscottl		goto bail;
48494663Sscottl	}
48594663Sscottl
48694663Sscottl	root_fentry = (struct file_entry *)bp->b_data;
48794663Sscottl	if ((error = udf_checktag(&root_fentry->tag, TAGID_FENTRY))) {
48894663Sscottl		printf("Invalid root file entry!\n");
48994663Sscottl		goto bail;
49094663Sscottl	}
49194663Sscottl
49294663Sscottl	brelse(bp);
49394663Sscottl	bp = NULL;
49494663Sscottl
49594663Sscottl	return 0;
49694663Sscottl
49794663Sscottlbail:
49894663Sscottl	if (udfmp != NULL)
499184205Sdes		free(udfmp, M_UDFMOUNT);
50094663Sscottl	if (bp != NULL)
50194663Sscottl		brelse(bp);
502188502Sjhb	if (cp != NULL) {
503188502Sjhb		DROP_GIANT();
504188502Sjhb		g_topology_lock();
505188502Sjhb		g_vfs_close(cp);
506188502Sjhb		g_topology_unlock();
507188502Sjhb		PICKUP_GIANT();
508188502Sjhb	}
509188502Sjhb	dev_rel(dev);
51094663Sscottl	return error;
51194663Sscottl};
51294663Sscottl
51394663Sscottlstatic int
514191990Sattilioudf_unmount(struct mount *mp, int mntflags)
51594663Sscottl{
51694663Sscottl	struct udf_mnt *udfmp;
51794663Sscottl	int error, flags = 0;
51894663Sscottl
51994663Sscottl	udfmp = VFSTOUDFFS(mp);
52094663Sscottl
52194663Sscottl	if (mntflags & MNT_FORCE)
52294663Sscottl		flags |= FORCECLOSE;
52394663Sscottl
524191990Sattilio	if ((error = vflush(mp, 0, flags, curthread)))
52594663Sscottl		return (error);
52694663Sscottl
527122102Sscottl	if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) {
528122102Sscottl		if (udfmp->im_d2l)
529122102Sscottl			udf_iconv->close(udfmp->im_d2l);
530122102Sscottl#if 0
531122102Sscottl		if (udfmp->im_l2d)
532122102Sscottl			udf_iconv->close(udfmp->im_l2d);
533122102Sscottl#endif
534122102Sscottl	}
535122102Sscottl
536143571Sphk	DROP_GIANT();
537143571Sphk	g_topology_lock();
538183754Sattilio	g_vfs_close(udfmp->im_cp);
539143571Sphk	g_topology_unlock();
540143571Sphk	PICKUP_GIANT();
54194663Sscottl	vrele(udfmp->im_devvp);
542188502Sjhb	dev_rel(udfmp->im_dev);
54394663Sscottl
54494663Sscottl	if (udfmp->s_table != NULL)
545184205Sdes		free(udfmp->s_table, M_UDFMOUNT);
546114632Sscottl
547184205Sdes	free(udfmp, M_UDFMOUNT);
54894663Sscottl
549172697Salfred	mp->mnt_data = NULL;
550162647Stegge	MNT_ILOCK(mp);
55194663Sscottl	mp->mnt_flag &= ~MNT_LOCAL;
552162647Stegge	MNT_IUNLOCK(mp);
55394663Sscottl
55494663Sscottl	return (0);
55594663Sscottl}
55694663Sscottl
55794663Sscottlstatic int
558191990Sattilioudf_root(struct mount *mp, int flags, struct vnode **vpp)
55994663Sscottl{
56094663Sscottl	struct udf_mnt *udfmp;
56194663Sscottl	ino_t id;
56294663Sscottl
56394663Sscottl	udfmp = VFSTOUDFFS(mp);
56494663Sscottl
56594663Sscottl	id = udf_getid(&udfmp->root_icb);
56694663Sscottl
567188407Sjhb	return (udf_vget(mp, id, flags, vpp));
56894663Sscottl}
56994663Sscottl
57094663Sscottlstatic int
571191990Sattilioudf_statfs(struct mount *mp, struct statfs *sbp)
57294663Sscottl{
57394663Sscottl	struct udf_mnt *udfmp;
57494663Sscottl
57594663Sscottl	udfmp = VFSTOUDFFS(mp);
57694663Sscottl
57794663Sscottl	sbp->f_bsize = udfmp->bsize;
57894663Sscottl	sbp->f_iosize = udfmp->bsize;
57994663Sscottl	sbp->f_blocks = udfmp->part_len;
58094663Sscottl	sbp->f_bfree = 0;
58194663Sscottl	sbp->f_bavail = 0;
58294663Sscottl	sbp->f_files = 0;
58394663Sscottl	sbp->f_ffree = 0;
58494663Sscottl	return 0;
58594663Sscottl}
58694663Sscottl
58794663Sscottlint
58894663Sscottludf_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
58994663Sscottl{
59094663Sscottl	struct buf *bp;
59194663Sscottl	struct vnode *devvp;
59294663Sscottl	struct udf_mnt *udfmp;
59394663Sscottl	struct thread *td;
59494663Sscottl	struct vnode *vp;
59594663Sscottl	struct udf_node *unode;
59694663Sscottl	struct file_entry *fe;
59794663Sscottl	int error, sector, size;
59894663Sscottl
599143692Sphk	error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL);
600143619Sphk	if (error || *vpp != NULL)
601143571Sphk		return (error);
602143571Sphk
603188407Sjhb	/*
604188407Sjhb	 * We must promote to an exclusive lock for vnode creation.  This
605188407Sjhb	 * can happen if lookup is passed LOCKSHARED.
606188407Sjhb 	 */
607188407Sjhb	if ((flags & LK_TYPE_MASK) == LK_SHARED) {
608188407Sjhb		flags &= ~LK_TYPE_MASK;
609188407Sjhb		flags |= LK_EXCLUSIVE;
610188407Sjhb	}
611188407Sjhb
612188407Sjhb	/*
613188407Sjhb	 * We do not lock vnode creation as it is believed to be too
614188407Sjhb	 * expensive for such rare case as simultaneous creation of vnode
615188407Sjhb	 * for same ino by different processes. We just allow them to race
616188407Sjhb	 * and check later to decide who wins. Let the race begin!
617188407Sjhb	 */
618188407Sjhb
61994663Sscottl	td = curthread;
62094663Sscottl	udfmp = VFSTOUDFFS(mp);
62194663Sscottl
622143571Sphk	unode = uma_zalloc(udf_zone_node, M_WAITOK | M_ZERO);
623143571Sphk
624143571Sphk	if ((error = udf_allocv(mp, &vp, td))) {
625143571Sphk		printf("Error from udf_allocv\n");
626143571Sphk		uma_zfree(udf_zone_node, unode);
62794663Sscottl		return (error);
62894663Sscottl	}
62994663Sscottl
630143571Sphk	unode->i_vnode = vp;
631143571Sphk	unode->hash_id = ino;
632143571Sphk	unode->udfmp = udfmp;
633143571Sphk	vp->v_data = unode;
634143571Sphk
635175635Sattilio	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
636167497Stegge	error = insmntque(vp, mp);
637167497Stegge	if (error != 0) {
638167497Stegge		uma_zfree(udf_zone_node, unode);
639167497Stegge		return (error);
640167497Stegge	}
641167497Stegge	error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL);
642143663Sphk	if (error || *vpp != NULL)
643143571Sphk		return (error);
64494663Sscottl
64594663Sscottl	/*
64694663Sscottl	 * Copy in the file entry.  Per the spec, the size can only be 1 block.
64794663Sscottl	 */
64894663Sscottl	sector = ino + udfmp->part_start;
64994663Sscottl	devvp = udfmp->im_devvp;
65094663Sscottl	if ((error = RDSECTOR(devvp, sector, udfmp->bsize, &bp)) != 0) {
65194663Sscottl		printf("Cannot read sector %d\n", sector);
652175436Skib		vgone(vp);
653143571Sphk		vput(vp);
654143571Sphk		brelse(bp);
655143571Sphk		*vpp = NULL;
65694663Sscottl		return (error);
65794663Sscottl	}
65894663Sscottl
65994663Sscottl	fe = (struct file_entry *)bp->b_data;
66094663Sscottl	if (udf_checktag(&fe->tag, TAGID_FENTRY)) {
66194663Sscottl		printf("Invalid file entry!\n");
662175436Skib		vgone(vp);
663143571Sphk		vput(vp);
66494663Sscottl		brelse(bp);
665143571Sphk		*vpp = NULL;
66694663Sscottl		return (ENOMEM);
66794663Sscottl	}
668130986Sscottl	size = UDF_FENTRY_SIZE + le32toh(fe->l_ea) + le32toh(fe->l_ad);
669184214Sdes	unode->fentry = malloc(size, M_UDFFENTRY, M_NOWAIT | M_ZERO);
67094663Sscottl	if (unode->fentry == NULL) {
67194663Sscottl		printf("Cannot allocate file entry block\n");
672175436Skib		vgone(vp);
673143571Sphk		vput(vp);
67494663Sscottl		brelse(bp);
675143571Sphk		*vpp = NULL;
67694663Sscottl		return (ENOMEM);
67794663Sscottl	}
67894663Sscottl
67994663Sscottl	bcopy(bp->b_data, unode->fentry, size);
68094663Sscottl
68194663Sscottl	brelse(bp);
68294663Sscottl	bp = NULL;
68394663Sscottl
68494663Sscottl	switch (unode->fentry->icbtag.file_type) {
68594663Sscottl	default:
68694663Sscottl		vp->v_type = VBAD;
68794663Sscottl		break;
68894663Sscottl	case 4:
68994663Sscottl		vp->v_type = VDIR;
69094663Sscottl		break;
69194663Sscottl	case 5:
69294663Sscottl		vp->v_type = VREG;
69394663Sscottl		break;
69494663Sscottl	case 6:
69594663Sscottl		vp->v_type = VBLK;
69694663Sscottl		break;
69794663Sscottl	case 7:
69894663Sscottl		vp->v_type = VCHR;
69994663Sscottl		break;
70094663Sscottl	case 9:
70194663Sscottl		vp->v_type = VFIFO;
702188245Sjhb		vp->v_op = &udf_fifoops;
70394663Sscottl		break;
70494663Sscottl	case 10:
70594663Sscottl		vp->v_type = VSOCK;
70694663Sscottl		break;
70794663Sscottl	case 12:
70894663Sscottl		vp->v_type = VLNK;
70994663Sscottl		break;
71094663Sscottl	}
711188407Sjhb
712210172Sjhb	if (vp->v_type != VFIFO)
713188407Sjhb		VN_LOCK_ASHARE(vp);
714188407Sjhb
715188407Sjhb	if (ino == udf_getid(&udfmp->root_icb))
716188407Sjhb		vp->v_vflag |= VV_ROOT;
717188407Sjhb
71894663Sscottl	*vpp = vp;
71994663Sscottl
72094663Sscottl	return (0);
72194663Sscottl}
72294663Sscottl
72394663Sscottlstatic int
724222167Srmacklemudf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
72594663Sscottl{
72694663Sscottl	struct ifid *ifhp;
72794663Sscottl	struct vnode *nvp;
728165879Spav	struct udf_node *np;
729165879Spav	off_t fsize;
73094663Sscottl	int error;
73194663Sscottl
73294663Sscottl	ifhp = (struct ifid *)fhp;
73394663Sscottl
73494663Sscottl	if ((error = VFS_VGET(mp, ifhp->ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
73594663Sscottl		*vpp = NULLVP;
73694663Sscottl		return (error);
73794663Sscottl	}
73894663Sscottl
739165879Spav	np = VTON(nvp);
740165879Spav	fsize = le64toh(np->fentry->inf_len);
741165879Spav
74294663Sscottl	*vpp = nvp;
743165879Spav	vnode_create_vobject(*vpp, fsize, curthread);
74494663Sscottl	return (0);
74594663Sscottl}
74694663Sscottl
74794663Sscottlstatic int
74894663Sscottludf_find_partmaps(struct udf_mnt *udfmp, struct logvol_desc *lvd)
74994663Sscottl{
75094663Sscottl	struct part_map_spare *pms;
75194663Sscottl	struct regid *pmap_id;
75294663Sscottl	struct buf *bp;
75394663Sscottl	unsigned char regid_id[UDF_REGID_ID_SIZE + 1];
754159939Sscottl	int i, k, ptype, psize, error;
755160664Syar	uint8_t *pmap = (uint8_t *) &lvd->maps[0];
75694663Sscottl
757130986Sscottl	for (i = 0; i < le32toh(lvd->n_pm); i++) {
758160664Syar		ptype = pmap[0];
759160664Syar		psize = pmap[1];
76094663Sscottl		if (((ptype != 1) && (ptype != 2)) ||
761160664Syar		    ((psize != UDF_PMAP_TYPE1_SIZE) &&
762160664Syar		     (psize != UDF_PMAP_TYPE2_SIZE))) {
76394663Sscottl			printf("Invalid partition map found\n");
76494663Sscottl			return (1);
76594663Sscottl		}
76694663Sscottl
76794663Sscottl		if (ptype == 1) {
76894663Sscottl			/* Type 1 map.  We don't care */
769160664Syar			pmap += UDF_PMAP_TYPE1_SIZE;
77094663Sscottl			continue;
77194663Sscottl		}
77294663Sscottl
77394663Sscottl		/* Type 2 map.  Gotta find out the details */
774160664Syar		pmap_id = (struct regid *)&pmap[4];
77594663Sscottl		bzero(&regid_id[0], UDF_REGID_ID_SIZE);
77694663Sscottl		bcopy(&pmap_id->id[0], &regid_id[0], UDF_REGID_ID_SIZE);
77794663Sscottl
77894663Sscottl		if (bcmp(&regid_id[0], "*UDF Sparable Partition",
77994663Sscottl		    UDF_REGID_ID_SIZE)) {
78094663Sscottl			printf("Unsupported partition map: %s\n", &regid_id[0]);
78194663Sscottl			return (1);
78294663Sscottl		}
78394663Sscottl
784160664Syar		pms = (struct part_map_spare *)pmap;
785160664Syar		pmap += UDF_PMAP_TYPE2_SIZE;
786184214Sdes		udfmp->s_table = malloc(le32toh(pms->st_size),
787184214Sdes		    M_UDFMOUNT, M_NOWAIT | M_ZERO);
78894663Sscottl		if (udfmp->s_table == NULL)
78994663Sscottl			return (ENOMEM);
79094663Sscottl
79194663Sscottl		/* Calculate the number of sectors per packet. */
79294663Sscottl		/* XXX Logical or physical? */
793130986Sscottl		udfmp->p_sectors = le16toh(pms->packet_len) / udfmp->bsize;
79494663Sscottl
79594663Sscottl		/*
79694663Sscottl		 * XXX If reading the first Sparing Table fails, should look
79794663Sscottl		 * for another table.
79894663Sscottl		 */
799189082Savg		if ((error = udf_readdevblks(udfmp, le32toh(pms->st_loc[0]),
800130986Sscottl					   le32toh(pms->st_size), &bp)) != 0) {
801127603Sscottl			if (bp != NULL)
802127603Sscottl				brelse(bp);
80394663Sscottl			printf("Failed to read Sparing Table at sector %d\n",
804130986Sscottl			    le32toh(pms->st_loc[0]));
805184205Sdes			free(udfmp->s_table, M_UDFMOUNT);
80694663Sscottl			return (error);
80794663Sscottl		}
808130986Sscottl		bcopy(bp->b_data, udfmp->s_table, le32toh(pms->st_size));
80994663Sscottl		brelse(bp);
81094663Sscottl
81194663Sscottl		if (udf_checktag(&udfmp->s_table->tag, 0)) {
81294663Sscottl			printf("Invalid sparing table found\n");
813184205Sdes			free(udfmp->s_table, M_UDFMOUNT);
81494663Sscottl			return (EINVAL);
81594663Sscottl		}
81694663Sscottl
81794663Sscottl		/* See how many valid entries there are here.  The list is
81894663Sscottl		 * supposed to be sorted. 0xfffffff0 and higher are not valid
81994663Sscottl		 */
820159939Sscottl		for (k = 0; k < le16toh(udfmp->s_table->rt_l); k++) {
821159939Sscottl			udfmp->s_table_entries = k;
822159939Sscottl			if (le32toh(udfmp->s_table->entries[k].org) >=
823130986Sscottl			    0xfffffff0)
82494663Sscottl				break;
82594663Sscottl		}
82694663Sscottl	}
82794663Sscottl
82894663Sscottl	return (0);
82994663Sscottl}
830