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.13 2008/01/01 01:00:03 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>
45 #include <sys/sysctl.h>
50 int hammer_debug_btree
;
52 int hammer_count_inodes
;
53 int hammer_count_records
;
54 int hammer_count_record_datas
;
55 int hammer_count_volumes
;
56 int hammer_count_supercls
;
57 int hammer_count_clusters
;
58 int hammer_count_buffers
;
59 int hammer_count_nodes
;
60 int hammer_count_spikes
;
62 SYSCTL_NODE(_vfs
, OID_AUTO
, hammer
, CTLFLAG_RW
, 0, "HAMMER filesystem");
63 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, debug_btree
, CTLFLAG_RW
,
64 &hammer_debug_btree
, 0, "");
65 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, debug_tid
, CTLFLAG_RW
,
66 &hammer_debug_tid
, 0, "");
67 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_inodes
, CTLFLAG_RD
,
68 &hammer_count_inodes
, 0, "");
69 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_records
, CTLFLAG_RD
,
70 &hammer_count_records
, 0, "");
71 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_record_datas
, CTLFLAG_RD
,
72 &hammer_count_record_datas
, 0, "");
73 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_volumes
, CTLFLAG_RD
,
74 &hammer_count_volumes
, 0, "");
75 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_supercls
, CTLFLAG_RD
,
76 &hammer_count_supercls
, 0, "");
77 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_clusters
, CTLFLAG_RD
,
78 &hammer_count_clusters
, 0, "");
79 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_buffers
, CTLFLAG_RD
,
80 &hammer_count_buffers
, 0, "");
81 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_nodes
, CTLFLAG_RD
,
82 &hammer_count_nodes
, 0, "");
83 SYSCTL_INT(_vfs_hammer
, OID_AUTO
, count_spikes
, CTLFLAG_RD
,
84 &hammer_count_spikes
, 0, "");
89 static void hammer_free_hmp(struct mount
*mp
);
91 static int hammer_vfs_mount(struct mount
*mp
, char *path
, caddr_t data
,
93 static int hammer_vfs_unmount(struct mount
*mp
, int mntflags
);
94 static int hammer_vfs_root(struct mount
*mp
, struct vnode
**vpp
);
95 static int hammer_vfs_statfs(struct mount
*mp
, struct statfs
*sbp
,
97 static int hammer_vfs_sync(struct mount
*mp
, int waitfor
);
98 static int hammer_vfs_init(struct vfsconf
*conf
);
100 static struct vfsops hammer_vfsops
= {
101 .vfs_mount
= hammer_vfs_mount
,
102 .vfs_unmount
= hammer_vfs_unmount
,
103 .vfs_root
= hammer_vfs_root
,
104 .vfs_statfs
= hammer_vfs_statfs
,
105 .vfs_sync
= hammer_vfs_sync
,
106 .vfs_vget
= hammer_vfs_vget
,
107 .vfs_init
= hammer_vfs_init
110 MALLOC_DEFINE(M_HAMMER
, "hammer-mount", "hammer mount");
112 VFS_SET(hammer_vfsops
, hammer
, 0);
113 MODULE_VERSION(hammer
, 1);
116 hammer_vfs_init(struct vfsconf
*conf
)
118 hammer_init_alist_config();
123 hammer_vfs_mount(struct mount
*mp
, char *mntpt
, caddr_t data
,
126 struct hammer_mount_info info
;
128 hammer_volume_t rootvol
;
129 struct vnode
*rootvp
;
130 const char *upath
; /* volume name in userspace */
131 char *path
; /* volume name in system space */
135 if ((error
= copyin(data
, &info
, sizeof(info
))) != 0)
137 if (info
.nvolumes
<= 0 || info
.nvolumes
>= 32768)
141 * Interal mount data structure
143 if (mp
->mnt_flag
& MNT_UPDATE
) {
144 hmp
= (void *)mp
->mnt_data
;
145 KKASSERT(hmp
!= NULL
);
147 hmp
= kmalloc(sizeof(*hmp
), M_HAMMER
, M_WAITOK
| M_ZERO
);
148 mp
->mnt_data
= (qaddr_t
)hmp
;
150 hmp
->zbuf
= kmalloc(HAMMER_BUFSIZE
, M_HAMMER
, M_WAITOK
|M_ZERO
);
151 hmp
->namekey_iterator
= mycpu
->gd_time_seconds
;
153 hmp
->hflags
= info
.hflags
;
155 mp
->mnt_flag
|= MNT_RDONLY
;
156 hmp
->asof
= info
.asof
;
158 hmp
->asof
= HAMMER_MAX_TID
;
162 * Re-open read-write if originally read-only, or vise-versa XXX
164 if (mp
->mnt_flag
& MNT_UPDATE
) {
165 if (hmp
->ronly
== 0 && (mp
->mnt_flag
& MNT_RDONLY
)) {
166 kprintf("HAMMER read-write -> read-only XXX\n");
168 } else if (hmp
->ronly
&& (mp
->mnt_flag
& MNT_RDONLY
) == 0) {
169 kprintf("HAMMER read-only -> read-write XXX\n");
175 RB_INIT(&hmp
->rb_vols_root
);
176 RB_INIT(&hmp
->rb_inos_root
);
177 hmp
->ronly
= ((mp
->mnt_flag
& MNT_RDONLY
) != 0);
182 path
= objcache_get(namei_oc
, M_WAITOK
);
183 hmp
->nvolumes
= info
.nvolumes
;
184 for (i
= 0; i
< info
.nvolumes
; ++i
) {
185 error
= copyin(&info
.volumes
[i
], &upath
, sizeof(char *));
187 error
= copyinstr(upath
, path
, MAXPATHLEN
, NULL
);
189 error
= hammer_install_volume(hmp
, path
);
193 objcache_put(namei_oc
, path
);
196 * Make sure we found a root volume
198 if (error
== 0 && hmp
->rootvol
== NULL
) {
199 kprintf("hammer_mount: No root volume found!\n");
202 if (error
== 0 && hmp
->rootcl
== NULL
) {
203 kprintf("hammer_mount: No root cluster found!\n");
212 * No errors, setup enough of the mount point so we can lookup the
215 mp
->mnt_iosize_max
= MAXPHYS
;
216 mp
->mnt_kern_flag
|= MNTK_FSMID
;
217 mp
->mnt_stat
.f_fsid
.val
[0] = 0; /* XXX */
218 mp
->mnt_stat
.f_fsid
.val
[1] = 0; /* XXX */
221 * note: f_iosize is used by vnode_pager_haspage() when constructing
224 mp
->mnt_stat
.f_iosize
= HAMMER_BUFSIZE
;
225 mp
->mnt_stat
.f_bsize
= HAMMER_BUFSIZE
;
226 vfs_getnewfsid(mp
); /* XXX */
227 mp
->mnt_maxsymlinklen
= 255;
228 mp
->mnt_flag
|= MNT_LOCAL
;
230 vfs_add_vnodeops(mp
, &hammer_vnode_vops
, &mp
->mnt_vn_norm_ops
);
231 vfs_add_vnodeops(mp
, &hammer_spec_vops
, &mp
->mnt_vn_spec_ops
);
232 vfs_add_vnodeops(mp
, &hammer_fifo_vops
, &mp
->mnt_vn_fifo_ops
);
235 * The root volume's ondisk pointer is only valid if we hold a
238 rootvol
= hammer_get_root_volume(hmp
, &error
);
241 ksnprintf(mp
->mnt_stat
.f_mntfromname
,
242 sizeof(mp
->mnt_stat
.f_mntfromname
), "%s",
243 rootvol
->ondisk
->vol_name
);
244 hammer_rel_volume(rootvol
, 0);
247 * Locate the root directory using the root cluster's B-Tree as a
248 * starting point. The root directory uses an obj_id of 1.
250 * FUTURE: Leave the root directory cached referenced but unlocked
251 * in hmp->rootvp (need to flush it on unmount).
253 error
= hammer_vfs_vget(mp
, 1, &rootvp
);
257 /*vn_unlock(hmp->rootvp);*/
261 * Cleanup and return.
269 hammer_vfs_unmount(struct mount
*mp
, int mntflags
)
272 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
278 * Clean out the vnodes
281 if (mntflags
& MNT_FORCE
)
283 if ((error
= vflush(mp
, 0, flags
)) != 0)
287 * Clean up the internal mount structure and related entities. This
295 * Clean up the internal mount structure and disassociate it from the mount.
296 * This may issue I/O.
299 hammer_free_hmp(struct mount
*mp
)
301 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
305 * Clean up the root vnode
314 * Unload & flush inodes
316 RB_SCAN(hammer_ino_rb_tree
, &hmp
->rb_inos_root
, NULL
,
317 hammer_unload_inode
, (void *)MNT_WAIT
);
320 * Unload & flush volumes
322 RB_SCAN(hammer_vol_rb_tree
, &hmp
->rb_vols_root
, NULL
,
323 hammer_unload_volume
, NULL
);
326 mp
->mnt_flag
&= ~MNT_LOCAL
;
328 kfree(hmp
->zbuf
, M_HAMMER
);
329 kfree(hmp
, M_HAMMER
);
333 * Return the root vnode for the filesystem.
335 * HAMMER stores the root vnode in the hammer_mount structure so
336 * getting it is easy.
339 hammer_vfs_root(struct mount
*mp
, struct vnode
**vpp
)
341 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
344 if (hmp
->rootcl
== NULL
)
347 error
= hammer_vfs_vget(mp
, 1, vpp
);
350 /* FUTURE - cached root vnode */
351 if ((vp
= hmp
->rootvp
) != NULL
) {
353 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
364 hammer_vfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct ucred
*cred
)
366 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
367 hammer_volume_t volume
;
368 hammer_volume_ondisk_t ondisk
;
371 volume
= hammer_get_root_volume(hmp
, &error
);
375 ondisk
= volume
->ondisk
;
377 mp
->mnt_stat
.f_bfree
= mp
->mnt_stat
.f_blocks
-
378 ondisk
->vol0_stat_idx_bufs
-
379 ondisk
->vol0_stat_rec_bufs
-
380 ondisk
->vol0_stat_data_bufs
;
381 if (mp
->mnt_stat
.f_bfree
< 0)
382 mp
->mnt_stat
.f_bfree
= 0;
383 mp
->mnt_stat
.f_bavail
= mp
->mnt_stat
.f_bfree
;
384 mp
->mnt_stat
.f_files
= ondisk
->vol0_stat_inodes
;
385 if (mp
->mnt_stat
.f_files
< 0)
386 mp
->mnt_stat
.f_files
= 0;
388 hammer_rel_volume(volume
, 0);
394 hammer_vfs_sync(struct mount
*mp
, int waitfor
)
396 struct hammer_mount
*hmp
= (void *)mp
->mnt_data
;
399 error
= hammer_sync_hmp(hmp
, waitfor
);