2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/vfs/hammer/hammer_vfsops.c,v 1.10 2007/12/29 09:01:27 dillon Exp $
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/vnode.h>
41 #include <sys/mount.h>
42 #include <sys/malloc.h>
43 #include <sys/nlookup.h>
44 #include <sys/fcntl.h>
52 static void hammer_free_hmp(struct mount
*mp
);
54 static int hammer_vfs_mount(struct mount
*mp
, char *path
, caddr_t data
,
56 static int hammer_vfs_unmount(struct mount
*mp
, int mntflags
);
57 static int hammer_vfs_root(struct mount
*mp
, struct vnode
**vpp
);
58 static int hammer_vfs_statfs(struct mount
*mp
, struct statfs
*sbp
,
60 static int hammer_vfs_sync(struct mount
*mp
, int waitfor
);
61 static int hammer_vfs_init(struct vfsconf
*conf
);
63 static struct vfsops hammer_vfsops
= {
64 .vfs_mount
= hammer_vfs_mount
,
65 .vfs_unmount
= hammer_vfs_unmount
,
66 .vfs_root
= hammer_vfs_root
,
67 .vfs_statfs
= hammer_vfs_statfs
,
68 .vfs_sync
= hammer_vfs_sync
,
69 .vfs_vget
= hammer_vfs_vget
,
70 .vfs_init
= hammer_vfs_init
73 MALLOC_DEFINE(M_HAMMER
, "hammer-mount", "hammer mount");
75 VFS_SET(hammer_vfsops
, hammer
, 0);
76 MODULE_VERSION(hammer
, 1);
79 hammer_vfs_init(struct vfsconf
*conf
)
81 hammer_init_alist_config();
86 hammer_vfs_mount(struct mount
*mp
, char *mntpt
, caddr_t data
,
89 struct hammer_mount_info info
;
91 hammer_volume_t rootvol
;
93 const char *upath
; /* volume name in userspace */
94 char *path
; /* volume name in system space */
98 if ((error
= copyin(data
, &info
, sizeof(info
))) != 0)
100 if (info
.nvolumes
<= 0 || info
.nvolumes
>= 32768)
104 * Interal mount data structure
106 if (mp
->mnt_flag
& MNT_UPDATE
) {
107 hmp
= (void *)mp
->mnt_data
;
108 KKASSERT(hmp
!= NULL
);
110 hmp
= kmalloc(sizeof(*hmp
), M_HAMMER
, M_WAITOK
| M_ZERO
);
111 mp
->mnt_data
= (qaddr_t
)hmp
;
113 hmp
->zbuf
= kmalloc(HAMMER_BUFSIZE
, M_HAMMER
, M_WAITOK
|M_ZERO
);
114 hmp
->namekey_iterator
= mycpu
->gd_time_seconds
;
116 hmp
->hflags
= info
.hflags
;
118 mp
->mnt_flag
|= MNT_RDONLY
;
119 hmp
->asof
= info
.asof
;
121 hmp
->asof
= HAMMER_MAX_TID
;
125 * Re-open read-write if originally read-only, or vise-versa XXX
127 if (mp
->mnt_flag
& MNT_UPDATE
) {
128 if (hmp
->ronly
== 0 && (mp
->mnt_flag
& MNT_RDONLY
)) {
129 kprintf("HAMMER read-write -> read-only XXX\n");
131 } else if (hmp
->ronly
&& (mp
->mnt_flag
& MNT_RDONLY
) == 0) {
132 kprintf("HAMMER read-only -> read-write XXX\n");
138 RB_INIT(&hmp
->rb_vols_root
);
139 RB_INIT(&hmp
->rb_inos_root
);
140 hmp
->ronly
= ((mp
->mnt_flag
& MNT_RDONLY
) != 0);
145 path
= objcache_get(namei_oc
, M_WAITOK
);
146 hmp
->nvolumes
= info
.nvolumes
;
147 for (i
= 0; i
< info
.nvolumes
; ++i
) {
148 error
= copyin(&info
.volumes
[i
], &upath
, sizeof(char *));
150 error
= copyinstr(upath
, path
, MAXPATHLEN
, NULL
);
152 error
= hammer_install_volume(hmp
, path
);
156 objcache_put(namei_oc
, path
);
159 * Make sure we found a root volume
161 if (error
== 0 && hmp
->rootvol
== NULL
) {
162 kprintf("hammer_mount: No root volume found!\n");
165 if (error
== 0 && hmp
->rootcl
== NULL
) {
166 kprintf("hammer_mount: No root cluster found!\n");
175 * No errors, setup enough of the mount point so we can lookup the
178 mp
->mnt_iosize_max
= MAXPHYS
;
179 mp
->mnt_kern_flag
|= MNTK_FSMID
;
180 mp
->mnt_stat
.f_fsid
.val
[0] = 0; /* XXX */
181 mp
->mnt_stat
.f_fsid
.val
[1] = 0; /* XXX */
184 * note: f_iosize is used by vnode_pager_haspage() when constructing
187 mp
->mnt_stat
.f_iosize
= HAMMER_BUFSIZE
;
188 mp
->mnt_stat
.f_bsize
= HAMMER_BUFSIZE
;
189 vfs_getnewfsid(mp
); /* XXX */
190 mp
->mnt_maxsymlinklen
= 255;
191 mp
->mnt_flag
|= MNT_LOCAL
;
193 vfs_add_vnodeops(mp
, &hammer_vnode_vops
, &mp
->mnt_vn_norm_ops
);
196 * The root volume's ondisk pointer is only valid if we hold a
199 rootvol
= hammer_get_root_volume(hmp
, &error
);
202 ksnprintf(mp
->mnt_stat
.f_mntfromname
,
203 sizeof(mp
->mnt_stat
.f_mntfromname
), "%s",
204 rootvol
->ondisk
->vol_name
);
205 hammer_rel_volume(rootvol
, 0);
208 * Locate the root directory using the root cluster's B-Tree as a
209 * starting point. The root directory uses an obj_id of 1.
211 * FUTURE: Leave the root directory cached referenced but unlocked
212 * in hmp->rootvp (need to flush it on unmount).
214 error
= hammer_vfs_vget(mp
, 1, &rootvp
);
218 /*vn_unlock(hmp->rootvp);*/
222 * Cleanup and return.
230 hammer_vfs_unmount(struct mount
*mp
, int mntflags
)
233 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
239 * Clean out the vnodes
242 if (mntflags
& MNT_FORCE
)
244 if ((error
= vflush(mp
, 0, flags
)) != 0)
248 * Clean up the internal mount structure and related entities. This
256 * Clean up the internal mount structure and disassociate it from the mount.
257 * This may issue I/O.
260 hammer_free_hmp(struct mount
*mp
)
262 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
266 * Clean up the root vnode
275 * Unload & flush inodes
277 RB_SCAN(hammer_ino_rb_tree
, &hmp
->rb_inos_root
, NULL
,
278 hammer_unload_inode
, NULL
);
281 * Unload & flush volumes
283 RB_SCAN(hammer_vol_rb_tree
, &hmp
->rb_vols_root
, NULL
,
284 hammer_unload_volume
, NULL
);
287 mp
->mnt_flag
&= ~MNT_LOCAL
;
289 kfree(hmp
->zbuf
, M_HAMMER
);
290 kfree(hmp
, M_HAMMER
);
294 * Return the root vnode for the filesystem.
296 * HAMMER stores the root vnode in the hammer_mount structure so
297 * getting it is easy.
300 hammer_vfs_root(struct mount
*mp
, struct vnode
**vpp
)
302 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
305 if (hmp
->rootcl
== NULL
)
308 error
= hammer_vfs_vget(mp
, 1, vpp
);
311 /* FUTURE - cached root vnode */
312 if ((vp
= hmp
->rootvp
) != NULL
) {
314 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
325 hammer_vfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
327 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
328 hammer_volume_t volume
;
329 hammer_volume_ondisk_t ondisk
;
332 volume
= hammer_get_root_volume(hmp
, &error
);
336 ondisk
= volume
->ondisk
;
338 mp
->mnt_stat
.f_bfree
= mp
->mnt_stat
.f_blocks
-
339 ondisk
->vol0_stat_idx_bufs
-
340 ondisk
->vol0_stat_rec_bufs
-
341 ondisk
->vol0_stat_data_bufs
;
342 if (mp
->mnt_stat
.f_bfree
< 0)
343 mp
->mnt_stat
.f_bfree
= 0;
344 mp
->mnt_stat
.f_bavail
= mp
->mnt_stat
.f_bfree
;
345 mp
->mnt_stat
.f_files
= ondisk
->vol0_stat_inodes
;
346 if (mp
->mnt_stat
.f_files
< 0)
347 mp
->mnt_stat
.f_files
= 0;
349 hammer_rel_volume(volume
, 0);
355 hammer_vfs_sync(struct mount
*mp
, int waitfor
)
357 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
360 error
= hammer_sync_hmp(hmp
, waitfor
);