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