1/*	$NetBSD: sysvbfs_vfsops.c,v 1.48 2022/05/03 07:34:38 hannken 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.48 2022/05/03 07:34:38 hannken 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 = (struct sysvbfs_mount *)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			bmp = (struct sysvbfs_mount *)mp->mnt_data;
122			if (devvp != bmp->devvp)
123				error = EINVAL;
124		}
125	}
126
127	/*
128	 * If mount by non-root, then verify that user has necessary
129	 * permissions on the device.
130	 *
131	 * Permission to update a mount is checked higher, so here we presume
132	 * updating the mount is okay (for example, as far as securelevel goes)
133	 * which leaves us with the normal check.
134	 */
135	if (error == 0) {
136		int accessmode = VREAD;
137		if (update ?
138		    (mp->mnt_iflag & IMNT_WANTRDWR) != 0 :
139		    (mp->mnt_flag & MNT_RDONLY) == 0)
140			accessmode |= VWRITE;
141
142		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
143		error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
144		    KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp,
145		    KAUTH_ARG(accessmode));
146		VOP_UNLOCK(devvp);
147	}
148
149	if (error) {
150		vrele(devvp);
151		return error;
152	}
153
154	if (!update) {
155		if ((error = sysvbfs_mountfs(devvp, mp, l)) != 0) {
156			vrele(devvp);
157			return error;
158		}
159	} else 	if (mp->mnt_flag & MNT_RDONLY) {
160		/* XXX: r/w -> read only */
161	}
162
163	return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
164	    mp->mnt_op->vfs_name, mp, l);
165}
166
167int
168sysvbfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l)
169{
170	kauth_cred_t cred = l->l_cred;
171	struct sysvbfs_mount *bmp;
172	int error, oflags;
173
174	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
175	error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0);
176	if (error)
177		goto out;
178
179	/* Open block device */
180	oflags = FREAD;
181	if ((mp->mnt_flag & MNT_RDONLY) == 0)
182		oflags |= FWRITE;
183	if ((error = VOP_OPEN(devvp, oflags, NOCRED)) != 0)
184		goto out;
185
186	bmp = malloc(sizeof(*bmp), M_SYSVBFS_VFS, M_WAITOK | M_ZERO);
187	bmp->devvp = devvp;
188	bmp->mountp = mp;
189	if ((error = sysvbfs_bfs_init(&bmp->bfs, devvp)) != 0) {
190		free(bmp, M_SYSVBFS_VFS);
191		VOP_CLOSE(devvp, oflags, NOCRED);
192		goto out;
193	}
194
195	mp->mnt_data = bmp;
196	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)devvp->v_rdev;
197	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_SYSVBFS);
198	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
199	mp->mnt_stat.f_namemax = BFS_FILENAME_MAXLEN;
200	mp->mnt_flag |= MNT_LOCAL;
201	mp->mnt_dev_bshift = BFS_BSHIFT;
202	mp->mnt_fs_bshift = BFS_BSHIFT;
203
204 out:
205	VOP_UNLOCK(devvp);
206	return error;
207}
208
209int
210sysvbfs_start(struct mount *mp, int flags)
211{
212
213	DPRINTF("%s:\n", __func__);
214	/* Nothing to do. */
215	return 0;
216}
217
218int
219sysvbfs_unmount(struct mount *mp, int mntflags)
220{
221	struct sysvbfs_mount *bmp = (void *)mp->mnt_data;
222	int error;
223
224	DPRINTF("%s: %p\n", __func__, bmp);
225
226	if ((error = vflush(mp, NULLVP,
227	    mntflags & MNT_FORCE ? FORCECLOSE : 0)) != 0)
228		return error;
229
230	vn_lock(bmp->devvp, LK_EXCLUSIVE | LK_RETRY);
231	error = VOP_CLOSE(bmp->devvp, FREAD, NOCRED);
232	vput(bmp->devvp);
233
234	sysvbfs_bfs_fini(bmp->bfs);
235
236	free(bmp, M_SYSVBFS_VFS);
237	mp->mnt_data = NULL;
238	mp->mnt_flag &= ~MNT_LOCAL;
239
240	return 0;
241}
242
243int
244sysvbfs_root(struct mount *mp, int lktype, struct vnode **vpp)
245{
246	struct vnode *vp;
247	int error;
248
249	DPRINTF("%s:\n", __func__);
250	if ((error = VFS_VGET(mp, BFS_ROOT_INODE, lktype, &vp)) != 0)
251		return error;
252	*vpp = vp;
253
254	return 0;
255}
256
257int
258sysvbfs_statvfs(struct mount *mp, struct statvfs *f)
259{
260	struct sysvbfs_mount *bmp = mp->mnt_data;
261	struct bfs *bfs = bmp->bfs;
262	int free_block;
263	size_t data_block;
264
265	data_block = (bfs->data_end - bfs->data_start) >> BFS_BSHIFT;
266	if (bfs_inode_alloc(bfs, 0, 0, &free_block) != 0)
267		free_block = 0;
268	else
269		free_block = (bfs->data_end >> BFS_BSHIFT) - free_block;
270
271	DPRINTF("%s: %d %d %d\n", __func__, bfs->data_start,
272	    bfs->data_end, free_block);
273
274	f->f_bsize = BFS_BSIZE;
275	f->f_frsize = BFS_BSIZE;
276	f->f_iosize = BFS_BSIZE;
277	f->f_blocks = data_block;
278	f->f_bfree = free_block;
279	f->f_bavail = f->f_bfree;
280	f->f_bresvd = 0;
281	f->f_files = bfs->max_inode;
282	f->f_ffree = bfs->max_inode - bfs->n_inode;
283	f->f_favail = f->f_ffree;
284	f->f_fresvd = 0;
285	copy_statvfs_info(f, mp);
286
287	return 0;
288}
289
290int
291sysvbfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
292{
293	struct vnode_iterator *marker;
294	struct vnode *vp;
295	int err, error;
296
297	DPRINTF("%s:\n", __func__);
298	error = 0;
299	vfs_vnode_iterator_init(mp, &marker);
300	while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL)) != NULL) {
301		err = vn_lock(vp, LK_EXCLUSIVE);
302		if (err) {
303			vrele(vp);
304			continue;
305		}
306		err = VOP_FSYNC(vp, cred, FSYNC_WAIT, 0, 0);
307		vput(vp);
308		if (err != 0)
309			error = err;
310	}
311	vfs_vnode_iterator_destroy(marker);
312
313	return error;
314}
315
316int
317sysvbfs_loadvnode(struct mount *mp, struct vnode *vp,
318    const void *key, size_t key_len, const void **new_key)
319{
320	struct sysvbfs_mount *bmp;
321	struct bfs *bfs;
322	struct sysvbfs_node *bnode;
323	struct bfs_inode *inode;
324	uint16_t ino;
325
326	KASSERT(key_len == sizeof(ino));
327	memcpy(&ino, key, key_len);
328
329	DPRINTF("%s: i-node=%u\n", __func__, ino);
330
331	bmp = mp->mnt_data;
332	bfs = bmp->bfs;
333
334	/* Lookup requested i-node */
335	if (!bfs_inode_lookup(bfs, ino, &inode)) {
336		DPRINTF("%s: bfs_inode_lookup failed.\n", __func__);
337		return ENOENT;
338	}
339
340	bnode = pool_get(&sysvbfs_node_pool, PR_WAITOK);
341	memset(bnode, 0, sizeof(*bnode));
342
343	vp->v_tag = VT_SYSVBFS;
344	vp->v_op = sysvbfs_vnodeop_p;
345	vp->v_data = bnode;
346	if (ino == BFS_ROOT_INODE) {	/* BFS is flat filesystem */
347		vp->v_type = VDIR;
348		vp->v_vflag |= VV_ROOT;
349	} else {
350		vp->v_type = VREG;
351	}
352
353	bnode->vnode = vp;
354	bnode->bmp = bmp;
355	bnode->inode = inode;
356	bnode->lockf = NULL; /* advlock */
357
358	genfs_node_init(vp, &sysvbfs_genfsops);
359	uvm_vnp_setsize(vp, bfs_file_size(inode));
360
361	*new_key = &bnode->inode->number;
362
363	return 0;
364}
365
366int
367sysvbfs_vget(struct mount *mp, ino_t ino, int lktype, struct vnode **vpp)
368{
369	int error;
370	uint16_t number;
371	struct vnode *vp;
372
373	KASSERT(ino <= UINT16_MAX);
374	number = ino;
375
376	DPRINTF("%s: i-node=%u\n", __func__, number);
377
378	error = vcache_get(mp, &number, sizeof(number), &vp);
379	if (error)
380		return error;
381	error = vn_lock(vp, lktype);
382	if (error) {
383		vrele(vp);
384		return error;
385	}
386
387	*vpp = vp;
388
389	return 0;
390}
391
392int
393sysvbfs_fhtovp(struct mount *mp, struct fid *fid, int lktype,
394    struct vnode **vpp)
395{
396
397	DPRINTF("%s:\n", __func__);
398	/* notyet */
399	return EOPNOTSUPP;
400}
401
402int
403sysvbfs_vptofh(struct vnode *vpp, struct fid *fid, size_t *fh_size)
404{
405
406	DPRINTF("%s:\n", __func__);
407	/* notyet */
408	return EOPNOTSUPP;
409}
410
411MALLOC_DECLARE(M_BFS);
412MALLOC_DECLARE(M_SYSVBFS_VNODE);
413
414void
415sysvbfs_init(void)
416{
417
418	DPRINTF("%s:\n", __func__);
419	malloc_type_attach(M_SYSVBFS_VFS);
420	malloc_type_attach(M_BFS);
421	malloc_type_attach(M_SYSVBFS_VNODE);
422	pool_init(&sysvbfs_node_pool, sizeof(struct sysvbfs_node), 0, 0, 0,
423	    "sysvbfs_node_pool", &pool_allocator_nointr, IPL_NONE);
424}
425
426void
427sysvbfs_reinit(void)
428{
429
430	/* Nothing to do. */
431	DPRINTF("%s:\n", __func__);
432}
433
434void
435sysvbfs_done(void)
436{
437
438	DPRINTF("%s:\n", __func__);
439	pool_destroy(&sysvbfs_node_pool);
440	malloc_type_detach(M_BFS);
441	malloc_type_detach(M_SYSVBFS_VFS);
442	malloc_type_detach(M_SYSVBFS_VNODE);
443}
444
445int
446sysvbfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
447    kauth_cred_t cred)
448{
449
450	return 0;
451}
452