xref: /openbsd-src/sys/kern/vfs_vops.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: vfs_vops.c,v 1.29 2020/10/07 12:33:03 mpi Exp $	*/
2 /*
3  * Copyright (c) 2010 Thordur I. Bjornsson <thib@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Copyright (c) 1992, 1993
18  *	The Regents of the University of California.  All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright
26  *    notice, this list of conditions and the following disclaimer in the
27  *    documentation and/or other materials provided with the distribution.
28  * 3. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/vnode.h>
47 #include <sys/unistd.h>
48 #include <sys/systm.h>
49 
50 #ifdef VFSLCKDEBUG
51 #include <sys/systm.h>		/* for panic() */
52 
53 #define ASSERT_VP_ISLOCKED(vp) do {				\
54 	if (((vp)->v_flag & VLOCKSWORK) && !VOP_ISLOCKED(vp)) {	\
55 		VOP_PRINT(vp);					\
56 		panic("vp not locked");				\
57 	}							\
58 } while (0)
59 #else
60 #define ASSERT_VP_ISLOCKED(vp)  /* nothing */
61 #endif
62 
63 int
64 VOP_ISLOCKED(struct vnode *vp)
65 {
66 	struct vop_islocked_args a;
67 	a.a_vp = vp;
68 
69 	if (vp->v_op->vop_islocked == NULL)
70 		return (EOPNOTSUPP);
71 
72 	return ((vp->v_op->vop_islocked)(&a));
73 }
74 
75 int
76 VOP_LOOKUP(struct vnode *dvp, struct vnode **vpp,
77     struct componentname *cnp)
78 {
79 	int r;
80 	struct vop_lookup_args a;
81 	a.a_dvp = dvp;
82 	a.a_vpp = vpp;
83 	a.a_cnp = cnp;
84 
85 	if (dvp->v_op->vop_lookup == NULL)
86 		return (EOPNOTSUPP);
87 
88 	dvp->v_inflight++;
89 	r = (dvp->v_op->vop_lookup)(&a);
90 	dvp->v_inflight--;
91 	return r;
92 }
93 
94 int
95 VOP_CREATE(struct vnode *dvp, struct vnode **vpp,
96     struct componentname *cnp, struct vattr *vap)
97 {
98 	int r;
99 	struct vop_create_args a;
100 	a.a_dvp = dvp;
101 	a.a_vpp = vpp;
102 	a.a_cnp = cnp;
103 	a.a_vap = vap;
104 
105 	ASSERT_VP_ISLOCKED(dvp);
106 
107 	if (dvp->v_op->vop_create == NULL)
108 		return (EOPNOTSUPP);
109 
110 	dvp->v_inflight++;
111 	r = (dvp->v_op->vop_create)(&a);
112 	dvp->v_inflight--;
113 	return r;
114 }
115 
116 int
117 VOP_MKNOD(struct vnode *dvp, struct vnode **vpp,
118     struct componentname *cnp, struct vattr *vap)
119 {
120 	int r;
121 	struct vop_mknod_args a;
122 	a.a_dvp = dvp;
123 	a.a_vpp = vpp;
124 	a.a_cnp = cnp;
125 	a.a_vap = vap;
126 
127 	ASSERT_VP_ISLOCKED(dvp);
128 
129 	if (dvp->v_op->vop_mknod == NULL)
130 		return (EOPNOTSUPP);
131 
132 	dvp->v_inflight++;
133 	r = (dvp->v_op->vop_mknod)(&a);
134 	dvp->v_inflight--;
135 	return r;
136 }
137 
138 int
139 VOP_OPEN(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
140 {
141 	int r;
142 	struct vop_open_args a;
143 	a.a_vp = vp;
144 	a.a_mode = mode;
145 	a.a_cred = cred;
146 	a.a_p = p;
147 
148 	KASSERT(p == curproc);
149 
150 	if (vp->v_op->vop_open == NULL)
151 		return (EOPNOTSUPP);
152 
153 	vp->v_inflight++;
154 	r = (vp->v_op->vop_open)(&a);
155 	vp->v_inflight--;
156 	return r;
157 }
158 
159 int
160 VOP_CLOSE(struct vnode *vp, int fflag, struct ucred *cred, struct proc *p)
161 {
162 	int r;
163 	struct vop_close_args a;
164 	a.a_vp = vp;
165 	a.a_fflag = fflag;
166 	a.a_cred = cred;
167 	a.a_p = p;
168 
169 	KASSERT(p == NULL || p == curproc);
170 	ASSERT_VP_ISLOCKED(vp);
171 
172 	if (vp->v_op->vop_close == NULL)
173 		return (EOPNOTSUPP);
174 
175 	vp->v_inflight++;
176 	r = (vp->v_op->vop_close)(&a);
177 	vp->v_inflight--;
178 	return r;
179 }
180 
181 int
182 VOP_ACCESS(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
183 {
184 	struct vop_access_args a;
185 	a.a_vp = vp;
186 	a.a_mode = mode;
187 	a.a_cred = cred;
188 	a.a_p = p;
189 
190 	KASSERT(p == curproc);
191 	ASSERT_VP_ISLOCKED(vp);
192 
193 	if (vp->v_op->vop_access == NULL)
194 		return (EOPNOTSUPP);
195 
196 	return ((vp->v_op->vop_access)(&a));
197 }
198 
199 int
200 VOP_GETATTR(struct vnode *vp, struct vattr *vap, struct ucred *cred,
201     struct proc *p)
202 {
203 	struct vop_getattr_args a;
204 	a.a_vp = vp;
205 	a.a_vap = vap;
206 	a.a_cred = cred;
207 	a.a_p = p;
208 
209 	KASSERT(p == curproc);
210 	if (vp->v_op->vop_getattr == NULL)
211 		return (EOPNOTSUPP);
212 
213 	return ((vp->v_op->vop_getattr)(&a));
214 }
215 
216 int
217 VOP_SETATTR(struct vnode *vp, struct vattr *vap, struct ucred *cred,
218     struct proc *p)
219 {
220 	int r;
221 	struct vop_setattr_args a;
222 	a.a_vp = vp;
223 	a.a_vap = vap;
224 	a.a_cred = cred;
225 	a.a_p = p;
226 
227 	KASSERT(p == curproc);
228 	ASSERT_VP_ISLOCKED(vp);
229 
230 	if (vp->v_op->vop_setattr == NULL)
231 		return (EOPNOTSUPP);
232 
233 	vp->v_inflight++;
234 	r = (vp->v_op->vop_setattr)(&a);
235 	vp->v_inflight--;
236 	return r;
237 }
238 
239 int
240 VOP_READ(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
241 {
242 	struct vop_read_args a;
243 	a.a_vp = vp;
244 	a.a_uio = uio;
245 	a.a_ioflag = ioflag;
246 	a.a_cred = cred;
247 
248 	ASSERT_VP_ISLOCKED(vp);
249 
250 	if (vp->v_op->vop_read == NULL)
251 		return (EOPNOTSUPP);
252 
253 	return ((vp->v_op->vop_read)(&a));
254 }
255 
256 int
257 VOP_WRITE(struct vnode *vp, struct uio *uio, int ioflag,
258     struct ucred *cred)
259 {
260 	int r;
261 	struct vop_write_args a;
262 	a.a_vp = vp;
263 	a.a_uio = uio;
264 	a.a_ioflag = ioflag;
265 	a.a_cred = cred;
266 
267 	ASSERT_VP_ISLOCKED(vp);
268 
269 	if (vp->v_op->vop_write == NULL)
270 		return (EOPNOTSUPP);
271 
272 	vp->v_inflight++;
273 	r = (vp->v_op->vop_write)(&a);
274 	vp->v_inflight--;
275 	return r;
276 }
277 
278 int
279 VOP_IOCTL(struct vnode *vp, u_long command, void *data, int fflag,
280     struct ucred *cred, struct proc *p)
281 {
282 	int r;
283 	struct vop_ioctl_args a;
284 	a.a_vp = vp;
285 	a.a_command = command;
286 	a.a_data = data;
287 	a.a_fflag = fflag;
288 	a.a_cred = cred;
289 	a.a_p = p;
290 
291 	KASSERT(p == curproc);
292 	if (vp->v_op->vop_ioctl == NULL)
293 		return (EOPNOTSUPP);
294 
295 	vp->v_inflight++;
296 	r = (vp->v_op->vop_ioctl)(&a);
297 	vp->v_inflight--;
298 	return r;
299 }
300 
301 int
302 VOP_POLL(struct vnode *vp, int fflag, int events, struct proc *p)
303 {
304 	struct vop_poll_args a;
305 	a.a_vp = vp;
306 	a.a_fflag = fflag;
307 	a.a_events = events;
308 	a.a_p = p;
309 
310 	KASSERT(p == curproc);
311 	if (vp->v_op->vop_poll == NULL)
312 		return (EOPNOTSUPP);
313 
314 	return ((vp->v_op->vop_poll)(&a));
315 }
316 
317 int
318 VOP_KQFILTER(struct vnode *vp, int fflag, struct knote *kn)
319 {
320 	struct vop_kqfilter_args a;
321 	a.a_vp = vp;
322 	a.a_fflag = fflag;
323 	a.a_kn = kn;
324 
325 	if (vp->v_op->vop_kqfilter == NULL)
326 		return (EOPNOTSUPP);
327 
328 	return ((vp->v_op->vop_kqfilter)(&a));
329 }
330 
331 int
332 VOP_REVOKE(struct vnode *vp, int flags)
333 {
334 	struct vop_revoke_args a;
335 	a.a_vp = vp;
336 	a.a_flags = flags;
337 
338 	if (vp->v_op->vop_revoke == NULL)
339 		return (EOPNOTSUPP);
340 
341 	return ((vp->v_op->vop_revoke)(&a));
342 }
343 
344 int
345 VOP_FSYNC(struct vnode *vp, struct ucred *cred, int waitfor,
346     struct proc *p)
347 {
348 	int r, s;
349 	struct vop_fsync_args a;
350 	a.a_vp = vp;
351 	a.a_cred = cred;
352 	a.a_waitfor = waitfor;
353 	a.a_p = p;
354 
355 	KASSERT(p == curproc);
356 	ASSERT_VP_ISLOCKED(vp);
357 
358 	if (vp->v_op->vop_fsync == NULL)
359 		return (EOPNOTSUPP);
360 
361 	vp->v_inflight++;
362 	r = (vp->v_op->vop_fsync)(&a);
363 	vp->v_inflight--;
364 	s = splbio();
365 	if (r == 0 && vp->v_bioflag & VBIOERROR)
366 		r = EIO;
367 	splx(s);
368 	return r;
369 }
370 
371 int
372 VOP_REMOVE(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
373 {
374 	int r;
375 	struct vop_remove_args a;
376 	a.a_dvp = dvp;
377         a.a_vp = vp;
378 	a.a_cnp = cnp;
379 
380 	ASSERT_VP_ISLOCKED(dvp);
381 	ASSERT_VP_ISLOCKED(vp);
382 
383 	if (dvp->v_op->vop_remove == NULL)
384 		return (EOPNOTSUPP);
385 
386 	dvp->v_inflight++;
387 	r = (dvp->v_op->vop_remove)(&a);
388 	dvp->v_inflight--;
389 	return r;
390 }
391 
392 int
393 VOP_LINK(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
394 {
395 	int r;
396 	struct vop_link_args a;
397 	a.a_dvp = dvp;
398 	a.a_vp = vp;
399 	a.a_cnp = cnp;
400 
401 	ASSERT_VP_ISLOCKED(dvp);
402 
403 	if (dvp->v_op->vop_link == NULL)
404 		return (EOPNOTSUPP);
405 
406 	dvp->v_inflight++;
407 	vp->v_inflight++;
408 	r = (dvp->v_op->vop_link)(&a);
409 	dvp->v_inflight--;
410 	vp->v_inflight--;
411 	return r;
412 }
413 
414 int
415 VOP_RENAME(struct vnode *fdvp, struct vnode *fvp,
416     struct componentname *fcnp, struct vnode *tdvp, struct vnode *tvp,
417     struct componentname *tcnp)
418 {
419 	int r;
420 	struct vop_rename_args a;
421 	a.a_fdvp = fdvp;
422 	a.a_fvp = fvp;
423 	a.a_fcnp = fcnp;
424 	a.a_tdvp = tdvp;
425 	a.a_tvp = tvp;
426 	a.a_tcnp = tcnp;
427 
428 	ASSERT_VP_ISLOCKED(tdvp);
429 
430 	if (fdvp->v_op->vop_rename == NULL)
431 		return (EOPNOTSUPP);
432 
433 	fdvp->v_inflight++;
434 	tdvp->v_inflight++;
435 	r = (fdvp->v_op->vop_rename)(&a);
436 	fdvp->v_inflight--;
437 	tdvp->v_inflight--;
438 	return r;
439 }
440 
441 int
442 VOP_MKDIR(struct vnode *dvp, struct vnode **vpp,
443     struct componentname *cnp, struct vattr *vap)
444 {
445 	int r;
446 	struct vop_mkdir_args a;
447 	a.a_dvp = dvp;
448 	a.a_vpp = vpp;
449 	a.a_cnp = cnp;
450 	a.a_vap = vap;
451 
452 	ASSERT_VP_ISLOCKED(dvp);
453 
454 	if (dvp->v_op->vop_mkdir == NULL)
455 		return (EOPNOTSUPP);
456 
457 	dvp->v_inflight++;
458 	r = (dvp->v_op->vop_mkdir)(&a);
459 	dvp->v_inflight--;
460 	return r;
461 }
462 
463 int
464 VOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
465 {
466 	int r;
467 	struct vop_rmdir_args a;
468 	a.a_dvp = dvp;
469 	a.a_vp = vp;
470 	a.a_cnp = cnp;
471 
472 	ASSERT_VP_ISLOCKED(dvp);
473 	ASSERT_VP_ISLOCKED(vp);
474 
475 	KASSERT(dvp != vp);
476 
477 	if (dvp->v_op->vop_rmdir == NULL)
478 		return (EOPNOTSUPP);
479 
480 	dvp->v_inflight++;
481 	vp->v_inflight++;
482 	r = (dvp->v_op->vop_rmdir)(&a);
483 	dvp->v_inflight--;
484 	vp->v_inflight--;
485 	return r;
486 }
487 
488 int
489 VOP_SYMLINK(struct vnode *dvp, struct vnode **vpp,
490     struct componentname *cnp, struct vattr *vap, char *target)
491 {
492 	int r;
493 	struct vop_symlink_args a;
494 	a.a_dvp = dvp;
495 	a.a_vpp = vpp;
496 	a.a_cnp = cnp;
497 	a.a_vap = vap;
498 	a.a_target = target;
499 
500 	ASSERT_VP_ISLOCKED(dvp);
501 
502 	if (dvp->v_op->vop_symlink == NULL)
503 		return (EOPNOTSUPP);
504 
505 	dvp->v_inflight++;
506 	r = (dvp->v_op->vop_symlink)(&a);
507 	dvp->v_inflight--;
508 	return r;
509 }
510 
511 int
512 VOP_READDIR(struct vnode *vp, struct uio *uio, struct ucred *cred,
513     int *eofflag)
514 {
515 	int r;
516 	struct vop_readdir_args a;
517 	a.a_vp = vp;
518 	a.a_uio = uio;
519 	a.a_cred = cred;
520 	a.a_eofflag = eofflag;
521 
522 	ASSERT_VP_ISLOCKED(vp);
523 
524 	if (vp->v_op->vop_readdir == NULL)
525 		return (EOPNOTSUPP);
526 
527 	vp->v_inflight++;
528 	r = (vp->v_op->vop_readdir)(&a);
529 	vp->v_inflight--;
530 	return r;
531 }
532 
533 int
534 VOP_READLINK(struct vnode *vp, struct uio *uio, struct ucred *cred)
535 {
536 	int r;
537 	struct vop_readlink_args a;
538 	a.a_vp = vp;
539 	a.a_uio = uio;
540 	a.a_cred = cred;
541 
542 	ASSERT_VP_ISLOCKED(vp);
543 
544 	if (vp->v_op->vop_readlink == NULL)
545 		return (EOPNOTSUPP);
546 
547 	vp->v_inflight++;
548 	r = (vp->v_op->vop_readlink)(&a);
549 	vp->v_inflight--;
550 	return r;
551 }
552 
553 int
554 VOP_ABORTOP(struct vnode *dvp, struct componentname *cnp)
555 {
556 	int r;
557 	struct vop_abortop_args a;
558 	a.a_dvp = dvp;
559 	a.a_cnp = cnp;
560 
561 	if (dvp->v_op->vop_abortop == NULL)
562 		return (EOPNOTSUPP);
563 
564 	dvp->v_inflight++;
565 	r = (dvp->v_op->vop_abortop)(&a);
566 	dvp->v_inflight--;
567 	return r;
568 }
569 
570 int
571 VOP_INACTIVE(struct vnode *vp, struct proc *p)
572 {
573 	struct vop_inactive_args a;
574 	a.a_vp = vp;
575 	a.a_p = p;
576 
577 	KASSERT(p == curproc);
578 	ASSERT_VP_ISLOCKED(vp);
579 
580 	if (vp->v_op->vop_inactive == NULL)
581 		return (EOPNOTSUPP);
582 
583 	return ((vp->v_op->vop_inactive)(&a));
584 }
585 
586 int
587 VOP_RECLAIM(struct vnode *vp, struct proc *p)
588 {
589 	int r;
590 	struct vop_reclaim_args a;
591 	a.a_vp = vp;
592 	a.a_p = p;
593 
594 	KASSERT(p == curproc);
595 	if (vp->v_op->vop_reclaim == NULL)
596 		return (EOPNOTSUPP);
597 
598 	vp->v_inflight++;
599 	r = (vp->v_op->vop_reclaim)(&a);
600 	vp->v_inflight--;
601 	return r;
602 }
603 
604 int
605 VOP_LOCK(struct vnode *vp, int flags)
606 {
607 	struct vop_lock_args a;
608 	a.a_vp = vp;
609 	a.a_flags = flags;
610 
611 	if (vp->v_op->vop_lock == NULL)
612 		return (EOPNOTSUPP);
613 
614 	return ((vp->v_op->vop_lock)(&a));
615 }
616 
617 int
618 VOP_UNLOCK(struct vnode *vp)
619 {
620 	struct vop_unlock_args a;
621 	a.a_vp = vp;
622 
623 	if (vp->v_op->vop_unlock == NULL)
624 		return (EOPNOTSUPP);
625 
626 	return ((vp->v_op->vop_unlock)(&a));
627 }
628 
629 int
630 VOP_BMAP(struct vnode *vp, daddr_t bn, struct vnode **vpp,
631     daddr_t *bnp, int *runp)
632 {
633 	struct vop_bmap_args a;
634 	a.a_vp = vp;
635 	a.a_bn = bn;
636 	a.a_vpp = vpp;
637 	a.a_bnp = bnp;
638 	a.a_runp = runp;
639 
640 	ASSERT_VP_ISLOCKED(vp);
641 
642 	if (vp->v_op->vop_bmap == NULL)
643 		return (EOPNOTSUPP);
644 
645 	return ((vp->v_op->vop_bmap)(&a));
646 }
647 
648 int
649 VOP_PRINT(struct vnode *vp)
650 {
651 	struct vop_print_args a;
652 	a.a_vp = vp;
653 
654 	if (vp->v_op->vop_print == NULL)
655 		return (EOPNOTSUPP);
656 
657 	return ((vp->v_op->vop_print)(&a));
658 }
659 
660 int
661 VOP_PATHCONF(struct vnode *vp, int name, register_t *retval)
662 {
663 	struct vop_pathconf_args a;
664 
665 	/*
666 	 * Handle names that are constant across filesystem
667 	 */
668 	switch (name) {
669 	case _PC_PATH_MAX:
670 		*retval = PATH_MAX;
671 		return (0);
672 	case _PC_PIPE_BUF:
673 		*retval = PIPE_BUF;
674 		return (0);
675 	case _PC_ASYNC_IO:
676 	case _PC_PRIO_IO:
677 	case _PC_SYNC_IO:
678 		*retval = 0;
679 		return (0);
680 
681 	}
682 
683 	a.a_vp = vp;
684 	a.a_name = name;
685 	a.a_retval = retval;
686 
687 	ASSERT_VP_ISLOCKED(vp);
688 
689 	if (vp->v_op->vop_pathconf == NULL)
690 		return (EOPNOTSUPP);
691 
692 	return ((vp->v_op->vop_pathconf)(&a));
693 }
694 
695 int
696 VOP_ADVLOCK(struct vnode *vp, void *id, int op, struct flock *fl, int flags)
697 {
698 	struct vop_advlock_args a;
699 	a.a_vp = vp;
700 	a.a_id = id;
701 	a.a_op = op;
702 	a.a_fl = fl;
703 	a.a_flags = flags;
704 
705 	if (vp->v_op->vop_advlock == NULL)
706 		return (EOPNOTSUPP);
707 
708 	return (vp->v_op->vop_advlock)(&a);
709 }
710 
711 int
712 VOP_STRATEGY(struct buf *bp)
713 {
714 	struct vop_strategy_args a;
715 	a.a_bp = bp;
716 
717 	if ((ISSET(bp->b_flags, B_BC)) && (!ISSET(bp->b_flags, B_DMA)))
718 		panic("Non dma reachable buffer passed to VOP_STRATEGY");
719 
720 	if (bp->b_vp->v_op->vop_strategy == NULL)
721 		return (EOPNOTSUPP);
722 
723 	return ((bp->b_vp->v_op->vop_strategy)(&a));
724 }
725 
726 int
727 VOP_BWRITE(struct buf *bp)
728 {
729 	struct vop_bwrite_args a;
730 	a.a_bp = bp;
731 
732 	if (bp->b_vp->v_op->vop_bwrite == NULL)
733 		return (EOPNOTSUPP);
734 
735 	return ((bp->b_vp->v_op->vop_bwrite)(&a));
736 }
737