2 * Copyright 2017 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #ifndef _SYS_VNODE_DISPATCH_H
18 #define _SYS_VNODE_DISPATCH_H
20 #include <sys/vnode.h>
21 #include <sys/stdbool.h>
23 #include <sys/fs_subr.h>
26 * Ideally these static inlines could be just inline statements in the
27 * corresponding fop_*() functions. Unfortunately, fem gets in the way and
28 * we have to make these to centralize the damage.
30 * Let's use the close vnode op as an example.
32 * fop_close() calls the fop_close_dispatch() static inline defined in this
33 * header. fop_close_dispatch() does one of three things:
35 * (1) checks if fem processing is required, and if so calls vhead_close()
36 * (2) checks if ->vop_close is NULL, and if it is returns not-implemented
37 * errno (i.e., ENOSYS)
38 * (3) calls ->vop_close
40 * The odd bit is because of how fem works. fem calls the first callback on
41 * its list of callbacks. That callback, is allowed to call the second
42 * callback, which is allowed the call the next, and so on. Eventually,
43 * there is no next callback to invoke and the actual vnode op is supposed
44 * to be called. Since the vnode op may be NULL (meaning default action) we
45 * need to do the default behavior checking in fem as well. We accomplish
46 * this by having fem call the dispatch function. The only difference
47 * between the fop_close() and the fem invocation is the value of the
48 * check_fem bool arg. The fem invocation sets it to false to avoid
49 * recursing back into fem.
52 #define FOP_DISPATCH(fname, vopname, vheadname, args, callargs) \
53 static inline int fname args \
55 if (check_fem && vnode->v_femhead != NULL) \
56 return vheadname callargs; \
57 if (vnode->v_op->vopname == NULL) \
59 return vnode->v_op->vopname callargs; \
62 /* open takes a struct vnode **, so it is hand-coded */
63 static inline int fop_open_dispatch(struct vnode
**vnode
, int mode
, cred_t
*cr
,
64 caller_context_t
*ct
, bool check_fem
)
66 if (check_fem
&& (*vnode
)->v_femhead
!= NULL
)
67 return vhead_open(vnode
, mode
, cr
, ct
);
69 if ((*vnode
)->v_op
->vop_open
== NULL
)
72 return (*vnode
)->v_op
->vop_open(vnode
, mode
, cr
, ct
);
75 FOP_DISPATCH(fop_close_dispatch
, vop_close
, vhead_close
,
76 (struct vnode
*vnode
, int flag
, int count
, offset_t offset
, cred_t
*cr
,
77 caller_context_t
*ct
, bool check_fem
),
78 (vnode
, flag
, count
, offset
, cr
, ct
))
79 FOP_DISPATCH(fop_read_dispatch
, vop_read
, vhead_read
,
80 (struct vnode
*vnode
, uio_t
*uio
, int ioflag
, cred_t
*cr
,
81 caller_context_t
*ct
, bool check_fem
),
82 (vnode
, uio
, ioflag
, cr
, ct
))
83 FOP_DISPATCH(fop_write_dispatch
, vop_write
, vhead_write
,
84 (struct vnode
*vnode
, uio_t
*uio
, int ioflag
, cred_t
*cr
,
85 caller_context_t
*ct
, bool check_fem
),
86 (vnode
, uio
, ioflag
, cr
, ct
))
87 FOP_DISPATCH(fop_ioctl_dispatch
, vop_ioctl
, vhead_ioctl
,
88 (struct vnode
*vnode
, int cmd
, intptr_t arg
, int flag
, cred_t
*cr
,
89 int *rvalp
, caller_context_t
*ct
, bool check_fem
),
90 (vnode
, cmd
, arg
, flag
, cr
, rvalp
, ct
))
92 /* no-op by default, so it is hand-coded */
93 static inline int fop_setfl_dispatch(struct vnode
*vnode
, int oflags
,
94 int nflags
, cred_t
*cr
,
95 caller_context_t
*ct
, bool check_fem
)
97 if (check_fem
&& vnode
->v_femhead
!= NULL
)
98 return vhead_setfl(vnode
, oflags
, nflags
, cr
, ct
);
100 if (vnode
->v_op
->vop_setfl
== NULL
)
103 return vnode
->v_op
->vop_setfl(vnode
, oflags
, nflags
, cr
, ct
);
106 FOP_DISPATCH(fop_getattr_dispatch
, vop_getattr
, vhead_getattr
,
107 (struct vnode
*vnode
, vattr_t
*vap
, int flags
, cred_t
*cr
,
108 caller_context_t
*ct
, bool check_fem
),
109 (vnode
, vap
, flags
, cr
, ct
))
110 FOP_DISPATCH(fop_setattr_dispatch
, vop_setattr
, vhead_setattr
,
111 (struct vnode
*vnode
, vattr_t
*vap
, int flags
, cred_t
*cr
,
112 caller_context_t
*ct
, bool check_fem
),
113 (vnode
, vap
, flags
, cr
, ct
))
114 FOP_DISPATCH(fop_access_dispatch
, vop_access
, vhead_access
,
115 (struct vnode
*vnode
, int mode
, int flags
, cred_t
*cr
,
116 caller_context_t
*ct
, bool check_fem
),
117 (vnode
, mode
, flags
, cr
, ct
))
118 FOP_DISPATCH(fop_lookup_dispatch
, vop_lookup
, vhead_lookup
,
119 (struct vnode
*vnode
, char *nm
, struct vnode
**vpp
, pathname_t
*pnp
,
120 int flags
, struct vnode
*rdir
, cred_t
*cr
, caller_context_t
*ct
,
121 int *direntflags
, pathname_t
*realpnp
, bool check_fem
),
122 (vnode
, nm
, vpp
, pnp
, flags
, rdir
, cr
, ct
, direntflags
, realpnp
))
123 FOP_DISPATCH(fop_create_dispatch
, vop_create
, vhead_create
,
124 (struct vnode
*vnode
, char *name
, vattr_t
*vap
, vcexcl_t excl
,
125 int mode
, struct vnode
**vpp
, cred_t
*cr
, int flag
, caller_context_t
*ct
,
126 vsecattr_t
*vsecattr
, bool check_fem
),
127 (vnode
, name
, vap
, excl
, mode
, vpp
, cr
, flag
, ct
, vsecattr
))
128 FOP_DISPATCH(fop_remove_dispatch
, vop_remove
, vhead_remove
,
129 (struct vnode
*vnode
, char *nm
, cred_t
*cr
, caller_context_t
*ct
,
130 int flags
, bool check_fem
),
131 (vnode
, nm
, cr
, ct
, flags
))
132 FOP_DISPATCH(fop_link_dispatch
, vop_link
, vhead_link
,
133 (struct vnode
*vnode
, struct vnode
*svp
, char *tnm
, cred_t
*cr
,
134 caller_context_t
*ct
, int flags
, bool check_fem
),
135 (vnode
, svp
, tnm
, cr
, ct
, flags
))
136 FOP_DISPATCH(fop_rename_dispatch
, vop_rename
, vhead_rename
,
137 (struct vnode
*vnode
, char *snm
, struct vnode
*tdvp
, char *tnm
,
138 cred_t
*cr
, caller_context_t
*ct
, int flags
, bool check_fem
),
139 (vnode
, snm
, tdvp
, tnm
, cr
, ct
, flags
))
140 FOP_DISPATCH(fop_mkdir_dispatch
, vop_mkdir
, vhead_mkdir
,
141 (struct vnode
*vnode
, char *dirname
, vattr_t
*vap
, struct vnode
**vpp
,
142 cred_t
*cr
, caller_context_t
*ct
, int flags
, vsecattr_t
*vsecp
,
144 (vnode
, dirname
, vap
, vpp
, cr
, ct
, flags
, vsecp
))
145 FOP_DISPATCH(fop_rmdir_dispatch
, vop_rmdir
, vhead_rmdir
,
146 (struct vnode
*vnode
, char *nm
, struct vnode
*cdir
, cred_t
*cr
,
147 caller_context_t
*ct
, int flags
, bool check_fem
),
148 (vnode
, nm
, cdir
, cr
, ct
, flags
))
149 FOP_DISPATCH(fop_readdir_dispatch
, vop_readdir
, vhead_readdir
,
150 (struct vnode
*vnode
, uio_t
*uiop
, cred_t
*cr
, int *eofp
,
151 caller_context_t
*ct
, int flags
, bool check_fem
),
152 (vnode
, uiop
, cr
, eofp
, ct
, flags
))
153 FOP_DISPATCH(fop_symlink_dispatch
, vop_symlink
, vhead_symlink
,
154 (struct vnode
*vnode
, char *linkname
, vattr_t
*vap
, char *target
,
155 cred_t
*cr
, caller_context_t
*ct
, int flags
, bool check_fem
),
156 (vnode
, linkname
, vap
, target
, cr
, ct
, flags
))
157 FOP_DISPATCH(fop_readlink_dispatch
, vop_readlink
, vhead_readlink
,
158 (struct vnode
*vnode
, uio_t
*uiop
, cred_t
*cr
, caller_context_t
*ct
,
160 (vnode
, uiop
, cr
, ct
))
161 FOP_DISPATCH(fop_fsync_dispatch
, vop_fsync
, vhead_fsync
,
162 (struct vnode
*vnode
, int syncflag
, cred_t
*cr
, caller_context_t
*ct
,
164 (vnode
, syncflag
, cr
, ct
))
166 /* returns void, so it is hand-coded */
167 static inline void fop_inactive_dispatch(struct vnode
*vnode
, cred_t
*cr
,
168 caller_context_t
*ct
, bool check_fem
)
170 if (check_fem
&& vnode
->v_femhead
!= NULL
)
171 vhead_inactive(vnode
, cr
, ct
);
172 else if (vnode
->v_op
->vop_inactive
!= NULL
)
173 vnode
->v_op
->vop_inactive(vnode
, cr
, ct
);
176 FOP_DISPATCH(fop_fid_dispatch
, vop_fid
, vhead_fid
,
177 (struct vnode
*vnode
, fid_t
*fidp
, caller_context_t
*ct
, bool check_fem
),
180 /* return -1 by default, so it is hand-coded */
181 static inline int fop_rwlock_dispatch(struct vnode
*vnode
, int write_lock
,
182 caller_context_t
*ct
, bool check_fem
)
184 if (check_fem
&& vnode
->v_femhead
!= NULL
)
185 return vhead_rwlock(vnode
, write_lock
, ct
);
187 if (vnode
->v_op
->vop_rwlock
== NULL
)
190 return vnode
->v_op
->vop_rwlock(vnode
, write_lock
, ct
);
193 /* returns void, so it is hand-coded */
194 static inline void fop_rwunlock_dispatch(struct vnode
*vnode
, int write_lock
,
195 caller_context_t
*ct
, bool check_fem
)
197 if (check_fem
&& vnode
->v_femhead
!= NULL
)
198 vhead_rwunlock(vnode
, write_lock
, ct
);
199 else if (vnode
->v_op
->vop_rwunlock
!= NULL
)
200 vnode
->v_op
->vop_rwunlock(vnode
, write_lock
, ct
);
203 FOP_DISPATCH(fop_seek_dispatch
, vop_seek
, vhead_seek
,
204 (struct vnode
*vnode
, offset_t off
, offset_t
*noff
, caller_context_t
*ct
,
206 (vnode
, off
, noff
, ct
))
208 /* compares pointers by default, so it is hand-coded */
209 static inline int fop_cmp_dispatch(struct vnode
*vnode1
, struct vnode
*vnode2
,
210 caller_context_t
*ct
, bool check_fem
)
212 if (check_fem
&& vnode1
->v_femhead
!= NULL
)
213 return vhead_cmp(vnode1
, vnode2
, ct
);
215 if (vnode1
->v_op
->vop_cmp
== NULL
)
216 return vnode1
== vnode2
;
218 return vnode1
->v_op
->vop_cmp(vnode1
, vnode2
, ct
);
221 /* calls fs_frlock by default, so it is hand-coded */
222 static inline int fop_frlock_dispatch(struct vnode
*vnode
, int cmd
,
223 flock64_t
*bfp
, int flag
, offset_t offset
,
224 struct flk_callback
*flk_cbp
, cred_t
*cr
,
225 caller_context_t
*ct
, bool check_fem
)
227 if (check_fem
&& vnode
->v_femhead
!= NULL
)
228 return vhead_frlock(vnode
, cmd
, bfp
, flag
, offset
, flk_cbp
, cr
,
231 if (vnode
->v_op
->vop_frlock
== NULL
)
232 return fs_frlock(vnode
, cmd
, bfp
, flag
, offset
, flk_cbp
, cr
,
235 return vnode
->v_op
->vop_frlock(vnode
, cmd
, bfp
, flag
, offset
,
239 FOP_DISPATCH(fop_space_dispatch
, vop_space
, vhead_space
,
240 (struct vnode
*vnode
, int cmd
, flock64_t
*bfp
, int flag
, offset_t offset
,
241 cred_t
*cr
, caller_context_t
*ct
, bool check_fem
),
242 (vnode
, cmd
, bfp
, flag
, offset
, cr
, ct
))
243 FOP_DISPATCH(fop_realvp_dispatch
, vop_realvp
, vhead_realvp
,
244 (struct vnode
*vnode
, struct vnode
**vpp
, caller_context_t
*ct
,
247 FOP_DISPATCH(fop_getpage_dispatch
, vop_getpage
, vhead_getpage
,
248 (struct vnode
*vnode
, offset_t off
, size_t len
, uint_t
*protp
,
249 struct page
**plarr
, size_t plsz
, struct seg
*seg
, caddr_t addr
,
250 enum seg_rw rw
, cred_t
*cr
, caller_context_t
*ct
, bool check_fem
),
251 (vnode
, off
, len
, protp
, plarr
, plsz
, seg
, addr
, rw
, cr
, ct
))
252 FOP_DISPATCH(fop_putpage_dispatch
, vop_putpage
, vhead_putpage
,
253 (struct vnode
*vnode
, offset_t off
, size_t len
, int flags
, cred_t
*cr
,
254 caller_context_t
*ct
, bool check_fem
),
255 (vnode
, off
, len
, flags
, cr
, ct
))
256 FOP_DISPATCH(fop_map_dispatch
, vop_map
, vhead_map
,
257 (struct vnode
*vnode
, offset_t off
, struct as
*as
, caddr_t
*addr
,
258 size_t len
, uchar_t prot
, uchar_t maxprot
, uint_t flags
, cred_t
*cr
,
259 caller_context_t
*ct
, bool check_fem
),
260 (vnode
, off
, as
, addr
, len
, prot
, maxprot
, flags
, cr
, ct
))
261 FOP_DISPATCH(fop_addmap_dispatch
, vop_addmap
, vhead_addmap
,
262 (struct vnode
*vnode
, offset_t off
, struct as
*as
, caddr_t addr
,
263 size_t len
, uchar_t prot
, uchar_t maxprot
, uint_t flags
, cred_t
*cr
,
264 caller_context_t
*ct
, bool check_fem
),
265 (vnode
, off
, as
, addr
, len
, prot
, maxprot
, flags
, cr
, ct
))
266 FOP_DISPATCH(fop_delmap_dispatch
, vop_delmap
, vhead_delmap
,
267 (struct vnode
*vnode
, offset_t off
, struct as
*as
, caddr_t addr
, size_t len
,
268 uint_t prot
, uint_t maxprot
, uint_t flags
, cred_t
*cr
,
269 caller_context_t
*ct
, bool check_fem
),
270 (vnode
, off
, as
, addr
, len
, prot
, maxprot
, flags
, cr
, ct
))
272 /* calls fs_poll by default, so it is hand-coded */
273 static inline int fop_poll_dispatch(struct vnode
*vnode
, short events
,
274 int anyyet
, short *reventsp
,
275 struct pollhead
**phpp
,
276 caller_context_t
*ct
, bool check_fem
)
278 if (check_fem
&& vnode
->v_femhead
!= NULL
)
279 return vhead_poll(vnode
, events
, anyyet
, reventsp
, phpp
, ct
);
281 if (vnode
->v_op
->vop_poll
== NULL
)
282 return fs_poll(vnode
, events
, anyyet
, reventsp
, phpp
, ct
);
284 return vnode
->v_op
->vop_poll(vnode
, events
, anyyet
, reventsp
, phpp
, ct
);
287 FOP_DISPATCH(fop_dump_dispatch
, vop_dump
, vhead_dump
,
288 (struct vnode
*vnode
, caddr_t addr
, offset_t lbdn
, offset_t dblks
,
289 caller_context_t
*ct
, bool check_fem
),
290 (vnode
, addr
, lbdn
, dblks
, ct
))
292 /* calls fs_pathconf by default, so it is hand-coded */
293 static inline int fop_pathconf_dispatch(struct vnode
*vnode
, int cmd
,
294 ulong_t
*valp
, cred_t
*cr
,
295 caller_context_t
*ct
, bool check_fem
)
297 if (check_fem
&& vnode
->v_femhead
!= NULL
)
298 return vhead_pathconf(vnode
, cmd
, valp
, cr
, ct
);
300 if (vnode
->v_op
->vop_pathconf
== NULL
)
301 return fs_pathconf(vnode
, cmd
, valp
, cr
, ct
);
303 return vnode
->v_op
->vop_pathconf(vnode
, cmd
, valp
, cr
, ct
);
306 FOP_DISPATCH(fop_pageio_dispatch
, vop_pageio
, vhead_pageio
,
307 (struct vnode
*vnode
, struct page
*page
, uoff_t io_off
, size_t io_len
,
308 int flags
, cred_t
*cr
, caller_context_t
*ct
, bool check_fem
),
309 (vnode
, page
, io_off
, io_len
, flags
, cr
, ct
))
310 FOP_DISPATCH(fop_dumpctl_dispatch
, vop_dumpctl
, vhead_dumpctl
,
311 (struct vnode
*vnode
, int action
, offset_t
*blkp
,
312 caller_context_t
*ct
, bool check_fem
),
313 (vnode
, action
, blkp
, ct
))
315 /* returns void & calls fs_dispose by default, so it is hand-coded */
316 static inline void fop_dispose_dispatch(struct vnode
*vnode
, struct page
*pp
,
317 int flag
, int dn
, cred_t
*cr
,
318 caller_context_t
*ct
, bool check_fem
)
320 if (check_fem
&& vnode
->v_femhead
!= NULL
)
321 vhead_dispose(vnode
, pp
, flag
, dn
, cr
, ct
);
322 else if (vnode
->v_op
->vop_dispose
== NULL
)
323 fs_dispose(vnode
, pp
, flag
, dn
, cr
, ct
);
325 vnode
->v_op
->vop_dispose(vnode
, pp
, flag
, dn
, cr
, ct
);
328 FOP_DISPATCH(fop_setsecattr_dispatch
, vop_setsecattr
, vhead_setsecattr
,
329 (struct vnode
*vnode
, vsecattr_t
*vsap
, int flag
, cred_t
*cr
,
330 caller_context_t
*ct
, bool check_fem
),
331 (vnode
, vsap
, flag
, cr
, ct
))
333 /* calls fs_fab_acl by default, so it is hand-coded */
334 static inline int fop_getsecattr_dispatch(struct vnode
*vnode
, vsecattr_t
*vsap
,
335 int flag
, cred_t
*cr
,
336 caller_context_t
*ct
, bool check_fem
)
338 if (check_fem
&& vnode
->v_femhead
!= NULL
)
339 return vhead_getsecattr(vnode
, vsap
, flag
, cr
, ct
);
341 if (vnode
->v_op
->vop_getsecattr
== NULL
)
342 return fs_fab_acl(vnode
, vsap
, flag
, cr
, ct
);
344 return vnode
->v_op
->vop_getsecattr(vnode
, vsap
, flag
, cr
, ct
);
347 /* calls fs_shrlock by default, so it is hand-coded */
348 static inline int fop_shrlock_dispatch(struct vnode
*vnode
, int cmd
,
349 struct shrlock
*shr
, int flag
,
350 cred_t
*cr
, caller_context_t
*ct
,
353 if (check_fem
&& vnode
->v_femhead
!= NULL
)
354 return vhead_shrlock(vnode
, cmd
, shr
, flag
, cr
, ct
);
356 if (vnode
->v_op
->vop_shrlock
== NULL
)
357 return fs_shrlock(vnode
, cmd
, shr
, flag
, cr
, ct
);
359 return vnode
->v_op
->vop_shrlock(vnode
, cmd
, shr
, flag
, cr
, ct
);
362 /* returns ENOTSUP by default, so it is hand-coded */
363 static inline int fop_vnevent_dispatch(struct vnode
*vnode
, vnevent_t vnevent
,
364 struct vnode
*dvp
, char *fnm
,
365 caller_context_t
*ct
, bool check_fem
)
367 if (check_fem
&& vnode
->v_femhead
!= NULL
)
368 return vhead_vnevent(vnode
, vnevent
, dvp
, fnm
, ct
);
370 if (vnode
->v_op
->vop_vnevent
== NULL
)
373 return vnode
->v_op
->vop_vnevent(vnode
, vnevent
, dvp
, fnm
, ct
);
376 FOP_DISPATCH(fop_reqzcbuf_dispatch
, vop_reqzcbuf
, vhead_reqzcbuf
,
377 (struct vnode
*vnode
, enum uio_rw ioflag
, xuio_t
*uio
, cred_t
*cr
,
378 caller_context_t
*ct
, bool check_fem
),
379 (vnode
, ioflag
, uio
, cr
, ct
))
380 FOP_DISPATCH(fop_retzcbuf_dispatch
, vop_retzcbuf
, vhead_retzcbuf
,
381 (struct vnode
*vnode
, xuio_t
*uio
, cred_t
*cr
, caller_context_t
*ct
,
383 (vnode
, uio
, cr
, ct
))