xref: /netbsd-src/sys/fs/sysvbfs/sysvbfs_vnops.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: sysvbfs_vnops.c,v 1.35 2010/11/30 10:43:04 dholland 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_vnops.c,v 1.35 2010/11/30 10:43:04 dholland Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/resource.h>
38 #include <sys/vnode.h>
39 #include <sys/namei.h>
40 #include <sys/dirent.h>
41 #include <sys/malloc.h>
42 #include <sys/lockf.h>
43 #include <sys/unistd.h>
44 #include <sys/fcntl.h>
45 #include <sys/kauth.h>
46 #include <sys/buf.h>
47 
48 #include <miscfs/genfs/genfs.h>
49 
50 #include <fs/sysvbfs/sysvbfs.h>
51 #include <fs/sysvbfs/bfs.h>
52 
53 #ifdef SYSVBFS_VNOPS_DEBUG
54 #define	DPRINTF(fmt, args...)	printf(fmt, ##args)
55 #else
56 #define	DPRINTF(arg...)		((void)0)
57 #endif
58 #define	ROUND_SECTOR(x)		(((x) + 511) & ~511)
59 
60 MALLOC_JUSTDEFINE(M_SYSVBFS_VNODE, "sysvbfs vnode", "sysvbfs vnode structures");
61 MALLOC_DECLARE(M_BFS);
62 
63 int
64 sysvbfs_lookup(void *arg)
65 {
66 	struct vop_lookup_args /* {
67 		struct vnode *a_dvp;
68 		struct vnode **a_vpp;
69 		struct componentname *a_cnp;
70 	} */ *a = arg;
71 	struct vnode *v = a->a_dvp;
72 	struct sysvbfs_node *bnode = v->v_data;
73 	struct bfs *bfs = bnode->bmp->bfs;	/* my filesystem */
74 	struct vnode *vpp = NULL;
75 	struct bfs_dirent *dirent = NULL;
76 	struct componentname *cnp = a->a_cnp;
77 	int nameiop = cnp->cn_nameiop;
78 	const char *name = cnp->cn_nameptr;
79 	int namelen = cnp->cn_namelen;
80 	int error;
81 
82 	DPRINTF("%s: %s op=%d %d\n", __func__, name, nameiop,
83 	    cnp->cn_flags);
84 
85 	*a->a_vpp = NULL;
86 
87 	KASSERT((cnp->cn_flags & ISDOTDOT) == 0);
88 	if ((error = VOP_ACCESS(a->a_dvp, VEXEC, cnp->cn_cred)) != 0) {
89 		return error;	/* directory permission. */
90 	}
91 
92 	if (namelen == 1 && name[0] == '.') {	/* "." */
93 		vref(v);
94 		*a->a_vpp = v;
95 	} else {				/* Regular file */
96 		if (!bfs_dirent_lookup_by_name(bfs, cnp->cn_nameptr,
97 		    &dirent)) {
98 			if (nameiop != CREATE && nameiop != RENAME) {
99 				DPRINTF("%s: no such a file. (1)\n",
100 				    __func__);
101 				return ENOENT;
102 			}
103 			if ((error = VOP_ACCESS(v, VWRITE, cnp->cn_cred)) != 0)
104 				return error;
105 			return EJUSTRETURN;
106 		}
107 
108 		/* Allocate v-node */
109 		if ((error = sysvbfs_vget(v->v_mount, dirent->inode, &vpp)) != 0) {
110 			DPRINTF("%s: can't get vnode.\n", __func__);
111 			return error;
112 		}
113 		*a->a_vpp = vpp;
114 	}
115 
116 	return 0;
117 }
118 
119 int
120 sysvbfs_create(void *arg)
121 {
122 	struct vop_create_args /* {
123 		struct vnode *a_dvp;
124 		struct vnode **a_vpp;
125 		struct componentname *a_cnp;
126 		struct vattr *a_vap;
127 	} */ *a = arg;
128 	struct sysvbfs_node *bnode = a->a_dvp->v_data;
129 	struct sysvbfs_mount *bmp = bnode->bmp;
130 	struct bfs *bfs = bmp->bfs;
131 	struct mount *mp = bmp->mountp;
132 	struct bfs_dirent *dirent;
133 	struct bfs_fileattr attr;
134 	struct vattr *va = a->a_vap;
135 	kauth_cred_t cr = a->a_cnp->cn_cred;
136 	int err = 0;
137 
138 	DPRINTF("%s: %s\n", __func__, a->a_cnp->cn_nameptr);
139 	KDASSERT(a->a_vap->va_type == VREG);
140 	attr.uid = kauth_cred_geteuid(cr);
141 	attr.gid = kauth_cred_getegid(cr);
142 	attr.mode = va->va_mode;
143 
144 	if ((err = bfs_file_create(bfs, a->a_cnp->cn_nameptr, 0, 0, &attr))
145 	    != 0) {
146 		DPRINTF("%s: bfs_file_create failed.\n", __func__);
147 		goto unlock_exit;
148 	}
149 
150 	if (!bfs_dirent_lookup_by_name(bfs, a->a_cnp->cn_nameptr, &dirent))
151 		panic("no dirent for created file.");
152 
153 	if ((err = sysvbfs_vget(mp, dirent->inode, a->a_vpp)) != 0) {
154 		DPRINTF("%s: sysvbfs_vget failed.\n", __func__);
155 		goto unlock_exit;
156 	}
157 	bnode = (*a->a_vpp)->v_data;
158 	bnode->update_ctime = true;
159 	bnode->update_mtime = true;
160 	bnode->update_atime = true;
161 
162  unlock_exit:
163 	/* unlock parent directory */
164 	vput(a->a_dvp);	/* locked at sysvbfs_lookup(); */
165 
166 	return err;
167 }
168 
169 int
170 sysvbfs_open(void *arg)
171 {
172 	struct vop_open_args /* {
173 		struct vnode *a_vp;
174 		int  a_mode;
175 		kauth_cred_t a_cred;
176 	} */ *a = arg;
177 	struct vnode *v = a->a_vp;
178 	struct sysvbfs_node *bnode = v->v_data;
179 	struct bfs_inode *inode = bnode->inode;
180 	struct bfs *bfs = bnode->bmp->bfs;
181 	struct bfs_dirent *dirent;
182 
183 	DPRINTF("%s:\n", __func__);
184 	KDASSERT(v->v_type == VREG || v->v_type == VDIR);
185 
186 	if (!bfs_dirent_lookup_by_inode(bfs, inode->number, &dirent))
187 		return ENOENT;
188 	bnode->update_atime = true;
189 	if ((a->a_mode & FWRITE) && !(a->a_mode & O_APPEND)) {
190 		bnode->size = 0;
191 	} else {
192 		bnode->size = bfs_file_size(inode);
193 	}
194 	bnode->data_block = inode->start_sector;
195 
196 	return 0;
197 }
198 
199 int
200 sysvbfs_close(void *arg)
201 {
202 	struct vop_close_args /* {
203 		struct vnodeop_desc *a_desc;
204 		struct vnode *a_vp;
205 		int  a_fflag;
206 		kauth_cred_t a_cred;
207 	} */ *a = arg;
208 	struct vnode *v = a->a_vp;
209 	struct sysvbfs_node *bnode = v->v_data;
210 	struct bfs_fileattr attr;
211 
212 	DPRINTF("%s:\n", __func__);
213 	uvm_vnp_setsize(v, bnode->size);
214 
215 	memset(&attr, 0xff, sizeof attr);	/* Set VNOVAL all */
216 	if (bnode->update_atime)
217 		attr.atime = time_second;
218 	if (bnode->update_ctime)
219 		attr.ctime = time_second;
220 	if (bnode->update_mtime)
221 		attr.mtime = time_second;
222 	bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr);
223 
224 	VOP_FSYNC(a->a_vp, a->a_cred, FSYNC_WAIT, 0, 0);
225 
226 	return 0;
227 }
228 
229 static int
230 sysvbfs_check_possible(struct vnode *vp, struct sysvbfs_node *bnode,
231     mode_t mode)
232 {
233 
234 	if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
235 		return EROFS;
236 
237 	return 0;
238 }
239 
240 static int
241 sysvbfs_check_permitted(struct vnode *vp, struct sysvbfs_node *bnode,
242     mode_t mode, kauth_cred_t cred)
243 {
244 	struct bfs_fileattr *attr = &bnode->inode->attr;
245 
246 	return genfs_can_access(vp->v_type, attr->mode, attr->uid, attr->gid,
247 	    mode, cred);
248 }
249 
250 int
251 sysvbfs_access(void *arg)
252 {
253 	struct vop_access_args /* {
254 		struct vnode	*a_vp;
255 		int		a_mode;
256 		kauth_cred_t	a_cred;
257 	} */ *ap = arg;
258 	struct vnode *vp = ap->a_vp;
259 	struct sysvbfs_node *bnode = vp->v_data;
260 	int error;
261 
262 	DPRINTF("%s:\n", __func__);
263 
264 	error = sysvbfs_check_possible(vp, bnode, ap->a_mode);
265 	if (error)
266 		return error;
267 
268 	error = sysvbfs_check_permitted(vp, bnode, ap->a_mode, ap->a_cred);
269 
270 	return error;
271 }
272 
273 int
274 sysvbfs_getattr(void *v)
275 {
276 	struct vop_getattr_args /* {
277 		struct vnode *a_vp;
278 		struct vattr *a_vap;
279 		kauth_cred_t a_cred;
280 	} */ *ap = v;
281 	struct vnode *vp = ap->a_vp;
282 	struct sysvbfs_node *bnode = vp->v_data;
283 	struct bfs_inode *inode = bnode->inode;
284 	struct bfs_fileattr *attr = &inode->attr;
285 	struct sysvbfs_mount *bmp = bnode->bmp;
286 	struct vattr *vap = ap->a_vap;
287 
288 	DPRINTF("%s:\n", __func__);
289 
290 	vap->va_type = vp->v_type;
291 	vap->va_mode = attr->mode;
292 	vap->va_nlink = attr->nlink;
293 	vap->va_uid = attr->uid;
294 	vap->va_gid = attr->gid;
295 	vap->va_fsid = bmp->devvp->v_rdev;
296 	vap->va_fileid = inode->number;
297 	vap->va_size = bfs_file_size(inode);
298 	vap->va_blocksize = BFS_BSIZE;
299 	vap->va_atime.tv_sec = attr->atime;
300 	vap->va_mtime.tv_sec = attr->mtime;
301 	vap->va_ctime.tv_sec = attr->ctime;
302 	vap->va_birthtime.tv_sec = 0;
303 	vap->va_gen = 1;
304 	vap->va_flags = 0;
305 	vap->va_rdev = 0;	/* No device file */
306 	vap->va_bytes = vap->va_size;
307 	vap->va_filerev = 0;
308 	vap->va_vaflags = 0;
309 
310 	return 0;
311 }
312 
313 int
314 sysvbfs_setattr(void *arg)
315 {
316 	struct vop_setattr_args /* {
317 		struct vnode *a_vp;
318 		struct vattr *a_vap;
319 		kauth_cred_t a_cred;
320 		struct proc *p;
321 	} */ *ap = arg;
322 	struct vnode *vp = ap->a_vp;
323 	struct vattr *vap = ap->a_vap;
324 	struct sysvbfs_node *bnode = vp->v_data;
325 	struct bfs_inode *inode = bnode->inode;
326 	struct bfs_fileattr *attr = &inode->attr;
327 	struct bfs *bfs = bnode->bmp->bfs;
328 
329 	DPRINTF("%s:\n", __func__);
330 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
331 		return EROFS;
332 
333 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
334 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
335 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
336 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL))
337 		return EINVAL;
338 
339 	if (vap->va_uid != (uid_t)VNOVAL)
340 		attr->uid = vap->va_uid;
341 	if (vap->va_gid != (uid_t)VNOVAL)
342 		attr->gid = vap->va_gid;
343 	if (vap->va_mode != (mode_t)VNOVAL)
344 		attr->mode = vap->va_mode;
345 	if (vap->va_atime.tv_sec != VNOVAL)
346 		attr->atime = vap->va_atime.tv_sec;
347 	if (vap->va_mtime.tv_sec != VNOVAL)
348 		attr->mtime = vap->va_mtime.tv_sec;
349 	if (vap->va_ctime.tv_sec != VNOVAL)
350 		attr->ctime = vap->va_ctime.tv_sec;
351 
352 	bfs_inode_set_attr(bfs, inode, attr);
353 
354 	return 0;
355 }
356 
357 int
358 sysvbfs_read(void *arg)
359 {
360 	struct vop_read_args /* {
361 		struct vnode *a_vp;
362 		struct uio *a_uio;
363 		int a_ioflag;
364 		kauth_cred_t a_cred;
365 	} */ *a = arg;
366 	struct vnode *v = a->a_vp;
367 	struct uio *uio = a->a_uio;
368 	struct sysvbfs_node *bnode = v->v_data;
369 	struct bfs_inode *inode = bnode->inode;
370 	vsize_t sz, filesz = bfs_file_size(inode);
371 	int err;
372 	const int advice = IO_ADV_DECODE(a->a_ioflag);
373 
374 	DPRINTF("%s: type=%d\n", __func__, v->v_type);
375 	if (v->v_type != VREG)
376 		return EINVAL;
377 
378 	while (uio->uio_resid > 0) {
379 		if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0)
380 			break;
381 
382 		err = ubc_uiomove(&v->v_uobj, uio, sz, advice,
383 		    UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(v));
384 		if (err)
385 			break;
386 		DPRINTF("%s: read %ldbyte\n", __func__, sz);
387 	}
388 
389 	return  sysvbfs_update(v, NULL, NULL, UPDATE_WAIT);
390 }
391 
392 int
393 sysvbfs_write(void *arg)
394 {
395 	struct vop_write_args /* {
396 		struct vnode *a_vp;
397 		struct uio *a_uio;
398 		int  a_ioflag;
399 		kauth_cred_t a_cred;
400 	} */ *a = arg;
401 	struct vnode *v = a->a_vp;
402 	struct uio *uio = a->a_uio;
403 	int advice = IO_ADV_DECODE(a->a_ioflag);
404 	struct sysvbfs_node *bnode = v->v_data;
405 	struct bfs_inode *inode = bnode->inode;
406 	bool extended = false;
407 	vsize_t sz;
408 	int err = 0;
409 
410 	if (a->a_vp->v_type != VREG)
411 		return EISDIR;
412 
413 	if (a->a_ioflag & IO_APPEND)
414 		uio->uio_offset = bnode->size;
415 
416 	if (uio->uio_resid == 0)
417 		return 0;
418 
419 	if (bnode->size < uio->uio_offset + uio->uio_resid) {
420 		bnode->size = uio->uio_offset + uio->uio_resid;
421 		uvm_vnp_setsize(v, bnode->size);
422 		extended = true;
423 	}
424 
425 	while (uio->uio_resid > 0) {
426 		sz = uio->uio_resid;
427 		err = ubc_uiomove(&v->v_uobj, uio, sz, advice,
428 		    UBC_WRITE | UBC_UNMAP_FLAG(v));
429 		if (err)
430 			break;
431 		DPRINTF("%s: write %ldbyte\n", __func__, sz);
432 	}
433 	inode->end_sector = bnode->data_block +
434 	    (ROUND_SECTOR(bnode->size) >> DEV_BSHIFT) - 1;
435 	inode->eof_offset_byte = bnode->data_block * DEV_BSIZE +
436 	    bnode->size - 1;
437 	bnode->update_mtime = true;
438 
439 	VN_KNOTE(v, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
440 
441 	return err;
442 }
443 
444 int
445 sysvbfs_remove(void *arg)
446 {
447 	struct vop_remove_args /* {
448 		struct vnodeop_desc *a_desc;
449 		struct vnode * a_dvp;
450 		struct vnode * a_vp;
451 		struct componentname * a_cnp;
452 	} */ *ap = arg;
453 	struct vnode *vp = ap->a_vp;
454 	struct vnode *dvp = ap->a_dvp;
455 	struct sysvbfs_node *bnode = vp->v_data;
456 	struct sysvbfs_mount *bmp = bnode->bmp;
457 	struct bfs *bfs = bmp->bfs;
458 	int err;
459 
460 	DPRINTF("%s: delete %s\n", __func__, ap->a_cnp->cn_nameptr);
461 
462 	if (vp->v_type == VDIR)
463 		return EPERM;
464 
465 	if ((err = bfs_file_delete(bfs, ap->a_cnp->cn_nameptr)) != 0)
466 		DPRINTF("%s: bfs_file_delete failed.\n", __func__);
467 
468 	VN_KNOTE(ap->a_vp, NOTE_DELETE);
469 	VN_KNOTE(ap->a_dvp, NOTE_WRITE);
470 	if (dvp == vp)
471 		vrele(vp);
472 	else
473 		vput(vp);
474 	vput(dvp);
475 
476 	if (err == 0) {
477 		bnode->removed = 1;
478 	}
479 
480 	return err;
481 }
482 
483 int
484 sysvbfs_rename(void *arg)
485 {
486 	struct vop_rename_args /* {
487 		struct vnode *a_fdvp;	from parent-directory v-node
488 		struct vnode *a_fvp;	from file v-node
489 		struct componentname *a_fcnp;
490 		struct vnode *a_tdvp;	to parent-directory
491 		struct vnode *a_tvp;	to file v-node
492 		struct componentname *a_tcnp;
493 	} */ *ap = arg;
494 	struct vnode *fvp = ap->a_fvp;
495 	struct vnode *fdvp = ap->a_fdvp;
496 	struct vnode *tvp = ap->a_tvp;
497 	struct vnode *tdvp = ap->a_tdvp;
498 	struct sysvbfs_node *bnode = fvp->v_data;
499 	struct bfs *bfs = bnode->bmp->bfs;
500 	const char *from_name = ap->a_fcnp->cn_nameptr;
501 	const char *to_name = ap->a_tcnp->cn_nameptr;
502 	int error;
503 
504 	DPRINTF("%s: %s->%s\n", __func__, from_name, to_name);
505 	if ((fvp->v_mount != tdvp->v_mount) ||
506 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
507 		error = EXDEV;
508 		printf("cross-device link\n");
509 		goto out;
510 	}
511 
512 	KDASSERT(fvp->v_type == VREG);
513 	KDASSERT(tvp == NULL ? true : tvp->v_type == VREG);
514 	KASSERT(tdvp == fdvp);
515 
516 	/*
517 	 * Make sure the source hasn't been removed between lookup
518 	 * and target directory lock.
519 	 */
520 	if (bnode->removed) {
521 		error = ENOENT;
522 		goto out;
523 	}
524 
525 	error = bfs_file_rename(bfs, from_name, to_name);
526  out:
527 	if (tvp) {
528 		if (error == 0) {
529 			struct sysvbfs_node *tbnode = tvp->v_data;
530 			tbnode->removed = 1;
531 		}
532 		vput(tvp);
533 	}
534 
535 	/* tdvp == tvp probably can't happen with this fs, but safety first */
536 	if (tdvp == tvp)
537 		vrele(tdvp);
538 	else
539 		vput(tdvp);
540 
541 	vrele(fdvp);
542 	vrele(fvp);
543 
544 	return 0;
545 }
546 
547 int
548 sysvbfs_readdir(void *v)
549 {
550 	struct vop_readdir_args /* {
551 		struct vnode *a_vp;
552 		struct uio *a_uio;
553 		kauth_cred_t a_cred;
554 		int *a_eofflag;
555 		off_t **a_cookies;
556 		int *a_ncookies;
557 	} */ *ap = v;
558 	struct uio *uio = ap->a_uio;
559 	struct vnode *vp = ap->a_vp;
560 	struct sysvbfs_node *bnode = vp->v_data;
561 	struct bfs *bfs = bnode->bmp->bfs;
562 	struct dirent *dp;
563 	struct bfs_dirent *file;
564 	int i, n, error;
565 
566 	DPRINTF("%s: offset=%" PRId64 " residue=%zu\n", __func__,
567 	    uio->uio_offset, uio->uio_resid);
568 
569 	KDASSERT(vp->v_type == VDIR);
570 	KDASSERT(uio->uio_offset >= 0);
571 
572 	dp = malloc(sizeof(struct dirent), M_BFS, M_WAITOK | M_ZERO);
573 
574 	i = uio->uio_offset / sizeof(struct dirent);
575 	n = uio->uio_resid / sizeof(struct dirent);
576 	if ((i + n) > bfs->n_dirent)
577 		n = bfs->n_dirent - i;
578 
579 	for (file = &bfs->dirent[i]; i < n; file++) {
580 		if (file->inode == 0)
581 			continue;
582 		if (i == bfs->max_dirent) {
583 			DPRINTF("%s: file system inconsistent.\n",
584 			    __func__);
585 			break;
586 		}
587 		i++;
588 		memset(dp, 0, sizeof(struct dirent));
589 		dp->d_fileno = file->inode;
590 		dp->d_type = file->inode == BFS_ROOT_INODE ? DT_DIR : DT_REG;
591 		dp->d_namlen = strlen(file->name);
592 		strncpy(dp->d_name, file->name, BFS_FILENAME_MAXLEN);
593 		dp->d_reclen = sizeof(struct dirent);
594 		if ((error = uiomove(dp, dp->d_reclen, uio)) != 0) {
595 			DPRINTF("%s: uiomove failed.\n", __func__);
596 			free(dp, M_BFS);
597 			return error;
598 		}
599 	}
600 	DPRINTF("%s: %d %d %d\n", __func__, i, n, bfs->n_dirent);
601 	*ap->a_eofflag = (i == bfs->n_dirent);
602 
603 	free(dp, M_BFS);
604 	return 0;
605 }
606 
607 int
608 sysvbfs_inactive(void *arg)
609 {
610 	struct vop_inactive_args /* {
611 		struct vnode *a_vp;
612 		bool *a_recycle;
613 	} */ *a = arg;
614 	struct vnode *v = a->a_vp;
615 	struct sysvbfs_node *bnode = v->v_data;
616 
617 	DPRINTF("%s:\n", __func__);
618 	if (bnode->removed)
619 		*a->a_recycle = true;
620 	else
621 		*a->a_recycle = false;
622 	VOP_UNLOCK(v);
623 
624 	return 0;
625 }
626 
627 int
628 sysvbfs_reclaim(void *v)
629 {
630 	extern struct pool sysvbfs_node_pool;
631 	struct vop_reclaim_args /* {
632 		struct vnode *a_vp;
633 	} */ *ap = v;
634 	struct vnode *vp = ap->a_vp;
635 	struct sysvbfs_node *bnode = vp->v_data;
636 
637 	DPRINTF("%s:\n", __func__);
638 	mutex_enter(&mntvnode_lock);
639 	LIST_REMOVE(bnode, link);
640 	mutex_exit(&mntvnode_lock);
641 	cache_purge(vp);
642 	genfs_node_destroy(vp);
643 	pool_put(&sysvbfs_node_pool, bnode);
644 	vp->v_data = NULL;
645 
646 	return 0;
647 }
648 
649 int
650 sysvbfs_bmap(void *arg)
651 {
652 	struct vop_bmap_args /* {
653 		struct vnode *a_vp;
654 		daddr_t  a_bn;
655 		struct vnode **a_vpp;
656 		daddr_t *a_bnp;
657 		int *a_runp;
658 	} */ *a = arg;
659 	struct vnode *v = a->a_vp;
660 	struct sysvbfs_node *bnode = v->v_data;
661 	struct sysvbfs_mount *bmp = bnode->bmp;
662 	struct bfs_inode *inode = bnode->inode;
663 	daddr_t blk;
664 
665 	DPRINTF("%s:\n", __func__);
666 	/* BFS algorithm is contiguous allocation */
667 	blk = inode->start_sector + a->a_bn;
668 
669 	if (blk * BFS_BSIZE > bmp->bfs->data_end)
670 		return ENOSPC;
671 
672 	*a->a_vpp = bmp->devvp;
673 	*a->a_runp = 0;
674 	DPRINTF("%s: %d + %" PRId64 "\n", __func__, inode->start_sector,
675 	    a->a_bn);
676 
677 	*a->a_bnp = blk;
678 
679 
680 	return 0;
681 }
682 
683 int
684 sysvbfs_strategy(void *arg)
685 {
686 	struct vop_strategy_args /* {
687 		struct vnode *a_vp;
688 		struct buf *a_bp;
689 	} */ *a = arg;
690 	struct buf *b = a->a_bp;
691 	struct vnode *v = a->a_vp;
692 	struct sysvbfs_node *bnode = v->v_data;
693 	struct sysvbfs_mount *bmp = bnode->bmp;
694 	int error;
695 
696 	DPRINTF("%s:\n", __func__);
697 	KDASSERT(v->v_type == VREG);
698 	if (b->b_blkno == b->b_lblkno) {
699 		error = VOP_BMAP(v, b->b_lblkno, NULL, &b->b_blkno, NULL);
700 		if (error) {
701 			b->b_error = error;
702 			biodone(b);
703 			return error;
704 		}
705 		if ((long)b->b_blkno == -1)
706 			clrbuf(b);
707 	}
708 	if ((long)b->b_blkno == -1) {
709 		biodone(b);
710 		return 0;
711 	}
712 
713 	return VOP_STRATEGY(bmp->devvp, b);
714 }
715 
716 int
717 sysvbfs_print(void *v)
718 {
719 	struct vop_print_args /* {
720 		struct vnode *a_vp;
721 	} */ *ap = v;
722 	struct sysvbfs_node *bnode = ap->a_vp->v_data;
723 
724 	DPRINTF("%s:\n", __func__);
725 	bfs_dump(bnode->bmp->bfs);
726 
727 	return 0;
728 }
729 
730 int
731 sysvbfs_advlock(void *v)
732 {
733 	struct vop_advlock_args /* {
734 		struct vnode *a_vp;
735 		void *a_id;
736 		int a_op;
737 		struct flock *a_fl;
738 		int a_flags;
739 	} */ *ap = v;
740 	struct sysvbfs_node *bnode = ap->a_vp->v_data;
741 
742 	DPRINTF("%s: op=%d\n", __func__, ap->a_op);
743 
744 	return lf_advlock(ap, &bnode->lockf, bfs_file_size(bnode->inode));
745 }
746 
747 int
748 sysvbfs_pathconf(void *v)
749 {
750 	struct vop_pathconf_args /* {
751 		struct vnode *a_vp;
752 		int a_name;
753 		register_t *a_retval;
754 	} */ *ap = v;
755 	int err = 0;
756 
757 	DPRINTF("%s:\n", __func__);
758 
759 	switch (ap->a_name) {
760 	case _PC_LINK_MAX:
761 		*ap->a_retval = 1;
762 		break;
763 	case _PC_NAME_MAX:
764 		*ap->a_retval = BFS_FILENAME_MAXLEN;
765 		break;
766 	case _PC_PATH_MAX:
767 		*ap->a_retval = BFS_FILENAME_MAXLEN;
768 		break;
769 	case _PC_CHOWN_RESTRICTED:
770 		*ap->a_retval = 1;
771 		break;
772 	case _PC_NO_TRUNC:
773 		*ap->a_retval = 0;
774 		break;
775 	case _PC_SYNC_IO:
776 		*ap->a_retval = 1;
777 		break;
778 	case _PC_FILESIZEBITS:
779 		*ap->a_retval = 32;
780 		break;
781 	default:
782 		err = EINVAL;
783 		break;
784 	}
785 
786 	return err;
787 }
788 
789 int
790 sysvbfs_fsync(void *v)
791 {
792 	struct vop_fsync_args /* {
793 		struct vnode *a_vp;
794 		kauth_cred_t a_cred;
795 		int a_flags;
796 		off_t offlo;
797 		off_t offhi;
798 	} */ *ap = v;
799 	struct vnode *vp = ap->a_vp;
800 	int error, wait;
801 
802 	if (ap->a_flags & FSYNC_CACHE) {
803 		return EOPNOTSUPP;
804 	}
805 
806 	wait = (ap->a_flags & FSYNC_WAIT) != 0;
807 	vflushbuf(vp, wait);
808 
809 	if ((ap->a_flags & FSYNC_DATAONLY) != 0)
810 		error = 0;
811 	else
812 		error = sysvbfs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
813 
814 	return error;
815 }
816 
817 int
818 sysvbfs_update(struct vnode *vp, const struct timespec *acc,
819     const struct timespec *mod, int flags)
820 {
821 	struct sysvbfs_node *bnode = vp->v_data;
822 	struct bfs_fileattr attr;
823 
824 	DPRINTF("%s:\n", __func__);
825 	memset(&attr, 0xff, sizeof attr);	/* Set VNOVAL all */
826 	if (bnode->update_atime) {
827 		attr.atime = acc ? acc->tv_sec : time_second;
828 		bnode->update_atime = false;
829 	}
830 	if (bnode->update_ctime) {
831 		attr.ctime = time_second;
832 		bnode->update_ctime = false;
833 	}
834 	if (bnode->update_mtime) {
835 		attr.mtime = mod ? mod->tv_sec : time_second;
836 		bnode->update_mtime = false;
837 	}
838 	bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr);
839 
840 	return 0;
841 }
842