xref: /dflybsd-src/sys/vfs/hammer/hammer_vfsops.c (revision a89aec1b5ac590a302c603b53ffc16011b2500e9)
1427e5fc6SMatthew Dillon /*
2427e5fc6SMatthew Dillon  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3427e5fc6SMatthew Dillon  *
4427e5fc6SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5427e5fc6SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6427e5fc6SMatthew Dillon  *
7427e5fc6SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8427e5fc6SMatthew Dillon  * modification, are permitted provided that the following conditions
9427e5fc6SMatthew Dillon  * are met:
10427e5fc6SMatthew Dillon  *
11427e5fc6SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12427e5fc6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13427e5fc6SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14427e5fc6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15427e5fc6SMatthew Dillon  *    the documentation and/or other materials provided with the
16427e5fc6SMatthew Dillon  *    distribution.
17427e5fc6SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18427e5fc6SMatthew Dillon  *    contributors may be used to endorse or promote products derived
19427e5fc6SMatthew Dillon  *    from this software without specific, prior written permission.
20427e5fc6SMatthew Dillon  *
21427e5fc6SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22427e5fc6SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23427e5fc6SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24427e5fc6SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25427e5fc6SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26427e5fc6SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27427e5fc6SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28427e5fc6SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29427e5fc6SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30427e5fc6SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31427e5fc6SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32427e5fc6SMatthew Dillon  * SUCH DAMAGE.
33427e5fc6SMatthew Dillon  *
34*a89aec1bSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_vfsops.c,v 1.5 2007/11/20 07:16:28 dillon Exp $
35427e5fc6SMatthew Dillon  */
36427e5fc6SMatthew Dillon 
37427e5fc6SMatthew Dillon #include <sys/param.h>
38427e5fc6SMatthew Dillon #include <sys/systm.h>
39427e5fc6SMatthew Dillon #include <sys/kernel.h>
40427e5fc6SMatthew Dillon #include <sys/vnode.h>
41427e5fc6SMatthew Dillon #include <sys/mount.h>
42427e5fc6SMatthew Dillon #include <sys/malloc.h>
43427e5fc6SMatthew Dillon #include <sys/nlookup.h>
44427e5fc6SMatthew Dillon #include <sys/fcntl.h>
45427e5fc6SMatthew Dillon #include <sys/buf.h>
46427e5fc6SMatthew Dillon #include <sys/buf2.h>
47427e5fc6SMatthew Dillon #include "hammer.h"
48427e5fc6SMatthew Dillon 
49427e5fc6SMatthew Dillon /*
50427e5fc6SMatthew Dillon  * VFS ABI
51427e5fc6SMatthew Dillon  */
52427e5fc6SMatthew Dillon static void	hammer_free_hmp(struct mount *mp);
53427e5fc6SMatthew Dillon 
54427e5fc6SMatthew Dillon static int	hammer_vfs_mount(struct mount *mp, char *path, caddr_t data,
55427e5fc6SMatthew Dillon 				struct ucred *cred);
56427e5fc6SMatthew Dillon static int	hammer_vfs_unmount(struct mount *mp, int mntflags);
57427e5fc6SMatthew Dillon static int	hammer_vfs_root(struct mount *mp, struct vnode **vpp);
58427e5fc6SMatthew Dillon static int	hammer_vfs_statfs(struct mount *mp, struct statfs *sbp,
59427e5fc6SMatthew Dillon 				struct ucred *cred);
60427e5fc6SMatthew Dillon static int	hammer_vfs_sync(struct mount *mp, int waitfor);
61427e5fc6SMatthew Dillon static int	hammer_vfs_init(struct vfsconf *conf);
62427e5fc6SMatthew Dillon 
63427e5fc6SMatthew Dillon static struct vfsops hammer_vfsops = {
64427e5fc6SMatthew Dillon 	.vfs_mount	= hammer_vfs_mount,
65427e5fc6SMatthew Dillon 	.vfs_unmount	= hammer_vfs_unmount,
66427e5fc6SMatthew Dillon 	.vfs_root 	= hammer_vfs_root,
67427e5fc6SMatthew Dillon 	.vfs_statfs	= hammer_vfs_statfs,
68427e5fc6SMatthew Dillon 	.vfs_sync	= hammer_vfs_sync,
69427e5fc6SMatthew Dillon 	.vfs_vget	= hammer_vfs_vget,
70427e5fc6SMatthew Dillon 	.vfs_init	= hammer_vfs_init
71427e5fc6SMatthew Dillon };
72427e5fc6SMatthew Dillon 
73427e5fc6SMatthew Dillon MALLOC_DEFINE(M_HAMMER, "hammer-mount", "hammer mount");
74427e5fc6SMatthew Dillon 
75427e5fc6SMatthew Dillon VFS_SET(hammer_vfsops, hammer, 0);
76427e5fc6SMatthew Dillon MODULE_VERSION(hammer, 1);
77427e5fc6SMatthew Dillon 
78427e5fc6SMatthew Dillon static int
79427e5fc6SMatthew Dillon hammer_vfs_init(struct vfsconf *conf)
80427e5fc6SMatthew Dillon {
81427e5fc6SMatthew Dillon 	hammer_init_alist_config();
82427e5fc6SMatthew Dillon 	return(0);
83427e5fc6SMatthew Dillon }
84427e5fc6SMatthew Dillon 
85427e5fc6SMatthew Dillon static int
86427e5fc6SMatthew Dillon hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data,
87427e5fc6SMatthew Dillon 		 struct ucred *cred)
88427e5fc6SMatthew Dillon {
89427e5fc6SMatthew Dillon 	struct hammer_mount_info info;
90*a89aec1bSMatthew Dillon 	hammer_mount_t hmp;
91*a89aec1bSMatthew Dillon 	hammer_volume_t rootvol;
9227ea2398SMatthew Dillon 	struct vnode *rootvp;
93427e5fc6SMatthew Dillon 	const char *upath;	/* volume name in userspace */
94427e5fc6SMatthew Dillon 	char *path;		/* volume name in system space */
95427e5fc6SMatthew Dillon 	int error;
96427e5fc6SMatthew Dillon 	int i;
97427e5fc6SMatthew Dillon 
98427e5fc6SMatthew Dillon 	if ((error = copyin(data, &info, sizeof(info))) != 0)
99427e5fc6SMatthew Dillon 		return (error);
100427e5fc6SMatthew Dillon 	if (info.nvolumes <= 0 || info.nvolumes >= 32768)
101427e5fc6SMatthew Dillon 		return (EINVAL);
102427e5fc6SMatthew Dillon 
103427e5fc6SMatthew Dillon 	/*
104427e5fc6SMatthew Dillon 	 * Interal mount data structure
105427e5fc6SMatthew Dillon 	 */
106427e5fc6SMatthew Dillon 	hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO);
107427e5fc6SMatthew Dillon 	mp->mnt_data = (qaddr_t)hmp;
108427e5fc6SMatthew Dillon 	hmp->mp = mp;
10966325755SMatthew Dillon 	hmp->zbuf = kmalloc(HAMMER_BUFSIZE, M_HAMMER, M_WAITOK | M_ZERO);
110*a89aec1bSMatthew Dillon 	hmp->namekey_iterator = mycpu->gd_time_seconds;
111427e5fc6SMatthew Dillon 	RB_INIT(&hmp->rb_vols_root);
112427e5fc6SMatthew Dillon 	RB_INIT(&hmp->rb_inos_root);
113427e5fc6SMatthew Dillon 
114427e5fc6SMatthew Dillon 	/*
115427e5fc6SMatthew Dillon 	 * Load volumes
116427e5fc6SMatthew Dillon 	 */
117427e5fc6SMatthew Dillon 	path = objcache_get(namei_oc, M_WAITOK);
118427e5fc6SMatthew Dillon 	for (i = 0; i < info.nvolumes; ++i) {
119427e5fc6SMatthew Dillon 		error = copyin(&info.volumes[i], &upath, sizeof(char *));
120427e5fc6SMatthew Dillon 		if (error == 0)
121427e5fc6SMatthew Dillon 			error = copyinstr(upath, path, MAXPATHLEN, NULL);
122427e5fc6SMatthew Dillon 		if (error == 0)
1238cd0a023SMatthew Dillon 			error = hammer_install_volume(hmp, path);
124427e5fc6SMatthew Dillon 		if (error)
125427e5fc6SMatthew Dillon 			break;
126427e5fc6SMatthew Dillon 	}
127427e5fc6SMatthew Dillon 	objcache_put(namei_oc, path);
128427e5fc6SMatthew Dillon 
129427e5fc6SMatthew Dillon 	/*
130427e5fc6SMatthew Dillon 	 * Make sure we found a root volume
131427e5fc6SMatthew Dillon 	 */
132427e5fc6SMatthew Dillon 	if (error == 0 && hmp->rootvol == NULL) {
133427e5fc6SMatthew Dillon 		kprintf("hammer_mount: No root volume found!\n");
134427e5fc6SMatthew Dillon 		error = EINVAL;
135427e5fc6SMatthew Dillon 	}
136427e5fc6SMatthew Dillon 	if (error == 0 && hmp->rootcl == NULL) {
137427e5fc6SMatthew Dillon 		kprintf("hammer_mount: No root cluster found!\n");
138427e5fc6SMatthew Dillon 		error = EINVAL;
139427e5fc6SMatthew Dillon 	}
140427e5fc6SMatthew Dillon 	if (error) {
141427e5fc6SMatthew Dillon 		hammer_free_hmp(mp);
142427e5fc6SMatthew Dillon 		return (error);
143427e5fc6SMatthew Dillon 	}
144427e5fc6SMatthew Dillon 
145427e5fc6SMatthew Dillon 	/*
14627ea2398SMatthew Dillon 	 * No errors, setup enough of the mount point so we can lookup the
14727ea2398SMatthew Dillon 	 * root vnode.
148427e5fc6SMatthew Dillon 	 */
149427e5fc6SMatthew Dillon 	mp->mnt_iosize_max = MAXPHYS;
150427e5fc6SMatthew Dillon 	mp->mnt_kern_flag |= MNTK_FSMID;
151427e5fc6SMatthew Dillon 	mp->mnt_stat.f_fsid.val[0] = 0;	/* XXX */
152427e5fc6SMatthew Dillon 	mp->mnt_stat.f_fsid.val[1] = 0;	/* XXX */
153427e5fc6SMatthew Dillon 	vfs_getnewfsid(mp);		/* XXX */
154427e5fc6SMatthew Dillon 	mp->mnt_maxsymlinklen = 255;
155427e5fc6SMatthew Dillon 	mp->mnt_flag |= MNT_LOCAL;
156427e5fc6SMatthew Dillon 
157427e5fc6SMatthew Dillon 	vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops);
15827ea2398SMatthew Dillon 
15927ea2398SMatthew Dillon 	/*
160*a89aec1bSMatthew Dillon 	 * The root volume's ondisk pointer is only valid if we hold a
161*a89aec1bSMatthew Dillon 	 * reference to it.
162*a89aec1bSMatthew Dillon 	 */
163*a89aec1bSMatthew Dillon 	rootvol = hammer_get_root_volume(hmp, &error);
164*a89aec1bSMatthew Dillon 	if (error)
165*a89aec1bSMatthew Dillon 		goto done;
166*a89aec1bSMatthew Dillon 	ksnprintf(mp->mnt_stat.f_mntfromname,
167*a89aec1bSMatthew Dillon 		  sizeof(mp->mnt_stat.f_mntfromname), "%s",
168*a89aec1bSMatthew Dillon 		  rootvol->ondisk->vol_name);
169*a89aec1bSMatthew Dillon 	hammer_rel_volume(rootvol, 0);
170*a89aec1bSMatthew Dillon 
171*a89aec1bSMatthew Dillon 	/*
17227ea2398SMatthew Dillon 	 * Locate the root directory using the root cluster's B-Tree as a
17327ea2398SMatthew Dillon 	 * starting point.  The root directory uses an obj_id of 1.
17427ea2398SMatthew Dillon 	 *
17527ea2398SMatthew Dillon 	 * FUTURE: Leave the root directory cached referenced but unlocked
17627ea2398SMatthew Dillon 	 * in hmp->rootvp (need to flush it on unmount).
17727ea2398SMatthew Dillon 	 */
17827ea2398SMatthew Dillon 	error = hammer_vfs_vget(mp, 1, &rootvp);
179*a89aec1bSMatthew Dillon 	if (error)
180*a89aec1bSMatthew Dillon 		goto done;
18127ea2398SMatthew Dillon 	vput(rootvp);
18227ea2398SMatthew Dillon 	/*vn_unlock(hmp->rootvp);*/
18327ea2398SMatthew Dillon 
184*a89aec1bSMatthew Dillon done:
18527ea2398SMatthew Dillon 	/*
18627ea2398SMatthew Dillon 	 * Cleanup and return.
18727ea2398SMatthew Dillon 	 */
18827ea2398SMatthew Dillon 	if (error)
18927ea2398SMatthew Dillon 		hammer_free_hmp(mp);
190427e5fc6SMatthew Dillon 	return (error);
191427e5fc6SMatthew Dillon }
192427e5fc6SMatthew Dillon 
193427e5fc6SMatthew Dillon static int
194427e5fc6SMatthew Dillon hammer_vfs_unmount(struct mount *mp, int mntflags)
195427e5fc6SMatthew Dillon {
196427e5fc6SMatthew Dillon #if 0
197427e5fc6SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
198427e5fc6SMatthew Dillon #endif
199427e5fc6SMatthew Dillon 	int flags;
20066325755SMatthew Dillon 	int error;
20127ea2398SMatthew Dillon 
20227ea2398SMatthew Dillon 	/*
203427e5fc6SMatthew Dillon 	 * Clean out the vnodes
204427e5fc6SMatthew Dillon 	 */
20566325755SMatthew Dillon 	flags = 0;
20666325755SMatthew Dillon 	if (mntflags & MNT_FORCE)
20766325755SMatthew Dillon 		flags |= FORCECLOSE;
20866325755SMatthew Dillon 	if ((error = vflush(mp, 0, flags)) != 0)
20966325755SMatthew Dillon 		return (error);
210427e5fc6SMatthew Dillon 
211427e5fc6SMatthew Dillon 	/*
212427e5fc6SMatthew Dillon 	 * Clean up the internal mount structure and related entities.  This
213427e5fc6SMatthew Dillon 	 * may issue I/O.
214427e5fc6SMatthew Dillon 	 */
215427e5fc6SMatthew Dillon 	hammer_free_hmp(mp);
216427e5fc6SMatthew Dillon 	return(0);
217427e5fc6SMatthew Dillon }
218427e5fc6SMatthew Dillon 
219427e5fc6SMatthew Dillon /*
220427e5fc6SMatthew Dillon  * Clean up the internal mount structure and disassociate it from the mount.
221427e5fc6SMatthew Dillon  * This may issue I/O.
222427e5fc6SMatthew Dillon  */
223427e5fc6SMatthew Dillon static void
224427e5fc6SMatthew Dillon hammer_free_hmp(struct mount *mp)
225427e5fc6SMatthew Dillon {
226427e5fc6SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
227427e5fc6SMatthew Dillon 
22827ea2398SMatthew Dillon #if 0
229427e5fc6SMatthew Dillon 	/*
230427e5fc6SMatthew Dillon 	 * Clean up the root vnode
231427e5fc6SMatthew Dillon 	 */
232427e5fc6SMatthew Dillon 	if (hmp->rootvp) {
233427e5fc6SMatthew Dillon 		vrele(hmp->rootvp);
234427e5fc6SMatthew Dillon 		hmp->rootvp = NULL;
235427e5fc6SMatthew Dillon 	}
23627ea2398SMatthew Dillon #endif
237427e5fc6SMatthew Dillon 
238427e5fc6SMatthew Dillon 	/*
239427e5fc6SMatthew Dillon 	 * Unload & flush inodes
240427e5fc6SMatthew Dillon 	 */
241427e5fc6SMatthew Dillon 	RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL,
24266325755SMatthew Dillon 		hammer_unload_inode, NULL);
243427e5fc6SMatthew Dillon 
244427e5fc6SMatthew Dillon 	/*
245427e5fc6SMatthew Dillon 	 * Unload & flush volumes
246427e5fc6SMatthew Dillon 	 */
247427e5fc6SMatthew Dillon 	RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL,
248427e5fc6SMatthew Dillon 		hammer_unload_volume, NULL);
249427e5fc6SMatthew Dillon 
250427e5fc6SMatthew Dillon 	mp->mnt_data = NULL;
25166325755SMatthew Dillon 	mp->mnt_flag &= ~MNT_LOCAL;
252427e5fc6SMatthew Dillon 	hmp->mp = NULL;
25366325755SMatthew Dillon 	kfree(hmp->zbuf, M_HAMMER);
254427e5fc6SMatthew Dillon 	kfree(hmp, M_HAMMER);
255427e5fc6SMatthew Dillon }
256427e5fc6SMatthew Dillon 
257427e5fc6SMatthew Dillon /*
258427e5fc6SMatthew Dillon  * Return the root vnode for the filesystem.
259427e5fc6SMatthew Dillon  *
260427e5fc6SMatthew Dillon  * HAMMER stores the root vnode in the hammer_mount structure so
261427e5fc6SMatthew Dillon  * getting it is easy.
262427e5fc6SMatthew Dillon  */
263427e5fc6SMatthew Dillon static int
264427e5fc6SMatthew Dillon hammer_vfs_root(struct mount *mp, struct vnode **vpp)
265427e5fc6SMatthew Dillon {
266427e5fc6SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
26727ea2398SMatthew Dillon 	int error;
268427e5fc6SMatthew Dillon 
26927ea2398SMatthew Dillon 	if (hmp->rootcl == NULL)
27027ea2398SMatthew Dillon 		error = EIO;
27127ea2398SMatthew Dillon 	else
27227ea2398SMatthew Dillon 		error = hammer_vfs_vget(mp, 1, vpp);
27327ea2398SMatthew Dillon 	return (error);
27427ea2398SMatthew Dillon #if 0
27527ea2398SMatthew Dillon 	/* FUTURE - cached root vnode */
276427e5fc6SMatthew Dillon 	if ((vp = hmp->rootvp) != NULL) {
277427e5fc6SMatthew Dillon 		vref(vp);
278427e5fc6SMatthew Dillon 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
279427e5fc6SMatthew Dillon 		*vpp = vp;
280427e5fc6SMatthew Dillon 		return (0);
281427e5fc6SMatthew Dillon 	} else {
282427e5fc6SMatthew Dillon 		*vpp = NULL;
283427e5fc6SMatthew Dillon 		return (EIO);
284427e5fc6SMatthew Dillon 	}
28527ea2398SMatthew Dillon #endif
286427e5fc6SMatthew Dillon }
287427e5fc6SMatthew Dillon 
288427e5fc6SMatthew Dillon static int
289427e5fc6SMatthew Dillon hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
290427e5fc6SMatthew Dillon {
29127ea2398SMatthew Dillon 	*sbp = mp->mnt_stat;
29227ea2398SMatthew Dillon 	return(0);
293427e5fc6SMatthew Dillon }
294427e5fc6SMatthew Dillon 
295427e5fc6SMatthew Dillon static int
296427e5fc6SMatthew Dillon hammer_vfs_sync(struct mount *mp, int waitfor)
297427e5fc6SMatthew Dillon {
298427e5fc6SMatthew Dillon 	return(0);
299427e5fc6SMatthew Dillon }
300427e5fc6SMatthew Dillon 
301