1/*	$NetBSD: chfs_vfsops.c,v 1.2 2011/11/24 21:09:37 agc Exp $	*/
2
3/*-
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>
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
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.
21 *
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
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36
37#include <sys/param.h>
38#include <sys/types.h>
39#include <sys/kmem.h>
40#include <sys/mount.h>
41#include <sys/stat.h>
42#include <sys/systm.h>
43#include <sys/proc.h>
44#include <sys/module.h>
45#include <sys/namei.h>
46#include <sys/malloc.h>
47#include <sys/fcntl.h>
48#include <sys/conf.h>
49#include <sys/buf.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>
55
56#include <uvm/uvm.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>
66#include "chfs.h"
67#include "chfs_args.h"
68
69MODULE(MODULE_CLASS_VFS, chfs, "flash");
70
71/* --------------------------------------------------------------------- */
72/* functions */
73
74static int chfs_mount(struct mount *, const char *, void *, size_t *);
75static int chfs_unmount(struct mount *, int);
76static int chfs_root(struct mount *, struct vnode **);
77static int chfs_vget(struct mount *, ino_t, struct vnode **);
78static int chfs_fhtovp(struct mount *, struct fid *, struct vnode **);
79static int chfs_vptofh(struct vnode *, struct fid *, size_t *);
80static int chfs_start(struct mount *, int);
81static int chfs_statvfs(struct mount *, struct statvfs *);
82static int chfs_sync(struct mount *, int, kauth_cred_t);
83static void chfs_init(void);
84static void chfs_reinit(void);
85static void chfs_done(void);
86static int chfs_snapshot(struct mount *, struct vnode *,
87    struct timespec *);
88
89/* --------------------------------------------------------------------- */
90/* structures */
91
92int
93chfs_gop_alloc(struct vnode *vp, off_t off, off_t len,  int flags,
94    kauth_cred_t cred)
95{
96	return (0);
97}
98
99const 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,
104};
105
106/*
107static const struct ufs_ops chfs_ufsops = {
108	.uo_itimes = chfs_itimes,
109	.uo_update = chfs_update,
110};
111*/
112
113struct pool chfs_inode_pool;
114
115/* for looking up the major for flash */
116extern const struct cdevsw flash_cdevsw;
117
118/* --------------------------------------------------------------------- */
119
120static int
121chfs_mount(struct mount *mp,
122    const char *path, void *data, size_t *data_len)
123{
124	struct lwp *l = curlwp;
125	struct nameidata nd;
126	struct pathbuf *pb;
127	struct vnode *devvp = NULL;
128	struct ufs_args *args = data;
129	struct ufsmount *ump = NULL;
130	struct chfs_mount *chmp;
131	int err = 0;
132	int xflags;
133
134	dbg("mount()\n");
135
136	if (args == NULL)
137		return EINVAL;
138	if (*data_len < sizeof *args)
139		return EINVAL;
140
141	if (mp->mnt_flag & MNT_GETARGS) {
142		ump = VFSTOUFS(mp);
143		if (ump == NULL)
144			return EIO;
145		memset(args, 0, sizeof *args);
146		args->fspec = NULL;
147		*data_len = sizeof *args;
148		return 0;
149	}
150
151	if (mp->mnt_flag & MNT_UPDATE) {
152		/* XXX: There is no support yet to update file system
153		 * settings.  Should be added. */
154
155		return ENODEV;
156	}
157
158	if (args->fspec != NULL) {
159		err = pathbuf_copyin(args->fspec, &pb);
160		if (err) {
161			return err;
162		}
163		/*
164		 * Look up the name and verify that it's sane.
165		 */
166		NDINIT(&nd, LOOKUP, FOLLOW, pb);
167		if ((err = namei(&nd)) != 0 )
168			return (err);
169		devvp = nd.ni_vp;
170
171		/*
172		 * Be sure this is a valid block device
173		 */
174		if (devvp->v_type != VBLK)
175			err = ENOTBLK;
176		else if (bdevsw_lookup(devvp->v_rdev) == NULL)
177			err = ENXIO;
178	}
179
180	if (err) {
181		vrele(devvp);
182		return (err);
183	}
184
185	if (mp->mnt_flag & MNT_RDONLY)
186		xflags = FREAD;
187	else
188		xflags = FREAD|FWRITE;
189
190	err = VOP_OPEN(devvp, xflags, FSCRED);
191	if (err)
192		goto fail;
193
194
195	err = chfs_mountfs(devvp, mp);
196	if (err) {
197		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
198		(void)VOP_CLOSE(devvp, xflags, NOCRED);
199		VOP_UNLOCK(devvp);
200		goto fail;
201	}
202	ump = VFSTOUFS(mp);
203	chmp = ump->um_chfs;
204
205	vfs_getnewfsid(mp);
206	chmp->chm_fsmp = mp;
207
208	return set_statvfs_info(path,
209	    UIO_USERSPACE, args->fspec,
210	    UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l);
211
212fail:
213	vrele(devvp);
214	return (err);
215}
216
217
218int
219chfs_mountfs(struct vnode *devvp, struct mount *mp)
220{
221	struct lwp *l = curlwp;
222	struct proc *p;
223	kauth_cred_t cred;
224	devmajor_t flash_major;
225	dev_t dev;
226	struct ufsmount* ump = NULL;
227	struct chfs_mount* chmp;
228	struct vnode *vp;
229	int err = 0;
230
231	dbg("mountfs()\n");
232
233	dev = devvp->v_rdev;
234	p = l ? l->l_proc : NULL;
235	cred = l ? l->l_cred : NOCRED;
236
237	/* Flush out any old buffers remaining from a previous use. */
238	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
239	err = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0);
240	VOP_UNLOCK(devvp);
241	if (err)
242		return (err);
243
244	flash_major = cdevsw_lookup_major(&flash_cdevsw);
245
246	if (devvp->v_type != VBLK)
247		err = ENOTBLK;
248	else if (bdevsw_lookup(dev) == NULL)
249		err = ENXIO;
250	else if (major(dev) != flash_major) {
251		dbg("major(dev): %d, flash_major: %d\n",
252		    major(dev), flash_major);
253		err = ENODEV;
254	}
255	if (err) {
256		vrele(devvp);
257		return (err);
258	}
259
260	ump = malloc(sizeof(*ump), M_UFSMNT, M_WAITOK);
261	memset(ump, 0, sizeof(*ump));
262	ump->um_fstype = UFS1;
263	//ump->um_ops = &chfs_ufsops;
264	ump->um_chfs = malloc(sizeof(struct chfs_mount),
265	    M_UFSMNT, M_WAITOK);
266	memset(ump->um_chfs, 0, sizeof(struct chfs_mount));
267
268	mutex_init(&ump->um_lock, MUTEX_DEFAULT, IPL_NONE);
269
270	/* Get superblock and set flash device number */
271	chmp = ump->um_chfs;
272	if (!chmp)
273		return ENOMEM;
274
275	chmp->chm_ebh = kmem_alloc(sizeof(struct chfs_ebh), KM_SLEEP);
276
277	dbg("[]opening flash: %u\n", (unsigned int)devvp->v_rdev);
278	err = ebh_open(chmp->chm_ebh, devvp->v_rdev);
279	if (err) {
280		dbg("error while opening flash\n");
281		kmem_free(chmp->chm_ebh, sizeof(struct chfs_ebh));
282		free(chmp, M_UFSMNT);
283		return err;
284	}
285
286	//TODO check flash sizes
287
288	chmp->chm_gbl_version = 0;
289	chmp->chm_vnocache_hash = chfs_vnocache_hash_init();
290
291	chmp->chm_blocks = kmem_zalloc(chmp->chm_ebh->peb_nr *
292	    sizeof(struct chfs_eraseblock), KM_SLEEP);
293
294	if (!chmp->chm_blocks) {
295		kmem_free(chmp->chm_ebh, chmp->chm_ebh->peb_nr *
296		    sizeof(struct chfs_eraseblock));
297		ebh_close(chmp->chm_ebh);
298		free(chmp, M_UFSMNT);
299		return ENOMEM;
300	}
301
302	mutex_init(&chmp->chm_lock_mountfields, MUTEX_DEFAULT, IPL_NONE);
303	mutex_init(&chmp->chm_lock_sizes, MUTEX_DEFAULT, IPL_NONE);
304	mutex_init(&chmp->chm_lock_vnocache, MUTEX_DEFAULT, IPL_NONE);
305
306	//XXX
307	chmp->chm_fs_bmask = -4096;
308	chmp->chm_fs_bsize = 4096;
309	chmp->chm_fs_qbmask = 4095;
310	chmp->chm_fs_bshift = 12;
311	chmp->chm_fs_fmask = -2048;
312	chmp->chm_fs_qfmask = 2047;
313
314	chmp->chm_wbuf_pagesize = chmp->chm_ebh->flash_if->page_size;
315	dbg("wbuf size: %zu\n", chmp->chm_wbuf_pagesize);
316	chmp->chm_wbuf = kmem_alloc(chmp->chm_wbuf_pagesize, KM_SLEEP);
317	rw_init(&chmp->chm_lock_wbuf);
318
319	//init queues
320	TAILQ_INIT(&chmp->chm_free_queue);
321	TAILQ_INIT(&chmp->chm_clean_queue);
322	TAILQ_INIT(&chmp->chm_dirty_queue);
323	TAILQ_INIT(&chmp->chm_very_dirty_queue);
324	TAILQ_INIT(&chmp->chm_erasable_pending_wbuf_queue);
325	TAILQ_INIT(&chmp->chm_erase_pending_queue);
326
327	chfs_calc_trigger_levels(chmp);
328
329	chmp->chm_nr_free_blocks = 0;
330	chmp->chm_nr_erasable_blocks = 0;
331	chmp->chm_max_vno = 2;
332	chmp->chm_checked_vno = 2;
333	chmp->chm_unchecked_size = 0;
334	chmp->chm_used_size = 0;
335	chmp->chm_dirty_size = 0;
336	chmp->chm_wasted_size = 0;
337	chmp->chm_free_size = chmp->chm_ebh->eb_size * chmp->chm_ebh->peb_nr;
338	err = chfs_build_filesystem(chmp);
339
340	if (err) {
341		chfs_vnocache_hash_destroy(chmp->chm_vnocache_hash);
342		kmem_free(chmp->chm_ebh, chmp->chm_ebh->peb_nr *
343		    sizeof(struct chfs_eraseblock));
344		ebh_close(chmp->chm_ebh);
345		free(chmp, M_UFSMNT);
346		return EIO;
347	}
348
349	mp->mnt_data = ump;
350	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
351	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_CHFS);
352	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
353	mp->mnt_stat.f_namemax = MAXNAMLEN;
354	mp->mnt_flag |= MNT_LOCAL;
355	mp->mnt_fs_bshift = PAGE_SHIFT;
356	mp->mnt_dev_bshift = DEV_BSHIFT;
357	mp->mnt_iflag |= IMNT_MPSAFE;
358	ump->um_flags = 0;
359	ump->um_mountp = mp;
360	ump->um_dev = dev;
361	ump->um_devvp = devvp;
362	ump->um_maxfilesize = 1048512 * 1024;
363	/*TODO fill these fields
364	  ump->um_nindir =
365	  ump->um_lognindir =
366	  ump->um_bptrtodb =
367	  ump->um_seqinc =
368	  ump->um_maxsymlinklen =
369	  ump->um_dirblksiz =
370	  ump->um_maxfilesize =
371	*/
372
373	/*
374	 * Allocate the root vnode.
375	 */
376	err = VFS_VGET(mp, CHFS_ROOTINO, &vp);
377	if (err) {
378		dbg("error: %d while allocating root node\n", err);
379		return err;
380	}
381	vput(vp);
382
383	chfs_gc_thread_start(chmp);
384	mutex_enter(&chmp->chm_lock_mountfields);
385	chfs_gc_trigger(chmp);
386	mutex_exit(&chmp->chm_lock_mountfields);
387
388	devvp->v_specmountpoint = mp;
389	return 0;
390}
391
392/* --------------------------------------------------------------------- */
393
394/* ARGSUSED2 */
395static int
396chfs_unmount(struct mount *mp, int mntflags)
397{
398	int flags = 0, i = 0;
399	struct ufsmount *ump;
400	struct chfs_mount *chmp;
401//	struct chfs_vnode_cache *vc, *next;
402
403	if (mntflags & MNT_FORCE)
404		flags |= FORCECLOSE;
405
406	dbg("[START]\n");
407
408	ump = VFSTOUFS(mp);
409	chmp = ump->um_chfs;
410
411	chfs_gc_thread_stop(chmp);
412
413	(void)vflush(mp, NULLVP, flags);
414
415	if (chmp->chm_wbuf_len) {
416		mutex_enter(&chmp->chm_lock_mountfields);
417		chfs_flush_pending_wbuf(chmp);
418		mutex_exit(&chmp->chm_lock_mountfields);
419	}
420
421	for (i = 0; i < chmp->chm_ebh->peb_nr; i++) {
422		chfs_free_node_refs(&chmp->chm_blocks[i]);
423	}
424
425	chfs_vnocache_hash_destroy(chmp->chm_vnocache_hash);
426
427	ebh_close(chmp->chm_ebh);
428
429	rw_destroy(&chmp->chm_lock_wbuf);
430	mutex_destroy(&chmp->chm_lock_vnocache);
431	mutex_destroy(&chmp->chm_lock_sizes);
432	mutex_destroy(&chmp->chm_lock_mountfields);
433
434	if (ump->um_devvp->v_type != VBAD) {
435		ump->um_devvp->v_specmountpoint = NULL;
436	}
437	vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
438	(void)VOP_CLOSE(ump->um_devvp, FREAD|FWRITE, NOCRED);
439	vput(ump->um_devvp);
440
441	mutex_destroy(&ump->um_lock);
442
443	//free(ump->um_chfs, M_UFSMNT);
444	free(ump, M_UFSMNT);
445	mp->mnt_data = NULL;
446	mp->mnt_flag &= ~MNT_LOCAL;
447	dbg("[END]\n");
448	return (0);
449}
450
451/* --------------------------------------------------------------------- */
452
453static int
454chfs_root(struct mount *mp, struct vnode **vpp)
455{
456	struct vnode *vp;
457	int error;
458
459	if ((error = VFS_VGET(mp, (ino_t)ROOTINO, &vp)) != 0)
460		return error;
461	*vpp = vp;
462	return 0;
463}
464
465/* --------------------------------------------------------------------- */
466
467extern rb_tree_ops_t frag_rbtree_ops;
468
469static int
470chfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
471{
472	struct chfs_mount *chmp;
473	struct chfs_inode *ip;
474	struct ufsmount *ump;
475	struct vnode *vp;
476	dev_t dev;
477	int error;
478	struct chfs_vnode_cache* chvc = NULL;
479	struct chfs_node_ref* nref = NULL;
480	struct buf *bp;
481
482	dbg("vget() | ino: %llu\n", (unsigned long long)ino);
483
484	ump = VFSTOUFS(mp);
485	dev = ump->um_dev;
486retry:
487	if (!vpp) {
488		vpp = kmem_alloc(sizeof(struct vnode*), KM_SLEEP);
489	}
490
491	if ((*vpp = chfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
492		return 0;
493	}
494
495	/* Allocate a new vnode/inode. */
496	if ((error = getnewvnode(VT_CHFS,
497		    mp, chfs_vnodeop_p, NULL, &vp)) != 0) {
498		*vpp = NULL;
499		return (error);
500	}
501	ip = pool_get(&chfs_inode_pool, PR_WAITOK);
502
503	mutex_enter(&chfs_hashlock);
504	if ((*vpp = chfs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
505		mutex_exit(&chfs_hashlock);
506		ungetnewvnode(vp);
507		pool_put(&chfs_inode_pool, ip);
508		goto retry;
509	}
510
511	vp->v_vflag |= VV_LOCKSWORK;
512
513	memset(ip, 0, sizeof(*ip));
514	vp->v_data = ip;
515	ip->vp = vp;
516	ip->ump = ump;
517	ip->chmp = chmp = ump->um_chfs;
518	ip->dev = dev;
519	ip->ino = ino;
520	vp->v_mount = mp;
521	genfs_node_init(vp, &chfs_genfsops);
522
523	rb_tree_init(&ip->fragtree, &frag_rbtree_ops);
524	//mutex_init(&ip->inode_lock, MUTEX_DEFAULT, IPL_NONE);
525
526	chfs_ihashins(ip);
527	mutex_exit(&chfs_hashlock);
528
529	// set root inode
530	if (ino == CHFS_ROOTINO) {
531		dbg("SETROOT\n");
532		vp->v_vflag |= VV_ROOT;
533		vp->v_type = VDIR;
534		ip->mode = IFMT | IEXEC | IWRITE | IREAD;
535		ip->iflag |= (IN_ACCESS | IN_CHANGE | IN_UPDATE);
536		chfs_update(vp, NULL, NULL, UPDATE_WAIT);
537//		ip->dents = NULL; XXXTAILQ
538		TAILQ_INIT(&ip->dents);
539		chfs_set_vnode_size(vp, 512);
540	}
541
542	// set vnode cache
543	mutex_enter(&chmp->chm_lock_vnocache);
544	chvc = chfs_vnode_cache_get(chmp, ino);
545	mutex_exit(&chmp->chm_lock_vnocache);
546	if (!chvc) {
547		dbg("!chvc\n");
548		/* XXX, we cant alloc under a lock, refactor this! */
549		chvc = chfs_vnode_cache_alloc(ino);
550		mutex_enter(&chmp->chm_lock_vnocache);
551		if (ino == CHFS_ROOTINO) {
552			chvc->nlink = 2;
553			chvc->pvno = CHFS_ROOTINO;
554			chfs_vnode_cache_set_state(chmp,
555			    chvc, VNO_STATE_CHECKEDABSENT);
556		}
557		chfs_vnode_cache_add(chmp, chvc);
558		mutex_exit(&chmp->chm_lock_vnocache);
559
560		ip->chvc = chvc;
561		TAILQ_INIT(&ip->dents);
562	} else {
563		dbg("chvc\n");
564		ip->chvc = chvc;
565		// if we have a vnode cache, the node is already on flash, so read it
566		if (ino == CHFS_ROOTINO) {
567			chvc->pvno = CHFS_ROOTINO;
568			TAILQ_INIT(&chvc->scan_dirents);
569		} else {
570			chfs_readvnode(mp, ino, &vp);
571		}
572
573		mutex_enter(&chmp->chm_lock_mountfields);
574		// init type specific things
575		switch (vp->v_type) {
576		case VDIR:
577			nref = chvc->dirents;
578			while (nref &&
579			    (struct chfs_vnode_cache *)nref != chvc) {
580				chfs_readdirent(mp, nref, ip);
581				nref = nref->nref_next;
582			}
583			chfs_set_vnode_size(vp, 512);
584			break;
585		case VREG:
586		case VSOCK:
587			//build the fragtree of the vnode
588			dbg("read_inode_internal | ino: %llu\n",
589				(unsigned long long)ip->ino);
590			error = chfs_read_inode(chmp, ip);
591			if (error) {
592				vput(vp);
593				*vpp = NULL;
594				mutex_exit(&chmp->chm_lock_mountfields);
595				return (error);
596			}
597			break;
598		case VLNK:
599			//build the fragtree of the vnode
600			dbg("read_inode_internal | ino: %llu\n",
601				(unsigned long long)ip->ino);
602			error = chfs_read_inode_internal(chmp, ip);
603			if (error) {
604				vput(vp);
605				*vpp = NULL;
606				mutex_exit(&chmp->chm_lock_mountfields);
607				return (error);
608			}
609
610			dbg("size: %llu\n", (unsigned long long)ip->size);
611			bp = getiobuf(vp, true);
612			bp->b_blkno = 0;
613			bp->b_bufsize = bp->b_resid =
614			    bp->b_bcount = ip->size;
615			bp->b_data = kmem_alloc(ip->size, KM_SLEEP);
616			chfs_read_data(chmp, vp, bp);
617			if (!ip->target)
618				ip->target = kmem_alloc(ip->size,
619				    KM_SLEEP);
620			memcpy(ip->target, bp->b_data, ip->size);
621			kmem_free(bp->b_data, ip->size);
622			putiobuf(bp);
623
624			break;
625		case VCHR:
626		case VBLK:
627		case VFIFO:
628			//build the fragtree of the vnode
629			dbg("read_inode_internal | ino: %llu\n",
630				(unsigned long long)ip->ino);
631			error = chfs_read_inode_internal(chmp, ip);
632			if (error) {
633				vput(vp);
634				*vpp = NULL;
635				mutex_exit(&chmp->chm_lock_mountfields);
636				return (error);
637			}
638
639			bp = getiobuf(vp, true);
640			bp->b_blkno = 0;
641			bp->b_bufsize = bp->b_resid =
642			    bp->b_bcount = sizeof(dev_t);
643			bp->b_data = kmem_alloc(sizeof(dev_t), KM_SLEEP);
644			chfs_read_data(chmp, vp, bp);
645			memcpy(&ip->rdev,
646			    bp->b_data, sizeof(dev_t));
647			kmem_free(bp->b_data, sizeof(dev_t));
648			putiobuf(bp);
649			if (vp->v_type == VFIFO)
650				vp->v_op = chfs_fifoop_p;
651			else {
652				vp->v_op = chfs_specop_p;
653				spec_node_init(vp, ip->rdev);
654			}
655
656		    break;
657		case VNON:
658		case VBAD:
659			break;
660		}
661		mutex_exit(&chmp->chm_lock_mountfields);
662
663	}
664
665	/* finish inode initalization */
666	ip->devvp = ump->um_devvp;
667	vref(ip->devvp);
668
669	uvm_vnp_setsize(vp, ip->size);
670	*vpp = vp;
671
672	return 0;
673}
674
675/* --------------------------------------------------------------------- */
676
677static int
678chfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
679{
680	return ENODEV;
681}
682
683/* --------------------------------------------------------------------- */
684
685static int
686chfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
687{
688	return ENODEV;
689}
690
691/* --------------------------------------------------------------------- */
692
693static int
694chfs_start(struct mount *mp, int flags)
695{
696	return 0;
697}
698
699/* --------------------------------------------------------------------- */
700
701/* ARGSUSED2 */
702static int
703chfs_statvfs(struct mount *mp, struct statvfs *sbp)
704{
705 	struct chfs_mount *chmp;
706	struct ufsmount *ump;
707	dbg("statvfs\n");
708
709	ump = VFSTOUFS(mp);
710	chmp = ump->um_chfs;
711
712	sbp->f_flag   = mp->mnt_flag;
713	sbp->f_bsize  = chmp->chm_ebh->eb_size;
714	sbp->f_frsize = chmp->chm_ebh->eb_size;
715	sbp->f_iosize = chmp->chm_ebh->eb_size;
716
717	sbp->f_blocks = chmp->chm_ebh->peb_nr;
718	sbp->f_files  = 0;
719	sbp->f_bavail = chmp->chm_nr_free_blocks - chmp->chm_resv_blocks_write;
720#if 0
721	printf("chmp->chm_nr_free_blocks: %jd\n",
722	    (intmax_t )chmp->chm_nr_free_blocks);
723	printf("chmp->chm_resv_blocks_write: %jd\n",
724	    (intmax_t) chmp->chm_resv_blocks_write);
725	printf("chmp->chm_ebh->peb_nr: %jd\n",
726	    (intmax_t) chmp->chm_ebh->peb_nr);
727#endif
728
729	sbp->f_bfree = chmp->chm_nr_free_blocks;
730	sbp->f_bresvd = chmp->chm_resv_blocks_write;
731
732	/* FFS specific */
733	sbp->f_ffree  = 0;
734	sbp->f_favail = 0;
735	sbp->f_fresvd = 0;
736
737	copy_statvfs_info(sbp, mp);
738
739	return 0;
740}
741
742/* --------------------------------------------------------------------- */
743
744/* ARGSUSED0 */
745static int
746chfs_sync(struct mount *mp, int waitfor,
747    kauth_cred_t uc)
748{
749	return 0;
750}
751
752/* --------------------------------------------------------------------- */
753
754static void
755chfs_init(void)
756{
757	chfs_alloc_pool_caches();
758	chfs_ihashinit();
759	pool_init(&chfs_inode_pool, sizeof(struct chfs_inode), 0, 0, 0,
760	    "chfsinopl", &pool_allocator_nointr, IPL_NONE);
761	ufs_init();
762}
763
764/* --------------------------------------------------------------------- */
765
766static void
767chfs_reinit(void)
768{
769	chfs_ihashreinit();
770	ufs_reinit();
771}
772
773/* --------------------------------------------------------------------- */
774
775static void
776chfs_done(void)
777{
778	ufs_done();
779	chfs_ihashdone();
780	pool_destroy(&chfs_inode_pool);
781	chfs_destroy_pool_caches();
782}
783
784/* --------------------------------------------------------------------- */
785
786static int
787chfs_snapshot(struct mount *mp, struct vnode *vp,
788    struct timespec *ctime)
789{
790	return ENODEV;
791}
792
793/* --------------------------------------------------------------------- */
794
795/*
796 * chfs vfs operations.
797 */
798
799extern const struct vnodeopv_desc chfs_fifoop_opv_desc;
800extern const struct vnodeopv_desc chfs_specop_opv_desc;
801extern const struct vnodeopv_desc chfs_vnodeop_opv_desc;
802
803const struct vnodeopv_desc * const chfs_vnodeopv_descs[] = {
804	&chfs_fifoop_opv_desc,
805	&chfs_specop_opv_desc,
806	&chfs_vnodeop_opv_desc,
807	NULL,
808};
809
810struct vfsops chfs_vfsops = {
811	MOUNT_CHFS,			/* vfs_name */
812	sizeof (struct chfs_args),
813	chfs_mount,			/* vfs_mount */
814	chfs_start,			/* vfs_start */
815	chfs_unmount,		/* vfs_unmount */
816	chfs_root,			/* vfs_root */
817	ufs_quotactl,			/* vfs_quotactl */
818	chfs_statvfs,		/* vfs_statvfs */
819	chfs_sync,			/* vfs_sync */
820	chfs_vget,			/* vfs_vget */
821	chfs_fhtovp,		/* vfs_fhtovp */
822	chfs_vptofh,		/* vfs_vptofh */
823	chfs_init,			/* vfs_init */
824	chfs_reinit,		/* vfs_reinit */
825	chfs_done,			/* vfs_done */
826	NULL,				/* vfs_mountroot */
827	chfs_snapshot,		/* vfs_snapshot */
828	vfs_stdextattrctl,		/* vfs_extattrctl */
829	(void *)eopnotsupp,		/* vfs_suspendctl */
830	genfs_renamelock_enter,
831	genfs_renamelock_exit,
832	(void *)eopnotsupp,
833	chfs_vnodeopv_descs,
834	0,				/* vfs_refcount */
835	{ NULL, NULL },
836};
837
838static int
839chfs_modcmd(modcmd_t cmd, void *arg)
840{
841	switch (cmd) {
842	case MODULE_CMD_INIT:
843		return vfs_attach(&chfs_vfsops);
844	case MODULE_CMD_FINI:
845		return vfs_detach(&chfs_vfsops);
846	default:
847		return ENOTTY;
848	}
849}
850