1 /* $NetBSD: chfs_vfsops.c,v 1.2 2011/11/24 21:09:37 agc Exp $ */
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu>
7 * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org>
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR 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
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/types.h>
40 #include <sys/mount.h>
42 #include <sys/systm.h>
44 #include <sys/module.h>
45 #include <sys/namei.h>
46 #include <sys/malloc.h>
47 #include <sys/fcntl.h>
50 //XXX needed just for debugging
51 #include <sys/fstrans.h>
52 #include <sys/sleepq.h>
53 #include <sys/lockdebug.h>
54 #include <sys/ktrace.h>
57 #include <uvm/uvm_pager.h>
58 #include <ufs/ufs/dir.h>
59 //#include <ufs/ufs/inode.h>
60 #include <ufs/ufs/ufs_extern.h>
61 #include <miscfs/genfs/genfs.h>
62 #include <miscfs/genfs/genfs_node.h>
63 #include <miscfs/specfs/specdev.h>
64 //#include </root/xipffs/netbsd.chfs/chfs.h>
65 //#include </root/xipffs/netbsd.chfs/chfs_args.h>
67 #include "chfs_args.h"
69 MODULE(MODULE_CLASS_VFS
, chfs
, "flash");
71 /* --------------------------------------------------------------------- */
74 static int chfs_mount(struct mount
*, const char *, void *, size_t *);
75 static int chfs_unmount(struct mount
*, int);
76 static int chfs_root(struct mount
*, struct vnode
**);
77 static int chfs_vget(struct mount
*, ino_t
, struct vnode
**);
78 static int chfs_fhtovp(struct mount
*, struct fid
*, struct vnode
**);
79 static int chfs_vptofh(struct vnode
*, struct fid
*, size_t *);
80 static int chfs_start(struct mount
*, int);
81 static int chfs_statvfs(struct mount
*, struct statvfs
*);
82 static int chfs_sync(struct mount
*, int, kauth_cred_t
);
83 static void chfs_init(void);
84 static void chfs_reinit(void);
85 static void chfs_done(void);
86 static int chfs_snapshot(struct mount
*, struct vnode
*,
89 /* --------------------------------------------------------------------- */
93 chfs_gop_alloc(struct vnode
*vp
, off_t off
, off_t len
, int flags
,
99 const struct genfs_ops chfs_genfsops
= {
100 .gop_size
= genfs_size
,
101 .gop_alloc
= chfs_gop_alloc
,
102 .gop_write
= genfs_gop_write
,
103 .gop_markupdate
= ufs_gop_markupdate
,
107 static const struct ufs_ops chfs_ufsops = {
108 .uo_itimes = chfs_itimes,
109 .uo_update = chfs_update,
113 struct pool chfs_inode_pool
;
115 /* for looking up the major for flash */
116 extern const struct cdevsw flash_cdevsw
;
118 /* --------------------------------------------------------------------- */
121 chfs_mount(struct mount
*mp
,
122 const char *path
, void *data
, size_t *data_len
)
124 struct lwp
*l
= curlwp
;
127 struct vnode
*devvp
= NULL
;
128 struct ufs_args
*args
= data
;
129 struct ufsmount
*ump
= NULL
;
130 struct chfs_mount
*chmp
;
136 if (*data_len
< sizeof *args
)
139 if (mp
->mnt_flag
& MNT_GETARGS
) {
143 memset(args
, 0, sizeof *args
);
145 *data_len
= sizeof *args
;
149 if (mp
->mnt_flag
& MNT_UPDATE
) {
150 /* XXX: There is no support yet to update file system
151 * settings. Should be added. */
156 if (args
->fspec
!= NULL
) {
157 err
= pathbuf_copyin(args
->fspec
, &pb
);
162 * Look up the name and verify that it's sane.
164 NDINIT(&nd
, LOOKUP
, FOLLOW
, pb
);
165 if ((err
= namei(&nd
)) != 0 )
170 * Be sure this is a valid block device
172 if (devvp
->v_type
!= VBLK
)
174 else if (bdevsw_lookup(devvp
->v_rdev
) == NULL
)
183 if (mp
->mnt_flag
& MNT_RDONLY
)
186 xflags
= FREAD
|FWRITE
;
188 err
= VOP_OPEN(devvp
, xflags
, FSCRED
);
193 err
= chfs_mountfs(devvp
, mp
);
195 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
196 (void)VOP_CLOSE(devvp
, xflags
, NOCRED
);
206 return set_statvfs_info(path
,
207 UIO_USERSPACE
, args
->fspec
,
208 UIO_USERSPACE
, mp
->mnt_op
->vfs_name
, mp
, l
);
217 chfs_mountfs(struct vnode
*devvp
, struct mount
*mp
)
219 struct lwp
*l
= curlwp
;
222 devmajor_t flash_major
;
224 struct ufsmount
* ump
= NULL
;
225 struct chfs_mount
* chmp
;
232 p
= l
? l
->l_proc
: NULL
;
233 cred
= l
? l
->l_cred
: NOCRED
;
235 /* Flush out any old buffers remaining from a previous use. */
236 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
237 err
= vinvalbuf(devvp
, V_SAVE
, cred
, l
, 0, 0);
242 flash_major
= cdevsw_lookup_major(&flash_cdevsw
);
244 if (devvp
->v_type
!= VBLK
)
246 else if (bdevsw_lookup(dev
) == NULL
)
248 else if (major(dev
) != flash_major
) {
249 dbg("major(dev): %d, flash_major: %d\n",
250 major(dev
), flash_major
);
258 ump
= malloc(sizeof(*ump
), M_UFSMNT
, M_WAITOK
);
259 memset(ump
, 0, sizeof(*ump
));
260 ump
->um_fstype
= UFS1
;
261 //ump->um_ops = &chfs_ufsops;
262 ump
->um_chfs
= malloc(sizeof(struct chfs_mount
),
264 memset(ump
->um_chfs
, 0, sizeof(struct chfs_mount
));
266 mutex_init(&ump
->um_lock
, MUTEX_DEFAULT
, IPL_NONE
);
268 /* Get superblock and set flash device number */
273 chmp
->chm_ebh
= kmem_alloc(sizeof(struct chfs_ebh
), KM_SLEEP
);
275 dbg("[]opening flash: %u\n", (unsigned int)devvp
->v_rdev
);
276 err
= ebh_open(chmp
->chm_ebh
, devvp
->v_rdev
);
278 dbg("error while opening flash\n");
279 kmem_free(chmp
->chm_ebh
, sizeof(struct chfs_ebh
));
280 free(chmp
, M_UFSMNT
);
284 //TODO check flash sizes
286 chmp
->chm_gbl_version
= 0;
287 chmp
->chm_vnocache_hash
= chfs_vnocache_hash_init();
289 chmp
->chm_blocks
= kmem_zalloc(chmp
->chm_ebh
->peb_nr
*
290 sizeof(struct chfs_eraseblock
), KM_SLEEP
);
292 if (!chmp
->chm_blocks
) {
293 kmem_free(chmp
->chm_ebh
, chmp
->chm_ebh
->peb_nr
*
294 sizeof(struct chfs_eraseblock
));
295 ebh_close(chmp
->chm_ebh
);
296 free(chmp
, M_UFSMNT
);
300 mutex_init(&chmp
->chm_lock_mountfields
, MUTEX_DEFAULT
, IPL_NONE
);
301 mutex_init(&chmp
->chm_lock_sizes
, MUTEX_DEFAULT
, IPL_NONE
);
302 mutex_init(&chmp
->chm_lock_vnocache
, MUTEX_DEFAULT
, IPL_NONE
);
305 chmp
->chm_fs_bmask
= -4096;
306 chmp
->chm_fs_bsize
= 4096;
307 chmp
->chm_fs_qbmask
= 4095;
308 chmp
->chm_fs_bshift
= 12;
309 chmp
->chm_fs_fmask
= -2048;
310 chmp
->chm_fs_qfmask
= 2047;
312 chmp
->chm_wbuf_pagesize
= chmp
->chm_ebh
->flash_if
->page_size
;
313 dbg("wbuf size: %zu\n", chmp
->chm_wbuf_pagesize
);
314 chmp
->chm_wbuf
= kmem_alloc(chmp
->chm_wbuf_pagesize
, KM_SLEEP
);
315 rw_init(&chmp
->chm_lock_wbuf
);
318 TAILQ_INIT(&chmp
->chm_free_queue
);
319 TAILQ_INIT(&chmp
->chm_clean_queue
);
320 TAILQ_INIT(&chmp
->chm_dirty_queue
);
321 TAILQ_INIT(&chmp
->chm_very_dirty_queue
);
322 TAILQ_INIT(&chmp
->chm_erasable_pending_wbuf_queue
);
323 TAILQ_INIT(&chmp
->chm_erase_pending_queue
);
325 chfs_calc_trigger_levels(chmp
);
327 chmp
->chm_nr_free_blocks
= 0;
328 chmp
->chm_nr_erasable_blocks
= 0;
329 chmp
->chm_max_vno
= 2;
330 chmp
->chm_checked_vno
= 2;
331 chmp
->chm_unchecked_size
= 0;
332 chmp
->chm_used_size
= 0;
333 chmp
->chm_dirty_size
= 0;
334 chmp
->chm_wasted_size
= 0;
335 chmp
->chm_free_size
= chmp
->chm_ebh
->eb_size
* chmp
->chm_ebh
->peb_nr
;
336 err
= chfs_build_filesystem(chmp
);
339 chfs_vnocache_hash_destroy(chmp
->chm_vnocache_hash
);
340 kmem_free(chmp
->chm_ebh
, chmp
->chm_ebh
->peb_nr
*
341 sizeof(struct chfs_eraseblock
));
342 ebh_close(chmp
->chm_ebh
);
343 free(chmp
, M_UFSMNT
);
348 mp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = (long)dev
;
349 mp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_CHFS
);
350 mp
->mnt_stat
.f_fsid
= mp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
351 mp
->mnt_stat
.f_namemax
= MAXNAMLEN
;
352 mp
->mnt_flag
|= MNT_LOCAL
;
353 mp
->mnt_fs_bshift
= PAGE_SHIFT
;
354 mp
->mnt_dev_bshift
= DEV_BSHIFT
;
355 mp
->mnt_iflag
|= IMNT_MPSAFE
;
359 ump
->um_devvp
= devvp
;
360 ump
->um_maxfilesize
= 1048512 * 1024;
361 /*TODO fill these fields
366 ump->um_maxsymlinklen =
368 ump->um_maxfilesize =
372 * Allocate the root vnode.
374 err
= VFS_VGET(mp
, CHFS_ROOTINO
, &vp
);
376 dbg("error: %d while allocating root node\n", err
);
381 chfs_gc_thread_start(chmp
);
382 mutex_enter(&chmp
->chm_lock_mountfields
);
383 chfs_gc_trigger(chmp
);
384 mutex_exit(&chmp
->chm_lock_mountfields
);
386 devvp
->v_specmountpoint
= mp
;
390 /* --------------------------------------------------------------------- */
394 chfs_unmount(struct mount
*mp
, int mntflags
)
396 int flags
= 0, i
= 0;
397 struct ufsmount
*ump
;
398 struct chfs_mount
*chmp
;
399 // struct chfs_vnode_cache *vc, *next;
401 if (mntflags
& MNT_FORCE
)
409 chfs_gc_thread_stop(chmp
);
411 (void)vflush(mp
, NULLVP
, flags
);
413 if (chmp
->chm_wbuf_len
) {
414 mutex_enter(&chmp
->chm_lock_mountfields
);
415 chfs_flush_pending_wbuf(chmp
);
416 mutex_exit(&chmp
->chm_lock_mountfields
);
419 for (i
= 0; i
< chmp
->chm_ebh
->peb_nr
; i
++) {
420 chfs_free_node_refs(&chmp
->chm_blocks
[i
]);
423 chfs_vnocache_hash_destroy(chmp
->chm_vnocache_hash
);
425 ebh_close(chmp
->chm_ebh
);
427 rw_destroy(&chmp
->chm_lock_wbuf
);
428 mutex_destroy(&chmp
->chm_lock_vnocache
);
429 mutex_destroy(&chmp
->chm_lock_sizes
);
430 mutex_destroy(&chmp
->chm_lock_mountfields
);
432 if (ump
->um_devvp
->v_type
!= VBAD
) {
433 ump
->um_devvp
->v_specmountpoint
= NULL
;
435 vn_lock(ump
->um_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
436 (void)VOP_CLOSE(ump
->um_devvp
, FREAD
|FWRITE
, NOCRED
);
439 mutex_destroy(&ump
->um_lock
);
441 //free(ump->um_chfs, M_UFSMNT);
444 mp
->mnt_flag
&= ~MNT_LOCAL
;
449 /* --------------------------------------------------------------------- */
452 chfs_root(struct mount
*mp
, struct vnode
**vpp
)
457 if ((error
= VFS_VGET(mp
, (ino_t
)ROOTINO
, &vp
)) != 0)
463 /* --------------------------------------------------------------------- */
465 extern rb_tree_ops_t frag_rbtree_ops
;
468 chfs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
470 struct chfs_mount
*chmp
;
471 struct chfs_inode
*ip
;
472 struct ufsmount
*ump
;
476 struct chfs_vnode_cache
* chvc
= NULL
;
477 struct chfs_node_ref
* nref
= NULL
;
480 dbg("vget() | ino: %llu\n", (unsigned long long)ino
);
486 vpp
= kmem_alloc(sizeof(struct vnode
*), KM_SLEEP
);
489 if ((*vpp
= chfs_ihashget(dev
, ino
, LK_EXCLUSIVE
)) != NULL
) {
493 /* Allocate a new vnode/inode. */
494 if ((error
= getnewvnode(VT_CHFS
,
495 mp
, chfs_vnodeop_p
, NULL
, &vp
)) != 0) {
499 ip
= pool_get(&chfs_inode_pool
, PR_WAITOK
);
501 mutex_enter(&chfs_hashlock
);
502 if ((*vpp
= chfs_ihashget(dev
, ino
, LK_EXCLUSIVE
)) != NULL
) {
503 mutex_exit(&chfs_hashlock
);
505 pool_put(&chfs_inode_pool
, ip
);
509 vp
->v_vflag
|= VV_LOCKSWORK
;
511 memset(ip
, 0, sizeof(*ip
));
515 ip
->chmp
= chmp
= ump
->um_chfs
;
519 genfs_node_init(vp
, &chfs_genfsops
);
521 rb_tree_init(&ip
->fragtree
, &frag_rbtree_ops
);
522 //mutex_init(&ip->inode_lock, MUTEX_DEFAULT, IPL_NONE);
525 mutex_exit(&chfs_hashlock
);
528 if (ino
== CHFS_ROOTINO
) {
530 vp
->v_vflag
|= VV_ROOT
;
532 ip
->mode
= IFMT
| IEXEC
| IWRITE
| IREAD
;
533 ip
->iflag
|= (IN_ACCESS
| IN_CHANGE
| IN_UPDATE
);
534 chfs_update(vp
, NULL
, NULL
, UPDATE_WAIT
);
535 // ip->dents = NULL; XXXTAILQ
536 TAILQ_INIT(&ip
->dents
);
537 chfs_set_vnode_size(vp
, 512);
541 mutex_enter(&chmp
->chm_lock_vnocache
);
542 chvc
= chfs_vnode_cache_get(chmp
, ino
);
543 mutex_exit(&chmp
->chm_lock_vnocache
);
546 /* XXX, we cant alloc under a lock, refactor this! */
547 chvc
= chfs_vnode_cache_alloc(ino
);
548 mutex_enter(&chmp
->chm_lock_vnocache
);
549 if (ino
== CHFS_ROOTINO
) {
551 chvc
->pvno
= CHFS_ROOTINO
;
552 chfs_vnode_cache_set_state(chmp
,
553 chvc
, VNO_STATE_CHECKEDABSENT
);
555 chfs_vnode_cache_add(chmp
, chvc
);
556 mutex_exit(&chmp
->chm_lock_vnocache
);
559 TAILQ_INIT(&ip
->dents
);
563 // if we have a vnode cache, the node is already on flash, so read it
564 if (ino
== CHFS_ROOTINO
) {
565 chvc
->pvno
= CHFS_ROOTINO
;
566 TAILQ_INIT(&chvc
->scan_dirents
);
568 chfs_readvnode(mp
, ino
, &vp
);
571 mutex_enter(&chmp
->chm_lock_mountfields
);
572 // init type specific things
573 switch (vp
->v_type
) {
575 nref
= chvc
->dirents
;
577 (struct chfs_vnode_cache
*)nref
!= chvc
) {
578 chfs_readdirent(mp
, nref
, ip
);
579 nref
= nref
->nref_next
;
581 chfs_set_vnode_size(vp
, 512);
585 //build the fragtree of the vnode
586 dbg("read_inode_internal | ino: %llu\n",
587 (unsigned long long)ip
->ino
);
588 error
= chfs_read_inode(chmp
, ip
);
592 mutex_exit(&chmp
->chm_lock_mountfields
);
597 //build the fragtree of the vnode
598 dbg("read_inode_internal | ino: %llu\n",
599 (unsigned long long)ip
->ino
);
600 error
= chfs_read_inode_internal(chmp
, ip
);
604 mutex_exit(&chmp
->chm_lock_mountfields
);
608 dbg("size: %llu\n", (unsigned long long)ip
->size
);
609 bp
= getiobuf(vp
, true);
611 bp
->b_bufsize
= bp
->b_resid
=
612 bp
->b_bcount
= ip
->size
;
613 bp
->b_data
= kmem_alloc(ip
->size
, KM_SLEEP
);
614 chfs_read_data(chmp
, vp
, bp
);
616 ip
->target
= kmem_alloc(ip
->size
,
618 memcpy(ip
->target
, bp
->b_data
, ip
->size
);
619 kmem_free(bp
->b_data
, ip
->size
);
626 //build the fragtree of the vnode
627 dbg("read_inode_internal | ino: %llu\n",
628 (unsigned long long)ip
->ino
);
629 error
= chfs_read_inode_internal(chmp
, ip
);
633 mutex_exit(&chmp
->chm_lock_mountfields
);
637 bp
= getiobuf(vp
, true);
639 bp
->b_bufsize
= bp
->b_resid
=
640 bp
->b_bcount
= sizeof(dev_t
);
641 bp
->b_data
= kmem_alloc(sizeof(dev_t
), KM_SLEEP
);
642 chfs_read_data(chmp
, vp
, bp
);
644 bp
->b_data
, sizeof(dev_t
));
645 kmem_free(bp
->b_data
, sizeof(dev_t
));
647 if (vp
->v_type
== VFIFO
)
648 vp
->v_op
= chfs_fifoop_p
;
650 vp
->v_op
= chfs_specop_p
;
651 spec_node_init(vp
, ip
->rdev
);
659 mutex_exit(&chmp
->chm_lock_mountfields
);
663 /* finish inode initalization */
664 ip
->devvp
= ump
->um_devvp
;
667 uvm_vnp_setsize(vp
, ip
->size
);
673 /* --------------------------------------------------------------------- */
676 chfs_fhtovp(struct mount
*mp
, struct fid
*fhp
, struct vnode
**vpp
)
681 /* --------------------------------------------------------------------- */
684 chfs_vptofh(struct vnode
*vp
, struct fid
*fhp
, size_t *fh_size
)
689 /* --------------------------------------------------------------------- */
692 chfs_start(struct mount
*mp
, int flags
)
697 /* --------------------------------------------------------------------- */
701 chfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
703 struct chfs_mount
*chmp
;
704 struct ufsmount
*ump
;
710 sbp
->f_flag
= mp
->mnt_flag
;
711 sbp
->f_bsize
= chmp
->chm_ebh
->eb_size
;
712 sbp
->f_frsize
= chmp
->chm_ebh
->eb_size
;
713 sbp
->f_iosize
= chmp
->chm_ebh
->eb_size
;
715 sbp
->f_blocks
= chmp
->chm_ebh
->peb_nr
;
717 sbp
->f_bavail
= chmp
->chm_nr_free_blocks
- chmp
->chm_resv_blocks_write
;
719 printf("chmp->chm_nr_free_blocks: %jd\n",
720 (intmax_t )chmp
->chm_nr_free_blocks
);
721 printf("chmp->chm_resv_blocks_write: %jd\n",
722 (intmax_t) chmp
->chm_resv_blocks_write
);
723 printf("chmp->chm_ebh->peb_nr: %jd\n",
724 (intmax_t) chmp
->chm_ebh
->peb_nr
);
727 sbp
->f_bfree
= chmp
->chm_nr_free_blocks
;
728 sbp
->f_bresvd
= chmp
->chm_resv_blocks_write
;
735 copy_statvfs_info(sbp
, mp
);
740 /* --------------------------------------------------------------------- */
744 chfs_sync(struct mount
*mp
, int waitfor
,
750 /* --------------------------------------------------------------------- */
755 chfs_alloc_pool_caches();
757 pool_init(&chfs_inode_pool
, sizeof(struct chfs_inode
), 0, 0, 0,
758 "chfsinopl", &pool_allocator_nointr
, IPL_NONE
);
762 /* --------------------------------------------------------------------- */
771 /* --------------------------------------------------------------------- */
778 pool_destroy(&chfs_inode_pool
);
779 chfs_destroy_pool_caches();
782 /* --------------------------------------------------------------------- */
785 chfs_snapshot(struct mount
*mp
, struct vnode
*vp
,
786 struct timespec
*ctime
)
791 /* --------------------------------------------------------------------- */
794 * chfs vfs operations.
797 extern const struct vnodeopv_desc chfs_fifoop_opv_desc
;
798 extern const struct vnodeopv_desc chfs_specop_opv_desc
;
799 extern const struct vnodeopv_desc chfs_vnodeop_opv_desc
;
801 const struct vnodeopv_desc
* const chfs_vnodeopv_descs
[] = {
802 &chfs_fifoop_opv_desc
,
803 &chfs_specop_opv_desc
,
804 &chfs_vnodeop_opv_desc
,
808 struct vfsops chfs_vfsops
= {
809 MOUNT_CHFS
, /* vfs_name */
810 sizeof (struct chfs_args
),
811 chfs_mount
, /* vfs_mount */
812 chfs_start
, /* vfs_start */
813 chfs_unmount
, /* vfs_unmount */
814 chfs_root
, /* vfs_root */
815 ufs_quotactl
, /* vfs_quotactl */
816 chfs_statvfs
, /* vfs_statvfs */
817 chfs_sync
, /* vfs_sync */
818 chfs_vget
, /* vfs_vget */
819 chfs_fhtovp
, /* vfs_fhtovp */
820 chfs_vptofh
, /* vfs_vptofh */
821 chfs_init
, /* vfs_init */
822 chfs_reinit
, /* vfs_reinit */
823 chfs_done
, /* vfs_done */
824 NULL
, /* vfs_mountroot */
825 chfs_snapshot
, /* vfs_snapshot */
826 vfs_stdextattrctl
, /* vfs_extattrctl */
827 (void *)eopnotsupp
, /* vfs_suspendctl */
828 genfs_renamelock_enter
,
829 genfs_renamelock_exit
,
832 0, /* vfs_refcount */
837 chfs_modcmd(modcmd_t cmd
, void *arg
)
840 case MODULE_CMD_INIT
:
841 return vfs_attach(&chfs_vfsops
);
842 case MODULE_CMD_FINI
:
843 return vfs_detach(&chfs_vfsops
);