1 /* $NetBSD: nilfs_vfsops.c,v 1.47 2008/08/06 13:41:12 reinoud Exp $ */
4 * Copyright (c) 2008, 2009 Reinoud Zandijk
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
29 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: nilfs_vfsops.c,v 1.47 2008/08/06 13:41:12 reinoud Exp $");
35 #if defined(_KERNEL_OPT)
36 #include "opt_compat_netbsd.h"
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/sysctl.h>
42 #include <sys/namei.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>
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>
58 #include <sys/kauth.h>
59 #include <sys/module.h>
61 #include <fs/nilfs/nilfs_mount.h>
62 #include <sys/dirhash.h>
66 #include "nilfs_subr.h"
67 #include "nilfs_bswap.h"
69 MODULE(MODULE_CLASS_VFS
, nilfs
, NULL
);
71 #define VTOI(vnode) ((struct nilfs_node *) vnode->v_data)
73 #define NILFS_SET_SYSTEMFILE(vp) { \
74 /* XXXAD Is the vnode locked? */ \
75 (vp)->v_vflag |= VV_SYSTEM; \
79 #define NILFS_UNSET_SYSTEMFILE(vp) { \
80 /* XXXAD Is the vnode locked? */ \
81 (vp)->v_vflag &= ~VV_SYSTEM; \
85 /* verbose levels of the nilfs filingsystem */
86 int nilfs_verbose
= NILFS_DEBUGGING
;
89 MALLOC_JUSTDEFINE(M_NILFSMNT
, "NILFS mount", "NILFS mount structures");
90 MALLOC_JUSTDEFINE(M_NILFSTEMP
, "NILFS temp", "NILFS scrap space");
91 struct pool nilfs_node_pool
;
94 struct _nilfs_devices nilfs_devices
;
95 static struct sysctllog
*nilfs_sysctl_log
;
97 /* supported functions predefined */
101 /* --------------------------------------------------------------------- */
103 /* predefine vnode-op list descriptor */
104 extern const struct vnodeopv_desc nilfs_vnodeop_opv_desc
;
106 const struct vnodeopv_desc
* const nilfs_vnodeopv_descs
[] = {
107 &nilfs_vnodeop_opv_desc
,
112 /* vfsops descriptor linked in as anchor point for the filingsystem */
113 struct vfsops nilfs_vfsops
= {
114 MOUNT_NILFS
, /* vfs_name */
115 sizeof (struct nilfs_args
),
120 (void *)eopnotsupp
, /* vfs_quotactl */
132 (void *)eopnotsupp
, /* vfs_suspendctl */
133 genfs_renamelock_enter
,
134 genfs_renamelock_exit
,
135 (void *)eopnotsupp
, /* vfs_full_fsync */
136 nilfs_vnodeopv_descs
,
137 0, /* int vfs_refcount */
138 { NULL
, NULL
, }, /* LIST_ENTRY(vfsops) */
141 /* --------------------------------------------------------------------- */
143 /* file system starts here */
149 /* setup memory types */
150 malloc_type_attach(M_NILFSMNT
);
151 malloc_type_attach(M_NILFSTEMP
);
153 /* init device lists */
154 SLIST_INIT(&nilfs_devices
);
156 /* init node pools */
157 size
= sizeof(struct nilfs_node
);
158 pool_init(&nilfs_node_pool
, size
, 0, 0, 0,
159 "nilfs_node_pool", NULL
, IPL_NONE
);
174 pool_destroy(&nilfs_node_pool
);
176 malloc_type_detach(M_NILFSMNT
);
177 malloc_type_detach(M_NILFSTEMP
);
181 * If running a DEBUG kernel, provide an easy way to set the debug flags when
182 * running into a problem.
184 #define NILFS_VERBOSE_SYSCTLOPT 1
187 nilfs_modcmd(modcmd_t cmd
, void *arg
)
189 const struct sysctlnode
*node
;
193 case MODULE_CMD_INIT
:
194 error
= vfs_attach(&nilfs_vfsops
);
198 * XXX the "30" below could be dynamic, thereby eliminating one
199 * more instance of the "number to vfs" mapping problem, but
200 * "30" is the order as taken from sys/mount.h
202 sysctl_createv(&nilfs_sysctl_log
, 0, NULL
, NULL
,
204 CTLTYPE_NODE
, "vfs", NULL
,
207 sysctl_createv(&nilfs_sysctl_log
, 0, NULL
, &node
,
209 CTLTYPE_NODE
, "nilfs",
210 SYSCTL_DESCR("NTT's NILFSv2"),
212 CTL_VFS
, 30, CTL_EOL
);
214 sysctl_createv(&nilfs_sysctl_log
, 0, NULL
, &node
,
215 CTLFLAG_PERMANENT
|CTLFLAG_READWRITE
,
216 CTLTYPE_INT
, "verbose",
217 SYSCTL_DESCR("Bitmask for filesystem debugging"),
218 NULL
, 0, &nilfs_verbose
, 0,
219 CTL_VFS
, 30, NILFS_VERBOSE_SYSCTLOPT
, CTL_EOL
);
222 case MODULE_CMD_FINI
:
223 error
= vfs_detach(&nilfs_vfsops
);
226 sysctl_teardown(&nilfs_sysctl_log
);
236 /* --------------------------------------------------------------------- */
239 nilfs_mountroot(void)
244 /* --------------------------------------------------------------------- */
248 nilfs_create_system_nodes(struct nilfs_device
*nilfsdev
)
252 error
= nilfs_get_node_raw(nilfsdev
, NULL
, NILFS_DAT_INO
,
253 &nilfsdev
->super_root
.sr_dat
, &nilfsdev
->dat_node
);
257 error
= nilfs_get_node_raw(nilfsdev
, NULL
, NILFS_CPFILE_INO
,
258 &nilfsdev
->super_root
.sr_cpfile
, &nilfsdev
->cp_node
);
262 error
= nilfs_get_node_raw(nilfsdev
, NULL
, NILFS_SUFILE_INO
,
263 &nilfsdev
->super_root
.sr_sufile
, &nilfsdev
->su_node
);
267 NILFS_SET_SYSTEMFILE(nilfsdev
->dat_node
->vnode
);
268 NILFS_SET_SYSTEMFILE(nilfsdev
->cp_node
->vnode
);
269 NILFS_SET_SYSTEMFILE(nilfsdev
->su_node
->vnode
);
273 nilfs_dispose_node(&nilfsdev
->dat_node
);
274 nilfs_dispose_node(&nilfsdev
->cp_node
);
275 nilfs_dispose_node(&nilfsdev
->su_node
);
282 nilfs_release_system_nodes(struct nilfs_device
*nilfsdev
)
286 if (nilfsdev
->refcnt
> 0)
289 if (nilfsdev
->dat_node
)
290 NILFS_UNSET_SYSTEMFILE(nilfsdev
->dat_node
->vnode
);
291 if (nilfsdev
->cp_node
)
292 NILFS_UNSET_SYSTEMFILE(nilfsdev
->cp_node
->vnode
);
293 if (nilfsdev
->su_node
)
294 NILFS_UNSET_SYSTEMFILE(nilfsdev
->su_node
->vnode
);
296 nilfs_dispose_node(&nilfsdev
->dat_node
);
297 nilfs_dispose_node(&nilfsdev
->cp_node
);
298 nilfs_dispose_node(&nilfsdev
->su_node
);
302 /* --------------------------------------------------------------------- */
305 nilfs_check_superblock_crc(struct nilfs_super_block
*super
)
307 uint32_t super_crc
, comp_crc
;
309 /* check super block magic */
310 if (nilfs_rw16(super
->s_magic
) != NILFS_SUPER_MAGIC
)
314 super_crc
= nilfs_rw32(super
->s_sum
);
318 comp_crc
= crc32_le(nilfs_rw32(super
->s_crc_seed
),
319 (uint8_t *) super
, nilfs_rw16(super
->s_bytes
));
322 super
->s_sum
= nilfs_rw32(super_crc
);
325 return (super_crc
== comp_crc
);
331 nilfs_read_superblock(struct nilfs_device
*nilfsdev
)
333 struct nilfs_super_block
*super
, tmp_super
;
335 uint64_t sb1off
, sb2off
;
336 uint64_t time1
, time2
;
338 int dev_bsize
, dev_blks
;
339 int sb1ok
, sb2ok
, swp
;
342 sb1off
= NILFS_SB_OFFSET_BYTES
;
343 sb2off
= NILFS_SB2_OFFSET_BYTES(nilfsdev
->devsize
);
345 dev_bsize
= 1 << nilfsdev
->devvp
->v_mount
->mnt_fs_bshift
;
347 /* read our superblock regardless of backing device blocksize */
349 dev_blks
= (sb1off
+ dev_bsize
-1)/dev_bsize
;
350 error
= bread(nilfsdev
->devvp
, dev_blk
, dev_blks
* dev_bsize
, NOCRED
, 0, &bp
);
356 /* copy read-in super block at the offset */
357 super
= &nilfsdev
->super
;
358 memcpy(super
, (uint8_t *) bp
->b_data
+ NILFS_SB_OFFSET_BYTES
,
359 sizeof(struct nilfs_super_block
));
362 /* read our 2nd superblock regardless of backing device blocksize */
363 dev_blk
= sb2off
/ dev_bsize
;
364 dev_blks
= 2; /* assumption max one dev_bsize */
365 error
= bread(nilfsdev
->devvp
, dev_blk
, dev_blks
* dev_bsize
, NOCRED
, 0, &bp
);
371 /* copy read-in superblock2 at the offset */
372 super
= &nilfsdev
->super2
;
373 memcpy(super
, (uint8_t *) bp
->b_data
+ NILFS_SB_OFFSET_BYTES
,
374 sizeof(struct nilfs_super_block
));
377 sb1ok
= nilfs_check_superblock_crc(&nilfsdev
->super
);
378 sb2ok
= nilfs_check_superblock_crc(&nilfsdev
->super2
);
380 time1
= nilfs_rw64(nilfsdev
->super
.s_wtime
);
381 time2
= nilfs_rw64(nilfsdev
->super2
.s_wtime
);
382 swp
= sb2ok
&& (time2
> time1
);
385 printf("nilfs warning: broken superblock, using spare\n");
386 tmp_super
= nilfsdev
->super2
;
387 nilfsdev
->super2
= nilfsdev
->super
; /* why preserve? */
388 nilfsdev
->super
= tmp_super
;
391 if (!sb1ok
&& !sb2ok
) {
392 printf("nilfs: no valid superblocks found\n");
400 /* XXX NOTHING from the system nodes should need to be written here */
402 nilfs_unmount_base(struct nilfs_device
*nilfsdev
)
409 /* remove all our information */
410 error
= vinvalbuf(nilfsdev
->devvp
, 0, FSCRED
, curlwp
, 0, 0);
413 /* release the device's system nodes */
414 nilfs_release_system_nodes(nilfsdev
);
416 /* TODO writeout super_block? */
421 nilfs_mount_base(struct nilfs_device
*nilfsdev
,
422 struct mount
*mp
, struct nilfs_args
*args
)
424 struct lwp
*l
= curlwp
;
425 uint64_t last_pseg
, last_cno
, last_seq
;
426 uint32_t log_blocksize
;
429 /* flush out any old buffers remaining from a previous use. */
430 if ((error
= vinvalbuf(nilfsdev
->devvp
, V_SAVE
, l
->l_cred
, l
, 0, 0)))
433 /* read in our superblock */
434 error
= nilfs_read_superblock(nilfsdev
);
436 printf("nilfs_mount: can't read in super block : %d\n", error
);
440 /* get our blocksize */
441 log_blocksize
= nilfs_rw32(nilfsdev
->super
.s_log_block_size
);
442 nilfsdev
->blocksize
= (uint64_t) 1 << (log_blocksize
+ 10);
443 /* TODO check superblock's blocksize limits */
445 /* calculate dat structure parameters */
446 nilfs_calc_mdt_consts(nilfsdev
, &nilfsdev
->dat_mdt
,
447 nilfs_rw16(nilfsdev
->super
.s_dat_entry_size
));
448 nilfs_calc_mdt_consts(nilfsdev
, &nilfsdev
->ifile_mdt
,
449 nilfs_rw16(nilfsdev
->super
.s_inode_size
));
451 DPRINTF(VOLUMES
, ("nilfs_mount: accepted super block\n"));
453 /* search for the super root and roll forward when needed */
454 nilfs_search_super_root(nilfsdev
);
456 nilfsdev
->mount_state
= nilfs_rw16(nilfsdev
->super
.s_state
);
457 if (nilfsdev
->mount_state
!= NILFS_VALID_FS
) {
458 printf("FS is seriously damaged, needs repairing\n");
459 printf("aborting mount\n");
464 * FS should be ok now. The superblock and the last segsum could be
465 * updated from the repair so extract running values again.
467 last_pseg
= nilfs_rw64(nilfsdev
->super
.s_last_pseg
); /*blknr */
468 last_cno
= nilfs_rw64(nilfsdev
->super
.s_last_cno
);
469 last_seq
= nilfs_rw64(nilfsdev
->super
.s_last_seq
);
471 nilfsdev
->last_seg_seq
= last_seq
;
472 nilfsdev
->last_seg_num
= nilfs_get_segnum_of_block(nilfsdev
, last_pseg
);
473 nilfsdev
->next_seg_num
= nilfs_get_segnum_of_block(nilfsdev
,
474 nilfs_rw64(nilfsdev
->last_segsum
.ss_next
));
475 nilfsdev
->last_cno
= last_cno
;
477 DPRINTF(VOLUMES
, ("nilfs_mount: accepted super root\n"));
479 /* create system vnodes for DAT, CP and SEGSUM */
480 error
= nilfs_create_system_nodes(nilfsdev
);
482 nilfs_unmount_base(nilfsdev
);
488 nilfs_unmount_device(struct nilfs_device
*nilfsdev
)
492 /* is there anything? */
493 if (nilfsdev
== NULL
)
496 /* remove the device only if we're the last reference */
498 if (nilfsdev
->refcnt
>= 1)
501 /* unmount our base */
502 nilfs_unmount_base(nilfsdev
);
504 /* remove from our device list */
505 SLIST_REMOVE(&nilfs_devices
, nilfsdev
, nilfs_device
, next_device
);
508 DPRINTF(VOLUMES
, ("closing device\n"));
510 /* remove our mount reference before closing device */
511 nilfsdev
->devvp
->v_specmountpoint
= NULL
;
513 /* devvp is still locked by us */
514 vn_lock(nilfsdev
->devvp
, LK_EXCLUSIVE
| LK_RETRY
);
515 error
= VOP_CLOSE(nilfsdev
->devvp
, FREAD
| FWRITE
, NOCRED
);
517 printf("Error during closure of device! error %d, "
518 "device might stay locked\n", error
);
519 DPRINTF(VOLUMES
, ("device close ok\n"));
521 /* clear our mount reference and release device node */
522 vput(nilfsdev
->devvp
);
524 /* free our device info */
525 free(nilfsdev
, M_NILFSMNT
);
530 nilfs_check_mounts(struct nilfs_device
*nilfsdev
, struct mount
*mp
,
531 struct nilfs_args
*args
)
533 struct nilfs_mount
*ump
;
536 /* no double-mounting of the same checkpoint */
537 STAILQ_FOREACH(ump
, &nilfsdev
->mounts
, next_mount
) {
538 if (ump
->mount_args
.cpno
== args
->cpno
)
542 /* allow readonly mounts without questioning here */
543 if (mp
->mnt_flag
& MNT_RDONLY
)
546 /* readwrite mount you want */
547 STAILQ_FOREACH(ump
, &nilfsdev
->mounts
, next_mount
) {
548 /* only one RW mount on this device! */
549 if ((ump
->vfs_mountp
->mnt_flag
& MNT_RDONLY
)==0)
551 /* RDONLY on last mountpoint is device busy */
552 last_cno
= nilfs_rw64(ump
->nilfsdev
->super
.s_last_cno
);
553 if (ump
->mount_args
.cpno
== last_cno
)
563 nilfs_mount_device(struct vnode
*devvp
, struct mount
*mp
, struct nilfs_args
*args
,
564 struct nilfs_device
**nilfsdev_p
)
566 struct partinfo dpart
;
567 struct nilfs_device
*nilfsdev
;
568 struct lwp
*l
= curlwp
;
569 int openflags
, accessmode
, error
;
571 DPRINTF(VOLUMES
, ("Mounting NILFS device\n"));
573 /* lookup device in our nilfs_mountpoints */
575 SLIST_FOREACH(nilfsdev
, &nilfs_devices
, next_device
)
576 if (nilfsdev
->devvp
== devvp
)
580 DPRINTF(VOLUMES
, ("device already mounted\n"));
581 error
= nilfs_check_mounts(nilfsdev
, mp
, args
);
585 *nilfsdev_p
= nilfsdev
;
589 DPRINTF(VOLUMES
, ("no previous mounts on this device, mounting device\n"));
591 /* check if its a block device specified */
592 if (devvp
->v_type
!= VBLK
) {
596 if (bdevsw_lookup(devvp
->v_rdev
) == NULL
) {
602 * If mount by non-root, then verify that user has necessary
603 * permissions on the device.
606 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
607 accessmode
|= VWRITE
;
608 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
609 error
= genfs_can_mount(devvp
, accessmode
, l
->l_cred
);
610 VOP_UNLOCK(devvp
, 0);
617 * Open device read-write; TODO how about upgrading later when needed?
619 openflags
= FREAD
| FWRITE
;
620 error
= VOP_OPEN(devvp
, openflags
, FSCRED
);
626 /* opened ok, try mounting */
627 nilfsdev
= malloc(sizeof(struct nilfs_device
), M_NILFSMNT
, M_WAITOK
);
631 memset(nilfsdev
, 0, sizeof(struct nilfs_device
));
632 nilfsdev
->refcnt
= 1;
633 nilfsdev
->devvp
= devvp
;
634 nilfsdev
->uncomitted_bl
= 0;
635 cv_init(&nilfsdev
->sync_cv
, "nilfssync");
636 STAILQ_INIT(&nilfsdev
->mounts
);
638 /* get our device's size */
639 error
= VOP_IOCTL(devvp
, DIOCGPART
, &dpart
, FREAD
, NOCRED
);
641 /* remove all our information */
642 nilfs_unmount_device(nilfsdev
);
645 nilfsdev
->devsize
= dpart
.part
->p_size
* dpart
.disklab
->d_secsize
;
647 /* register nilfs_device in list */
648 SLIST_INSERT_HEAD(&nilfs_devices
, nilfsdev
, next_device
);
650 /* connect to the head for most recent files XXX really pass mp and args? */
651 error
= nilfs_mount_base(nilfsdev
, mp
, args
);
653 /* remove all our information */
654 nilfs_unmount_device(nilfsdev
);
658 *nilfsdev_p
= nilfsdev
;
659 DPRINTF(VOLUMES
, ("NILFS device mounted ok\n"));
666 nilfs_mount_checkpoint(struct nilfs_mount
*ump
)
668 struct nilfs_cpfile_header
*cphdr
;
669 struct nilfs_checkpoint
*cp
;
670 struct nilfs_inode ifile_inode
;
671 struct nilfs_node
*cp_node
;
673 uint64_t ncp
, nsn
, fcpno
, blocknr
, last_cno
;
675 int cp_per_block
, error
;
677 DPRINTF(VOLUMES
, ("mount_nilfs: trying to mount checkpoint number "
678 "%"PRIu64
"\n", ump
->mount_args
.cpno
));
680 cp_node
= ump
->nilfsdev
->cp_node
;
682 /* get cpfile header from 1st block of cp file */
683 error
= nilfs_bread(cp_node
, 0, NOCRED
, 0, &bp
);
686 cphdr
= (struct nilfs_cpfile_header
*) bp
->b_data
;
687 ncp
= nilfs_rw64(cphdr
->ch_ncheckpoints
);
688 nsn
= nilfs_rw64(cphdr
->ch_nsnapshots
);
692 DPRINTF(VOLUMES
, ("mount_nilfs: checkpoint header read in\n"));
693 DPRINTF(VOLUMES
, ("\tNumber of checkpoints %"PRIu64
"\n", ncp
));
694 DPRINTF(VOLUMES
, ("\tNumber of snapshots %"PRIu64
"\n", nsn
));
696 /* read in our specified checkpoint */
697 dlen
= nilfs_rw16(ump
->nilfsdev
->super
.s_checkpoint_size
);
698 cp_per_block
= ump
->nilfsdev
->blocksize
/ dlen
;
700 fcpno
= ump
->mount_args
.cpno
+ NILFS_CPFILE_FIRST_CHECKPOINT_OFFSET
-1;
701 blocknr
= fcpno
/ cp_per_block
;
702 off
= (fcpno
% cp_per_block
) * dlen
;
704 error
= nilfs_bread(cp_node
, blocknr
, NOCRED
, 0, &bp
);
706 printf("mount_nilfs: couldn't read cp block %"PRIu64
"\n",
711 /* needs to be a valid checkpoint */
712 cp
= (struct nilfs_checkpoint
*) ((uint8_t *) bp
->b_data
+ off
);
713 if (cp
->cp_flags
& NILFS_CHECKPOINT_INVALID
) {
714 printf("mount_nilfs: checkpoint marked invalid\n");
719 /* is this really the checkpoint we want? */
720 if (nilfs_rw64(cp
->cp_cno
) != ump
->mount_args
.cpno
) {
721 printf("mount_nilfs: checkpoint file corrupt? "
722 "expected cpno %"PRIu64
", found cpno %"PRIu64
"\n",
723 ump
->mount_args
.cpno
, nilfs_rw64(cp
->cp_cno
));
728 /* check if its a snapshot ! */
729 last_cno
= nilfs_rw64(ump
->nilfsdev
->super
.s_last_cno
);
730 if (ump
->mount_args
.cpno
!= last_cno
) {
731 /* only allow snapshots if not mounting on the last cp */
732 if ((cp
->cp_flags
& NILFS_CHECKPOINT_SNAPSHOT
) == 0) {
733 printf( "mount_nilfs: checkpoint %"PRIu64
" is not a "
734 "snapshot\n", ump
->mount_args
.cpno
);
740 ifile_inode
= cp
->cp_ifile_inode
;
743 /* get ifile inode */
744 error
= nilfs_get_node_raw(ump
->nilfsdev
, NULL
, NILFS_IFILE_INO
,
745 &ifile_inode
, &ump
->ifile_node
);
747 printf("mount_nilfs: can't read ifile node\n");
750 NILFS_SET_SYSTEMFILE(ump
->ifile_node
->vnode
);
759 nilfs_stop_writing(struct nilfs_mount
*ump
)
761 /* readonly mounts won't write */
762 if (ump
->vfs_mountp
->mnt_flag
& MNT_RDONLY
)
765 DPRINTF(CALL
, ("nilfs_stop_writing called for RW mount\n"));
767 /* TODO writeout super_block? */
768 /* XXX no support for writing yet anyway */
773 /* --------------------------------------------------------------------- */
777 #define MPFREE(a, lst) \
778 if ((a)) free((a), lst);
780 free_nilfs_mountinfo(struct mount
*mp
)
782 struct nilfs_mount
*ump
= VFSTONILFS(mp
);
787 mutex_destroy(&ump
->ihash_lock
);
788 mutex_destroy(&ump
->get_node_lock
);
789 MPFREE(ump
, M_NILFSMNT
);
794 nilfs_mount(struct mount
*mp
, const char *path
,
795 void *data
, size_t *data_len
)
797 struct nilfs_args
*args
= data
;
798 struct nilfs_device
*nilfsdev
;
799 struct nilfs_mount
*ump
;
803 DPRINTF(VFSCALL
, ("nilfs_mount called\n"));
805 if (*data_len
< sizeof *args
)
808 if (mp
->mnt_flag
& MNT_GETARGS
) {
809 /* request for the mount arguments */
810 ump
= VFSTONILFS(mp
);
813 *args
= ump
->mount_args
;
814 *data_len
= sizeof *args
;
818 /* check/translate struct version */
819 if (args
->version
!= 1) {
820 printf("mount_nilfs: unrecognized argument structure version\n");
823 /* TODO sanity checking other mount arguments */
825 /* handle request for updating mount parameters */
826 if (mp
->mnt_flag
& MNT_UPDATE
) {
827 /* TODO can't update my mountpoint yet */
831 /* lookup name to get its vnode */
832 error
= namei_simple_user(args
->fspec
, NSM_FOLLOW_NOEMULROOT
, &devvp
);
837 if (nilfs_verbose
& NILFS_DEBUG_VOLUMES
)
838 vprint("NILFS mount, trying to mount \n", devvp
);
841 error
= nilfs_mount_device(devvp
, mp
, args
, &nilfsdev
);
846 * Create a nilfs_mount on the specified checkpoint. Note that only
847 * ONE RW mount point can exist and it needs to have the highest
848 * checkpoint nr. If mounting RW and its not on the last checkpoint we
849 * need to invalidate all checkpoints that follow!!! This is an
853 /* setup basic mountpoint structure */
855 mp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = (uint32_t) devvp
->v_rdev
;
856 mp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_NILFS
);
857 mp
->mnt_stat
.f_fsid
= mp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
858 mp
->mnt_stat
.f_namemax
= NILFS_NAME_LEN
;
859 mp
->mnt_flag
|= MNT_LOCAL
;
861 /* XXX can't enable MPSAFE yet since genfs barfs on bad CV */
862 // mp->mnt_iflag |= IMNT_MPSAFE;
864 /* set our dev and fs units */
865 mp
->mnt_dev_bshift
= nilfs_rw32(nilfsdev
->super
.s_log_block_size
) + 10;
866 mp
->mnt_fs_bshift
= mp
->mnt_dev_bshift
;
868 /* allocate nilfs part of mount structure; malloc always succeeds */
869 ump
= malloc(sizeof(struct nilfs_mount
), M_NILFSMNT
, M_WAITOK
| M_ZERO
);
872 mutex_init(&ump
->ihash_lock
, MUTEX_DEFAULT
, IPL_NONE
);
873 mutex_init(&ump
->get_node_lock
, MUTEX_DEFAULT
, IPL_NONE
);
875 /* init our hash table for inode lookup */
876 for (lst
= 0; lst
< NILFS_INODE_HASHSIZE
; lst
++) {
877 LIST_INIT(&ump
->nilfs_nodes
[lst
]);
882 ump
->vfs_mountp
= mp
;
883 ump
->nilfsdev
= nilfsdev
;
886 #ifndef NILFS_READWRITE
887 /* force read-only for now */
888 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0) {
889 printf( "Enable kernel/module option NILFS_READWRITE for "
890 "writing, downgrading access to read-only\n");
891 mp
->mnt_flag
|= MNT_RDONLY
;
896 /* DONT register our nilfs mountpoint on our vfs mountpoint */
897 devvp
->v_specmountpoint
= NULL
;
899 if (devvp
->v_specmountpoint
== NULL
)
900 devvp
->v_specmountpoint
= mp
;
901 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
902 devvp
->v_specmountpoint
= mp
;
905 /* add our mountpoint */
906 STAILQ_INSERT_TAIL(&nilfsdev
->mounts
, ump
, next_mount
);
908 /* get our selected checkpoint */
910 args
->cpno
= nilfsdev
->last_cno
;
911 args
->cpno
= MIN(args
->cpno
, nilfsdev
->last_cno
);
913 /* setting up other parameters */
914 ump
->mount_args
= *args
;
915 error
= nilfs_mount_checkpoint(ump
);
917 nilfs_unmount(mp
, MNT_FORCE
);
922 error
= set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
, UIO_USERSPACE
,
923 mp
->mnt_op
->vfs_name
, mp
, curlwp
);
925 nilfs_unmount(mp
, MNT_FORCE
);
929 /* successfully mounted */
930 DPRINTF(VOLUMES
, ("nilfs_mount() successfull\n"));
935 /* --------------------------------------------------------------------- */
938 /* remove our mountpoint and if its the last reference, remove our device */
940 nilfs_unmount(struct mount
*mp
, int mntflags
)
942 struct nilfs_device
*nilfsdev
;
943 struct nilfs_mount
*ump
;
946 DPRINTF(VFSCALL
, ("nilfs_umount called\n"));
948 ump
= VFSTONILFS(mp
);
950 panic("NILFS unmount: empty ump\n");
951 nilfsdev
= ump
->nilfsdev
;
954 * Flush all nodes associated to this mountpoint. By specifying
955 * SKIPSYSTEM we can skip vnodes marked with VV_SYSTEM. This hardly
956 * documented feature allows us to exempt certain files from being
959 flags
= (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0;
960 if ((error
= vflush(mp
, NULLVP
, flags
| SKIPSYSTEM
)) != 0)
963 /* if we're the write mount, we ought to close the writing session */
964 error
= nilfs_stop_writing(ump
);
969 NILFS_UNSET_SYSTEMFILE(ump
->ifile_node
->vnode
);
970 nilfs_dispose_node(&ump
->ifile_node
);
972 /* remove our mount point */
973 STAILQ_REMOVE(&nilfsdev
->mounts
, ump
, nilfs_mount
, next_mount
);
974 free_nilfs_mountinfo(mp
);
976 /* free ump struct references */
978 mp
->mnt_flag
&= ~MNT_LOCAL
;
980 /* unmount the device itself when we're the last one */
981 nilfs_unmount_device(nilfsdev
);
983 DPRINTF(VOLUMES
, ("Fin unmount\n"));
987 /* --------------------------------------------------------------------- */
990 nilfs_start(struct mount
*mp
, int flags
)
992 /* do we have to do something here? */
996 /* --------------------------------------------------------------------- */
999 nilfs_root(struct mount
*mp
, struct vnode
**vpp
)
1001 struct nilfs_mount
*ump
= VFSTONILFS(mp
);
1002 struct nilfs_node
*node
;
1005 DPRINTF(NODE
, ("nilfs_root called\n"));
1007 error
= nilfs_get_node(ump
, NILFS_ROOT_INO
, &node
);
1010 KASSERT(node
->vnode
->v_vflag
& VV_ROOT
);
1013 DPRINTF(NODE
, ("nilfs_root finished\n"));
1017 /* --------------------------------------------------------------------- */
1020 nilfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
1022 struct nilfs_mount
*ump
= VFSTONILFS(mp
);
1025 DPRINTF(VFSCALL
, ("nilfs_statvfs called\n"));
1027 blocksize
= ump
->nilfsdev
->blocksize
;
1028 sbp
->f_flag
= mp
->mnt_flag
;
1029 sbp
->f_bsize
= blocksize
;
1030 sbp
->f_frsize
= blocksize
;
1031 sbp
->f_iosize
= blocksize
;
1033 copy_statvfs_info(sbp
, mp
);
1037 /* --------------------------------------------------------------------- */
1040 nilfs_sync(struct mount
*mp
, int waitfor
, kauth_cred_t cred
)
1042 // struct nilfs_mount *ump = VFSTONILFS(mp);
1044 DPRINTF(VFSCALL
, ("nilfs_sync called\n"));
1045 /* if called when mounted readonly, just ignore */
1046 if (mp
->mnt_flag
& MNT_RDONLY
)
1049 DPRINTF(VFSCALL
, ("end of nilfs_sync()\n"));
1054 /* --------------------------------------------------------------------- */
1057 * Get vnode for the file system type specific file id ino for the fs. Its
1058 * used for reference to files by unique ID and for NFSv3.
1059 * (optional) TODO lookup why some sources state NFSv3
1062 nilfs_vget(struct mount
*mp
, ino_t ino
,
1065 DPRINTF(NOTIMPL
, ("nilfs_vget called\n"));
1069 /* --------------------------------------------------------------------- */
1072 * Lookup vnode for file handle specified
1075 nilfs_fhtovp(struct mount
*mp
, struct fid
*fhp
,
1078 DPRINTF(NOTIMPL
, ("nilfs_fhtovp called\n"));
1082 /* --------------------------------------------------------------------- */
1085 * Create an unique file handle. Its structure is opaque and won't be used by
1086 * other subsystems. It should uniquely identify the file in the filingsystem
1087 * and enough information to know if a file has been removed and/or resources
1088 * have been recycled.
1091 nilfs_vptofh(struct vnode
*vp
, struct fid
*fid
,
1094 DPRINTF(NOTIMPL
, ("nilfs_vptofh called\n"));
1098 /* --------------------------------------------------------------------- */
1101 * Create a file system snapshot at the specified timestamp.
1104 nilfs_snapshot(struct mount
*mp
, struct vnode
*vp
,
1105 struct timespec
*tm
)
1107 DPRINTF(NOTIMPL
, ("nilfs_snapshot called\n"));
1111 /* --------------------------------------------------------------------- */