xref: /netbsd-src/sys/fs/udf/udf_vfsops.c (revision d82e4b430a477be8506121a054943ca37ac3692d)
1*d82e4b43Shannken /* $NetBSD: udf_vfsops.c,v 1.85 2022/05/03 07:33:07 hannken Exp $ */
2cff5e7adSreinoud 
3cff5e7adSreinoud /*
4e979c658Sreinoud  * Copyright (c) 2006, 2008 Reinoud Zandijk
5cff5e7adSreinoud  * All rights reserved.
6cff5e7adSreinoud  *
7cff5e7adSreinoud  * Redistribution and use in source and binary forms, with or without
8cff5e7adSreinoud  * modification, are permitted provided that the following conditions
9cff5e7adSreinoud  * are met:
10cff5e7adSreinoud  * 1. Redistributions of source code must retain the above copyright
11cff5e7adSreinoud  *    notice, this list of conditions and the following disclaimer.
12cff5e7adSreinoud  * 2. Redistributions in binary form must reproduce the above copyright
13cff5e7adSreinoud  *    notice, this list of conditions and the following disclaimer in the
14cff5e7adSreinoud  *    documentation and/or other materials provided with the distribution.
15cff5e7adSreinoud  *
16cff5e7adSreinoud  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17cff5e7adSreinoud  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18cff5e7adSreinoud  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19cff5e7adSreinoud  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20cff5e7adSreinoud  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21cff5e7adSreinoud  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22cff5e7adSreinoud  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23cff5e7adSreinoud  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24cff5e7adSreinoud  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25cff5e7adSreinoud  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26cff5e7adSreinoud  *
27cff5e7adSreinoud  */
28cff5e7adSreinoud 
29cff5e7adSreinoud #include <sys/cdefs.h>
30cff5e7adSreinoud #ifndef lint
31*d82e4b43Shannken __KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.85 2022/05/03 07:33:07 hannken Exp $");
32cff5e7adSreinoud #endif /* not lint */
33cff5e7adSreinoud 
34cff5e7adSreinoud 
35cff5e7adSreinoud #if defined(_KERNEL_OPT)
36cff5e7adSreinoud #include "opt_compat_netbsd.h"
37cff5e7adSreinoud #endif
38cff5e7adSreinoud 
39cff5e7adSreinoud #include <sys/param.h>
40cff5e7adSreinoud #include <sys/systm.h>
41cff5e7adSreinoud #include <sys/sysctl.h>
42cff5e7adSreinoud #include <sys/namei.h>
43cff5e7adSreinoud #include <sys/proc.h>
44cff5e7adSreinoud #include <sys/kernel.h>
45cff5e7adSreinoud #include <sys/vnode.h>
46717e1785Sdholland #include <miscfs/genfs/genfs.h>
47cff5e7adSreinoud #include <miscfs/specfs/specdev.h>
48cff5e7adSreinoud #include <sys/mount.h>
49cff5e7adSreinoud #include <sys/buf.h>
50cff5e7adSreinoud #include <sys/file.h>
51cff5e7adSreinoud #include <sys/device.h>
52cff5e7adSreinoud #include <sys/disklabel.h>
53cff5e7adSreinoud #include <sys/ioctl.h>
54cff5e7adSreinoud #include <sys/malloc.h>
55cff5e7adSreinoud #include <sys/dirent.h>
56cff5e7adSreinoud #include <sys/stat.h>
57cff5e7adSreinoud #include <sys/conf.h>
58fc6d984bSchristos #include <sys/kauth.h>
59a1221b6dSrumble #include <sys/module.h>
60cff5e7adSreinoud 
61cff5e7adSreinoud #include <fs/udf/ecma167-udf.h>
62cff5e7adSreinoud #include <fs/udf/udf_mount.h>
631bd1646aSreinoud #include <sys/dirhash.h>
64cff5e7adSreinoud 
65cff5e7adSreinoud #include "udf.h"
66cff5e7adSreinoud #include "udf_subr.h"
67cff5e7adSreinoud #include "udf_bswap.h"
68cff5e7adSreinoud 
69a1221b6dSrumble MODULE(MODULE_CLASS_VFS, udf, NULL);
70cff5e7adSreinoud 
71e979c658Sreinoud #define VTOI(vnode) ((struct udf_node *) vnode->v_data)
72e979c658Sreinoud 
73cff5e7adSreinoud /* verbose levels of the udf filingsystem */
74cff5e7adSreinoud int udf_verbose = UDF_DEBUGGING;
75cff5e7adSreinoud 
76cff5e7adSreinoud /* malloc regions */
77835b0326Spooka MALLOC_JUSTDEFINE(M_UDFMNT,   "UDF mount",	"UDF mount structures");
78835b0326Spooka MALLOC_JUSTDEFINE(M_UDFVOLD,  "UDF volspace",	"UDF volume space descriptors");
79835b0326Spooka MALLOC_JUSTDEFINE(M_UDFTEMP,  "UDF temp",	"UDF scrap space");
80cff5e7adSreinoud struct pool udf_node_pool;
81cff5e7adSreinoud 
82cff5e7adSreinoud /* internal functions */
83cff5e7adSreinoud static int udf_mountfs(struct vnode *, struct mount *, struct lwp *, struct udf_args *);
84cff5e7adSreinoud 
85cff5e7adSreinoud 
86cff5e7adSreinoud /* --------------------------------------------------------------------- */
87cff5e7adSreinoud 
88cff5e7adSreinoud /* predefine vnode-op list descriptor */
89cff5e7adSreinoud extern const struct vnodeopv_desc udf_vnodeop_opv_desc;
90cff5e7adSreinoud 
91cff5e7adSreinoud const struct vnodeopv_desc * const udf_vnodeopv_descs[] = {
92cff5e7adSreinoud 	&udf_vnodeop_opv_desc,
93cff5e7adSreinoud 	NULL,
94cff5e7adSreinoud };
95cff5e7adSreinoud 
96cff5e7adSreinoud 
97cff5e7adSreinoud /* vfsops descriptor linked in as anchor point for the filingsystem */
98cff5e7adSreinoud struct vfsops udf_vfsops = {
996d285189Shannken 	.vfs_name = MOUNT_UDF,
1006d285189Shannken 	.vfs_min_mount_data = sizeof (struct udf_args),
1016d285189Shannken 	.vfs_mount = udf_mount,
1026d285189Shannken 	.vfs_start = udf_start,
1036d285189Shannken 	.vfs_unmount = udf_unmount,
1046d285189Shannken 	.vfs_root = udf_root,
1056d285189Shannken 	.vfs_quotactl = (void *)eopnotsupp,
1066d285189Shannken 	.vfs_statvfs = udf_statvfs,
1076d285189Shannken 	.vfs_sync = udf_sync,
1086d285189Shannken 	.vfs_vget = udf_vget,
109a494ee15Shannken 	.vfs_loadvnode = udf_loadvnode,
110a494ee15Shannken 	.vfs_newvnode = udf_newvnode,
1116d285189Shannken 	.vfs_fhtovp = udf_fhtovp,
1126d285189Shannken 	.vfs_vptofh = udf_vptofh,
1136d285189Shannken 	.vfs_init = udf_init,
1146d285189Shannken 	.vfs_reinit = udf_reinit,
1156d285189Shannken 	.vfs_done = udf_done,
1166d285189Shannken 	.vfs_mountroot = udf_mountroot,
1176d285189Shannken 	.vfs_snapshot = udf_snapshot,
1186d285189Shannken 	.vfs_extattrctl = vfs_stdextattrctl,
119326db3aaShannken 	.vfs_suspendctl = genfs_suspendctl,
1206d285189Shannken 	.vfs_renamelock_enter = genfs_renamelock_enter,
1216d285189Shannken 	.vfs_renamelock_exit = genfs_renamelock_exit,
1226d285189Shannken 	.vfs_fsync = (void *)eopnotsupp,
1236d285189Shannken 	.vfs_opv_descs = udf_vnodeopv_descs
124cff5e7adSreinoud };
125cff5e7adSreinoud 
126cff5e7adSreinoud /* --------------------------------------------------------------------- */
127cff5e7adSreinoud 
128cff5e7adSreinoud /* file system starts here */
129cff5e7adSreinoud void
udf_init(void)130cff5e7adSreinoud udf_init(void)
131cff5e7adSreinoud {
132cff5e7adSreinoud 	size_t size;
133ff7ad972Sreinoud 
134ff7ad972Sreinoud 	/* setup memory types */
135cff5e7adSreinoud 	malloc_type_attach(M_UDFMNT);
136cff5e7adSreinoud 	malloc_type_attach(M_UDFVOLD);
137cff5e7adSreinoud 	malloc_type_attach(M_UDFTEMP);
138cff5e7adSreinoud 
1392ac28d55Sreinoud 	/* init node pools */
140cff5e7adSreinoud 	size = sizeof(struct udf_node);
1412ac28d55Sreinoud 	pool_init(&udf_node_pool, size, 0, 0, 0,
1422ac28d55Sreinoud 		"udf_node_pool", NULL, IPL_NONE);
143cff5e7adSreinoud }
144cff5e7adSreinoud 
145cff5e7adSreinoud 
146cff5e7adSreinoud void
udf_reinit(void)147cff5e7adSreinoud udf_reinit(void)
148cff5e7adSreinoud {
1492ac28d55Sreinoud 	/* nothing to do */
150cff5e7adSreinoud }
151cff5e7adSreinoud 
152cff5e7adSreinoud 
153cff5e7adSreinoud void
udf_done(void)154cff5e7adSreinoud udf_done(void)
155cff5e7adSreinoud {
1562ac28d55Sreinoud 	/* remove pools */
157cff5e7adSreinoud 	pool_destroy(&udf_node_pool);
158cff5e7adSreinoud 
159cff5e7adSreinoud 	malloc_type_detach(M_UDFMNT);
160cff5e7adSreinoud 	malloc_type_detach(M_UDFVOLD);
161cff5e7adSreinoud 	malloc_type_detach(M_UDFTEMP);
162cff5e7adSreinoud }
163cff5e7adSreinoud 
16428f5ebd8Srumble /*
16528f5ebd8Srumble  * If running a DEBUG kernel, provide an easy way to set the debug flags when
16628f5ebd8Srumble  * running into a problem.
16728f5ebd8Srumble  */
16828f5ebd8Srumble #define UDF_VERBOSE_SYSCTLOPT        1
169e979c658Sreinoud 
1700376c5faSreinoud /*
1710376c5faSreinoud  * XXX the "24" below could be dynamic, thereby eliminating one
1720376c5faSreinoud  * more instance of the "number to vfs" mapping problem, but
1730376c5faSreinoud  * "24" is the order as taken from sys/mount.h
1740376c5faSreinoud  */
1759120d451Spgoyette SYSCTL_SETUP(udf_sysctl_setup, "udf sysctl")
1769120d451Spgoyette {
1779120d451Spgoyette 	const struct sysctlnode *node;
1789120d451Spgoyette 
1799120d451Spgoyette 	sysctl_createv(clog, 0, NULL, &node,
1809120d451Spgoyette 		       CTLFLAG_PERMANENT,
1819120d451Spgoyette 		       CTLTYPE_NODE, "udf",
1829120d451Spgoyette 		       SYSCTL_DESCR("OSTA Universal File System"),
1839120d451Spgoyette 		       NULL, 0, NULL, 0,
1849120d451Spgoyette 		       CTL_VFS, 24, CTL_EOL);
18529d402aeSreinoud #ifdef UDF_DEBUG
1869120d451Spgoyette 	sysctl_createv(clog, 0, NULL, &node,
1879120d451Spgoyette 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
1889120d451Spgoyette 		       CTLTYPE_INT, "verbose",
1899120d451Spgoyette 		       SYSCTL_DESCR("Bitmask for filesystem debugging"),
1909120d451Spgoyette 		       NULL, 0, &udf_verbose, 0,
1919120d451Spgoyette 		       CTL_VFS, 24, UDF_VERBOSE_SYSCTLOPT, CTL_EOL);
1929120d451Spgoyette #endif
1939120d451Spgoyette }
1949120d451Spgoyette 
195e979c658Sreinoud static int
udf_modcmd(modcmd_t cmd,void * arg)196e979c658Sreinoud udf_modcmd(modcmd_t cmd, void *arg)
197e979c658Sreinoud {
19828f5ebd8Srumble 	int error;
199e979c658Sreinoud 
200e979c658Sreinoud 	switch (cmd) {
201e979c658Sreinoud 	case MODULE_CMD_INIT:
20228f5ebd8Srumble 		error = vfs_attach(&udf_vfsops);
20328f5ebd8Srumble 		if (error != 0)
20428f5ebd8Srumble 			break;
20528f5ebd8Srumble 		break;
206e979c658Sreinoud 	case MODULE_CMD_FINI:
20728f5ebd8Srumble 		error = vfs_detach(&udf_vfsops);
20828f5ebd8Srumble 		if (error != 0)
20928f5ebd8Srumble 			break;
21028f5ebd8Srumble 		break;
211e979c658Sreinoud 	default:
21228f5ebd8Srumble 		error = ENOTTY;
21328f5ebd8Srumble 		break;
214e979c658Sreinoud 	}
21528f5ebd8Srumble 
21628f5ebd8Srumble 	return (error);
217e979c658Sreinoud }
218e979c658Sreinoud 
219cff5e7adSreinoud /* --------------------------------------------------------------------- */
220cff5e7adSreinoud 
221cff5e7adSreinoud int
udf_mountroot(void)222cff5e7adSreinoud udf_mountroot(void)
223cff5e7adSreinoud {
224cff5e7adSreinoud 	return EOPNOTSUPP;
225cff5e7adSreinoud }
226cff5e7adSreinoud 
227cff5e7adSreinoud /* --------------------------------------------------------------------- */
228cff5e7adSreinoud 
229cff5e7adSreinoud #define MPFREE(a, lst) \
230cff5e7adSreinoud 	if ((a)) free((a), lst);
231cff5e7adSreinoud static void
free_udf_mountinfo(struct mount * mp)232cff5e7adSreinoud free_udf_mountinfo(struct mount *mp)
233cff5e7adSreinoud {
234cff5e7adSreinoud 	struct udf_mount *ump;
235cff5e7adSreinoud 	int i;
236cff5e7adSreinoud 
23721d69215Sreinoud 	if (!mp)
23821d69215Sreinoud 		return;
23921d69215Sreinoud 
240cff5e7adSreinoud 	ump = VFSTOUDF(mp);
241cff5e7adSreinoud 	if (ump) {
242445a215fSreinoud 		/* clear our data */
243cff5e7adSreinoud 		for (i = 0; i < UDF_ANCHORS; i++)
244cff5e7adSreinoud 			MPFREE(ump->anchors[i], M_UDFVOLD);
245cff5e7adSreinoud 		MPFREE(ump->primary_vol,      M_UDFVOLD);
246cff5e7adSreinoud 		MPFREE(ump->logical_vol,      M_UDFVOLD);
247cff5e7adSreinoud 		MPFREE(ump->unallocated,      M_UDFVOLD);
248cff5e7adSreinoud 		MPFREE(ump->implementation,   M_UDFVOLD);
249cff5e7adSreinoud 		MPFREE(ump->logvol_integrity, M_UDFVOLD);
250e979c658Sreinoud 		for (i = 0; i < UDF_PARTITIONS; i++) {
251cff5e7adSreinoud 			MPFREE(ump->partitions[i],        M_UDFVOLD);
252e979c658Sreinoud 			MPFREE(ump->part_unalloc_dscr[i], M_UDFVOLD);
253e979c658Sreinoud 			MPFREE(ump->part_freed_dscr[i],   M_UDFVOLD);
254e979c658Sreinoud 		}
2555c3627bcSreinoud 		MPFREE(ump->metadata_unalloc_dscr, M_UDFVOLD);
2565c3627bcSreinoud 
257cff5e7adSreinoud 		MPFREE(ump->fileset_desc,   M_UDFVOLD);
258cff5e7adSreinoud 		MPFREE(ump->sparing_table,  M_UDFVOLD);
259e979c658Sreinoud 
260e979c658Sreinoud 		MPFREE(ump->la_node_ad_cpy, M_UDFMNT);
261e979c658Sreinoud 		MPFREE(ump->la_pmapping,    M_TEMP);
262e979c658Sreinoud 		MPFREE(ump->la_lmapping,    M_TEMP);
263cff5e7adSreinoud 
26417f11577Sreinoud 		mutex_destroy(&ump->logvol_mutex);
265e979c658Sreinoud 		mutex_destroy(&ump->allocate_mutex);
2664207afb7Shannken 		mutex_destroy(&ump->sync_lock);
26717f11577Sreinoud 
268e979c658Sreinoud 		MPFREE(ump->vat_table, M_UDFVOLD);
269e979c658Sreinoud 
270cff5e7adSreinoud 		free(ump, M_UDFMNT);
2710c1391f0Schristos 	}
272cff5e7adSreinoud }
273cff5e7adSreinoud #undef MPFREE
274cff5e7adSreinoud 
275cff5e7adSreinoud /* --------------------------------------------------------------------- */
276cff5e7adSreinoud 
277e979c658Sreinoud /* if the system nodes exist, release them */
278e979c658Sreinoud static void
udf_release_system_nodes(struct mount * mp)279e979c658Sreinoud udf_release_system_nodes(struct mount *mp)
280e979c658Sreinoud {
281e979c658Sreinoud 	struct udf_mount *ump = VFSTOUDF(mp);
282e979c658Sreinoud 
283e979c658Sreinoud 	/* if we haven't even got an ump, dont bother */
284e979c658Sreinoud 	if (!ump)
285e979c658Sreinoud 		return;
286e979c658Sreinoud 
287e979c658Sreinoud 	/* VAT partition support */
288e979c658Sreinoud 	if (ump->vat_node)
289e979c658Sreinoud 		vrele(ump->vat_node->vnode);
290e979c658Sreinoud 
291e979c658Sreinoud 	/* Metadata partition support */
292e979c658Sreinoud 	if (ump->metadata_node)
293e979c658Sreinoud 		vrele(ump->metadata_node->vnode);
294e979c658Sreinoud 	if (ump->metadatamirror_node)
295e979c658Sreinoud 		vrele(ump->metadatamirror_node->vnode);
296e979c658Sreinoud 	if (ump->metadatabitmap_node)
297e979c658Sreinoud 		vrele(ump->metadatabitmap_node->vnode);
298e979c658Sreinoud }
299e979c658Sreinoud 
300e979c658Sreinoud 
301cff5e7adSreinoud int
udf_mount(struct mount * mp,const char * path,void * data,size_t * data_len)302cff5e7adSreinoud udf_mount(struct mount *mp, const char *path,
30361e8303eSpooka 	  void *data, size_t *data_len)
304cff5e7adSreinoud {
30561e8303eSpooka 	struct lwp *l = curlwp;
3062721ab6cSdsl 	struct udf_args *args = data;
307cff5e7adSreinoud 	struct udf_mount *ump;
308cff5e7adSreinoud 	struct vnode *devvp;
309cff5e7adSreinoud 	int openflags, accessmode, error;
310cff5e7adSreinoud 
311cff5e7adSreinoud 	DPRINTF(CALL, ("udf_mount called\n"));
312cff5e7adSreinoud 
31323f76b6dSmaxv 	if (args == NULL)
31423f76b6dSmaxv 		return EINVAL;
3152721ab6cSdsl 	if (*data_len < sizeof *args)
3162721ab6cSdsl 		return EINVAL;
3172721ab6cSdsl 
318cff5e7adSreinoud 	if (mp->mnt_flag & MNT_GETARGS) {
319cff5e7adSreinoud 		/* request for the mount arguments */
320cff5e7adSreinoud 		ump = VFSTOUDF(mp);
321cff5e7adSreinoud 		if (ump == NULL)
322cff5e7adSreinoud 			return EINVAL;
3232721ab6cSdsl 		*args = ump->mount_args;
3242721ab6cSdsl 		*data_len = sizeof *args;
3252721ab6cSdsl 		return 0;
3260c1391f0Schristos 	}
327cff5e7adSreinoud 
328cff5e7adSreinoud 	/* handle request for updating mount parameters */
329cff5e7adSreinoud 	/* TODO can't update my mountpoint yet */
330cff5e7adSreinoud 	if (mp->mnt_flag & MNT_UPDATE) {
331cff5e7adSreinoud 		return EOPNOTSUPP;
3320c1391f0Schristos 	}
333cff5e7adSreinoud 
33421d69215Sreinoud 	/* OK, so we are asked to mount the device */
335cff5e7adSreinoud 
336cff5e7adSreinoud 	/* check/translate struct version */
337cff5e7adSreinoud 	/* TODO sanity checking other mount arguments */
3382721ab6cSdsl 	if (args->version != 1) {
339cff5e7adSreinoud 		printf("mount_udf: unrecognized argument structure version\n");
340cff5e7adSreinoud 		return EINVAL;
3410c1391f0Schristos 	}
342cff5e7adSreinoud 
343cff5e7adSreinoud 	/* lookup name to get its vnode */
344effcf1afSdholland 	error = namei_simple_user(args->fspec,
345effcf1afSdholland 				NSM_FOLLOW_NOEMULROOT, &devvp);
346cff5e7adSreinoud 	if (error)
347cff5e7adSreinoud 		return error;
3486014bf8aSreinoud 
349cff5e7adSreinoud #ifdef DEBUG
350cff5e7adSreinoud 	if (udf_verbose & UDF_DEBUG_VOLUMES)
351cff5e7adSreinoud 		vprint("UDF mount, trying to mount \n", devvp);
352cff5e7adSreinoud #endif
353cff5e7adSreinoud 
354cff5e7adSreinoud 	/* check if its a block device specified */
355cff5e7adSreinoud 	if (devvp->v_type != VBLK) {
356cff5e7adSreinoud 		vrele(devvp);
357cff5e7adSreinoud 		return ENOTBLK;
358cff5e7adSreinoud 	}
359cff5e7adSreinoud 	if (bdevsw_lookup(devvp->v_rdev) == NULL) {
360cff5e7adSreinoud 		vrele(devvp);
361cff5e7adSreinoud 		return ENXIO;
362cff5e7adSreinoud 	}
363cff5e7adSreinoud 
364cff5e7adSreinoud 	/*
365cff5e7adSreinoud 	 * If mount by non-root, then verify that user has necessary
366cff5e7adSreinoud 	 * permissions on the device.
367cff5e7adSreinoud 	 */
368cff5e7adSreinoud 	accessmode = VREAD;
369cff5e7adSreinoud 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
370cff5e7adSreinoud 		accessmode |= VWRITE;
3716014bf8aSreinoud 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
3720c9d8d15Selad 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
3730c9d8d15Selad 	    KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
3741423e65bShannken 	VOP_UNLOCK(devvp);
375cff5e7adSreinoud 	if (error) {
3766014bf8aSreinoud 		vrele(devvp);
3776014bf8aSreinoud 		return error;
378cff5e7adSreinoud 	}
379cff5e7adSreinoud 
380cff5e7adSreinoud 	/*
381cff5e7adSreinoud 	 * Open device and try to mount it!
382cff5e7adSreinoud 	 */
383cff5e7adSreinoud 	if (mp->mnt_flag & MNT_RDONLY) {
384cff5e7adSreinoud 		openflags = FREAD;
385cff5e7adSreinoud 	} else {
386cff5e7adSreinoud 		openflags = FREAD | FWRITE;
3870c1391f0Schristos 	}
388d84a65ddShannken 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
38961e8303eSpooka 	error = VOP_OPEN(devvp, openflags, FSCRED);
390d84a65ddShannken 	VOP_UNLOCK(devvp);
391cff5e7adSreinoud 	if (error == 0) {
392cff5e7adSreinoud 		/* opened ok, try mounting */
3932721ab6cSdsl 		error = udf_mountfs(devvp, mp, l, args);
394cff5e7adSreinoud 		if (error) {
395e979c658Sreinoud 			udf_release_system_nodes(mp);
396e979c658Sreinoud 			/* cleanup */
397e979c658Sreinoud 			udf_discstrat_finish(VFSTOUDF(mp));
398cff5e7adSreinoud 			free_udf_mountinfo(mp);
3996014bf8aSreinoud 			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
40061e8303eSpooka 			(void) VOP_CLOSE(devvp, openflags, NOCRED);
4011423e65bShannken 			VOP_UNLOCK(devvp);
4020c1391f0Schristos 		}
4030c1391f0Schristos 	}
404cff5e7adSreinoud 	if (error) {
405cff5e7adSreinoud 		/* devvp is still locked */
4066014bf8aSreinoud 		vrele(devvp);
407cff5e7adSreinoud 		return error;
4080c1391f0Schristos 	}
409cff5e7adSreinoud 
410cff5e7adSreinoud 	/* register our mountpoint being on this device */
4113881f4f3Shannken 	spec_node_setmountedfs(devvp, mp);
412cff5e7adSreinoud 
413cff5e7adSreinoud 	/* successfully mounted */
414b5860281Sandvar 	DPRINTF(VOLUMES, ("udf_mount() successful\n"));
415cff5e7adSreinoud 
416e979c658Sreinoud 	error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
417e24b0872Spooka 			mp->mnt_op->vfs_name, mp, l);
418e979c658Sreinoud 	if (error)
419e979c658Sreinoud 		return error;
420e979c658Sreinoud 
421e979c658Sreinoud 	/* If we're not opened read-only, open its logical volume */
422e979c658Sreinoud 	if ((mp->mnt_flag & MNT_RDONLY) == 0) {
423e979c658Sreinoud 		if ((error = udf_open_logvol(VFSTOUDF(mp))) != 0) {
424e979c658Sreinoud 			printf( "mount_udf: can't open logical volume for "
425e979c658Sreinoud 				"writing, downgrading access to read-only\n");
426e979c658Sreinoud 			mp->mnt_flag |= MNT_RDONLY;
427e979c658Sreinoud 			/* FIXME we can't return error now on open failure */
428e979c658Sreinoud 			return 0;
429e979c658Sreinoud 		}
430e979c658Sreinoud 	}
431e979c658Sreinoud 
432e979c658Sreinoud 	return 0;
433cff5e7adSreinoud }
434cff5e7adSreinoud 
435cff5e7adSreinoud /* --------------------------------------------------------------------- */
436cff5e7adSreinoud 
437cff5e7adSreinoud #ifdef DEBUG
438f731f08dShannken static bool
udf_sanity_selector(void * cl,struct vnode * vp)439f731f08dShannken udf_sanity_selector(void *cl, struct vnode *vp)
440cff5e7adSreinoud {
441cff5e7adSreinoud 
44230509f80Sriastradh 	KASSERT(mutex_owned(vp->v_interlock));
44330509f80Sriastradh 
444cff5e7adSreinoud 	vprint("", vp);
445cff5e7adSreinoud 	if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) {
446cff5e7adSreinoud 		printf("  is locked\n");
4470c1391f0Schristos 	}
44823bf8800Sad 	if (vrefcnt(vp) > 1)
44923bf8800Sad 		printf("  more than one usecount %d\n", vrefcnt(vp));
450f731f08dShannken 	return false;
4510c1391f0Schristos }
452f731f08dShannken 
453f731f08dShannken static void
udf_unmount_sanity_check(struct mount * mp)454f731f08dShannken udf_unmount_sanity_check(struct mount *mp)
455f731f08dShannken {
456f731f08dShannken 	struct vnode_iterator *marker;
457f731f08dShannken 
458f731f08dShannken 	printf("On unmount, i found the following nodes:\n");
459f731f08dShannken 	vfs_vnode_iterator_init(mp, &marker);
460f731f08dShannken 	vfs_vnode_iterator_next(marker, udf_sanity_selector, NULL);
461f731f08dShannken 	vfs_vnode_iterator_destroy(marker);
462cff5e7adSreinoud }
463cff5e7adSreinoud #endif
464cff5e7adSreinoud 
465cff5e7adSreinoud 
466cff5e7adSreinoud int
udf_unmount(struct mount * mp,int mntflags)46761e8303eSpooka udf_unmount(struct mount *mp, int mntflags)
468cff5e7adSreinoud {
469cff5e7adSreinoud 	struct udf_mount *ump;
470cff5e7adSreinoud 	int error, flags, closeflags;
471cff5e7adSreinoud 
472cff5e7adSreinoud 	DPRINTF(CALL, ("udf_umount called\n"));
473cff5e7adSreinoud 
474cff5e7adSreinoud 	ump = VFSTOUDF(mp);
475cff5e7adSreinoud 	if (!ump)
476cff5e7adSreinoud 		panic("UDF unmount: empty ump\n");
477cff5e7adSreinoud 
478e54e795bSreinoud 	flags = (mntflags & MNT_FORCE) ? FORCECLOSE : 0;
479cff5e7adSreinoud 	/* TODO remove these paranoid functions */
480cff5e7adSreinoud #ifdef DEBUG
481cff5e7adSreinoud 	if (udf_verbose & UDF_DEBUG_LOCKING)
482cff5e7adSreinoud 		udf_unmount_sanity_check(mp);
483cff5e7adSreinoud #endif
484cff5e7adSreinoud 
485e54e795bSreinoud 	/*
4867dad9f73Sad 	 * By specifying SKIPSYSTEM we can skip vnodes marked with VV_SYSTEM.
487e54e795bSreinoud 	 * This hardly documented feature allows us to exempt certain files
488e54e795bSreinoud 	 * from being flushed.
489e54e795bSreinoud 	 */
4907dad9f73Sad 	if ((error = vflush(mp, NULLVP, flags | SKIPSYSTEM)) != 0)
491cff5e7adSreinoud 		return error;
492cff5e7adSreinoud 
493e979c658Sreinoud 	/* update nodes and wait for completion of writeout of system nodes */
494e979c658Sreinoud 	udf_sync(mp, FSYNC_WAIT, NOCRED);
495e979c658Sreinoud 
496cff5e7adSreinoud #ifdef DEBUG
497cff5e7adSreinoud 	if (udf_verbose & UDF_DEBUG_LOCKING)
498cff5e7adSreinoud 		udf_unmount_sanity_check(mp);
499cff5e7adSreinoud #endif
500cff5e7adSreinoud 
501e979c658Sreinoud 	/* flush again, to check if we are still busy for something else */
502e979c658Sreinoud 	if ((error = vflush(ump->vfs_mountp, NULLVP, flags | SKIPSYSTEM)) != 0)
503e979c658Sreinoud 		return error;
504cff5e7adSreinoud 
505e979c658Sreinoud 	DPRINTF(VOLUMES, ("flush OK on unmount\n"));
506e979c658Sreinoud 
507e979c658Sreinoud 	/* close logical volume and close session if requested */
508e979c658Sreinoud 	if ((error = udf_close_logvol(ump, mntflags)) != 0)
509e979c658Sreinoud 		return error;
510e979c658Sreinoud 
511e979c658Sreinoud #ifdef DEBUG
512e979c658Sreinoud 	DPRINTF(VOLUMES, ("FINAL sanity check\n"));
513e979c658Sreinoud 	if (udf_verbose & UDF_DEBUG_LOCKING)
514e979c658Sreinoud 		udf_unmount_sanity_check(mp);
515e979c658Sreinoud #endif
516e979c658Sreinoud 
517e979c658Sreinoud 	/* NOTE release system nodes should NOT write anything */
518e979c658Sreinoud 	udf_release_system_nodes(mp);
519e979c658Sreinoud 
5205985f105Shannken 	/* This flush should NOT write anything nor allow any node to remain */
5215985f105Shannken 	if ((error = vflush(ump->vfs_mountp, NULLVP, 0)) != 0)
5225985f105Shannken 		panic("Failure to flush UDF system vnodes\n");
5235985f105Shannken 
524e979c658Sreinoud 	/* finalise disc strategy */
525e979c658Sreinoud 	udf_discstrat_finish(ump);
526e979c658Sreinoud 
527e979c658Sreinoud 	/* synchronise device caches */
528e979c658Sreinoud 	(void) udf_synchronise_caches(ump);
529cff5e7adSreinoud 
530cff5e7adSreinoud 	/* close device */
531cff5e7adSreinoud 	DPRINTF(VOLUMES, ("closing device\n"));
532cff5e7adSreinoud 	if (mp->mnt_flag & MNT_RDONLY) {
533cff5e7adSreinoud 		closeflags = FREAD;
534cff5e7adSreinoud 	} else {
535cff5e7adSreinoud 		closeflags = FREAD | FWRITE;
5360c1391f0Schristos 	}
537cff5e7adSreinoud 
538cff5e7adSreinoud 	/* devvp is still locked by us */
539cff5e7adSreinoud 	vn_lock(ump->devvp, LK_EXCLUSIVE | LK_RETRY);
54061e8303eSpooka 	error = VOP_CLOSE(ump->devvp, closeflags, NOCRED);
541cff5e7adSreinoud 	if (error)
542cff5e7adSreinoud 		printf("Error during closure of device! error %d, "
543cff5e7adSreinoud 		       "device might stay locked\n", error);
544cff5e7adSreinoud 	DPRINTF(VOLUMES, ("device close ok\n"));
545cff5e7adSreinoud 
546cff5e7adSreinoud 	/* clear our mount reference and release device node */
5473881f4f3Shannken 	spec_node_setmountedfs(ump->devvp, NULL);
548cff5e7adSreinoud 	vput(ump->devvp);
549cff5e7adSreinoud 
550e979c658Sreinoud 	/* free our ump */
551cff5e7adSreinoud 	free_udf_mountinfo(mp);
552cff5e7adSreinoud 
553e979c658Sreinoud 	/* free ump struct references */
55421d69215Sreinoud 	mp->mnt_data = NULL;
55521d69215Sreinoud 	mp->mnt_flag &= ~MNT_LOCAL;
55621d69215Sreinoud 
557cff5e7adSreinoud 	DPRINTF(VOLUMES, ("Fin unmount\n"));
558cff5e7adSreinoud 	return error;
559cff5e7adSreinoud }
560cff5e7adSreinoud 
561cff5e7adSreinoud /* --------------------------------------------------------------------- */
562cff5e7adSreinoud 
563cff5e7adSreinoud /*
564cff5e7adSreinoud  * Helper function of udf_mount() that actually mounts the disc.
565cff5e7adSreinoud  */
566cff5e7adSreinoud 
567cff5e7adSreinoud static int
udf_mountfs(struct vnode * devvp,struct mount * mp,struct lwp * l,struct udf_args * args)568cff5e7adSreinoud udf_mountfs(struct vnode *devvp, struct mount *mp,
569cff5e7adSreinoud 	    struct lwp *l, struct udf_args *args)
570cff5e7adSreinoud {
571cff5e7adSreinoud 	struct udf_mount     *ump;
572cff5e7adSreinoud 	uint32_t sector_size, lb_size, bshift;
573e979c658Sreinoud 	uint32_t logvol_integrity;
574c093c252Sreinoud 	int    num_anchors, error;
575cff5e7adSreinoud 
576cff5e7adSreinoud 	/* flush out any old buffers remaining from a previous use. */
577*d82e4b43Shannken 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
578*d82e4b43Shannken 	error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0);
579*d82e4b43Shannken 	VOP_UNLOCK(devvp);
580*d82e4b43Shannken 	if (error)
581cff5e7adSreinoud 		return error;
582cff5e7adSreinoud 
583e979c658Sreinoud 	/* setup basic mount information */
584e979c658Sreinoud 	mp->mnt_data = NULL;
585e979c658Sreinoud 	mp->mnt_stat.f_fsidx.__fsid_val[0] = (uint32_t) devvp->v_rdev;
586e979c658Sreinoud 	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_UDF);
587e979c658Sreinoud 	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
5883a8df9f0Schristos 	mp->mnt_stat.f_namemax = UDF_MAXNAMLEN;
589e979c658Sreinoud 	mp->mnt_flag |= MNT_LOCAL;
590c093c252Sreinoud //	mp->mnt_iflag |= IMNT_MPSAFE;
591e979c658Sreinoud 
5928ce1f4ffSmsaitoh 	/* allocate udf part of mount structure; malloc always succeeds */
5937dad9f73Sad 	ump = malloc(sizeof(struct udf_mount), M_UDFMNT, M_WAITOK | M_ZERO);
594cff5e7adSreinoud 
595cff5e7adSreinoud 	/* init locks */
596e979c658Sreinoud 	mutex_init(&ump->logvol_mutex, MUTEX_DEFAULT, IPL_NONE);
597e979c658Sreinoud 	mutex_init(&ump->allocate_mutex, MUTEX_DEFAULT, IPL_NONE);
5984207afb7Shannken 	mutex_init(&ump->sync_lock, MUTEX_DEFAULT, IPL_NONE);
599cff5e7adSreinoud 
600c093c252Sreinoud 	/* init rbtree for nodes, ordered by their icb address (long_ad) */
601c093c252Sreinoud 	udf_init_nodes_tree(ump);
602cff5e7adSreinoud 
603cff5e7adSreinoud 	/* set up linkage */
604cff5e7adSreinoud 	mp->mnt_data    = ump;
605cff5e7adSreinoud 	ump->vfs_mountp = mp;
606cff5e7adSreinoud 
607cff5e7adSreinoud 	/* set up arguments and device */
608cff5e7adSreinoud 	ump->mount_args = *args;
609cff5e7adSreinoud 	ump->devvp      = devvp;
6109e6b6751Sreinoud 	if ((error = udf_update_discinfo(ump))) {
611cff5e7adSreinoud 		printf("UDF mount: error inspecting fs node\n");
612cff5e7adSreinoud 		return error;
6130c1391f0Schristos 	}
614cff5e7adSreinoud 
615cff5e7adSreinoud 	/* inspect sector size */
616cff5e7adSreinoud 	sector_size = ump->discinfo.sector_size;
617cff5e7adSreinoud 	bshift = 1;
618cff5e7adSreinoud 	while ((1 << bshift) < sector_size)
619cff5e7adSreinoud 		bshift++;
620cff5e7adSreinoud 	if ((1 << bshift) != sector_size) {
621cff5e7adSreinoud 		printf("UDF mount: "
622cff5e7adSreinoud 		       "hit NetBSD implementation fence on sector size\n");
623cff5e7adSreinoud 		return EIO;
6240c1391f0Schristos 	}
625cff5e7adSreinoud 
6263efc85e7Sreinoud 	/* temporary check to overcome sectorsize >= 8192 bytes panic */
6273efc85e7Sreinoud 	if (sector_size >= 8192) {
6283efc85e7Sreinoud 		printf("UDF mount: "
6293efc85e7Sreinoud 			"hit implementation limit, sectorsize to big\n");
6303efc85e7Sreinoud 		return EIO;
6313efc85e7Sreinoud 	}
6323efc85e7Sreinoud 
633e979c658Sreinoud 	/*
634e979c658Sreinoud 	 * Inspect if we're asked to mount read-write on a non recordable or
635e979c658Sreinoud 	 * closed sequential disc.
636e979c658Sreinoud 	 */
637e979c658Sreinoud 	if ((mp->mnt_flag & MNT_RDONLY) == 0) {
638e979c658Sreinoud 		if ((ump->discinfo.mmc_cur & MMC_CAP_RECORDABLE) == 0) {
639e979c658Sreinoud 			printf("UDF mount: disc is not recordable\n");
640e979c658Sreinoud 			return EROFS;
641e979c658Sreinoud 		}
6423e0547f2Sreinoud 		if (ump->discinfo.mmc_cur & MMC_CAP_SEQUENTIAL) {
6433e0547f2Sreinoud 			if (ump->discinfo.disc_state == MMC_STATE_FULL) {
6443e0547f2Sreinoud 				printf("UDF mount: disc is not appendable\n");
6453e0547f2Sreinoud 				return EROFS;
6463e0547f2Sreinoud 			}
6473e0547f2Sreinoud 
648e979c658Sreinoud 			/*
6493e0547f2Sreinoud 			 * TODO if the last session is closed check if there
6503e0547f2Sreinoud 			 * is enough space to open/close new session
651e979c658Sreinoud 			 */
652e979c658Sreinoud 		}
653a41f6947Sandvar 		/* double check if we're not mounting a previous session RW */
6542ac9ba8cSreinoud 		if (args->sessionnr != 0) {
6552ac9ba8cSreinoud 			printf("UDF mount: updating a previous session "
6562ac9ba8cSreinoud 				"not yet allowed\n");
6572ac9ba8cSreinoud 			return EROFS;
6582ac9ba8cSreinoud 		}
6593e0547f2Sreinoud 	}
660e979c658Sreinoud 
661e979c658Sreinoud 	/* initialise bootstrap disc strategy */
662e979c658Sreinoud 	ump->strategy = &udf_strat_bootstrap;
663e979c658Sreinoud 	udf_discstrat_init(ump);
664e979c658Sreinoud 
665cff5e7adSreinoud 	/* read all anchors to get volume descriptor sequence */
666e979c658Sreinoud 	num_anchors = udf_read_anchors(ump);
667cff5e7adSreinoud 	if (num_anchors == 0)
668e979c658Sreinoud 		return EINVAL;
669cff5e7adSreinoud 
670cff5e7adSreinoud 	DPRINTF(VOLUMES, ("Read %d anchors on this disc, session %d\n",
671cff5e7adSreinoud 	    num_anchors, args->sessionnr));
672cff5e7adSreinoud 
673cff5e7adSreinoud 	/* read in volume descriptor sequence */
6749e6b6751Sreinoud 	if ((error = udf_read_vds_space(ump))) {
675cff5e7adSreinoud 		printf("UDF mount: error reading volume space\n");
6769e6b6751Sreinoud 		return error;
6779e6b6751Sreinoud 	}
678cff5e7adSreinoud 
6792ac9ba8cSreinoud 	/* close down bootstrap disc strategy */
680e979c658Sreinoud 	udf_discstrat_finish(ump);
681e979c658Sreinoud 
682cff5e7adSreinoud 	/* check consistency and completeness */
683e979c658Sreinoud 	if ((error = udf_process_vds(ump))) {
684e54e795bSreinoud 		printf( "UDF mount: disc not properly formatted"
685e54e795bSreinoud 			"(bad VDS)\n");
6869e6b6751Sreinoud 		return error;
6870c1391f0Schristos 	}
688cff5e7adSreinoud 
689e979c658Sreinoud 	/* switch to new disc strategy */
690e979c658Sreinoud 	KASSERT(ump->strategy != &udf_strat_bootstrap);
691e979c658Sreinoud 	udf_discstrat_init(ump);
692cff5e7adSreinoud 
693e979c658Sreinoud 	/* initialise late allocation administration space */
694e979c658Sreinoud 	ump->la_lmapping = malloc(sizeof(uint64_t) * UDF_MAX_MAPPINGS,
695e979c658Sreinoud 			M_TEMP, M_WAITOK);
696e979c658Sreinoud 	ump->la_pmapping = malloc(sizeof(uint64_t) * UDF_MAX_MAPPINGS,
697e979c658Sreinoud 			M_TEMP, M_WAITOK);
698e979c658Sreinoud 
699e979c658Sreinoud 	/* setup node cleanup extents copy space */
700e979c658Sreinoud 	lb_size = udf_rw32(ump->logical_vol->lb_size);
701e979c658Sreinoud 	ump->la_node_ad_cpy = malloc(lb_size * UDF_MAX_ALLOC_EXTENTS,
702e979c658Sreinoud 		M_UDFMNT, M_WAITOK);
703e979c658Sreinoud 	memset(ump->la_node_ad_cpy, 0, lb_size * UDF_MAX_ALLOC_EXTENTS);
704e979c658Sreinoud 
705e979c658Sreinoud 	/* setup rest of mount information */
706e979c658Sreinoud 	mp->mnt_data = ump;
707e979c658Sreinoud 
7087991f5a7Sandvar 	/* bshift is always equal to disc sector size */
709e979c658Sreinoud 	mp->mnt_dev_bshift = bshift;
710e979c658Sreinoud 	mp->mnt_fs_bshift  = bshift;
711e979c658Sreinoud 
712e979c658Sreinoud 	/* note that the mp info needs to be initialised for reading! */
713cff5e7adSreinoud 	/* read vds support tables like VAT, sparable etc. */
714e979c658Sreinoud 	if ((error = udf_read_vds_tables(ump))) {
715e54e795bSreinoud 		printf( "UDF mount: error in format or damaged disc "
716e54e795bSreinoud 			"(VDS tables failing)\n");
7179e6b6751Sreinoud 		return error;
7180c1391f0Schristos 	}
7199e6b6751Sreinoud 
720e979c658Sreinoud 	/* check if volume integrity is closed otherwise its dirty */
721e979c658Sreinoud 	logvol_integrity = udf_rw32(ump->logvol_integrity->integrity_type);
722e979c658Sreinoud 	if (logvol_integrity != UDF_INTEGRITY_CLOSED) {
723e979c658Sreinoud 		printf("UDF mount: file system is not clean; ");
724e979c658Sreinoud 		printf("please fsck(8)\n");
725e979c658Sreinoud 		return EPERM;
726e979c658Sreinoud 	}
727e979c658Sreinoud 
728e979c658Sreinoud 	/* read root directory */
729e979c658Sreinoud 	if ((error = udf_read_rootdirs(ump))) {
730cff5e7adSreinoud 		printf( "UDF mount: "
731e54e795bSreinoud 			"disc not properly formatted or damaged disc "
732e54e795bSreinoud 			"(rootdirs failing)\n");
733cff5e7adSreinoud 		return error;
7349e6b6751Sreinoud 	}
735cff5e7adSreinoud 
736cff5e7adSreinoud 	/* success! */
737cff5e7adSreinoud 	return 0;
738cff5e7adSreinoud }
739cff5e7adSreinoud 
740cff5e7adSreinoud /* --------------------------------------------------------------------- */
741cff5e7adSreinoud 
742cff5e7adSreinoud int
udf_start(struct mount * mp,int flags)74361e8303eSpooka udf_start(struct mount *mp, int flags)
744cff5e7adSreinoud {
745cff5e7adSreinoud 	/* do we have to do something here? */
746cff5e7adSreinoud 	return 0;
747cff5e7adSreinoud }
748cff5e7adSreinoud 
749cff5e7adSreinoud /* --------------------------------------------------------------------- */
750cff5e7adSreinoud 
751cff5e7adSreinoud int
udf_root(struct mount * mp,int lktype,struct vnode ** vpp)752c2e9cb94Sad udf_root(struct mount *mp, int lktype, struct vnode **vpp)
753cff5e7adSreinoud {
754cff5e7adSreinoud 	struct vnode *vp;
755cff5e7adSreinoud 	struct long_ad *dir_loc;
756cff5e7adSreinoud 	struct udf_mount *ump = VFSTOUDF(mp);
757cff5e7adSreinoud 	struct udf_node *root_dir;
758cff5e7adSreinoud 	int error;
759cff5e7adSreinoud 
760cff5e7adSreinoud 	DPRINTF(CALL, ("udf_root called\n"));
761cff5e7adSreinoud 
762cff5e7adSreinoud 	dir_loc = &ump->fileset_desc->rootdir_icb;
763c2e9cb94Sad 	error = udf_get_node(ump, dir_loc, &root_dir, lktype);
764cff5e7adSreinoud 
765cff5e7adSreinoud 	if (error)
766cff5e7adSreinoud 		return error;
767cff5e7adSreinoud 
768d384368fSchristos 	if (!root_dir)
769d384368fSchristos 		error = ENOENT;
770d384368fSchristos 
771cff5e7adSreinoud 	vp = root_dir->vnode;
77262c3c2d1Sreinoud 	KASSERT(vp->v_vflag & VV_ROOT);
773cff5e7adSreinoud 
774cff5e7adSreinoud 	*vpp = vp;
775cff5e7adSreinoud 	return 0;
776cff5e7adSreinoud }
777cff5e7adSreinoud 
778cff5e7adSreinoud /* --------------------------------------------------------------------- */
779cff5e7adSreinoud 
780cff5e7adSreinoud int
udf_statvfs(struct mount * mp,struct statvfs * sbp)78161e8303eSpooka udf_statvfs(struct mount *mp, struct statvfs *sbp)
782cff5e7adSreinoud {
783cff5e7adSreinoud 	struct udf_mount *ump = VFSTOUDF(mp);
784cff5e7adSreinoud 	struct logvol_int_desc *lvid;
785cff5e7adSreinoud 	struct udf_logvol_info *impl;
786cff5e7adSreinoud 	uint64_t freeblks, sizeblks;
787706de0e5Sreinoud 	int num_part;
788cff5e7adSreinoud 
789cff5e7adSreinoud 	DPRINTF(CALL, ("udf_statvfs called\n"));
790cff5e7adSreinoud 	sbp->f_flag   = mp->mnt_flag;
791cff5e7adSreinoud 	sbp->f_bsize  = ump->discinfo.sector_size;
792cff5e7adSreinoud 	sbp->f_frsize = ump->discinfo.sector_size;
793cff5e7adSreinoud 	sbp->f_iosize = ump->discinfo.sector_size;
794cff5e7adSreinoud 
795e979c658Sreinoud 	mutex_enter(&ump->allocate_mutex);
796e979c658Sreinoud 
797706de0e5Sreinoud 	udf_calc_freespace(ump, &sizeblks, &freeblks);
798e979c658Sreinoud 
799cff5e7adSreinoud 	sbp->f_blocks = sizeblks;
800cff5e7adSreinoud 	sbp->f_bfree  = freeblks;
801e979c658Sreinoud 	sbp->f_files  = 0;
802706de0e5Sreinoud 
803706de0e5Sreinoud 	lvid = ump->logvol_integrity;
804706de0e5Sreinoud 	num_part = udf_rw32(lvid->num_part);
805706de0e5Sreinoud 	impl = (struct udf_logvol_info *) (lvid->tables + 2*num_part);
806e979c658Sreinoud 	if (impl) {
807cff5e7adSreinoud 		sbp->f_files  = udf_rw32(impl->num_files);
808cff5e7adSreinoud 		sbp->f_files += udf_rw32(impl->num_directories);
809e979c658Sreinoud 	}
810cff5e7adSreinoud 
811cff5e7adSreinoud 	/* XXX read only for now XXX */
812cff5e7adSreinoud 	sbp->f_bavail = 0;
813cff5e7adSreinoud 	sbp->f_bresvd = 0;
814cff5e7adSreinoud 
815cff5e7adSreinoud 	/* tricky, next only aplies to ffs i think, so set to zero */
816cff5e7adSreinoud 	sbp->f_ffree  = 0;
817cff5e7adSreinoud 	sbp->f_favail = 0;
818cff5e7adSreinoud 	sbp->f_fresvd = 0;
819e979c658Sreinoud 
820e979c658Sreinoud 	mutex_exit(&ump->allocate_mutex);
821cff5e7adSreinoud 
822cff5e7adSreinoud 	copy_statvfs_info(sbp, mp);
823cff5e7adSreinoud 	return 0;
824cff5e7adSreinoud }
825cff5e7adSreinoud 
826cff5e7adSreinoud /* --------------------------------------------------------------------- */
827cff5e7adSreinoud 
828e979c658Sreinoud /*
829e979c658Sreinoud  * TODO what about writing out free space maps, lvid etc? only on `waitfor'
830e979c658Sreinoud  * i.e. explicit syncing by the user?
831e979c658Sreinoud  */
832e979c658Sreinoud 
833a287d23dSreinoud static int
udf_sync_writeout_system_files(struct udf_mount * ump,int clearflags)834a287d23dSreinoud udf_sync_writeout_system_files(struct udf_mount *ump, int clearflags)
835a287d23dSreinoud {
836a287d23dSreinoud 	int error;
837a287d23dSreinoud 
838a287d23dSreinoud 	/* XXX lock for VAT en bitmaps? */
839a287d23dSreinoud 	/* metadata nodes are written synchronous */
840a287d23dSreinoud 	DPRINTF(CALL, ("udf_sync: syncing metadata\n"));
841a287d23dSreinoud 	if (ump->lvclose & UDF_WRITE_VAT)
842a287d23dSreinoud 		udf_writeout_vat(ump);
843a287d23dSreinoud 
844a287d23dSreinoud 	error = 0;
845a287d23dSreinoud 	if (ump->lvclose & UDF_WRITE_PART_BITMAPS) {
846a287d23dSreinoud 		/* writeout metadata spacetable if existing */
847a287d23dSreinoud 		error = udf_write_metadata_partition_spacetable(ump, MNT_WAIT);
848a287d23dSreinoud 		if (error)
849a287d23dSreinoud 			printf( "udf_writeout_system_files : "
850a287d23dSreinoud 				" writeout of metadata space bitmap failed\n");
851a287d23dSreinoud 
852a287d23dSreinoud 		/* writeout partition spacetables */
853a287d23dSreinoud 		error = udf_write_physical_partition_spacetables(ump, MNT_WAIT);
854a287d23dSreinoud 		if (error)
855a287d23dSreinoud 			printf( "udf_writeout_system_files : "
856a287d23dSreinoud 				"writeout of space tables failed\n");
857a287d23dSreinoud 		if (!error && clearflags)
858a287d23dSreinoud 			ump->lvclose &= ~UDF_WRITE_PART_BITMAPS;
859a287d23dSreinoud 	}
860a287d23dSreinoud 
861a287d23dSreinoud 	return error;
862a287d23dSreinoud }
863a287d23dSreinoud 
864a287d23dSreinoud 
865cff5e7adSreinoud int
udf_sync(struct mount * mp,int waitfor,kauth_cred_t cred)866e979c658Sreinoud udf_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
867cff5e7adSreinoud {
868e979c658Sreinoud 	struct udf_mount *ump = VFSTOUDF(mp);
869e979c658Sreinoud 
870cff5e7adSreinoud 	DPRINTF(CALL, ("udf_sync called\n"));
871e979c658Sreinoud 	/* if called when mounted readonly, just ignore */
872e979c658Sreinoud 	if (mp->mnt_flag & MNT_RDONLY)
873e979c658Sreinoud 		return 0;
874e979c658Sreinoud 
875e979c658Sreinoud 	if (ump->syncing && !waitfor) {
876e979c658Sreinoud 		printf("UDF: skipping autosync\n");
877e979c658Sreinoud 		return 0;
878e979c658Sreinoud 	}
879e979c658Sreinoud 
880e979c658Sreinoud 	/* get sync lock */
881e979c658Sreinoud 	ump->syncing = 1;
882e979c658Sreinoud 
88371c9aa33Sreinoud 	/* pre-sync */
884e979c658Sreinoud 	udf_do_sync(ump, cred, waitfor);
885e979c658Sreinoud 
886a287d23dSreinoud 	if (waitfor == MNT_WAIT)
887a287d23dSreinoud 		udf_sync_writeout_system_files(ump, true);
88871c9aa33Sreinoud 
889e979c658Sreinoud 	DPRINTF(CALL, ("end of udf_sync()\n"));
890e979c658Sreinoud 	ump->syncing = 0;
891e979c658Sreinoud 
892cff5e7adSreinoud 	return 0;
893cff5e7adSreinoud }
894cff5e7adSreinoud 
895cff5e7adSreinoud /* --------------------------------------------------------------------- */
896cff5e7adSreinoud 
897cff5e7adSreinoud /*
898cff5e7adSreinoud  * Get vnode for the file system type specific file id ino for the fs. Its
899cff5e7adSreinoud  * used for reference to files by unique ID and for NFSv3.
900cff5e7adSreinoud  * (optional) TODO lookup why some sources state NFSv3
901cff5e7adSreinoud  */
902cff5e7adSreinoud int
udf_vget(struct mount * mp,ino_t ino,int lktype,struct vnode ** vpp)903c2e9cb94Sad udf_vget(struct mount *mp, ino_t ino, int lktype,
904168cd830Schristos     struct vnode **vpp)
905cff5e7adSreinoud {
906cff5e7adSreinoud 	DPRINTF(NOTIMPL, ("udf_vget called\n"));
907cff5e7adSreinoud 	return EOPNOTSUPP;
908cff5e7adSreinoud }
909cff5e7adSreinoud 
910cff5e7adSreinoud /* --------------------------------------------------------------------- */
911cff5e7adSreinoud 
912cff5e7adSreinoud /*
913cff5e7adSreinoud  * Lookup vnode for file handle specified
914cff5e7adSreinoud  */
915cff5e7adSreinoud int
udf_fhtovp(struct mount * mp,struct fid * fhp,int lktype,struct vnode ** vpp)916c2e9cb94Sad udf_fhtovp(struct mount *mp, struct fid *fhp, int lktype,
917168cd830Schristos     struct vnode **vpp)
918cff5e7adSreinoud {
919cff5e7adSreinoud 	DPRINTF(NOTIMPL, ("udf_fhtovp called\n"));
920cff5e7adSreinoud 	return EOPNOTSUPP;
921cff5e7adSreinoud }
922cff5e7adSreinoud 
923cff5e7adSreinoud /* --------------------------------------------------------------------- */
924cff5e7adSreinoud 
925cff5e7adSreinoud /*
926cff5e7adSreinoud  * Create an unique file handle. Its structure is opaque and won't be used by
927cff5e7adSreinoud  * other subsystems. It should uniquely identify the file in the filingsystem
928cff5e7adSreinoud  * and enough information to know if a file has been removed and/or resources
929cff5e7adSreinoud  * have been recycled.
930cff5e7adSreinoud  */
931cff5e7adSreinoud int
udf_vptofh(struct vnode * vp,struct fid * fid,size_t * fh_size)932168cd830Schristos udf_vptofh(struct vnode *vp, struct fid *fid,
933168cd830Schristos     size_t *fh_size)
934cff5e7adSreinoud {
935cff5e7adSreinoud 	DPRINTF(NOTIMPL, ("udf_vptofh called\n"));
936cff5e7adSreinoud 	return EOPNOTSUPP;
937cff5e7adSreinoud }
938cff5e7adSreinoud 
939cff5e7adSreinoud /* --------------------------------------------------------------------- */
940cff5e7adSreinoud 
941cff5e7adSreinoud /*
942cff5e7adSreinoud  * Create a filingsystem snapshot at the specified timestamp. Could be
943cff5e7adSreinoud  * implemented by explicitly creating a new session or with spare room in the
944cff5e7adSreinoud  * integrity descriptor space
945cff5e7adSreinoud  */
946cff5e7adSreinoud int
udf_snapshot(struct mount * mp,struct vnode * vp,struct timespec * tm)947168cd830Schristos udf_snapshot(struct mount *mp, struct vnode *vp,
948168cd830Schristos     struct timespec *tm)
949cff5e7adSreinoud {
950cff5e7adSreinoud 	DPRINTF(NOTIMPL, ("udf_snapshot called\n"));
951cff5e7adSreinoud 	return EOPNOTSUPP;
952cff5e7adSreinoud }
953d9df4ed2Sreinoud 
954d9df4ed2Sreinoud /* --------------------------------------------------------------------- */
955