1/*	$NetBSD: sysvbfs_vfsops.c,v 1.38.6.1 2012/06/24 16:03:39 jdc Exp $	*/
2
3/*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: sysvbfs_vfsops.c,v 1.38.6.1 2012/06/24 16:03:39 jdc Exp $");
34
35#include <sys/types.h>
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/pool.h>
39#include <sys/time.h>
40#include <sys/ucred.h>
41#include <sys/mount.h>
42#include <sys/fcntl.h>
43#include <sys/malloc.h>
44#include <sys/kauth.h>
45#include <sys/proc.h>
46
47/* v-node */
48#include <sys/namei.h>
49#include <sys/vnode.h>
50/* devsw */
51#include <sys/conf.h>
52
53#include <fs/sysvbfs/sysvbfs.h>	/* external interface */
54#include <fs/sysvbfs/bfs.h>	/* internal interface */
55
56#ifdef SYSVBFS_VNOPS_DEBUG
57#define	DPRINTF(fmt, args...)	printf(fmt, ##args)
58#else
59#define	DPRINTF(arg...)		((void)0)
60#endif
61
62MALLOC_JUSTDEFINE(M_SYSVBFS_VFS, "sysvbfs vfs", "sysvbfs vfs structures");
63
64struct pool sysvbfs_node_pool;
65
66int sysvbfs_mountfs(struct vnode *, struct mount *, struct lwp *);
67
68int
69sysvbfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
70{
71	struct lwp *l = curlwp;
72	struct sysvbfs_args *args = data;
73	struct sysvbfs_mount *bmp = NULL;
74	struct vnode *devvp = NULL;
75	int error = 0;
76	bool update;
77
78	DPRINTF("%s: mnt_flag=%x\n", __func__, mp->mnt_flag);
79
80	if (args == NULL)
81		return EINVAL;
82	if (*data_len < sizeof *args)
83		return EINVAL;
84
85	if (mp->mnt_flag & MNT_GETARGS) {
86		if ((bmp = (void *)mp->mnt_data) == NULL)
87			return EIO;
88		args->fspec = NULL;
89		*data_len = sizeof *args;
90		return 0;
91	}
92
93
94	DPRINTF("%s: args->fspec=%s\n", __func__, args->fspec);
95	update = mp->mnt_flag & MNT_UPDATE;
96	if (args->fspec == NULL) {
97		/* nothing to do. */
98		return EINVAL;
99	}
100
101	if (args->fspec != NULL) {
102		/* Look up the name and verify that it's sane. */
103		error = namei_simple_user(args->fspec,
104					NSM_FOLLOW_NOEMULROOT, &devvp);
105		if (error != 0)
106			return (error);
107
108		if (!update) {
109			/*
110			 * Be sure this is a valid block device
111			 */
112			if (devvp->v_type != VBLK)
113				error = ENOTBLK;
114			else if (bdevsw_lookup(devvp->v_rdev) == NULL)
115				error = ENXIO;
116		} else {
117			/*
118			 * Be sure we're still naming the same device
119			 * used for our initial mount
120			 */
121			if (devvp != bmp->devvp)
122				error = EINVAL;
123		}
124	}
125
126	/*
127	 * If mount by non-root, then verify that user has necessary
128	 * permissions on the device.
129	 *
130	 * Permission to update a mount is checked higher, so here we presume
131	 * updating the mount is okay (for example, as far as securelevel goes)
132	 * which leaves us with the normal check.
133	 */
134	if (error == 0) {
135		int accessmode = VREAD;
136		if (update ?
137		    (mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
138		    (mp->mnt_flag & MNT_RDONLY) == 0)
139			accessmode |= VWRITE;
140
141		error = genfs_can_mount(devvp, accessmode, l->l_cred);
142	}
143
144	if (error) {
145		vrele(devvp);
146		return error;
147	}
148
149	if (!update) {
150		if ((error = sysvbfs_mountfs(devvp, mp, l)) != 0) {
151			vrele(devvp);
152			return error;
153		}
154	} else 	if (mp->mnt_flag & MNT_RDONLY) {
155		/* XXX: r/w -> read only */
156	}
157
158	return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
159	    mp->mnt_op->vfs_name, mp, l);
160}
161
162int
163sysvbfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
164{
165	kauth_cred_t cred = l->l_cred;
166	struct sysvbfs_mount *bmp;
167	int error, oflags;
168	bool devopen = false;
169
170	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
171	error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0);
172	if (error)
173		goto out;
174
175	/* Open block device */
176	oflags = FREAD;
177	if ((mp->mnt_flag & MNT_RDONLY) == 0)
178		oflags |= FWRITE;
179	if ((error = VOP_OPEN(devvp, oflags, NOCRED)) != 0)
180		goto out;
181	devopen = true;
182
183	bmp = malloc(sizeof(*bmp), M_SYSVBFS_VFS, M_WAITOK | M_ZERO);
184	bmp->devvp = devvp;
185	bmp->mountp = mp;
186	if ((error = sysvbfs_bfs_init(&bmp->bfs, devvp)) != 0) {
187		free(bmp, M_SYSVBFS_VFS);
188		goto out;
189	}
190	LIST_INIT(&bmp->bnode_head);
191
192	mp->mnt_data = bmp;
193	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)devvp->v_rdev;
194	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_SYSVBFS);
195	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
196	mp->mnt_stat.f_namemax = BFS_FILENAME_MAXLEN;
197	mp->mnt_flag |= MNT_LOCAL;
198	mp->mnt_dev_bshift = BFS_BSHIFT;
199	mp->mnt_fs_bshift = BFS_BSHIFT;
200
201 out:
202	if (devopen && error)
203		VOP_CLOSE(devvp, oflags, NOCRED);
204	VOP_UNLOCK(devvp);
205	return error;
206}
207
208int
209sysvbfs_start(struct mount *mp, int flags)
210{
211
212	DPRINTF("%s:\n", __func__);
213	/* Nothing to do. */
214	return 0;
215}
216
217int
218sysvbfs_unmount(struct mount *mp, int mntflags)
219{
220	struct sysvbfs_mount *bmp = (void *)mp->mnt_data;
221	int error;
222
223	DPRINTF("%s: %p\n", __func__, bmp);
224
225	if ((error = vflush(mp, NULLVP,
226	    mntflags & MNT_FORCE ? FORCECLOSE : 0)) != 0)
227		return error;
228
229	vn_lock(bmp->devvp, LK_EXCLUSIVE | LK_RETRY);
230	error = VOP_CLOSE(bmp->devvp, FREAD, NOCRED);
231	vput(bmp->devvp);
232
233	sysvbfs_bfs_fini(bmp->bfs);
234
235	free(bmp, M_SYSVBFS_VFS);
236	mp->mnt_data = NULL;
237	mp->mnt_flag &= ~MNT_LOCAL;
238
239	return 0;
240}
241
242int
243sysvbfs_root(struct mount *mp, struct vnode **vpp)
244{
245	struct vnode *vp;
246	int error;
247
248	DPRINTF("%s:\n", __func__);
249	if ((error = VFS_VGET(mp, BFS_ROOT_INODE, &vp)) != 0)
250		return error;
251	*vpp = vp;
252
253	return 0;
254}
255
256int
257sysvbfs_statvfs(struct mount *mp, struct statvfs *f)
258{
259	struct sysvbfs_mount *bmp = mp->mnt_data;
260	struct bfs *bfs = bmp->bfs;
261	int free_block;
262	size_t data_block;
263
264	data_block = (bfs->data_end - bfs->data_start) >> BFS_BSHIFT;
265	if (bfs_inode_alloc(bfs, 0, 0, &free_block) != 0)
266		free_block = 0;
267	else
268		free_block = (bfs->data_end >> BFS_BSHIFT) - free_block;
269
270	DPRINTF("%s: %d %d %d\n", __func__, bfs->data_start,
271	    bfs->data_end, free_block);
272
273	f->f_bsize = BFS_BSIZE;
274	f->f_frsize = BFS_BSIZE;
275	f->f_iosize = BFS_BSIZE;
276	f->f_blocks = data_block;
277	f->f_bfree = free_block;
278	f->f_bavail = f->f_bfree;
279	f->f_bresvd = 0;
280	f->f_files = bfs->n_inode;
281	f->f_ffree = bfs->max_inode - f->f_files;
282	f->f_favail = f->f_ffree;
283	f->f_fresvd = 0;
284	copy_statvfs_info(f, mp);
285
286	return 0;
287}
288
289int
290sysvbfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
291{
292	struct sysvbfs_mount *bmp = mp->mnt_data;
293	struct sysvbfs_node *bnode;
294	struct vnode *v;
295	int err, error;
296
297	DPRINTF("%s:\n", __func__);
298	error = 0;
299	mutex_enter(&mntvnode_lock);
300	for (bnode = LIST_FIRST(&bmp->bnode_head); bnode != NULL;
301	    bnode = LIST_NEXT(bnode, link)) {
302		v = bnode->vnode;
303	    	mutex_enter(v->v_interlock);
304		mutex_exit(&mntvnode_lock);
305		err = vget(v, LK_EXCLUSIVE | LK_NOWAIT);
306		if (err == 0) {
307			err = VOP_FSYNC(v, cred, FSYNC_WAIT, 0, 0);
308			vput(v);
309		}
310		if (err != 0)
311			error = err;
312		mutex_enter(&mntvnode_lock);
313	}
314	mutex_exit(&mntvnode_lock);
315
316	return error;
317}
318
319int
320sysvbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
321{
322	struct sysvbfs_mount *bmp = mp->mnt_data;
323	struct bfs *bfs = bmp->bfs;
324	struct vnode *vp;
325	struct sysvbfs_node *bnode;
326	struct bfs_inode *inode;
327	int error;
328
329	DPRINTF("%s: i-node=%lld\n", __func__, (long long)ino);
330	/* Lookup requested i-node */
331	if (!bfs_inode_lookup(bfs, ino, &inode)) {
332		DPRINTF("%s: bfs_inode_lookup failed.\n", __func__);
333		return ENOENT;
334	}
335
336 retry:
337	mutex_enter(&mntvnode_lock);
338	for (bnode = LIST_FIRST(&bmp->bnode_head); bnode != NULL;
339	    bnode = LIST_NEXT(bnode, link)) {
340		if (bnode->inode->number == ino) {
341			vp = bnode->vnode;
342			mutex_enter(vp->v_interlock);
343			mutex_exit(&mntvnode_lock);
344			if (vget(vp, LK_EXCLUSIVE) == 0) {
345				*vpp = vp;
346				return 0;
347			} else {
348				goto retry;
349			}
350		}
351	}
352	mutex_exit(&mntvnode_lock);
353
354	/* Allocate v-node. */
355	error = getnewvnode(VT_SYSVBFS, mp, sysvbfs_vnodeop_p, NULL, &vp);
356	if (error) {
357		DPRINTF("%s: getnewvnode error.\n", __func__);
358		return error;
359	}
360	/* Lock vnode here */
361	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
362
363	/* Allocate i-node */
364	vp->v_data = pool_get(&sysvbfs_node_pool, PR_WAITOK);
365	memset(vp->v_data, 0, sizeof(struct sysvbfs_node));
366	bnode = vp->v_data;
367	mutex_enter(&mntvnode_lock);
368	LIST_INSERT_HEAD(&bmp->bnode_head, bnode, link);
369	mutex_exit(&mntvnode_lock);
370	bnode->vnode = vp;
371	bnode->bmp = bmp;
372	bnode->inode = inode;
373	bnode->lockf = NULL; /* advlock */
374
375	if (ino == BFS_ROOT_INODE) {	/* BFS is flat filesystem */
376		vp->v_type = VDIR;
377		vp->v_vflag |= VV_ROOT;
378	} else {
379		vp->v_type = VREG;
380	}
381
382	genfs_node_init(vp, &sysvbfs_genfsops);
383	uvm_vnp_setsize(vp, bfs_file_size(inode));
384	*vpp = vp;
385
386	return 0;
387}
388
389int
390sysvbfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
391{
392
393	DPRINTF("%s:\n", __func__);
394	/* notyet */
395	return EOPNOTSUPP;
396}
397
398int
399sysvbfs_vptofh(struct vnode *vpp, struct fid *fid, size_t *fh_size)
400{
401
402	DPRINTF("%s:\n", __func__);
403	/* notyet */
404	return EOPNOTSUPP;
405}
406
407MALLOC_DECLARE(M_BFS);
408MALLOC_DECLARE(M_SYSVBFS_VNODE);
409
410void
411sysvbfs_init(void)
412{
413
414	DPRINTF("%s:\n", __func__);
415	malloc_type_attach(M_SYSVBFS_VFS);
416	malloc_type_attach(M_BFS);
417	malloc_type_attach(M_SYSVBFS_VNODE);
418	pool_init(&sysvbfs_node_pool, sizeof(struct sysvbfs_node), 0, 0, 0,
419	    "sysvbfs_node_pool", &pool_allocator_nointr, IPL_NONE);
420}
421
422void
423sysvbfs_reinit(void)
424{
425
426	/* Nothing to do. */
427	DPRINTF("%s:\n", __func__);
428}
429
430void
431sysvbfs_done(void)
432{
433
434	DPRINTF("%s:\n", __func__);
435	pool_destroy(&sysvbfs_node_pool);
436	malloc_type_detach(M_BFS);
437	malloc_type_detach(M_SYSVBFS_VFS);
438	malloc_type_detach(M_SYSVBFS_VNODE);
439}
440
441int
442sysvbfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
443    kauth_cred_t cred)
444{
445
446	return 0;
447}
448