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