xref: /openbsd/sys/kern/vfs_vops.c (revision 771fbea0)
1 /*	$OpenBSD: vfs_vops.c,v 1.30 2021/04/28 09:53:53 claudio 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 #define ASSERT_VP_ISLOCKED(vp) do {				\
52 	if (((vp)->v_flag & VLOCKSWORK) && !VOP_ISLOCKED(vp)) {	\
53 		VOP_PRINT(vp);					\
54 		panic("vp not locked");				\
55 	}							\
56 } while (0)
57 #else
58 #define ASSERT_VP_ISLOCKED(vp)  /* nothing */
59 #endif
60 
61 int
62 VOP_ISLOCKED(struct vnode *vp)
63 {
64 	struct vop_islocked_args a;
65 	a.a_vp = vp;
66 
67 	if (vp->v_op->vop_islocked == NULL)
68 		return (EOPNOTSUPP);
69 
70 	return ((vp->v_op->vop_islocked)(&a));
71 }
72 
73 int
74 VOP_LOOKUP(struct vnode *dvp, struct vnode **vpp,
75     struct componentname *cnp)
76 {
77 	int r;
78 	struct vop_lookup_args a;
79 	a.a_dvp = dvp;
80 	a.a_vpp = vpp;
81 	a.a_cnp = cnp;
82 
83 	if (dvp->v_op->vop_lookup == NULL)
84 		return (EOPNOTSUPP);
85 
86 	dvp->v_inflight++;
87 	r = (dvp->v_op->vop_lookup)(&a);
88 	dvp->v_inflight--;
89 	return r;
90 }
91 
92 int
93 VOP_CREATE(struct vnode *dvp, struct vnode **vpp,
94     struct componentname *cnp, struct vattr *vap)
95 {
96 	int r;
97 	struct vop_create_args a;
98 	a.a_dvp = dvp;
99 	a.a_vpp = vpp;
100 	a.a_cnp = cnp;
101 	a.a_vap = vap;
102 
103 	ASSERT_VP_ISLOCKED(dvp);
104 
105 	if (dvp->v_op->vop_create == NULL)
106 		return (EOPNOTSUPP);
107 
108 	dvp->v_inflight++;
109 	r = (dvp->v_op->vop_create)(&a);
110 	dvp->v_inflight--;
111 	return r;
112 }
113 
114 int
115 VOP_MKNOD(struct vnode *dvp, struct vnode **vpp,
116     struct componentname *cnp, struct vattr *vap)
117 {
118 	int r;
119 	struct vop_mknod_args a;
120 	a.a_dvp = dvp;
121 	a.a_vpp = vpp;
122 	a.a_cnp = cnp;
123 	a.a_vap = vap;
124 
125 	ASSERT_VP_ISLOCKED(dvp);
126 
127 	if (dvp->v_op->vop_mknod == NULL)
128 		return (EOPNOTSUPP);
129 
130 	dvp->v_inflight++;
131 	r = (dvp->v_op->vop_mknod)(&a);
132 	dvp->v_inflight--;
133 	return r;
134 }
135 
136 int
137 VOP_OPEN(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
138 {
139 	int r;
140 	struct vop_open_args a;
141 	a.a_vp = vp;
142 	a.a_mode = mode;
143 	a.a_cred = cred;
144 	a.a_p = p;
145 
146 	KASSERT(p == curproc);
147 
148 	if (vp->v_op->vop_open == NULL)
149 		return (EOPNOTSUPP);
150 
151 	vp->v_inflight++;
152 	r = (vp->v_op->vop_open)(&a);
153 	vp->v_inflight--;
154 	return r;
155 }
156 
157 int
158 VOP_CLOSE(struct vnode *vp, int fflag, struct ucred *cred, struct proc *p)
159 {
160 	int r;
161 	struct vop_close_args a;
162 	a.a_vp = vp;
163 	a.a_fflag = fflag;
164 	a.a_cred = cred;
165 	a.a_p = p;
166 
167 	KASSERT(p == NULL || p == curproc);
168 	ASSERT_VP_ISLOCKED(vp);
169 
170 	if (vp->v_op->vop_close == NULL)
171 		return (EOPNOTSUPP);
172 
173 	vp->v_inflight++;
174 	r = (vp->v_op->vop_close)(&a);
175 	vp->v_inflight--;
176 	return r;
177 }
178 
179 int
180 VOP_ACCESS(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
181 {
182 	struct vop_access_args a;
183 	a.a_vp = vp;
184 	a.a_mode = mode;
185 	a.a_cred = cred;
186 	a.a_p = p;
187 
188 	KASSERT(p == curproc);
189 	ASSERT_VP_ISLOCKED(vp);
190 
191 	if (vp->v_op->vop_access == NULL)
192 		return (EOPNOTSUPP);
193 
194 	return ((vp->v_op->vop_access)(&a));
195 }
196 
197 int
198 VOP_GETATTR(struct vnode *vp, struct vattr *vap, struct ucred *cred,
199     struct proc *p)
200 {
201 	struct vop_getattr_args a;
202 	a.a_vp = vp;
203 	a.a_vap = vap;
204 	a.a_cred = cred;
205 	a.a_p = p;
206 
207 	KASSERT(p == curproc);
208 	if (vp->v_op->vop_getattr == NULL)
209 		return (EOPNOTSUPP);
210 
211 	return ((vp->v_op->vop_getattr)(&a));
212 }
213 
214 int
215 VOP_SETATTR(struct vnode *vp, struct vattr *vap, struct ucred *cred,
216     struct proc *p)
217 {
218 	int r;
219 	struct vop_setattr_args a;
220 	a.a_vp = vp;
221 	a.a_vap = vap;
222 	a.a_cred = cred;
223 	a.a_p = p;
224 
225 	KASSERT(p == curproc);
226 	ASSERT_VP_ISLOCKED(vp);
227 
228 	if (vp->v_op->vop_setattr == NULL)
229 		return (EOPNOTSUPP);
230 
231 	vp->v_inflight++;
232 	r = (vp->v_op->vop_setattr)(&a);
233 	vp->v_inflight--;
234 	return r;
235 }
236 
237 int
238 VOP_READ(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
239 {
240 	struct vop_read_args a;
241 	a.a_vp = vp;
242 	a.a_uio = uio;
243 	a.a_ioflag = ioflag;
244 	a.a_cred = cred;
245 
246 	ASSERT_VP_ISLOCKED(vp);
247 
248 	if (vp->v_op->vop_read == NULL)
249 		return (EOPNOTSUPP);
250 
251 	return ((vp->v_op->vop_read)(&a));
252 }
253 
254 int
255 VOP_WRITE(struct vnode *vp, struct uio *uio, int ioflag,
256     struct ucred *cred)
257 {
258 	int r;
259 	struct vop_write_args a;
260 	a.a_vp = vp;
261 	a.a_uio = uio;
262 	a.a_ioflag = ioflag;
263 	a.a_cred = cred;
264 
265 	ASSERT_VP_ISLOCKED(vp);
266 
267 	if (vp->v_op->vop_write == NULL)
268 		return (EOPNOTSUPP);
269 
270 	vp->v_inflight++;
271 	r = (vp->v_op->vop_write)(&a);
272 	vp->v_inflight--;
273 	return r;
274 }
275 
276 int
277 VOP_IOCTL(struct vnode *vp, u_long command, void *data, int fflag,
278     struct ucred *cred, struct proc *p)
279 {
280 	int r;
281 	struct vop_ioctl_args a;
282 	a.a_vp = vp;
283 	a.a_command = command;
284 	a.a_data = data;
285 	a.a_fflag = fflag;
286 	a.a_cred = cred;
287 	a.a_p = p;
288 
289 	KASSERT(p == curproc);
290 	if (vp->v_op->vop_ioctl == NULL)
291 		return (EOPNOTSUPP);
292 
293 	vp->v_inflight++;
294 	r = (vp->v_op->vop_ioctl)(&a);
295 	vp->v_inflight--;
296 	return r;
297 }
298 
299 int
300 VOP_POLL(struct vnode *vp, int fflag, int events, struct proc *p)
301 {
302 	struct vop_poll_args a;
303 	a.a_vp = vp;
304 	a.a_fflag = fflag;
305 	a.a_events = events;
306 	a.a_p = p;
307 
308 	KASSERT(p == curproc);
309 	if (vp->v_op->vop_poll == NULL)
310 		return (EOPNOTSUPP);
311 
312 	return ((vp->v_op->vop_poll)(&a));
313 }
314 
315 int
316 VOP_KQFILTER(struct vnode *vp, int fflag, struct knote *kn)
317 {
318 	struct vop_kqfilter_args a;
319 	a.a_vp = vp;
320 	a.a_fflag = fflag;
321 	a.a_kn = kn;
322 
323 	if (vp->v_op->vop_kqfilter == NULL)
324 		return (EOPNOTSUPP);
325 
326 	return ((vp->v_op->vop_kqfilter)(&a));
327 }
328 
329 int
330 VOP_REVOKE(struct vnode *vp, int flags)
331 {
332 	struct vop_revoke_args a;
333 	a.a_vp = vp;
334 	a.a_flags = flags;
335 
336 	if (vp->v_op->vop_revoke == NULL)
337 		return (EOPNOTSUPP);
338 
339 	return ((vp->v_op->vop_revoke)(&a));
340 }
341 
342 int
343 VOP_FSYNC(struct vnode *vp, struct ucred *cred, int waitfor,
344     struct proc *p)
345 {
346 	int r, s;
347 	struct vop_fsync_args a;
348 	a.a_vp = vp;
349 	a.a_cred = cred;
350 	a.a_waitfor = waitfor;
351 	a.a_p = p;
352 
353 	KASSERT(p == curproc);
354 	ASSERT_VP_ISLOCKED(vp);
355 
356 	if (vp->v_op->vop_fsync == NULL)
357 		return (EOPNOTSUPP);
358 
359 	vp->v_inflight++;
360 	r = (vp->v_op->vop_fsync)(&a);
361 	vp->v_inflight--;
362 	s = splbio();
363 	if (r == 0 && vp->v_bioflag & VBIOERROR)
364 		r = EIO;
365 	splx(s);
366 	return r;
367 }
368 
369 int
370 VOP_REMOVE(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
371 {
372 	int r;
373 	struct vop_remove_args a;
374 	a.a_dvp = dvp;
375         a.a_vp = vp;
376 	a.a_cnp = cnp;
377 
378 	ASSERT_VP_ISLOCKED(dvp);
379 	ASSERT_VP_ISLOCKED(vp);
380 
381 	if (dvp->v_op->vop_remove == NULL)
382 		return (EOPNOTSUPP);
383 
384 	dvp->v_inflight++;
385 	r = (dvp->v_op->vop_remove)(&a);
386 	dvp->v_inflight--;
387 	return r;
388 }
389 
390 int
391 VOP_LINK(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
392 {
393 	int r;
394 	struct vop_link_args a;
395 	a.a_dvp = dvp;
396 	a.a_vp = vp;
397 	a.a_cnp = cnp;
398 
399 	ASSERT_VP_ISLOCKED(dvp);
400 
401 	if (dvp->v_op->vop_link == NULL)
402 		return (EOPNOTSUPP);
403 
404 	dvp->v_inflight++;
405 	vp->v_inflight++;
406 	r = (dvp->v_op->vop_link)(&a);
407 	dvp->v_inflight--;
408 	vp->v_inflight--;
409 	return r;
410 }
411 
412 int
413 VOP_RENAME(struct vnode *fdvp, struct vnode *fvp,
414     struct componentname *fcnp, struct vnode *tdvp, struct vnode *tvp,
415     struct componentname *tcnp)
416 {
417 	int r;
418 	struct vop_rename_args a;
419 	a.a_fdvp = fdvp;
420 	a.a_fvp = fvp;
421 	a.a_fcnp = fcnp;
422 	a.a_tdvp = tdvp;
423 	a.a_tvp = tvp;
424 	a.a_tcnp = tcnp;
425 
426 	ASSERT_VP_ISLOCKED(tdvp);
427 
428 	if (fdvp->v_op->vop_rename == NULL)
429 		return (EOPNOTSUPP);
430 
431 	fdvp->v_inflight++;
432 	tdvp->v_inflight++;
433 	r = (fdvp->v_op->vop_rename)(&a);
434 	fdvp->v_inflight--;
435 	tdvp->v_inflight--;
436 	return r;
437 }
438 
439 int
440 VOP_MKDIR(struct vnode *dvp, struct vnode **vpp,
441     struct componentname *cnp, struct vattr *vap)
442 {
443 	int r;
444 	struct vop_mkdir_args a;
445 	a.a_dvp = dvp;
446 	a.a_vpp = vpp;
447 	a.a_cnp = cnp;
448 	a.a_vap = vap;
449 
450 	ASSERT_VP_ISLOCKED(dvp);
451 
452 	if (dvp->v_op->vop_mkdir == NULL)
453 		return (EOPNOTSUPP);
454 
455 	dvp->v_inflight++;
456 	r = (dvp->v_op->vop_mkdir)(&a);
457 	dvp->v_inflight--;
458 	return r;
459 }
460 
461 int
462 VOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
463 {
464 	int r;
465 	struct vop_rmdir_args a;
466 	a.a_dvp = dvp;
467 	a.a_vp = vp;
468 	a.a_cnp = cnp;
469 
470 	ASSERT_VP_ISLOCKED(dvp);
471 	ASSERT_VP_ISLOCKED(vp);
472 
473 	KASSERT(dvp != vp);
474 
475 	if (dvp->v_op->vop_rmdir == NULL)
476 		return (EOPNOTSUPP);
477 
478 	dvp->v_inflight++;
479 	vp->v_inflight++;
480 	r = (dvp->v_op->vop_rmdir)(&a);
481 	dvp->v_inflight--;
482 	vp->v_inflight--;
483 	return r;
484 }
485 
486 int
487 VOP_SYMLINK(struct vnode *dvp, struct vnode **vpp,
488     struct componentname *cnp, struct vattr *vap, char *target)
489 {
490 	int r;
491 	struct vop_symlink_args a;
492 	a.a_dvp = dvp;
493 	a.a_vpp = vpp;
494 	a.a_cnp = cnp;
495 	a.a_vap = vap;
496 	a.a_target = target;
497 
498 	ASSERT_VP_ISLOCKED(dvp);
499 
500 	if (dvp->v_op->vop_symlink == NULL)
501 		return (EOPNOTSUPP);
502 
503 	dvp->v_inflight++;
504 	r = (dvp->v_op->vop_symlink)(&a);
505 	dvp->v_inflight--;
506 	return r;
507 }
508 
509 int
510 VOP_READDIR(struct vnode *vp, struct uio *uio, struct ucred *cred,
511     int *eofflag)
512 {
513 	int r;
514 	struct vop_readdir_args a;
515 	a.a_vp = vp;
516 	a.a_uio = uio;
517 	a.a_cred = cred;
518 	a.a_eofflag = eofflag;
519 
520 	ASSERT_VP_ISLOCKED(vp);
521 
522 	if (vp->v_op->vop_readdir == NULL)
523 		return (EOPNOTSUPP);
524 
525 	vp->v_inflight++;
526 	r = (vp->v_op->vop_readdir)(&a);
527 	vp->v_inflight--;
528 	return r;
529 }
530 
531 int
532 VOP_READLINK(struct vnode *vp, struct uio *uio, struct ucred *cred)
533 {
534 	int r;
535 	struct vop_readlink_args a;
536 	a.a_vp = vp;
537 	a.a_uio = uio;
538 	a.a_cred = cred;
539 
540 	ASSERT_VP_ISLOCKED(vp);
541 
542 	if (vp->v_op->vop_readlink == NULL)
543 		return (EOPNOTSUPP);
544 
545 	vp->v_inflight++;
546 	r = (vp->v_op->vop_readlink)(&a);
547 	vp->v_inflight--;
548 	return r;
549 }
550 
551 int
552 VOP_ABORTOP(struct vnode *dvp, struct componentname *cnp)
553 {
554 	int r;
555 	struct vop_abortop_args a;
556 	a.a_dvp = dvp;
557 	a.a_cnp = cnp;
558 
559 	if (dvp->v_op->vop_abortop == NULL)
560 		return (EOPNOTSUPP);
561 
562 	dvp->v_inflight++;
563 	r = (dvp->v_op->vop_abortop)(&a);
564 	dvp->v_inflight--;
565 	return r;
566 }
567 
568 int
569 VOP_INACTIVE(struct vnode *vp, struct proc *p)
570 {
571 	struct vop_inactive_args a;
572 	a.a_vp = vp;
573 	a.a_p = p;
574 
575 	KASSERT(p == curproc);
576 	ASSERT_VP_ISLOCKED(vp);
577 
578 	if (vp->v_op->vop_inactive == NULL)
579 		return (EOPNOTSUPP);
580 
581 	return ((vp->v_op->vop_inactive)(&a));
582 }
583 
584 int
585 VOP_RECLAIM(struct vnode *vp, struct proc *p)
586 {
587 	int r;
588 	struct vop_reclaim_args a;
589 	a.a_vp = vp;
590 	a.a_p = p;
591 
592 	KASSERT(p == curproc);
593 	if (vp->v_op->vop_reclaim == NULL)
594 		return (EOPNOTSUPP);
595 
596 	vp->v_inflight++;
597 	r = (vp->v_op->vop_reclaim)(&a);
598 	vp->v_inflight--;
599 	return r;
600 }
601 
602 int
603 VOP_LOCK(struct vnode *vp, int flags)
604 {
605 	struct vop_lock_args a;
606 	a.a_vp = vp;
607 	a.a_flags = flags;
608 
609 	MUTEX_ASSERT_UNLOCKED(&vnode_mtx);
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