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