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