hammer2 - complain if the hammer2 kld module isn't loaded
[dragonfly.git] / sys / vfs / hammer2 / hammer2_vfsops.c
CommitLineData
47902fef 1/*-
703720e4
MD
2 * Copyright (c) 2011, 2012 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
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
16 * distribution.
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.
20 *
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
32 * SUCH DAMAGE.
33 */
703720e4
MD
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/nlookup.h>
38#include <sys/vnode.h>
39#include <sys/mount.h>
40#include <sys/fcntl.h>
41#include <sys/buf.h>
42#include <sys/uuid.h>
a74bc66c 43#include <sys/vfsops.h>
703720e4
MD
44
45#include "hammer2.h"
46#include "hammer2_disk.h"
47#include "hammer2_mount.h"
48
49static int hammer2_init(struct vfsconf *conf);
50static int hammer2_mount(struct mount *mp, char *path, caddr_t data,
51 struct ucred *cred);
52static int hammer2_remount(struct mount *, char *, struct vnode *,
53 struct ucred *);
54static int hammer2_unmount(struct mount *mp, int mntflags);
55static int hammer2_root(struct mount *mp, struct vnode **vpp);
56static int hammer2_statfs(struct mount *mp, struct statfs *sbp,
57 struct ucred *cred);
58static int hammer2_statvfs(struct mount *mp, struct statvfs *sbp,
59 struct ucred *cred);
60static int hammer2_sync(struct mount *mp, int waitfor);
61static int hammer2_vget(struct mount *mp, struct vnode *dvp,
62 ino_t ino, struct vnode **vpp);
63static int hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
64 struct fid *fhp, struct vnode **vpp);
65static int hammer2_vptofh(struct vnode *vp, struct fid *fhp);
66static int hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
67 int *exflagsp, struct ucred **credanonp);
68
703720e4
MD
69/*
70 * HAMMER2 vfs operations.
71 */
72static struct vfsops hammer2_vfsops = {
703720e4
MD
73 .vfs_init = hammer2_init,
74 .vfs_sync = hammer2_sync,
75 .vfs_mount = hammer2_mount,
76 .vfs_unmount = hammer2_unmount,
703720e4 77 .vfs_root = hammer2_root,
703720e4 78 .vfs_statfs = hammer2_statfs,
47902fef 79 .vfs_statvfs = hammer2_statvfs,
703720e4
MD
80 .vfs_vget = hammer2_vget,
81 .vfs_vptofh = hammer2_vptofh,
82 .vfs_fhtovp = hammer2_fhtovp,
83 .vfs_checkexp = hammer2_checkexp
84};
85
703720e4
MD
86MALLOC_DEFINE(M_HAMMER2, "HAMMER2-mount", "");
87
88VFS_SET(hammer2_vfsops, hammer2, 0);
89MODULE_VERSION(hammer2, 1);
90
e118c14f
MD
91static
92int
703720e4
MD
93hammer2_init(struct vfsconf *conf)
94{
95 int error;
96
97 error = 0;
98
0e92b724 99 if (HAMMER2_BLOCKREF_BYTES != sizeof(struct hammer2_blockref))
703720e4 100 error = EINVAL;
0e92b724 101 if (HAMMER2_INODE_BYTES != sizeof(struct hammer2_inode_data))
703720e4 102 error = EINVAL;
0e92b724 103 if (HAMMER2_ALLOCREF_BYTES != sizeof(struct hammer2_allocref))
703720e4 104 error = EINVAL;
0e92b724 105 if (HAMMER2_VOLUME_BYTES != sizeof(struct hammer2_volume_data))
703720e4
MD
106 error = EINVAL;
107
108 if (error)
109 kprintf("HAMMER2 structure size mismatch; cannot continue.\n");
110
111 return (error);
112}
113
114/*
115 * Mount or remount HAMMER2 fileystem from physical media
116 *
117 * mountroot
118 * mp mount point structure
119 * path NULL
120 * data <unused>
121 * cred <unused>
122 *
123 * mount
124 * mp mount point structure
125 * path path to mount point
126 * data pointer to argument structure in user space
127 * volume volume path (device@LABEL form)
128 * hflags user mount flags
129 * cred user credentials
130 *
131 * RETURNS: 0 Success
132 * !0 error number
133 */
e118c14f
MD
134static
135int
703720e4
MD
136hammer2_mount(struct mount *mp, char *path, caddr_t data,
137 struct ucred *cred)
138{
139 struct hammer2_mount_info info;
140 struct hammer2_mount *hmp;
141 struct vnode *devvp;
142 struct nlookupdata nd;
143 char devstr[MNAMELEN];
144 size_t size;
145 size_t done;
146 char *dev, *label;
147 int ronly;
148 int error;
e118c14f 149#if 0
703720e4 150 int rc;
e118c14f 151#endif
703720e4
MD
152
153 hmp = NULL;
154 dev = label = NULL;
155 devvp = NULL;
156
157 kprintf("hammer2_mount\n");
158
159 if (path == NULL) {
160 /*
161 * Root mount
162 */
163
164 return (EOPNOTSUPP);
165 } else {
166 /*
167 * Non-root mount or updating a mount
168 */
169
170 error = copyin(data, &info, sizeof(info));
171 if (error)
172 return (error);
173
174 error = copyinstr(info.volume, devstr, MNAMELEN - 1, &done);
175 if (error)
176 return (error);
177
178 /* Extract device and label */
179 dev = devstr;
180 label = strchr(devstr, '@');
181 if (label == NULL ||
182 ((label + 1) - dev) > done)
183 return (EINVAL);
184 *label = '\0';
185 label++;
186 if (*label == '\0')
187 return (EINVAL);
188
189 if (mp->mnt_flag & MNT_UPDATE) {
190 /* Update mount */
191 /* HAMMER2 implements NFS export via mountctl */
192 hmp = MPTOH2(mp);
193 devvp = hmp->hm_devvp;
194 return hammer2_remount(mp, path, devvp, cred);
195 }
196 }
197
198 /*
199 * New non-root mount
200 */
201 /* Lookup name and verify it refers to a block device */
202 error = nlookup_init(&nd, dev, UIO_SYSSPACE, NLC_FOLLOW);
203 if (error)
204 return (error);
205 error = nlookup(&nd);
206 if (error)
207 return (error);
208 error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp);
209 if (error)
210 return (error);
211 nlookup_done(&nd);
212
213 if (!vn_isdisk(devvp, &error)) {
214 vrele(devvp);
215 return (error);
216 }
217
218 /*
219 * Common path for new root/non-root mounts;
220 * devvp is a ref-ed by not locked vnode referring to the fs device
221 */
222
223 error = vfs_mountedon(devvp);
224 if (error) {
225 vrele(devvp);
226 return (error);
227 }
228
229 if (vcount(devvp) > 0) {
230 vrele(devvp);
231 return (EBUSY);
232 }
233
234 /*
235 * Open the fs device
236 */
237 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
238 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
239 error = vinvalbuf(devvp, V_SAVE, 0, 0);
240 if (error) {
241 vn_unlock(devvp);
242 vrele(devvp);
243 return (error);
244 }
245 /* This is correct; however due to an NFS quirk of my setup, FREAD
246 * is required... */
247 /*
248 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, NULL);
249 */
f0206a67 250
703720e4
MD
251 error = VOP_OPEN(devvp, FREAD, FSCRED, NULL);
252 vn_unlock(devvp);
253 if (error) {
254 vrele(devvp);
255 return (error);
256 }
257
258#ifdef notyet
259 /* VOP_IOCTL(EXTENDED_DISK_INFO, devvp); */
260 /* if vn device, never use bdwrite(); */
261 /* check if device supports BUF_CMD_READALL; */
262 /* check if device supports BUF_CMD_WRITEALL; */
263#endif
264
265 hmp = kmalloc(sizeof(*hmp), M_HAMMER2, M_WAITOK | M_ZERO);
f0206a67 266 mp->mnt_data = (qaddr_t) hmp;
703720e4 267 hmp->hm_mp = mp;
f0206a67
VS
268 hmp->hm_ronly = ronly;
269 hmp->hm_devvp = devvp;
703720e4
MD
270 lockinit(&hmp->hm_lk, "h2mp", 0, 0);
271 kmalloc_create(&hmp->hm_inodes, "HAMMER2-inodes");
272 kmalloc_create(&hmp->hm_ipstacks, "HAMMER2-ipstacks");
74d91941 273
f0206a67 274 mp->mnt_flag = MNT_LOCAL;
703720e4
MD
275
276 /*
277 * Filesystem subroutines are self-synchronized
278 */
f0206a67 279 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE;
703720e4
MD
280
281 /* Setup root inode */
282 hmp->hm_iroot = alloci(hmp);
0e92b724
VS
283 hmp->hm_iroot->type = HAMMER2_INODE_TYPE_DIR | HAMMER2_INODE_TYPE_ROOT;
284 hmp->hm_iroot->inum = 1;
703720e4
MD
285
286 /* currently rely on tmpfs routines */
f0206a67
VS
287 vfs_getnewfsid(mp);
288 vfs_add_vnodeops(mp, &hammer2_vnode_vops, &mp->mnt_vn_norm_ops);
289 vfs_add_vnodeops(mp, &hammer2_spec_vops, &mp->mnt_vn_spec_ops);
290 vfs_add_vnodeops(mp, &hammer2_fifo_vops, &mp->mnt_vn_fifo_ops);
703720e4 291
f0206a67 292 copystr(info.volume, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
703720e4
MD
293 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
294 bzero(mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname));
295 copyinstr(path, mp->mnt_stat.f_mntonname,
296 sizeof(mp->mnt_stat.f_mntonname) - 1,
297 &size);
298
299 hammer2_statfs(mp, &mp->mnt_stat, cred);
300
301 hammer2_inode_unlock_ex(hmp->hm_iroot);
302
47902fef 303 return 0;
703720e4
MD
304}
305
e118c14f
MD
306static
307int
703720e4
MD
308hammer2_remount(struct mount *mp, char *path, struct vnode *devvp,
309 struct ucred *cred)
310{
311 return (0);
312}
313
e118c14f
MD
314static
315int
703720e4
MD
316hammer2_unmount(struct mount *mp, int mntflags)
317{
318 struct hammer2_mount *hmp;
319 int flags;
320 int error;
321
322 kprintf("hammer2_unmount\n");
323
324 hmp = MPTOH2(mp);
325 flags = 0;
326
327 if (mntflags & MNT_FORCE)
328 flags |= FORCECLOSE;
329
330 hammer2_mount_exlock(hmp);
331
332 error = vflush(mp, 0, flags);
333
334 /*
335 * Work to do:
336 * 1) Wait on the flusher having no work; heat up if needed
337 * 2) Scan inode RB tree till all the inodes are free
338 * 3) Destroy the kmalloc inode zone
339 * 4) Free the mount point
340 */
341
342 kmalloc_destroy(&hmp->hm_inodes);
343 kmalloc_destroy(&hmp->hm_ipstacks);
344
345 hammer2_mount_unlock(hmp);
346
347 // Tmpfs does this
348 //kfree(hmp, M_HAMMER2);
349
703720e4
MD
350
351 return (error);
352}
353
e118c14f
MD
354static
355int
703720e4
MD
356hammer2_vget(struct mount *mp, struct vnode *dvp,
357 ino_t ino, struct vnode **vpp)
358{
359 kprintf("hammer2_vget\n");
360 return (EOPNOTSUPP);
361}
362
e118c14f
MD
363static
364int
703720e4
MD
365hammer2_root(struct mount *mp, struct vnode **vpp)
366{
367 struct hammer2_mount *hmp;
368 int error;
369 struct vnode *vp;
370
371 kprintf("hammer2_root\n");
372
373 hmp = MPTOH2(mp);
e118c14f 374 hammer2_mount_exlock(hmp);
703720e4
MD
375 if (hmp->hm_iroot == NULL) {
376 *vpp = NULL;
377 error = EINVAL;
378 } else {
379 vp = igetv(hmp->hm_iroot, &error);
380 *vpp = vp;
381 if (vp == NULL)
382 kprintf("vnodefail\n");
383 }
384 hammer2_mount_unlock(hmp);
385
386 return (error);
387}
388
e118c14f
MD
389static
390int
703720e4
MD
391hammer2_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
392{
393 struct hammer2_mount *hmp;
394
395 kprintf("hammer2_statfs\n");
396
397 hmp = MPTOH2(mp);
398
399 sbp->f_iosize = PAGE_SIZE;
400 sbp->f_bsize = PAGE_SIZE;
401
402 sbp->f_blocks = 10;
403 sbp->f_bavail = 10;
404 sbp->f_bfree = 10;
405
406 sbp->f_files = 10;
407 sbp->f_ffree = 10;
408 sbp->f_owner = 0;
409
410 return (0);
411}
412
e118c14f
MD
413static
414int
703720e4
MD
415hammer2_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
416{
417 kprintf("hammer2_statvfs\n");
418 return (EOPNOTSUPP);
419}
420
421/*
422 * Sync the entire filesystem; this is called from the filesystem syncer
423 * process periodically and whenever a user calls sync(1) on the hammer
424 * mountpoint.
425 *
426 * Currently is actually called from the syncer! \o/
427 *
428 * This task will have to snapshot the state of the dirty inode chain.
429 * From that, it will have to make sure all of the inodes on the dirty
430 * chain have IO initiated. We make sure that io is initiated for the root
431 * block.
432 *
433 * If waitfor is set, we wait for media to acknowledge the new rootblock.
434 *
435 * THINKS: side A vs side B, to have sync not stall all I/O?
436 */
e118c14f
MD
437static
438int
703720e4
MD
439hammer2_sync(struct mount *mp, int waitfor)
440{
e118c14f 441#if 0
703720e4
MD
442 struct hammer2_mount *hmp;
443 struct hammer2_inode *ip;
e118c14f 444#endif
703720e4
MD
445
446 kprintf("hammer2_sync \n");
447
e118c14f
MD
448#if 0
449 hmp = MPTOH2(mp);
450#endif
703720e4
MD
451
452 return (0);
453}
454
e118c14f
MD
455static
456int
703720e4
MD
457hammer2_vptofh(struct vnode *vp, struct fid *fhp)
458{
459 return (0);
460}
461
e118c14f
MD
462static
463int
703720e4
MD
464hammer2_fhtovp(struct mount *mp, struct vnode *rootvp,
465 struct fid *fhp, struct vnode **vpp)
466{
467 return (0);
468}
469
e118c14f
MD
470static
471int
703720e4
MD
472hammer2_checkexp(struct mount *mp, struct sockaddr *nam,
473 int *exflagsp, struct ucred **credanonp)
474{
475 return (0);
476}