nilfs_vfsops.c revision 1.17 1 /* $NetBSD: nilfs_vfsops.c,v 1.17 2014/10/15 09:03:53 hannken Exp $ */
2
3 /*
4 * Copyright (c) 2008, 2009 Reinoud Zandijk
5 * All rights reserved.
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 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __KERNEL_RCSID(0, "$NetBSD: nilfs_vfsops.c,v 1.17 2014/10/15 09:03:53 hannken Exp $");
32 #endif /* not lint */
33
34
35 #if defined(_KERNEL_OPT)
36 #include "opt_compat_netbsd.h"
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/sysctl.h>
42 #include <sys/namei.h>
43 #include <sys/proc.h>
44 #include <sys/kernel.h>
45 #include <sys/vnode.h>
46 #include <miscfs/genfs/genfs.h>
47 #include <miscfs/specfs/specdev.h>
48 #include <sys/mount.h>
49 #include <sys/buf.h>
50 #include <sys/file.h>
51 #include <sys/device.h>
52 #include <sys/disklabel.h>
53 #include <sys/ioctl.h>
54 #include <sys/malloc.h>
55 #include <sys/dirent.h>
56 #include <sys/stat.h>
57 #include <sys/conf.h>
58 #include <sys/kauth.h>
59 #include <sys/module.h>
60
61 #include <fs/nilfs/nilfs_mount.h>
62 #include <sys/dirhash.h>
63
64
65 #include "nilfs.h"
66 #include "nilfs_subr.h"
67 #include "nilfs_bswap.h"
68
69 MODULE(MODULE_CLASS_VFS, nilfs, NULL);
70
71 #define VTOI(vnode) ((struct nilfs_node *) vnode->v_data)
72
73 /* verbose levels of the nilfs filingsystem */
74 int nilfs_verbose = NILFS_DEBUGGING;
75
76 /* malloc regions */
77 MALLOC_JUSTDEFINE(M_NILFSMNT, "NILFS mount", "NILFS mount structures");
78 MALLOC_JUSTDEFINE(M_NILFSTEMP, "NILFS temp", "NILFS scrap space");
79 struct pool nilfs_node_pool;
80
81 /* globals */
82 struct _nilfs_devices nilfs_devices;
83 static struct sysctllog *nilfs_sysctl_log;
84
85 /* supported functions predefined */
86 VFS_PROTOS(nilfs);
87
88
89 /* --------------------------------------------------------------------- */
90
91 /* predefine vnode-op list descriptor */
92 extern const struct vnodeopv_desc nilfs_vnodeop_opv_desc;
93
94 const struct vnodeopv_desc * const nilfs_vnodeopv_descs[] = {
95 &nilfs_vnodeop_opv_desc,
96 NULL,
97 };
98
99
100 /* vfsops descriptor linked in as anchor point for the filingsystem */
101 struct vfsops nilfs_vfsops = {
102 .vfs_name = MOUNT_NILFS,
103 .vfs_min_mount_data = sizeof (struct nilfs_args),
104 .vfs_mount = nilfs_mount,
105 .vfs_start = nilfs_start,
106 .vfs_unmount = nilfs_unmount,
107 .vfs_root = nilfs_root,
108 .vfs_quotactl = (void *)eopnotsupp,
109 .vfs_statvfs = nilfs_statvfs,
110 .vfs_sync = nilfs_sync,
111 .vfs_vget = nilfs_vget,
112 .vfs_fhtovp = nilfs_fhtovp,
113 .vfs_vptofh = nilfs_vptofh,
114 .vfs_init = nilfs_init,
115 .vfs_reinit = nilfs_reinit,
116 .vfs_done = nilfs_done,
117 .vfs_mountroot = nilfs_mountroot,
118 .vfs_snapshot = nilfs_snapshot,
119 .vfs_extattrctl = vfs_stdextattrctl,
120 .vfs_suspendctl = (void *)eopnotsupp,
121 .vfs_renamelock_enter = genfs_renamelock_enter,
122 .vfs_renamelock_exit = genfs_renamelock_exit,
123 .vfs_fsync = (void *)eopnotsupp,
124 .vfs_opv_descs = nilfs_vnodeopv_descs
125 };
126
127 /* --------------------------------------------------------------------- */
128
129 /* file system starts here */
130 void
131 nilfs_init(void)
132 {
133 size_t size;
134
135 /* setup memory types */
136 malloc_type_attach(M_NILFSMNT);
137 malloc_type_attach(M_NILFSTEMP);
138
139 /* init device lists */
140 SLIST_INIT(&nilfs_devices);
141
142 /* init node pools */
143 size = sizeof(struct nilfs_node);
144 pool_init(&nilfs_node_pool, size, 0, 0, 0,
145 "nilfs_node_pool", NULL, IPL_NONE);
146 }
147
148
149 void
150 nilfs_reinit(void)
151 {
152 /* nothing to do */
153 }
154
155
156 void
157 nilfs_done(void)
158 {
159 /* remove pools */
160 pool_destroy(&nilfs_node_pool);
161
162 malloc_type_detach(M_NILFSMNT);
163 malloc_type_detach(M_NILFSTEMP);
164 }
165
166 /*
167 * If running a DEBUG kernel, provide an easy way to set the debug flags when
168 * running into a problem.
169 */
170 #define NILFS_VERBOSE_SYSCTLOPT 1
171
172 static int
173 nilfs_modcmd(modcmd_t cmd, void *arg)
174 {
175 const struct sysctlnode *node;
176 int error;
177
178 switch (cmd) {
179 case MODULE_CMD_INIT:
180 error = vfs_attach(&nilfs_vfsops);
181 if (error != 0)
182 break;
183 /*
184 * XXX the "30" below could be dynamic, thereby eliminating one
185 * more instance of the "number to vfs" mapping problem, but
186 * "30" is the order as taken from sys/mount.h
187 */
188 sysctl_createv(&nilfs_sysctl_log, 0, NULL, &node,
189 CTLFLAG_PERMANENT,
190 CTLTYPE_NODE, "nilfs",
191 SYSCTL_DESCR("NTT's NILFSv2"),
192 NULL, 0, NULL, 0,
193 CTL_VFS, 30, CTL_EOL);
194 #ifdef DEBUG
195 sysctl_createv(&nilfs_sysctl_log, 0, NULL, &node,
196 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
197 CTLTYPE_INT, "verbose",
198 SYSCTL_DESCR("Bitmask for filesystem debugging"),
199 NULL, 0, &nilfs_verbose, 0,
200 CTL_VFS, 30, NILFS_VERBOSE_SYSCTLOPT, CTL_EOL);
201 #endif
202 break;
203 case MODULE_CMD_FINI:
204 error = vfs_detach(&nilfs_vfsops);
205 if (error != 0)
206 break;
207 sysctl_teardown(&nilfs_sysctl_log);
208 break;
209 default:
210 error = ENOTTY;
211 break;
212 }
213
214 return (error);
215 }
216
217 /* --------------------------------------------------------------------- */
218
219 int
220 nilfs_mountroot(void)
221 {
222 return EOPNOTSUPP;
223 }
224
225 /* --------------------------------------------------------------------- */
226
227 /* system nodes */
228 static int
229 nilfs_create_system_nodes(struct nilfs_device *nilfsdev)
230 {
231 int error;
232
233 error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_DAT_INO,
234 &nilfsdev->super_root.sr_dat, &nilfsdev->dat_node);
235 if (error)
236 goto errorout;
237
238 error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_CPFILE_INO,
239 &nilfsdev->super_root.sr_cpfile, &nilfsdev->cp_node);
240 if (error)
241 goto errorout;
242
243 error = nilfs_get_node_raw(nilfsdev, NULL, NILFS_SUFILE_INO,
244 &nilfsdev->super_root.sr_sufile, &nilfsdev->su_node);
245 if (error)
246 goto errorout;
247
248 return 0;
249 errorout:
250 nilfs_dispose_node(&nilfsdev->dat_node);
251 nilfs_dispose_node(&nilfsdev->cp_node);
252 nilfs_dispose_node(&nilfsdev->su_node);
253
254 return error;
255 }
256
257
258 static void
259 nilfs_release_system_nodes(struct nilfs_device *nilfsdev)
260 {
261 if (!nilfsdev)
262 return;
263 if (nilfsdev->refcnt > 0)
264 return;
265
266 nilfs_dispose_node(&nilfsdev->dat_node);
267 nilfs_dispose_node(&nilfsdev->cp_node);
268 nilfs_dispose_node(&nilfsdev->su_node);
269 }
270
271
272 /* --------------------------------------------------------------------- */
273
274 static int
275 nilfs_check_superblock_crc(struct nilfs_super_block *super)
276 {
277 uint32_t super_crc, comp_crc;
278
279 /* check super block magic */
280 if (nilfs_rw16(super->s_magic) != NILFS_SUPER_MAGIC)
281 return 0;
282
283 /* preserve crc */
284 super_crc = nilfs_rw32(super->s_sum);
285
286 /* calculate */
287 super->s_sum = 0;
288 comp_crc = crc32_le(nilfs_rw32(super->s_crc_seed),
289 (uint8_t *) super, nilfs_rw16(super->s_bytes));
290
291 /* restore */
292 super->s_sum = nilfs_rw32(super_crc);
293
294 /* check CRC */
295 return (super_crc == comp_crc);
296 }
297
298
299
300 static int
301 nilfs_read_superblock(struct nilfs_device *nilfsdev)
302 {
303 struct nilfs_super_block *super, tmp_super;
304 struct buf *bp;
305 uint64_t sb1off, sb2off;
306 uint64_t last_cno1, last_cno2;
307 uint64_t dev_blk;
308 int dev_bsize, dev_blks;
309 int sb1ok, sb2ok, swp;
310 int error;
311
312 sb1off = NILFS_SB_OFFSET_BYTES;
313 sb2off = NILFS_SB2_OFFSET_BYTES(nilfsdev->devsize);
314
315 dev_bsize = 1 << nilfsdev->devvp->v_mount->mnt_fs_bshift;
316
317 /* read our superblock regardless of backing device blocksize */
318 dev_blk = 0;
319 dev_blks = (sb1off + dev_bsize -1)/dev_bsize;
320 error = bread(nilfsdev->devvp, dev_blk, dev_blks * dev_bsize, NOCRED, 0, &bp);
321 if (error) {
322 return error;
323 }
324
325 /* copy read-in super block at the offset */
326 super = &nilfsdev->super;
327 memcpy(super, (uint8_t *) bp->b_data + NILFS_SB_OFFSET_BYTES,
328 sizeof(struct nilfs_super_block));
329 brelse(bp, BC_AGE);
330
331 /* read our 2nd superblock regardless of backing device blocksize */
332 dev_blk = sb2off / dev_bsize;
333 dev_blks = 2; /* assumption max one dev_bsize */
334 error = bread(nilfsdev->devvp, dev_blk, dev_blks * dev_bsize, NOCRED, 0, &bp);
335 if (error) {
336 return error;
337 }
338
339 /* copy read-in superblock2 at the offset */
340 super = &nilfsdev->super2;
341 memcpy(super, (uint8_t *) bp->b_data + NILFS_SB_OFFSET_BYTES,
342 sizeof(struct nilfs_super_block));
343 brelse(bp, BC_AGE);
344
345 sb1ok = nilfs_check_superblock_crc(&nilfsdev->super);
346 sb2ok = nilfs_check_superblock_crc(&nilfsdev->super2);
347
348 last_cno1 = nilfs_rw64(nilfsdev->super.s_last_cno);
349 last_cno2 = nilfs_rw64(nilfsdev->super2.s_last_cno);
350 swp = sb2ok && (last_cno2 > last_cno1);
351
352 if (swp) {
353 printf("nilfs warning: broken superblock, using spare\n");
354 tmp_super = nilfsdev->super2;
355 nilfsdev->super2 = nilfsdev->super; /* why preserve? */
356 nilfsdev->super = tmp_super;
357 }
358
359 if (!sb1ok && !sb2ok) {
360 printf("nilfs: no valid superblocks found\n");
361 return EINVAL;
362 }
363
364 return 0;
365 }
366
367
368 /* XXX NOTHING from the system nodes should need to be written here */
369 static void
370 nilfs_unmount_base(struct nilfs_device *nilfsdev)
371 {
372 int error __diagused;
373
374 if (!nilfsdev)
375 return;
376
377 /* remove all our information */
378 error = vinvalbuf(nilfsdev->devvp, 0, FSCRED, curlwp, 0, 0);
379 KASSERT(error == 0);
380
381 /* release the device's system nodes */
382 nilfs_release_system_nodes(nilfsdev);
383
384 /* TODO writeout super_block? */
385 }
386
387
388 static int
389 nilfs_mount_base(struct nilfs_device *nilfsdev,
390 struct mount *mp, struct nilfs_args *args)
391 {
392 struct lwp *l = curlwp;
393 uint64_t last_pseg, last_cno, last_seq;
394 uint32_t log_blocksize;
395 int error;
396
397 /* flush out any old buffers remaining from a previous use. */
398 if ((error = vinvalbuf(nilfsdev->devvp, V_SAVE, l->l_cred, l, 0, 0)))
399 return error;
400
401 /* read in our superblock */
402 error = nilfs_read_superblock(nilfsdev);
403 if (error) {
404 printf("nilfs_mount: can't read in super block : %d\n", error);
405 return error;
406 }
407
408 /* get our blocksize */
409 log_blocksize = nilfs_rw32(nilfsdev->super.s_log_block_size);
410 nilfsdev->blocksize = (uint64_t) 1 << (log_blocksize + 10);
411 /* TODO check superblock's blocksize limits */
412
413 /* calculate dat structure parameters */
414 nilfs_calc_mdt_consts(nilfsdev, &nilfsdev->dat_mdt,
415 nilfs_rw16(nilfsdev->super.s_dat_entry_size));
416 nilfs_calc_mdt_consts(nilfsdev, &nilfsdev->ifile_mdt,
417 nilfs_rw16(nilfsdev->super.s_inode_size));
418
419 DPRINTF(VOLUMES, ("nilfs_mount: accepted super block\n"));
420
421 /* search for the super root and roll forward when needed */
422 nilfs_search_super_root(nilfsdev);
423
424 nilfsdev->mount_state = nilfs_rw16(nilfsdev->super.s_state);
425 if (nilfsdev->mount_state != NILFS_VALID_FS) {
426 printf("FS is seriously damaged, needs repairing\n");
427 printf("aborting mount\n");
428 return EINVAL;
429 }
430
431 /*
432 * FS should be ok now. The superblock and the last segsum could be
433 * updated from the repair so extract running values again.
434 */
435 last_pseg = nilfs_rw64(nilfsdev->super.s_last_pseg); /*blknr */
436 last_cno = nilfs_rw64(nilfsdev->super.s_last_cno);
437 last_seq = nilfs_rw64(nilfsdev->super.s_last_seq);
438
439 nilfsdev->last_seg_seq = last_seq;
440 nilfsdev->last_seg_num = nilfs_get_segnum_of_block(nilfsdev, last_pseg);
441 nilfsdev->next_seg_num = nilfs_get_segnum_of_block(nilfsdev,
442 nilfs_rw64(nilfsdev->last_segsum.ss_next));
443 nilfsdev->last_cno = last_cno;
444
445 DPRINTF(VOLUMES, ("nilfs_mount: accepted super root\n"));
446
447 /* create system vnodes for DAT, CP and SEGSUM */
448 error = nilfs_create_system_nodes(nilfsdev);
449 if (error)
450 nilfs_unmount_base(nilfsdev);
451 return error;
452 }
453
454
455 static void
456 nilfs_unmount_device(struct nilfs_device *nilfsdev)
457 {
458 int error;
459
460 /* is there anything? */
461 if (nilfsdev == NULL)
462 return;
463
464 /* remove the device only if we're the last reference */
465 nilfsdev->refcnt--;
466 if (nilfsdev->refcnt >= 1)
467 return;
468
469 /* unmount our base */
470 nilfs_unmount_base(nilfsdev);
471
472 /* remove from our device list */
473 SLIST_REMOVE(&nilfs_devices, nilfsdev, nilfs_device, next_device);
474
475 /* close device */
476 DPRINTF(VOLUMES, ("closing device\n"));
477
478 /* remove our mount reference before closing device */
479 spec_node_setmountedfs(nilfsdev->devvp, NULL);
480
481 /* devvp is still locked by us */
482 vn_lock(nilfsdev->devvp, LK_EXCLUSIVE | LK_RETRY);
483 error = VOP_CLOSE(nilfsdev->devvp, FREAD | FWRITE, NOCRED);
484 if (error)
485 printf("Error during closure of device! error %d, "
486 "device might stay locked\n", error);
487 DPRINTF(VOLUMES, ("device close ok\n"));
488
489 /* clear our mount reference and release device node */
490 vput(nilfsdev->devvp);
491
492 /* free our device info */
493 cv_destroy(&nilfsdev->sync_cv);
494 free(nilfsdev, M_NILFSMNT);
495 }
496
497
498 static int
499 nilfs_check_mounts(struct nilfs_device *nilfsdev, struct mount *mp,
500 struct nilfs_args *args)
501 {
502 struct nilfs_mount *ump;
503 uint64_t last_cno;
504
505 /* no double-mounting of the same checkpoint */
506 STAILQ_FOREACH(ump, &nilfsdev->mounts, next_mount) {
507 if (ump->mount_args.cpno == args->cpno)
508 return EBUSY;
509 }
510
511 /* allow readonly mounts without questioning here */
512 if (mp->mnt_flag & MNT_RDONLY)
513 return 0;
514
515 /* readwrite mount you want */
516 STAILQ_FOREACH(ump, &nilfsdev->mounts, next_mount) {
517 /* only one RW mount on this device! */
518 if ((ump->vfs_mountp->mnt_flag & MNT_RDONLY)==0)
519 return EROFS;
520 /* RDONLY on last mountpoint is device busy */
521 last_cno = nilfs_rw64(ump->nilfsdev->super.s_last_cno);
522 if (ump->mount_args.cpno == last_cno)
523 return EBUSY;
524 }
525
526 /* OK for now */
527 return 0;
528 }
529
530
531 static int
532 nilfs_mount_device(struct vnode *devvp, struct mount *mp, struct nilfs_args *args,
533 struct nilfs_device **nilfsdev_p)
534 {
535 uint64_t psize;
536 unsigned secsize;
537 struct nilfs_device *nilfsdev;
538 struct lwp *l = curlwp;
539 int openflags, accessmode, error;
540
541 DPRINTF(VOLUMES, ("Mounting NILFS device\n"));
542
543 /* lookup device in our nilfs_mountpoints */
544 *nilfsdev_p = NULL;
545 SLIST_FOREACH(nilfsdev, &nilfs_devices, next_device)
546 if (nilfsdev->devvp == devvp)
547 break;
548
549 if (nilfsdev) {
550 DPRINTF(VOLUMES, ("device already mounted\n"));
551 error = nilfs_check_mounts(nilfsdev, mp, args);
552 if (error)
553 return error;
554 nilfsdev->refcnt++;
555 *nilfsdev_p = nilfsdev;
556 return 0;
557 }
558
559 DPRINTF(VOLUMES, ("no previous mounts on this device, mounting device\n"));
560
561 /* check if its a block device specified */
562 if (devvp->v_type != VBLK) {
563 vrele(devvp);
564 return ENOTBLK;
565 }
566 if (bdevsw_lookup(devvp->v_rdev) == NULL) {
567 vrele(devvp);
568 return ENXIO;
569 }
570
571 /*
572 * If mount by non-root, then verify that user has necessary
573 * permissions on the device.
574 */
575 accessmode = VREAD;
576 if ((mp->mnt_flag & MNT_RDONLY) == 0)
577 accessmode |= VWRITE;
578 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
579 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
580 KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
581 VOP_UNLOCK(devvp);
582 if (error) {
583 vrele(devvp);
584 return error;
585 }
586
587 /*
588 * Open device read-write; TODO how about upgrading later when needed?
589 */
590 openflags = FREAD | FWRITE;
591 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
592 error = VOP_OPEN(devvp, openflags, FSCRED);
593 VOP_UNLOCK(devvp);
594 if (error) {
595 vrele(devvp);
596 return error;
597 }
598
599 /* opened ok, try mounting */
600 nilfsdev = malloc(sizeof(*nilfsdev), M_NILFSMNT, M_WAITOK | M_ZERO);
601
602 /* initialise */
603 nilfsdev->refcnt = 1;
604 nilfsdev->devvp = devvp;
605 nilfsdev->uncomitted_bl = 0;
606 cv_init(&nilfsdev->sync_cv, "nilfssyn");
607 STAILQ_INIT(&nilfsdev->mounts);
608
609 /* register nilfs_device in list */
610 SLIST_INSERT_HEAD(&nilfs_devices, nilfsdev, next_device);
611
612 /* get our device's size */
613 error = getdisksize(devvp, &psize, &secsize);
614 if (error) {
615 /* remove all our information */
616 nilfs_unmount_device(nilfsdev);
617 return EINVAL;
618 }
619
620 nilfsdev->devsize = psize * secsize;
621
622 /* connect to the head for most recent files XXX really pass mp and args? */
623 error = nilfs_mount_base(nilfsdev, mp, args);
624 if (error) {
625 /* remove all our information */
626 nilfs_unmount_device(nilfsdev);
627 return EINVAL;
628 }
629
630 *nilfsdev_p = nilfsdev;
631 DPRINTF(VOLUMES, ("NILFS device mounted ok\n"));
632
633 return 0;
634 }
635
636
637 static int
638 nilfs_mount_checkpoint(struct nilfs_mount *ump)
639 {
640 struct nilfs_cpfile_header *cphdr;
641 struct nilfs_checkpoint *cp;
642 struct nilfs_inode ifile_inode;
643 struct nilfs_node *cp_node;
644 struct buf *bp;
645 uint64_t ncp, nsn, fcpno, blocknr, last_cno;
646 uint32_t off, dlen;
647 int cp_per_block, error;
648
649 DPRINTF(VOLUMES, ("mount_nilfs: trying to mount checkpoint number "
650 "%"PRIu64"\n", ump->mount_args.cpno));
651
652 cp_node = ump->nilfsdev->cp_node;
653
654 /* get cpfile header from 1st block of cp file */
655 error = nilfs_bread(cp_node, 0, NOCRED, 0, &bp);
656 if (error)
657 return error;
658 cphdr = (struct nilfs_cpfile_header *) bp->b_data;
659 ncp = nilfs_rw64(cphdr->ch_ncheckpoints);
660 nsn = nilfs_rw64(cphdr->ch_nsnapshots);
661
662 brelse(bp, BC_AGE);
663
664 DPRINTF(VOLUMES, ("mount_nilfs: checkpoint header read in\n"));
665 DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp));
666 DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn));
667 #ifndef NILFS_DEBUG
668 __USE(ncp);
669 __USE(nsn);
670 #endif
671
672 /* read in our specified checkpoint */
673 dlen = nilfs_rw16(ump->nilfsdev->super.s_checkpoint_size);
674 cp_per_block = ump->nilfsdev->blocksize / dlen;
675
676 fcpno = ump->mount_args.cpno + NILFS_CPFILE_FIRST_CHECKPOINT_OFFSET -1;
677 blocknr = fcpno / cp_per_block;
678 off = (fcpno % cp_per_block) * dlen;
679
680 error = nilfs_bread(cp_node, blocknr, NOCRED, 0, &bp);
681 if (error) {
682 printf("mount_nilfs: couldn't read cp block %"PRIu64"\n",
683 fcpno);
684 return EINVAL;
685 }
686
687 /* needs to be a valid checkpoint */
688 cp = (struct nilfs_checkpoint *) ((uint8_t *) bp->b_data + off);
689 if (cp->cp_flags & NILFS_CHECKPOINT_INVALID) {
690 printf("mount_nilfs: checkpoint marked invalid\n");
691 brelse(bp, BC_AGE);
692 return EINVAL;
693 }
694
695 /* is this really the checkpoint we want? */
696 if (nilfs_rw64(cp->cp_cno) != ump->mount_args.cpno) {
697 printf("mount_nilfs: checkpoint file corrupt? "
698 "expected cpno %"PRIu64", found cpno %"PRIu64"\n",
699 ump->mount_args.cpno, nilfs_rw64(cp->cp_cno));
700 brelse(bp, BC_AGE);
701 return EINVAL;
702 }
703
704 /* check if its a snapshot ! */
705 last_cno = nilfs_rw64(ump->nilfsdev->super.s_last_cno);
706 if (ump->mount_args.cpno != last_cno) {
707 /* only allow snapshots if not mounting on the last cp */
708 if ((cp->cp_flags & NILFS_CHECKPOINT_SNAPSHOT) == 0) {
709 printf( "mount_nilfs: checkpoint %"PRIu64" is not a "
710 "snapshot\n", ump->mount_args.cpno);
711 brelse(bp, BC_AGE);
712 return EINVAL;
713 }
714 }
715
716 ifile_inode = cp->cp_ifile_inode;
717 brelse(bp, BC_AGE);
718
719 /* get ifile inode */
720 error = nilfs_get_node_raw(ump->nilfsdev, NULL, NILFS_IFILE_INO,
721 &ifile_inode, &ump->ifile_node);
722 if (error) {
723 printf("mount_nilfs: can't read ifile node\n");
724 return EINVAL;
725 }
726
727 /* get root node? */
728
729 return 0;
730 }
731
732
733 static int
734 nilfs_stop_writing(struct nilfs_mount *ump)
735 {
736 /* readonly mounts won't write */
737 if (ump->vfs_mountp->mnt_flag & MNT_RDONLY)
738 return 0;
739
740 DPRINTF(CALL, ("nilfs_stop_writing called for RW mount\n"));
741
742 /* TODO writeout super_block? */
743 /* XXX no support for writing yet anyway */
744 return 0;
745 }
746
747
748 /* --------------------------------------------------------------------- */
749
750
751
752 #define MPFREE(a, lst) \
753 if ((a)) free((a), lst);
754 static void
755 free_nilfs_mountinfo(struct mount *mp)
756 {
757 struct nilfs_mount *ump = VFSTONILFS(mp);
758
759 if (ump == NULL)
760 return;
761
762 mutex_destroy(&ump->ihash_lock);
763 mutex_destroy(&ump->get_node_lock);
764 MPFREE(ump, M_NILFSMNT);
765 }
766 #undef MPFREE
767
768 int
769 nilfs_mount(struct mount *mp, const char *path,
770 void *data, size_t *data_len)
771 {
772 struct nilfs_args *args = data;
773 struct nilfs_device *nilfsdev;
774 struct nilfs_mount *ump;
775 struct vnode *devvp;
776 int lst, error;
777
778 DPRINTF(VFSCALL, ("nilfs_mount called\n"));
779
780 if (args == NULL)
781 return EINVAL;
782 if (*data_len < sizeof *args)
783 return EINVAL;
784
785 if (mp->mnt_flag & MNT_GETARGS) {
786 /* request for the mount arguments */
787 ump = VFSTONILFS(mp);
788 if (ump == NULL)
789 return EINVAL;
790 *args = ump->mount_args;
791 *data_len = sizeof *args;
792 return 0;
793 }
794
795 /* check/translate struct version */
796 if (args->version != 1) {
797 printf("mount_nilfs: unrecognized argument structure version\n");
798 return EINVAL;
799 }
800 /* TODO sanity checking other mount arguments */
801
802 /* handle request for updating mount parameters */
803 if (mp->mnt_flag & MNT_UPDATE) {
804 /* TODO can't update my mountpoint yet */
805 return EOPNOTSUPP;
806 }
807
808 /* lookup name to get its vnode */
809 error = namei_simple_user(args->fspec, NSM_FOLLOW_NOEMULROOT, &devvp);
810 if (error)
811 return error;
812
813 #ifdef DEBUG
814 if (nilfs_verbose & NILFS_DEBUG_VOLUMES)
815 vprint("NILFS mount, trying to mount \n", devvp);
816 #endif
817
818 error = nilfs_mount_device(devvp, mp, args, &nilfsdev);
819 if (error)
820 return error;
821
822 /*
823 * Create a nilfs_mount on the specified checkpoint. Note that only
824 * ONE RW mount point can exist and it needs to have the highest
825 * checkpoint nr. If mounting RW and its not on the last checkpoint we
826 * need to invalidate all checkpoints that follow!!! This is an
827 * advanced option.
828 */
829
830 /* setup basic mountpoint structure */
831 mp->mnt_data = NULL;
832 mp->mnt_stat.f_fsidx.__fsid_val[0] = (uint32_t) devvp->v_rdev;
833 mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_NILFS);
834 mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
835 mp->mnt_stat.f_namemax = NILFS_NAME_LEN;
836 mp->mnt_flag |= MNT_LOCAL;
837
838 /* XXX can't enable MPSAFE yet since genfs barfs on bad CV */
839 // mp->mnt_iflag |= IMNT_MPSAFE;
840
841 /* set our dev and fs units */
842 mp->mnt_dev_bshift = nilfs_rw32(nilfsdev->super.s_log_block_size) + 10;
843 mp->mnt_fs_bshift = mp->mnt_dev_bshift;
844
845 /* allocate nilfs part of mount structure; malloc always succeeds */
846 ump = malloc(sizeof(struct nilfs_mount), M_NILFSMNT, M_WAITOK | M_ZERO);
847
848 /* init locks */
849 mutex_init(&ump->ihash_lock, MUTEX_DEFAULT, IPL_NONE);
850 mutex_init(&ump->get_node_lock, MUTEX_DEFAULT, IPL_NONE);
851
852 /* init our hash table for inode lookup */
853 for (lst = 0; lst < NILFS_INODE_HASHSIZE; lst++) {
854 LIST_INIT(&ump->nilfs_nodes[lst]);
855 }
856
857 /* set up linkage */
858 mp->mnt_data = ump;
859 ump->vfs_mountp = mp;
860 ump->nilfsdev = nilfsdev;
861
862 #if 0
863 #ifndef NILFS_READWRITE
864 /* force read-only for now */
865 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
866 printf( "Enable kernel/module option NILFS_READWRITE for "
867 "writing, downgrading access to read-only\n");
868 mp->mnt_flag |= MNT_RDONLY;
869 }
870 #endif
871 #endif
872
873 /* DONT register our nilfs mountpoint on our vfs mountpoint */
874 spec_node_setmountedfs(devvp, NULL);
875 #if 0
876 if (spec_node_getmountedfs(devvp) == NULL)
877 spec_node_setmountedfs(devvp, mp);
878 if ((mp->mnt_flag & MNT_RDONLY) == 0)
879 spec_node_setmountedfs(devvp, mp);
880 #endif
881
882 /* add our mountpoint */
883 STAILQ_INSERT_TAIL(&nilfsdev->mounts, ump, next_mount);
884
885 /* get our selected checkpoint */
886 if (args->cpno == 0)
887 args->cpno = nilfsdev->last_cno;
888 args->cpno = MIN(args->cpno, nilfsdev->last_cno);
889
890 /* setting up other parameters */
891 ump->mount_args = *args;
892 error = nilfs_mount_checkpoint(ump);
893 if (error) {
894 nilfs_unmount(mp, MNT_FORCE);
895 return error;
896 }
897
898 /* set VFS info */
899 error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
900 mp->mnt_op->vfs_name, mp, curlwp);
901 if (error) {
902 nilfs_unmount(mp, MNT_FORCE);
903 return error;
904 }
905
906 /* successfully mounted */
907 DPRINTF(VOLUMES, ("nilfs_mount() successfull\n"));
908
909 return 0;
910 }
911
912 /* --------------------------------------------------------------------- */
913
914
915 /* remove our mountpoint and if its the last reference, remove our device */
916 int
917 nilfs_unmount(struct mount *mp, int mntflags)
918 {
919 struct nilfs_device *nilfsdev;
920 struct nilfs_mount *ump;
921 int error, flags;
922
923 DPRINTF(VFSCALL, ("nilfs_umount called\n"));
924
925 ump = VFSTONILFS(mp);
926 if (!ump)
927 panic("NILFS unmount: empty ump\n");
928 nilfsdev = ump->nilfsdev;
929
930 /*
931 * Flush all nodes associated to this mountpoint.
932 */
933 flags = (mntflags & MNT_FORCE) ? FORCECLOSE : 0;
934 if ((error = vflush(mp, NULLVP, flags)) != 0)
935 return error;
936
937 /* if we're the write mount, we ought to close the writing session */
938 error = nilfs_stop_writing(ump);
939 if (error)
940 return error;
941
942 nilfs_dispose_node(&ump->ifile_node);
943
944 /* remove our mount point */
945 STAILQ_REMOVE(&nilfsdev->mounts, ump, nilfs_mount, next_mount);
946 free_nilfs_mountinfo(mp);
947
948 /* free ump struct references */
949 mp->mnt_data = NULL;
950 mp->mnt_flag &= ~MNT_LOCAL;
951
952 /* unmount the device itself when we're the last one */
953 nilfs_unmount_device(nilfsdev);
954
955 DPRINTF(VOLUMES, ("Fin unmount\n"));
956 return error;
957 }
958
959 /* --------------------------------------------------------------------- */
960
961 int
962 nilfs_start(struct mount *mp, int flags)
963 {
964 /* do we have to do something here? */
965 return 0;
966 }
967
968 /* --------------------------------------------------------------------- */
969
970 int
971 nilfs_root(struct mount *mp, struct vnode **vpp)
972 {
973 int error;
974
975 DPRINTF(NODE, ("nilfs_root called\n"));
976
977 error = nilfs_get_node(mp, NILFS_ROOT_INO, vpp);
978 if (error == 0) {
979 error = vn_lock(*vpp, LK_EXCLUSIVE);
980 if (error) {
981 vrele(*vpp);
982 *vpp = NULL;
983 return error;
984 }
985 }
986 KASSERT(error != 0 || ((*vpp)->v_vflag & VV_ROOT));
987
988 DPRINTF(NODE, ("nilfs_root finished\n"));
989 return error;
990 }
991
992 /* --------------------------------------------------------------------- */
993
994 int
995 nilfs_statvfs(struct mount *mp, struct statvfs *sbp)
996 {
997 struct nilfs_mount *ump = VFSTONILFS(mp);
998 uint32_t blocksize;
999
1000 DPRINTF(VFSCALL, ("nilfs_statvfs called\n"));
1001
1002 blocksize = ump->nilfsdev->blocksize;
1003 sbp->f_flag = mp->mnt_flag;
1004 sbp->f_bsize = blocksize;
1005 sbp->f_frsize = blocksize;
1006 sbp->f_iosize = blocksize;
1007
1008 copy_statvfs_info(sbp, mp);
1009 return 0;
1010 }
1011
1012 /* --------------------------------------------------------------------- */
1013
1014 int
1015 nilfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
1016 {
1017 // struct nilfs_mount *ump = VFSTONILFS(mp);
1018
1019 DPRINTF(VFSCALL, ("nilfs_sync called\n"));
1020 /* if called when mounted readonly, just ignore */
1021 if (mp->mnt_flag & MNT_RDONLY)
1022 return 0;
1023
1024 DPRINTF(VFSCALL, ("end of nilfs_sync()\n"));
1025
1026 return 0;
1027 }
1028
1029 /* --------------------------------------------------------------------- */
1030
1031 /*
1032 * Get vnode for the file system type specific file id ino for the fs. Its
1033 * used for reference to files by unique ID and for NFSv3.
1034 * (optional) TODO lookup why some sources state NFSv3
1035 */
1036 int
1037 nilfs_vget(struct mount *mp, ino_t ino,
1038 struct vnode **vpp)
1039 {
1040 DPRINTF(NOTIMPL, ("nilfs_vget called\n"));
1041 return EOPNOTSUPP;
1042 }
1043
1044 /* --------------------------------------------------------------------- */
1045
1046 /*
1047 * Lookup vnode for file handle specified
1048 */
1049 int
1050 nilfs_fhtovp(struct mount *mp, struct fid *fhp,
1051 struct vnode **vpp)
1052 {
1053 DPRINTF(NOTIMPL, ("nilfs_fhtovp called\n"));
1054 return EOPNOTSUPP;
1055 }
1056
1057 /* --------------------------------------------------------------------- */
1058
1059 /*
1060 * Create an unique file handle. Its structure is opaque and won't be used by
1061 * other subsystems. It should uniquely identify the file in the filingsystem
1062 * and enough information to know if a file has been removed and/or resources
1063 * have been recycled.
1064 */
1065 int
1066 nilfs_vptofh(struct vnode *vp, struct fid *fid,
1067 size_t *fh_size)
1068 {
1069 DPRINTF(NOTIMPL, ("nilfs_vptofh called\n"));
1070 return EOPNOTSUPP;
1071 }
1072
1073 /* --------------------------------------------------------------------- */
1074
1075 /*
1076 * Create a file system snapshot at the specified timestamp.
1077 */
1078 int
1079 nilfs_snapshot(struct mount *mp, struct vnode *vp,
1080 struct timespec *tm)
1081 {
1082 DPRINTF(NOTIMPL, ("nilfs_snapshot called\n"));
1083 return EOPNOTSUPP;
1084 }
1085
1086 /* --------------------------------------------------------------------- */
1087