1 /* $NetBSD: chfs_vfsops.c,v 1.15 2015/01/11 17:29:57 hannken 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/fcntl.h>
49 //XXX needed just for debugging
50 #include <sys/fstrans.h>
51 #include <sys/sleepq.h>
52 #include <sys/lockdebug.h>
53 #include <sys/ktrace.h>
56 #include <uvm/uvm_pager.h>
57 #include <ufs/ufs/dir.h>
58 #include <ufs/ufs/ufs_extern.h>
59 #include <miscfs/genfs/genfs.h>
60 #include <miscfs/genfs/genfs_node.h>
61 #include <miscfs/specfs/specdev.h>
63 #include "chfs_args.h"
65 MODULE(MODULE_CLASS_VFS
, chfs
, "flash");
67 /* --------------------------------------------------------------------- */
70 static int chfs_mount(struct mount
*, const char *, void *, size_t *);
71 static int chfs_unmount(struct mount
*, int);
72 static int chfs_root(struct mount
*, struct vnode
**);
73 static int chfs_loadvnode(struct mount
*, struct vnode
*,
74 const void *, size_t, const void **);
75 static int chfs_vget(struct mount
*, ino_t
, struct vnode
**);
76 static int chfs_fhtovp(struct mount
*, struct fid
*, struct vnode
**);
77 static int chfs_vptofh(struct vnode
*, struct fid
*, size_t *);
78 static int chfs_start(struct mount
*, int);
79 static int chfs_statvfs(struct mount
*, struct statvfs
*);
80 static int chfs_sync(struct mount
*, int, kauth_cred_t
);
81 static void chfs_init(void);
82 static void chfs_reinit(void);
83 static void chfs_done(void);
84 static int chfs_snapshot(struct mount
*, struct vnode
*,
87 /* --------------------------------------------------------------------- */
91 chfs_gop_alloc(struct vnode
*vp
, off_t off
, off_t len
, int flags
,
97 const struct genfs_ops chfs_genfsops
= {
98 .gop_size
= genfs_size
,
99 .gop_alloc
= chfs_gop_alloc
,
100 .gop_write
= genfs_gop_write
,
101 .gop_markupdate
= ufs_gop_markupdate
,
104 struct pool chfs_inode_pool
;
106 /* for looking up the major for flash */
107 extern const struct cdevsw flash_cdevsw
;
109 /* --------------------------------------------------------------------- */
112 chfs_mount(struct mount
*mp
,
113 const char *path
, void *data
, size_t *data_len
)
115 struct lwp
*l
= curlwp
;
118 struct vnode
*devvp
= NULL
;
119 struct ufs_args
*args
= data
;
120 struct ufsmount
*ump
= NULL
;
121 struct chfs_mount
*chmp
;
129 if (*data_len
< sizeof *args
)
132 if (mp
->mnt_flag
& MNT_GETARGS
) {
136 memset(args
, 0, sizeof *args
);
138 *data_len
= sizeof *args
;
142 if (mp
->mnt_flag
& MNT_UPDATE
) {
143 /* XXX: There is no support yet to update file system
144 * settings. Should be added. */
149 if (args
->fspec
!= NULL
) {
150 err
= pathbuf_copyin(args
->fspec
, &pb
);
154 /* Look up the name and verify that it's sane. */
155 NDINIT(&nd
, LOOKUP
, FOLLOW
, pb
);
162 /* Be sure this is a valid block device */
163 if (devvp
->v_type
!= VBLK
)
165 else if (bdevsw_lookup(devvp
->v_rdev
) == NULL
)
174 if (mp
->mnt_flag
& MNT_RDONLY
)
177 xflags
= FREAD
|FWRITE
;
179 err
= VOP_OPEN(devvp
, xflags
, FSCRED
);
183 /* call CHFS mount function */
184 err
= chfs_mountfs(devvp
, mp
);
186 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
187 (void)VOP_CLOSE(devvp
, xflags
, NOCRED
);
198 return set_statvfs_info(path
,
199 UIO_USERSPACE
, args
->fspec
,
200 UIO_USERSPACE
, mp
->mnt_op
->vfs_name
, mp
, l
);
207 /* chfs_mountfs - init CHFS */
209 chfs_mountfs(struct vnode
*devvp
, struct mount
*mp
)
211 struct lwp
*l
= curlwp
;
213 devmajor_t flash_major
;
215 struct ufsmount
* ump
= NULL
;
216 struct chfs_mount
* chmp
;
223 cred
= l
? l
->l_cred
: NOCRED
;
225 /* Flush out any old buffers remaining from a previous use. */
226 vn_lock(devvp
, LK_EXCLUSIVE
| LK_RETRY
);
227 err
= vinvalbuf(devvp
, V_SAVE
, cred
, l
, 0, 0);
233 flash_major
= cdevsw_lookup_major(&flash_cdevsw
);
235 if (devvp
->v_type
!= VBLK
)
237 else if (bdevsw_lookup(dev
) == NULL
)
239 else if (major(dev
) != flash_major
) {
240 dbg("major(dev): %d, flash_major: %d\n",
241 major(dev
), flash_major
);
249 /* Connect CHFS to UFS. */
250 ump
= kmem_zalloc(sizeof(struct ufsmount
), KM_SLEEP
);
252 ump
->um_fstype
= UFS1
;
253 ump
->um_chfs
= kmem_zalloc(sizeof(struct chfs_mount
), KM_SLEEP
);
254 mutex_init(&ump
->um_lock
, MUTEX_DEFAULT
, IPL_NONE
);
258 /* Initialize erase block handler. */
259 chmp
->chm_ebh
= kmem_alloc(sizeof(struct chfs_ebh
), KM_SLEEP
);
261 dbg("[]opening flash: %u\n", (unsigned int)devvp
->v_rdev
);
262 err
= ebh_open(chmp
->chm_ebh
, devvp
->v_rdev
);
264 dbg("error while opening flash\n");
268 //TODO check flash sizes
270 /* Initialize vnode cache's hashtable and eraseblock array. */
271 chmp
->chm_gbl_version
= 0;
272 chmp
->chm_vnocache_hash
= chfs_vnocache_hash_init();
274 chmp
->chm_blocks
= kmem_zalloc(chmp
->chm_ebh
->peb_nr
*
275 sizeof(struct chfs_eraseblock
), KM_SLEEP
);
277 /* Initialize mutexes. */
278 mutex_init(&chmp
->chm_lock_mountfields
, MUTEX_DEFAULT
, IPL_NONE
);
279 mutex_init(&chmp
->chm_lock_sizes
, MUTEX_DEFAULT
, IPL_NONE
);
280 mutex_init(&chmp
->chm_lock_vnocache
, MUTEX_DEFAULT
, IPL_NONE
);
282 /* Initialize read/write contants. (from UFS) */
283 chmp
->chm_fs_bmask
= -4096;
284 chmp
->chm_fs_bsize
= 4096;
285 chmp
->chm_fs_qbmask
= 4095;
286 chmp
->chm_fs_bshift
= 12;
287 chmp
->chm_fs_fmask
= -2048;
288 chmp
->chm_fs_qfmask
= 2047;
290 /* Initialize writebuffer. */
291 chmp
->chm_wbuf_pagesize
= chmp
->chm_ebh
->flash_if
->page_size
;
292 dbg("wbuf size: %zu\n", chmp
->chm_wbuf_pagesize
);
293 chmp
->chm_wbuf
= kmem_alloc(chmp
->chm_wbuf_pagesize
, KM_SLEEP
);
294 rw_init(&chmp
->chm_lock_wbuf
);
296 /* Initialize queues. */
297 TAILQ_INIT(&chmp
->chm_free_queue
);
298 TAILQ_INIT(&chmp
->chm_clean_queue
);
299 TAILQ_INIT(&chmp
->chm_dirty_queue
);
300 TAILQ_INIT(&chmp
->chm_very_dirty_queue
);
301 TAILQ_INIT(&chmp
->chm_erasable_pending_wbuf_queue
);
302 TAILQ_INIT(&chmp
->chm_erase_pending_queue
);
304 /* Initialize flash-specific constants. */
305 chfs_calc_trigger_levels(chmp
);
307 /* Initialize sizes. */
308 chmp
->chm_nr_free_blocks
= 0;
309 chmp
->chm_nr_erasable_blocks
= 0;
310 chmp
->chm_max_vno
= 2;
311 chmp
->chm_checked_vno
= 2;
312 chmp
->chm_unchecked_size
= 0;
313 chmp
->chm_used_size
= 0;
314 chmp
->chm_dirty_size
= 0;
315 chmp
->chm_wasted_size
= 0;
316 chmp
->chm_free_size
= chmp
->chm_ebh
->eb_size
* chmp
->chm_ebh
->peb_nr
;
318 /* Build filesystem. */
319 err
= chfs_build_filesystem(chmp
);
322 /* Armageddon and return. */
323 chfs_vnocache_hash_destroy(chmp
->chm_vnocache_hash
);
324 ebh_close(chmp
->chm_ebh
);
329 /* Initialize UFS. */
331 mp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = (long)dev
;
332 mp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_CHFS
);
333 mp
->mnt_stat
.f_fsid
= mp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
334 mp
->mnt_stat
.f_namemax
= MAXNAMLEN
;
335 mp
->mnt_flag
|= MNT_LOCAL
;
336 mp
->mnt_fs_bshift
= PAGE_SHIFT
;
337 mp
->mnt_dev_bshift
= DEV_BSHIFT
;
338 mp
->mnt_iflag
|= IMNT_MPSAFE
;
342 ump
->um_devvp
= devvp
;
343 ump
->um_maxfilesize
= 1048512 * 1024;
345 /* Allocate the root vnode. */
346 err
= VFS_VGET(mp
, CHFS_ROOTINO
, &vp
);
348 dbg("error: %d while allocating root node\n", err
);
354 chfs_gc_thread_start(chmp
);
355 mutex_enter(&chmp
->chm_lock_mountfields
);
356 chfs_gc_trigger(chmp
);
357 mutex_exit(&chmp
->chm_lock_mountfields
);
359 spec_node_setmountedfs(devvp
, mp
);
363 kmem_free(chmp
->chm_ebh
, sizeof(struct chfs_ebh
));
364 kmem_free(chmp
, sizeof(struct chfs_mount
));
365 kmem_free(ump
, sizeof(struct ufsmount
));
369 /* --------------------------------------------------------------------- */
372 chfs_unmount(struct mount
*mp
, int mntflags
)
374 int flags
= 0, i
= 0;
375 struct ufsmount
*ump
;
376 struct chfs_mount
*chmp
;
378 if (mntflags
& MNT_FORCE
)
387 chfs_gc_thread_stop(chmp
);
389 /* Flush everyt buffer. */
390 (void)vflush(mp
, NULLVP
, flags
);
392 if (chmp
->chm_wbuf_len
) {
393 mutex_enter(&chmp
->chm_lock_mountfields
);
394 chfs_flush_pending_wbuf(chmp
);
395 mutex_exit(&chmp
->chm_lock_mountfields
);
398 /* Free node references. */
399 for (i
= 0; i
< chmp
->chm_ebh
->peb_nr
; i
++) {
400 chfs_free_node_refs(&chmp
->chm_blocks
[i
]);
403 /* Destroy vnode cache hashtable. */
404 chfs_vnocache_hash_destroy(chmp
->chm_vnocache_hash
);
406 /* Close eraseblock handler. */
407 ebh_close(chmp
->chm_ebh
);
409 /* Destroy mutexes. */
410 rw_destroy(&chmp
->chm_lock_wbuf
);
411 mutex_destroy(&chmp
->chm_lock_vnocache
);
412 mutex_destroy(&chmp
->chm_lock_sizes
);
413 mutex_destroy(&chmp
->chm_lock_mountfields
);
416 if (ump
->um_devvp
->v_type
!= VBAD
) {
417 spec_node_setmountedfs(ump
->um_devvp
, NULL
);
419 vn_lock(ump
->um_devvp
, LK_EXCLUSIVE
| LK_RETRY
);
420 (void)VOP_CLOSE(ump
->um_devvp
, FREAD
|FWRITE
, NOCRED
);
423 mutex_destroy(&ump
->um_lock
);
425 /* Everything done. */
426 kmem_free(ump
, sizeof(struct ufsmount
));
428 mp
->mnt_flag
&= ~MNT_LOCAL
;
433 /* --------------------------------------------------------------------- */
436 chfs_root(struct mount
*mp
, struct vnode
**vpp
)
441 if ((error
= VFS_VGET(mp
, (ino_t
)UFS_ROOTINO
, &vp
)) != 0)
447 /* --------------------------------------------------------------------- */
449 extern rb_tree_ops_t frag_rbtree_ops
;
452 chfs_loadvnode(struct mount
*mp
, struct vnode
*vp
,
453 const void *key
, size_t key_len
, const void **new_key
)
455 struct chfs_mount
*chmp
;
456 struct chfs_inode
*ip
;
457 struct ufsmount
*ump
;
460 struct chfs_vnode_cache
* chvc
= NULL
;
461 struct chfs_node_ref
* nref
= NULL
;
465 KASSERT(key_len
== sizeof(ino
));
466 memcpy(&ino
, key
, key_len
);
468 dbg("vget() | ino: %llu\n", (unsigned long long)ino
);
473 ip
= pool_get(&chfs_inode_pool
, PR_WAITOK
);
475 /* Initialize vnode/inode. */
476 memset(ip
, 0, sizeof(*ip
));
479 ip
->chmp
= chmp
= ump
->um_chfs
;
483 rb_tree_init(&ip
->fragtree
, &frag_rbtree_ops
);
486 vp
->v_op
= chfs_vnodeop_p
;
487 vp
->v_vflag
|= VV_LOCKSWORK
;
488 if (ino
== CHFS_ROOTINO
)
489 vp
->v_vflag
|= VV_ROOT
;
492 /* Set root inode. */
493 if (ino
== CHFS_ROOTINO
) {
496 ip
->ch_type
= CHT_DIR
;
497 ip
->mode
= IFMT
| IEXEC
| IWRITE
| IREAD
;
498 ip
->iflag
|= (IN_ACCESS
| IN_CHANGE
| IN_UPDATE
);
499 chfs_update(vp
, NULL
, NULL
, UPDATE_WAIT
);
500 TAILQ_INIT(&ip
->dents
);
501 chfs_set_vnode_size(vp
, 512);
504 mutex_enter(&chmp
->chm_lock_vnocache
);
505 chvc
= chfs_vnode_cache_get(chmp
, ino
);
506 mutex_exit(&chmp
->chm_lock_vnocache
);
509 /* Initialize the corresponding vnode cache. */
510 /* XXX, we cant alloc under a lock, refactor this! */
511 chvc
= chfs_vnode_cache_alloc(ino
);
512 mutex_enter(&chmp
->chm_lock_vnocache
);
513 if (ino
== CHFS_ROOTINO
) {
515 chvc
->pvno
= CHFS_ROOTINO
;
516 chvc
->state
= VNO_STATE_CHECKEDABSENT
;
518 chfs_vnode_cache_add(chmp
, chvc
);
519 mutex_exit(&chmp
->chm_lock_vnocache
);
522 TAILQ_INIT(&ip
->dents
);
526 /* We had a vnode cache, the node is already on flash, so read it */
527 if (ino
== CHFS_ROOTINO
) {
528 chvc
->pvno
= CHFS_ROOTINO
;
529 TAILQ_INIT(&chvc
->scan_dirents
);
531 chfs_readvnode(mp
, ino
, &vp
);
534 mutex_enter(&chmp
->chm_lock_mountfields
);
535 /* Initialize type specific things. */
537 switch (ip
->ch_type
) {
539 /* Read every dirent. */
540 nref
= chvc
->dirents
;
542 (struct chfs_vnode_cache
*)nref
!= chvc
) {
543 chfs_readdirent(mp
, nref
, ip
);
544 nref
= nref
->nref_next
;
546 chfs_set_vnode_size(vp
, 512);
552 dbg("read_inode_internal | ino: %llu\n",
553 (unsigned long long)ip
->ino
);
554 error
= chfs_read_inode(chmp
, ip
);
558 dbg("read_inode_internal | ino: %llu\n",
559 (unsigned long long)ip
->ino
);
560 error
= chfs_read_inode_internal(chmp
, ip
);
565 dbg("size: %llu\n", (unsigned long long)ip
->size
);
566 bp
= getiobuf(vp
, true);
568 bp
->b_bufsize
= bp
->b_resid
=
569 bp
->b_bcount
= ip
->size
;
570 bp
->b_data
= kmem_alloc(ip
->size
, KM_SLEEP
);
571 chfs_read_data(chmp
, vp
, bp
);
573 ip
->target
= kmem_alloc(ip
->size
,
575 memcpy(ip
->target
, bp
->b_data
, ip
->size
);
576 kmem_free(bp
->b_data
, ip
->size
);
586 dbg("read_inode_internal | ino: %llu\n",
587 (unsigned long long)ip
->ino
);
588 error
= chfs_read_inode_internal(chmp
, ip
);
593 bp
= getiobuf(vp
, true);
595 bp
->b_bufsize
= bp
->b_resid
=
596 bp
->b_bcount
= sizeof(dev_t
);
597 bp
->b_data
= kmem_alloc(sizeof(dev_t
), KM_SLEEP
);
598 chfs_read_data(chmp
, vp
, bp
);
600 bp
->b_data
, sizeof(dev_t
));
601 kmem_free(bp
->b_data
, sizeof(dev_t
));
603 /* Set specific operations. */
604 if (ip
->ch_type
== CHT_FIFO
) {
605 vp
->v_op
= chfs_fifoop_p
;
607 vp
->v_op
= chfs_specop_p
;
608 spec_node_init(vp
, ip
->rdev
);
617 mutex_exit(&chmp
->chm_lock_mountfields
);
620 KASSERT(TAILQ_FIRST(&ip
->dents
) == NULL
);
621 pool_put(&chfs_inode_pool
, ip
);
627 /* Finish inode initalization. */
628 ip
->ch_type
= VTTOCHT(vp
->v_type
);
629 ip
->devvp
= ump
->um_devvp
;
632 genfs_node_init(vp
, &chfs_genfsops
);
633 uvm_vnp_setsize(vp
, ip
->size
);
640 /* --------------------------------------------------------------------- */
643 chfs_vget(struct mount
*mp
, ino_t ino
, struct vnode
**vpp
)
647 error
= vcache_get(mp
, &ino
, sizeof(ino
), vpp
);
651 error
= vn_lock(*vpp
, LK_EXCLUSIVE
);
661 /* --------------------------------------------------------------------- */
665 chfs_fhtovp(struct mount
*mp
, struct fid
*fhp
, struct vnode
**vpp
)
670 /* --------------------------------------------------------------------- */
673 chfs_vptofh(struct vnode
*vp
, struct fid
*fhp
, size_t *fh_size
)
678 /* --------------------------------------------------------------------- */
681 chfs_start(struct mount
*mp
, int flags
)
686 /* --------------------------------------------------------------------- */
689 chfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
691 struct chfs_mount
*chmp
;
692 struct ufsmount
*ump
;
698 sbp
->f_flag
= mp
->mnt_flag
;
699 sbp
->f_bsize
= chmp
->chm_ebh
->eb_size
;
700 sbp
->f_frsize
= chmp
->chm_ebh
->eb_size
;
701 sbp
->f_iosize
= chmp
->chm_ebh
->eb_size
;
703 sbp
->f_blocks
= chmp
->chm_ebh
->peb_nr
;
705 sbp
->f_bavail
= chmp
->chm_nr_free_blocks
- chmp
->chm_resv_blocks_write
;
707 sbp
->f_bfree
= chmp
->chm_nr_free_blocks
;
708 sbp
->f_bresvd
= chmp
->chm_resv_blocks_write
;
715 copy_statvfs_info(sbp
, mp
);
720 /* --------------------------------------------------------------------- */
723 chfs_sync(struct mount
*mp
, int waitfor
,
729 /* --------------------------------------------------------------------- */
734 /* Initialize pools and inode hash. */
735 chfs_alloc_pool_caches();
736 pool_init(&chfs_inode_pool
, sizeof(struct chfs_inode
), 0, 0, 0,
737 "chfsinopl", &pool_allocator_nointr
, IPL_NONE
);
741 /* --------------------------------------------------------------------- */
749 /* --------------------------------------------------------------------- */
755 pool_destroy(&chfs_inode_pool
);
756 chfs_destroy_pool_caches();
759 /* --------------------------------------------------------------------- */
762 chfs_snapshot(struct mount
*mp
, struct vnode
*vp
,
763 struct timespec
*ctime
)
768 /* --------------------------------------------------------------------- */
771 * chfs vfs operations.
774 extern const struct vnodeopv_desc chfs_fifoop_opv_desc
;
775 extern const struct vnodeopv_desc chfs_specop_opv_desc
;
776 extern const struct vnodeopv_desc chfs_vnodeop_opv_desc
;
778 const struct vnodeopv_desc
* const chfs_vnodeopv_descs
[] = {
779 &chfs_fifoop_opv_desc
,
780 &chfs_specop_opv_desc
,
781 &chfs_vnodeop_opv_desc
,
785 struct vfsops chfs_vfsops
= {
786 .vfs_name
= MOUNT_CHFS
,
787 .vfs_min_mount_data
= sizeof (struct chfs_args
),
788 .vfs_mount
= chfs_mount
,
789 .vfs_start
= chfs_start
,
790 .vfs_unmount
= chfs_unmount
,
791 .vfs_root
= chfs_root
,
792 .vfs_quotactl
= ufs_quotactl
,
793 .vfs_statvfs
= chfs_statvfs
,
794 .vfs_sync
= chfs_sync
,
795 .vfs_vget
= chfs_vget
,
796 .vfs_loadvnode
= chfs_loadvnode
,
797 .vfs_fhtovp
= chfs_fhtovp
,
798 .vfs_vptofh
= chfs_vptofh
,
799 .vfs_init
= chfs_init
,
800 .vfs_reinit
= chfs_reinit
,
801 .vfs_done
= chfs_done
,
802 .vfs_snapshot
= chfs_snapshot
,
803 .vfs_extattrctl
= vfs_stdextattrctl
,
804 .vfs_suspendctl
= (void *)eopnotsupp
,
805 .vfs_renamelock_enter
= genfs_renamelock_enter
,
806 .vfs_renamelock_exit
= genfs_renamelock_exit
,
807 .vfs_fsync
= (void *)eopnotsupp
,
808 .vfs_opv_descs
= chfs_vnodeopv_descs
811 /* For using CHFS as a module. */
813 chfs_modcmd(modcmd_t cmd
, void *arg
)
816 case MODULE_CMD_INIT
:
817 return vfs_attach(&chfs_vfsops
);
818 case MODULE_CMD_FINI
:
819 return vfs_detach(&chfs_vfsops
);