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