1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/errno.h>
31 #include <sys/vnode.h>
32 #include <sys/vfs.h>
33 #include <sys/vfs_opreg.h>
34 #include <sys/uio.h>
35 #include <sys/cred.h>
36 #include <sys/pathname.h>
37 #include <sys/debug.h>
38 #include <sys/fs/lofs_node.h>
39 #include <sys/fs/lofs_info.h>
40 #include <fs/fs_subr.h>
41 #include <vm/as.h>
42 #include <vm/seg.h>
43
44 /*
45 * These are the vnode ops routines which implement the vnode interface to
46 * the looped-back file system. These routines just take their parameters,
47 * and then calling the appropriate real vnode routine(s) to do the work.
48 */
49
50 static int
lo_open(vnode_t ** vpp,int flag,struct cred * cr,caller_context_t * ct)51 lo_open(vnode_t **vpp, int flag, struct cred *cr, caller_context_t *ct)
52 {
53 vnode_t *vp = *vpp;
54 vnode_t *rvp;
55 vnode_t *oldvp;
56 int error;
57
58 #ifdef LODEBUG
59 lo_dprint(4, "lo_open vp %p cnt=%d realvp %p cnt=%d\n",
60 vp, vp->v_count, realvp(vp), realvp(vp)->v_count);
61 #endif
62
63 oldvp = vp;
64 vp = rvp = realvp(vp);
65 /*
66 * Need to hold new reference to vp since VOP_OPEN() may
67 * decide to release it.
68 */
69 VN_HOLD(vp);
70 error = VOP_OPEN(&rvp, flag, cr, ct);
71
72 if (!error && rvp != vp) {
73 /*
74 * the FS which we called should have released the
75 * new reference on vp
76 */
77 *vpp = makelonode(rvp, vtoli(oldvp->v_vfsp), 0);
78 if ((*vpp)->v_type == VDIR) {
79 /*
80 * Copy over any looping flags to the new lnode.
81 */
82 (vtol(*vpp))->lo_looping |= (vtol(oldvp))->lo_looping;
83 }
84 if (IS_DEVVP(*vpp)) {
85 vnode_t *svp;
86
87 svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
88 VN_RELE(*vpp);
89 if (svp == NULL)
90 error = ENOSYS;
91 else
92 *vpp = svp;
93 }
94 VN_RELE(oldvp);
95 } else {
96 ASSERT(rvp->v_count > 1);
97 VN_RELE(rvp);
98 }
99
100 return (error);
101 }
102
103 static int
lo_close(vnode_t * vp,int flag,int count,offset_t offset,struct cred * cr,caller_context_t * ct)104 lo_close(
105 vnode_t *vp,
106 int flag,
107 int count,
108 offset_t offset,
109 struct cred *cr,
110 caller_context_t *ct)
111 {
112 #ifdef LODEBUG
113 lo_dprint(4, "lo_close vp %p realvp %p\n", vp, realvp(vp));
114 #endif
115 vp = realvp(vp);
116 return (VOP_CLOSE(vp, flag, count, offset, cr, ct));
117 }
118
119 static int
lo_read(vnode_t * vp,struct uio * uiop,int ioflag,struct cred * cr,caller_context_t * ct)120 lo_read(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
121 caller_context_t *ct)
122 {
123 #ifdef LODEBUG
124 lo_dprint(4, "lo_read vp %p realvp %p\n", vp, realvp(vp));
125 #endif
126 vp = realvp(vp);
127 return (VOP_READ(vp, uiop, ioflag, cr, ct));
128 }
129
130 static int
lo_write(vnode_t * vp,struct uio * uiop,int ioflag,struct cred * cr,caller_context_t * ct)131 lo_write(vnode_t *vp, struct uio *uiop, int ioflag, struct cred *cr,
132 caller_context_t *ct)
133 {
134 #ifdef LODEBUG
135 lo_dprint(4, "lo_write vp %p realvp %p\n", vp, realvp(vp));
136 #endif
137 vp = realvp(vp);
138 return (VOP_WRITE(vp, uiop, ioflag, cr, ct));
139 }
140
141 static int
lo_ioctl(vnode_t * vp,int cmd,intptr_t arg,int flag,struct cred * cr,int * rvalp,caller_context_t * ct)142 lo_ioctl(
143 vnode_t *vp,
144 int cmd,
145 intptr_t arg,
146 int flag,
147 struct cred *cr,
148 int *rvalp,
149 caller_context_t *ct)
150 {
151 #ifdef LODEBUG
152 lo_dprint(4, "lo_ioctl vp %p realvp %p\n", vp, realvp(vp));
153 #endif
154 vp = realvp(vp);
155 return (VOP_IOCTL(vp, cmd, arg, flag, cr, rvalp, ct));
156 }
157
158 static int
lo_setfl(vnode_t * vp,int oflags,int nflags,cred_t * cr,caller_context_t * ct)159 lo_setfl(vnode_t *vp, int oflags, int nflags, cred_t *cr, caller_context_t *ct)
160 {
161 vp = realvp(vp);
162 return (VOP_SETFL(vp, oflags, nflags, cr, ct));
163 }
164
165 static int
lo_getattr(vnode_t * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)166 lo_getattr(
167 vnode_t *vp,
168 struct vattr *vap,
169 int flags,
170 struct cred *cr,
171 caller_context_t *ct)
172 {
173 int error;
174
175 #ifdef LODEBUG
176 lo_dprint(4, "lo_getattr vp %p realvp %p\n", vp, realvp(vp));
177 #endif
178 if (error = VOP_GETATTR(realvp(vp), vap, flags, cr, ct))
179 return (error);
180
181 return (0);
182 }
183
184 static int
lo_setattr(vnode_t * vp,struct vattr * vap,int flags,struct cred * cr,caller_context_t * ct)185 lo_setattr(
186 vnode_t *vp,
187 struct vattr *vap,
188 int flags,
189 struct cred *cr,
190 caller_context_t *ct)
191 {
192 #ifdef LODEBUG
193 lo_dprint(4, "lo_setattr vp %p realvp %p\n", vp, realvp(vp));
194 #endif
195 vp = realvp(vp);
196 return (VOP_SETATTR(vp, vap, flags, cr, ct));
197 }
198
199 static int
lo_access(vnode_t * vp,int mode,int flags,struct cred * cr,caller_context_t * ct)200 lo_access(
201 vnode_t *vp,
202 int mode,
203 int flags,
204 struct cred *cr,
205 caller_context_t *ct)
206 {
207 #ifdef LODEBUG
208 lo_dprint(4, "lo_access vp %p realvp %p\n", vp, realvp(vp));
209 #endif
210 if (mode & VWRITE) {
211 if (vp->v_type == VREG && vn_is_readonly(vp))
212 return (EROFS);
213 }
214 vp = realvp(vp);
215 return (VOP_ACCESS(vp, mode, flags, cr, ct));
216 }
217
218 static int
lo_fsync(vnode_t * vp,int syncflag,struct cred * cr,caller_context_t * ct)219 lo_fsync(vnode_t *vp, int syncflag, struct cred *cr, caller_context_t *ct)
220 {
221 #ifdef LODEBUG
222 lo_dprint(4, "lo_fsync vp %p realvp %p\n", vp, realvp(vp));
223 #endif
224 vp = realvp(vp);
225 return (VOP_FSYNC(vp, syncflag, cr, ct));
226 }
227
228 /*ARGSUSED*/
229 static void
lo_inactive(vnode_t * vp,struct cred * cr,caller_context_t * ct)230 lo_inactive(vnode_t *vp, struct cred *cr, caller_context_t *ct)
231 {
232 #ifdef LODEBUG
233 lo_dprint(4, "lo_inactive %p, realvp %p\n", vp, realvp(vp));
234 #endif
235 freelonode(vtol(vp));
236 }
237
238 /* ARGSUSED */
239 static int
lo_fid(vnode_t * vp,struct fid * fidp,caller_context_t * ct)240 lo_fid(vnode_t *vp, struct fid *fidp, caller_context_t *ct)
241 {
242 #ifdef LODEBUG
243 lo_dprint(4, "lo_fid %p, realvp %p\n", vp, realvp(vp));
244 #endif
245 vp = realvp(vp);
246 return (VOP_FID(vp, fidp, ct));
247 }
248
249 /*
250 * Given a vnode of lofs type, lookup nm name and
251 * return a shadow vnode (of lofs type) of the
252 * real vnode found.
253 *
254 * Due to the nature of lofs, there is a potential
255 * looping in path traversal.
256 *
257 * starting from the mount point of an lofs;
258 * a loop is defined to be a traversal path
259 * where the mount point or the real vnode of
260 * the root of this lofs is encountered twice.
261 * Once at the start of traversal and second
262 * when the looping is found.
263 *
264 * When a loop is encountered, a shadow of the
265 * covered vnode is returned to stop the looping.
266 *
267 * This normally works, but with the advent of
268 * the new automounter, returning the shadow of the
269 * covered vnode (autonode, in this case) does not
270 * stop the loop. Because further lookup on this
271 * lonode will cause the autonode to call lo_lookup()
272 * on the lonode covering it.
273 *
274 * example "/net/jurassic/net/jurassic" is a loop.
275 * returning the shadow of the autonode corresponding to
276 * "/net/jurassic/net/jurassic" will not terminate the
277 * loop. To solve this problem we allow the loop to go
278 * through one more level component lookup. Whichever
279 * directory is then looked up in "/net/jurassic/net/jurassic"
280 * the vnode returned is the vnode covered by the autonode
281 * "net" and this will terminate the loop.
282 *
283 * Lookup for dot dot has to be dealt with separately.
284 * It will be nice to have a "one size fits all" kind
285 * of solution, so that we don't have so many ifs statement
286 * in the lo_lookup() to handle dotdot. But, since
287 * there are so many special cases to handle different
288 * kinds looping above, we need special codes to handle
289 * dotdot lookup as well.
290 */
291 static int
lo_lookup(vnode_t * dvp,char * nm,vnode_t ** vpp,struct pathname * pnp,int flags,vnode_t * rdir,struct cred * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)292 lo_lookup(
293 vnode_t *dvp,
294 char *nm,
295 vnode_t **vpp,
296 struct pathname *pnp,
297 int flags,
298 vnode_t *rdir,
299 struct cred *cr,
300 caller_context_t *ct,
301 int *direntflags,
302 pathname_t *realpnp)
303 {
304 vnode_t *vp = NULL, *tvp = NULL, *nonlovp;
305 int error, is_indirectloop;
306 vnode_t *realdvp = realvp(dvp);
307 struct loinfo *li = vtoli(dvp->v_vfsp);
308 int looping = 0;
309 int autoloop = 0;
310 int doingdotdot = 0;
311 int nosub = 0;
312 int mkflag = 0;
313
314 /*
315 * If name is empty and no XATTR flags are set, then return
316 * dvp (empty name == lookup "."). If an XATTR flag is set
317 * then we need to call VOP_LOOKUP to get the xattr dir.
318 */
319 if (nm[0] == '\0' && ! (flags & (CREATE_XATTR_DIR|LOOKUP_XATTR))) {
320 VN_HOLD(dvp);
321 *vpp = dvp;
322 return (0);
323 }
324
325 if (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0') {
326 doingdotdot++;
327 /*
328 * Handle ".." out of mounted filesystem
329 */
330 while ((realdvp->v_flag & VROOT) && realdvp != rootdir) {
331 realdvp = realdvp->v_vfsp->vfs_vnodecovered;
332 ASSERT(realdvp != NULL);
333 }
334 }
335
336 *vpp = NULL; /* default(error) case */
337
338 /*
339 * Do the normal lookup
340 */
341 if (error = VOP_LOOKUP(realdvp, nm, &vp, pnp, flags, rdir, cr,
342 ct, direntflags, realpnp)) {
343 vp = NULL;
344 goto out;
345 }
346
347 /*
348 * We do this check here to avoid returning a stale file handle to the
349 * caller.
350 */
351 if (nm[0] == '.' && nm[1] == '\0') {
352 ASSERT(vp == realdvp);
353 VN_HOLD(dvp);
354 VN_RELE(vp);
355 *vpp = dvp;
356 return (0);
357 }
358
359 if (doingdotdot) {
360 if ((vtol(dvp))->lo_looping & LO_LOOPING) {
361 vfs_t *vfsp;
362
363 error = vn_vfsrlock_wait(realdvp);
364 if (error)
365 goto out;
366 vfsp = vn_mountedvfs(realdvp);
367 /*
368 * In the standard case if the looping flag is set and
369 * performing dotdot we would be returning from a
370 * covered vnode, implying vfsp could not be null. The
371 * exceptions being if we have looping and overlay
372 * mounts or looping and covered file systems.
373 */
374 if (vfsp == NULL) {
375 /*
376 * Overlay mount or covered file system,
377 * so just make the shadow node.
378 */
379 vn_vfsunlock(realdvp);
380 *vpp = makelonode(vp, li, 0);
381 (vtol(*vpp))->lo_looping |= LO_LOOPING;
382 return (0);
383 }
384 /*
385 * When looping get the actual found vnode
386 * instead of the vnode covered.
387 * Here we have to hold the lock for realdvp
388 * since an unmount during the traversal to the
389 * root vnode would turn *vfsp into garbage
390 * which would be fatal.
391 */
392 error = VFS_ROOT(vfsp, &tvp);
393 vn_vfsunlock(realdvp);
394
395 if (error)
396 goto out;
397
398 if ((tvp == li->li_rootvp) && (vp == realvp(tvp))) {
399 /*
400 * we're back at the real vnode
401 * of the rootvp
402 *
403 * return the rootvp
404 * Ex: /mnt/mnt/..
405 * where / has been lofs-mounted
406 * onto /mnt. Return the lofs
407 * node mounted at /mnt.
408 */
409 *vpp = tvp;
410 VN_RELE(vp);
411 return (0);
412 } else {
413 /*
414 * We are returning from a covered
415 * node whose vfs_mountedhere is
416 * not pointing to vfs of the current
417 * root vnode.
418 * This is a condn where in we
419 * returned a covered node say Zc
420 * but Zc is not the cover of current
421 * root.
422 * i.e.., if X is the root vnode
423 * lookup(Zc,"..") is taking us to
424 * X.
425 * Ex: /net/X/net/X/Y
426 *
427 * If LO_AUTOLOOP (autofs/lofs looping detected)
428 * has been set then we are encountering the
429 * cover of Y (Y being any directory vnode
430 * under /net/X/net/X/).
431 * When performing a dotdot set the
432 * returned vp to the vnode covered
433 * by the mounted lofs, ie /net/X/net/X
434 */
435 VN_RELE(tvp);
436 if ((vtol(dvp))->lo_looping & LO_AUTOLOOP) {
437 VN_RELE(vp);
438 vp = li->li_rootvp;
439 vp = vp->v_vfsp->vfs_vnodecovered;
440 VN_HOLD(vp);
441 *vpp = makelonode(vp, li, 0);
442 (vtol(*vpp))->lo_looping |= LO_LOOPING;
443 return (0);
444 }
445 }
446 } else {
447 /*
448 * No frills just make the shadow node.
449 */
450 *vpp = makelonode(vp, li, 0);
451 return (0);
452 }
453 }
454
455 nosub = (vtoli(dvp->v_vfsp)->li_flag & LO_NOSUB);
456
457 /*
458 * If this vnode is mounted on, then we
459 * traverse to the vnode which is the root of
460 * the mounted file system.
461 */
462 if (!nosub && (error = traverse(&vp)))
463 goto out;
464
465 /*
466 * Make a lnode for the real vnode.
467 */
468 if (vp->v_type != VDIR || nosub) {
469 *vpp = makelonode(vp, li, 0);
470 if (IS_DEVVP(*vpp)) {
471 vnode_t *svp;
472
473 svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
474 VN_RELE(*vpp);
475 if (svp == NULL)
476 error = ENOSYS;
477 else
478 *vpp = svp;
479 }
480 return (error);
481 }
482
483 /*
484 * if the found vnode (vp) is not of type lofs
485 * then we're just going to make a shadow of that
486 * vp and get out.
487 *
488 * If the found vnode (vp) is of lofs type, and
489 * we're not doing dotdot, check if we are
490 * looping.
491 */
492 if (!doingdotdot && vfs_matchops(vp->v_vfsp, lo_vfsops)) {
493 /*
494 * Check if we're looping, i.e.
495 * vp equals the root vp of the lofs, directly
496 * or indirectly, return the covered node.
497 */
498
499 if (!((vtol(dvp))->lo_looping & LO_LOOPING)) {
500 if (vp == li->li_rootvp) {
501 /*
502 * Direct looping condn.
503 * Ex:- X is / mounted directory so lookup of
504 * /X/X is a direct looping condn.
505 */
506 tvp = vp;
507 vp = vp->v_vfsp->vfs_vnodecovered;
508 VN_HOLD(vp);
509 VN_RELE(tvp);
510 looping++;
511 } else {
512 /*
513 * Indirect looping can be defined as
514 * real lookup returning rootvp of the current
515 * tree in any level of recursion.
516 *
517 * This check is useful if there are multiple
518 * levels of lofs indirections. Suppose vnode X
519 * in the current lookup has as its real vnode
520 * another lofs node. Y = realvp(X) Y should be
521 * a lofs node for the check to continue or Y
522 * is not the rootvp of X.
523 * Ex:- say X and Y are two vnodes
524 * say real(Y) is X and real(X) is Z
525 * parent vnode for X and Y is Z
526 * lookup(Y,"path") say we are looking for Y
527 * again under Y and we have to return Yc.
528 * but the lookup of Y under Y doesnot return
529 * Y the root vnode again here is why.
530 * 1. lookup(Y,"path of Y") will go to
531 * 2. lookup(real(Y),"path of Y") and then to
532 * 3. lookup(real(X),"path of Y").
533 * and now what lookup level 1 sees is the
534 * outcome of 2 but the vnode Y is due to
535 * lookup(Z,"path of Y") so we have to skip
536 * intermediate levels to find if in any level
537 * there is a looping.
538 */
539 is_indirectloop = 0;
540 nonlovp = vp;
541 while (
542 vfs_matchops(nonlovp->v_vfsp, lo_vfsops) &&
543 !(is_indirectloop)) {
544 if (li->li_rootvp == nonlovp) {
545 is_indirectloop++;
546 break;
547 }
548 nonlovp = realvp(nonlovp);
549 }
550
551 if (is_indirectloop) {
552 VN_RELE(vp);
553 vp = nonlovp;
554 vp = vp->v_vfsp->vfs_vnodecovered;
555 VN_HOLD(vp);
556 looping++;
557 }
558 }
559 } else {
560 /*
561 * come here only because of the interaction between
562 * the autofs and lofs.
563 *
564 * Lookup of "/net/X/net/X" will return a shadow of
565 * an autonode X_a which we call X_l.
566 *
567 * Lookup of anything under X_l, will trigger a call to
568 * auto_lookup(X_a,nm) which will eventually call
569 * lo_lookup(X_lr,nm) where X_lr is the root vnode of
570 * the current lofs.
571 *
572 * We come here only when we are called with X_l as dvp
573 * and look for something underneath.
574 *
575 * Now that an autofs/lofs looping condition has been
576 * identified any directory vnode contained within
577 * dvp will be set to the vnode covered by the
578 * mounted autofs. Thus all directories within dvp
579 * will appear empty hence teminating the looping.
580 * The LO_AUTOLOOP flag is set on the returned lonode
581 * to indicate the termination of the autofs/lofs
582 * looping. This is required for the correct behaviour
583 * when performing a dotdot.
584 */
585 realdvp = realvp(dvp);
586 while (vfs_matchops(realdvp->v_vfsp, lo_vfsops)) {
587 realdvp = realvp(realdvp);
588 }
589
590 error = VFS_ROOT(realdvp->v_vfsp, &tvp);
591 if (error)
592 goto out;
593 /*
594 * tvp now contains the rootvp of the vfs of the
595 * real vnode of dvp. The directory vnode vp is set
596 * to the covered vnode to terminate looping. No
597 * distinction is made between any vp as all directory
598 * vnodes contained in dvp are returned as the covered
599 * vnode.
600 */
601 VN_RELE(vp);
602 vp = tvp; /* possibly is an autonode */
603
604 /*
605 * Need to find the covered vnode
606 */
607 if (vp->v_vfsp->vfs_vnodecovered == NULL) {
608 /*
609 * We don't have a covered vnode so this isn't
610 * an autonode. To find the autonode simply
611 * find the vnode covered by the lofs rootvp.
612 */
613 vp = li->li_rootvp;
614 vp = vp->v_vfsp->vfs_vnodecovered;
615 VN_RELE(tvp);
616 error = VFS_ROOT(vp->v_vfsp, &tvp);
617 if (error)
618 goto out;
619 vp = tvp; /* now this is an autonode */
620 if (vp->v_vfsp->vfs_vnodecovered == NULL) {
621 /*
622 * Still can't find a covered vnode.
623 * Fail the lookup, or we'd loop.
624 */
625 error = ENOENT;
626 goto out;
627 }
628 }
629 vp = vp->v_vfsp->vfs_vnodecovered;
630 VN_HOLD(vp);
631 VN_RELE(tvp);
632 /*
633 * Force the creation of a new lnode even if the hash
634 * table contains a lnode that references this vnode.
635 */
636 mkflag = LOF_FORCE;
637 autoloop++;
638 }
639 }
640 *vpp = makelonode(vp, li, mkflag);
641
642 if ((looping) ||
643 (((vtol(dvp))->lo_looping & LO_LOOPING) && !doingdotdot)) {
644 (vtol(*vpp))->lo_looping |= LO_LOOPING;
645 }
646
647 if (autoloop) {
648 (vtol(*vpp))->lo_looping |= LO_AUTOLOOP;
649 }
650
651 out:
652 if (error != 0 && vp != NULL)
653 VN_RELE(vp);
654 #ifdef LODEBUG
655 lo_dprint(4,
656 "lo_lookup dvp %x realdvp %x nm '%s' newvp %x real vp %x error %d\n",
657 dvp, realvp(dvp), nm, *vpp, vp, error);
658 #endif
659 return (error);
660 }
661
662 /*ARGSUSED*/
663 static int
lo_create(vnode_t * dvp,char * nm,struct vattr * va,enum vcexcl exclusive,int mode,vnode_t ** vpp,struct cred * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)664 lo_create(
665 vnode_t *dvp,
666 char *nm,
667 struct vattr *va,
668 enum vcexcl exclusive,
669 int mode,
670 vnode_t **vpp,
671 struct cred *cr,
672 int flag,
673 caller_context_t *ct,
674 vsecattr_t *vsecp)
675 {
676 int error;
677 vnode_t *vp = NULL;
678
679 #ifdef LODEBUG
680 lo_dprint(4, "lo_create vp %p realvp %p\n", dvp, realvp(dvp));
681 #endif
682 if (*nm == '\0') {
683 ASSERT(vpp && dvp == *vpp);
684 vp = realvp(*vpp);
685 }
686
687 error = VOP_CREATE(realvp(dvp), nm, va, exclusive, mode, &vp, cr, flag,
688 ct, vsecp);
689 if (!error) {
690 *vpp = makelonode(vp, vtoli(dvp->v_vfsp), 0);
691 if (IS_DEVVP(*vpp)) {
692 vnode_t *svp;
693
694 svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr);
695 VN_RELE(*vpp);
696 if (svp == NULL)
697 error = ENOSYS;
698 else
699 *vpp = svp;
700 }
701 }
702 return (error);
703 }
704
705 static int
lo_remove(vnode_t * dvp,char * nm,struct cred * cr,caller_context_t * ct,int flags)706 lo_remove(
707 vnode_t *dvp,
708 char *nm,
709 struct cred *cr,
710 caller_context_t *ct,
711 int flags)
712 {
713 #ifdef LODEBUG
714 lo_dprint(4, "lo_remove vp %p realvp %p\n", dvp, realvp(dvp));
715 #endif
716 dvp = realvp(dvp);
717 return (VOP_REMOVE(dvp, nm, cr, ct, flags));
718 }
719
720 static int
lo_link(vnode_t * tdvp,vnode_t * vp,char * tnm,struct cred * cr,caller_context_t * ct,int flags)721 lo_link(
722 vnode_t *tdvp,
723 vnode_t *vp,
724 char *tnm,
725 struct cred *cr,
726 caller_context_t *ct,
727 int flags)
728 {
729 vnode_t *realvp;
730
731 #ifdef LODEBUG
732 lo_dprint(4, "lo_link vp %p realvp %p\n", vp, realvp(vp));
733 #endif
734
735 /*
736 * The source and destination vnodes may be in different lofs
737 * filesystems sharing the same underlying filesystem, so we need to
738 * make sure that the filesystem containing the source vnode is not
739 * mounted read-only (vn_link() has already checked the target vnode).
740 *
741 * In a situation such as:
742 *
743 * /data - regular filesystem
744 * /foo - lofs mount of /data/foo
745 * /bar - read-only lofs mount of /data/bar
746 *
747 * This disallows a link from /bar/somefile to /foo/somefile,
748 * which would otherwise allow changes to somefile on the read-only
749 * mounted /bar.
750 */
751
752 if (vn_is_readonly(vp)) {
753 return (EROFS);
754 }
755 while (vn_matchops(vp, lo_vnodeops)) {
756 vp = realvp(vp);
757 }
758
759 /*
760 * In the case where the source vnode is on another stacking
761 * filesystem (such as specfs), the loop above will
762 * terminate before finding the true underlying vnode.
763 *
764 * We use VOP_REALVP here to continue the search.
765 */
766 if (VOP_REALVP(vp, &realvp, ct) == 0)
767 vp = realvp;
768
769 while (vn_matchops(tdvp, lo_vnodeops)) {
770 tdvp = realvp(tdvp);
771 }
772 if (vp->v_vfsp != tdvp->v_vfsp)
773 return (EXDEV);
774 return (VOP_LINK(tdvp, vp, tnm, cr, ct, flags));
775 }
776
777 static int
lo_rename(vnode_t * odvp,char * onm,vnode_t * ndvp,char * nnm,struct cred * cr,caller_context_t * ct,int flags)778 lo_rename(
779 vnode_t *odvp,
780 char *onm,
781 vnode_t *ndvp,
782 char *nnm,
783 struct cred *cr,
784 caller_context_t *ct,
785 int flags)
786 {
787 vnode_t *tnvp;
788
789 #ifdef LODEBUG
790 lo_dprint(4, "lo_rename vp %p realvp %p\n", odvp, realvp(odvp));
791 #endif
792 /*
793 * If we are coming from a loop back mounted fs, that has been
794 * mounted in the same filesystem as where we want to move to,
795 * and that filesystem is read/write, but the lofs filesystem is
796 * read only, we don't want to allow a rename of the file. The
797 * vn_rename code checks to be sure the target is read/write already
798 * so that is not necessary here. However, consider the following
799 * example:
800 * / - regular root fs
801 * /foo - directory in root
802 * /foo/bar - file in foo directory(in root fs)
803 * /baz - directory in root
804 * mount -F lofs -o ro /foo /baz - all still in root
805 * directory
806 * The fact that we mounted /foo on /baz read only should stop us
807 * from renaming the file /foo/bar /bar, but it doesn't since
808 * / is read/write. We are still renaming here since we are still
809 * in the same filesystem, it is just that we do not check to see
810 * if the filesystem we are coming from in this case is read only.
811 */
812 if (odvp->v_vfsp->vfs_flag & VFS_RDONLY)
813 return (EROFS);
814 /*
815 * We need to make sure we're not trying to remove a mount point for a
816 * filesystem mounted on top of lofs, which only we know about.
817 */
818 if (vn_matchops(ndvp, lo_vnodeops)) /* Not our problem. */
819 goto rename;
820
821 /*
822 * XXXci - Once case-insensitive behavior is implemented, it should
823 * be added here.
824 */
825 if (VOP_LOOKUP(ndvp, nnm, &tnvp, NULL, 0, NULL, cr,
826 ct, NULL, NULL) != 0)
827 goto rename;
828 if (tnvp->v_type != VDIR) {
829 VN_RELE(tnvp);
830 goto rename;
831 }
832 if (vn_mountedvfs(tnvp)) {
833 VN_RELE(tnvp);
834 return (EBUSY);
835 }
836 VN_RELE(tnvp);
837 rename:
838 /*
839 * Since the case we're dealing with above can happen at any layer in
840 * the stack of lofs filesystems, we need to recurse down the stack,
841 * checking to see if there are any instances of a filesystem mounted on
842 * top of lofs. In order to keep on using the lofs version of
843 * VOP_RENAME(), we make sure that while the target directory is of type
844 * lofs, the source directory (the one used for getting the fs-specific
845 * version of VOP_RENAME()) is also of type lofs.
846 */
847 if (vn_matchops(ndvp, lo_vnodeops)) {
848 ndvp = realvp(ndvp); /* Check the next layer */
849 } else {
850 /*
851 * We can go fast here
852 */
853 while (vn_matchops(odvp, lo_vnodeops)) {
854 odvp = realvp(odvp);
855 }
856 if (odvp->v_vfsp != ndvp->v_vfsp)
857 return (EXDEV);
858 }
859 return (VOP_RENAME(odvp, onm, ndvp, nnm, cr, ct, flags));
860 }
861
862 static int
lo_mkdir(vnode_t * dvp,char * nm,struct vattr * va,vnode_t ** vpp,struct cred * cr,caller_context_t * ct,int flags,vsecattr_t * vsecp)863 lo_mkdir(
864 vnode_t *dvp,
865 char *nm,
866 struct vattr *va,
867 vnode_t **vpp,
868 struct cred *cr,
869 caller_context_t *ct,
870 int flags,
871 vsecattr_t *vsecp)
872 {
873 int error;
874
875 #ifdef LODEBUG
876 lo_dprint(4, "lo_mkdir vp %p realvp %p\n", dvp, realvp(dvp));
877 #endif
878 error = VOP_MKDIR(realvp(dvp), nm, va, vpp, cr, ct, flags, vsecp);
879 if (!error)
880 *vpp = makelonode(*vpp, vtoli(dvp->v_vfsp), 0);
881 return (error);
882 }
883
884 static int
lo_realvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)885 lo_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
886 {
887 #ifdef LODEBUG
888 lo_dprint(4, "lo_realvp %p\n", vp);
889 #endif
890 while (vn_matchops(vp, lo_vnodeops))
891 vp = realvp(vp);
892
893 if (VOP_REALVP(vp, vpp, ct) != 0)
894 *vpp = vp;
895 return (0);
896 }
897
898 static int
lo_rmdir(vnode_t * dvp,char * nm,vnode_t * cdir,struct cred * cr,caller_context_t * ct,int flags)899 lo_rmdir(
900 vnode_t *dvp,
901 char *nm,
902 vnode_t *cdir,
903 struct cred *cr,
904 caller_context_t *ct,
905 int flags)
906 {
907 vnode_t *rvp = cdir;
908
909 #ifdef LODEBUG
910 lo_dprint(4, "lo_rmdir vp %p realvp %p\n", dvp, realvp(dvp));
911 #endif
912 /* if cdir is lofs vnode ptr get its real vnode ptr */
913 if (vn_matchops(dvp, vn_getops(rvp)))
914 (void) lo_realvp(cdir, &rvp, ct);
915 dvp = realvp(dvp);
916 return (VOP_RMDIR(dvp, nm, rvp, cr, ct, flags));
917 }
918
919 static int
lo_symlink(vnode_t * dvp,char * lnm,struct vattr * tva,char * tnm,struct cred * cr,caller_context_t * ct,int flags)920 lo_symlink(
921 vnode_t *dvp,
922 char *lnm,
923 struct vattr *tva,
924 char *tnm,
925 struct cred *cr,
926 caller_context_t *ct,
927 int flags)
928 {
929 #ifdef LODEBUG
930 lo_dprint(4, "lo_symlink vp %p realvp %p\n", dvp, realvp(dvp));
931 #endif
932 dvp = realvp(dvp);
933 return (VOP_SYMLINK(dvp, lnm, tva, tnm, cr, ct, flags));
934 }
935
936 static int
lo_readlink(vnode_t * vp,struct uio * uiop,struct cred * cr,caller_context_t * ct)937 lo_readlink(
938 vnode_t *vp,
939 struct uio *uiop,
940 struct cred *cr,
941 caller_context_t *ct)
942 {
943 vp = realvp(vp);
944 return (VOP_READLINK(vp, uiop, cr, ct));
945 }
946
947 static int
lo_readdir(vnode_t * vp,struct uio * uiop,struct cred * cr,int * eofp,caller_context_t * ct,int flags)948 lo_readdir(
949 vnode_t *vp,
950 struct uio *uiop,
951 struct cred *cr,
952 int *eofp,
953 caller_context_t *ct,
954 int flags)
955 {
956 #ifdef LODEBUG
957 lo_dprint(4, "lo_readdir vp %p realvp %p\n", vp, realvp(vp));
958 #endif
959 vp = realvp(vp);
960 return (VOP_READDIR(vp, uiop, cr, eofp, ct, flags));
961 }
962
963 static int
lo_rwlock(vnode_t * vp,int write_lock,caller_context_t * ct)964 lo_rwlock(vnode_t *vp, int write_lock, caller_context_t *ct)
965 {
966 vp = realvp(vp);
967 return (VOP_RWLOCK(vp, write_lock, ct));
968 }
969
970 static void
lo_rwunlock(vnode_t * vp,int write_lock,caller_context_t * ct)971 lo_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ct)
972 {
973 vp = realvp(vp);
974 VOP_RWUNLOCK(vp, write_lock, ct);
975 }
976
977 static int
lo_seek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)978 lo_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
979 {
980 vp = realvp(vp);
981 return (VOP_SEEK(vp, ooff, noffp, ct));
982 }
983
984 static int
lo_cmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)985 lo_cmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
986 {
987 while (vn_matchops(vp1, lo_vnodeops))
988 vp1 = realvp(vp1);
989 while (vn_matchops(vp2, lo_vnodeops))
990 vp2 = realvp(vp2);
991 return (VOP_CMP(vp1, vp2, ct));
992 }
993
994 static int
lo_frlock(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,struct flk_callback * flk_cbp,cred_t * cr,caller_context_t * ct)995 lo_frlock(
996 vnode_t *vp,
997 int cmd,
998 struct flock64 *bfp,
999 int flag,
1000 offset_t offset,
1001 struct flk_callback *flk_cbp,
1002 cred_t *cr,
1003 caller_context_t *ct)
1004 {
1005 vp = realvp(vp);
1006 return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
1007 }
1008
1009 static int
lo_space(vnode_t * vp,int cmd,struct flock64 * bfp,int flag,offset_t offset,struct cred * cr,caller_context_t * ct)1010 lo_space(
1011 vnode_t *vp,
1012 int cmd,
1013 struct flock64 *bfp,
1014 int flag,
1015 offset_t offset,
1016 struct cred *cr,
1017 caller_context_t *ct)
1018 {
1019 vp = realvp(vp);
1020 return (VOP_SPACE(vp, cmd, bfp, flag, offset, cr, ct));
1021 }
1022
1023 static int
lo_getpage(vnode_t * vp,offset_t off,size_t len,uint_t * prot,struct page * parr[],size_t psz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr,caller_context_t * ct)1024 lo_getpage(
1025 vnode_t *vp,
1026 offset_t off,
1027 size_t len,
1028 uint_t *prot,
1029 struct page *parr[],
1030 size_t psz,
1031 struct seg *seg,
1032 caddr_t addr,
1033 enum seg_rw rw,
1034 struct cred *cr,
1035 caller_context_t *ct)
1036 {
1037 vp = realvp(vp);
1038 return (VOP_GETPAGE(vp, off, len, prot, parr, psz, seg, addr, rw, cr,
1039 ct));
1040 }
1041
1042 static int
lo_putpage(vnode_t * vp,offset_t off,size_t len,int flags,struct cred * cr,caller_context_t * ct)1043 lo_putpage(
1044 vnode_t *vp,
1045 offset_t off,
1046 size_t len,
1047 int flags,
1048 struct cred *cr,
1049 caller_context_t *ct)
1050 {
1051 vp = realvp(vp);
1052 return (VOP_PUTPAGE(vp, off, len, flags, cr, ct));
1053 }
1054
1055 static int
lo_map(vnode_t * vp,offset_t off,struct as * as,caddr_t * addrp,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)1056 lo_map(
1057 vnode_t *vp,
1058 offset_t off,
1059 struct as *as,
1060 caddr_t *addrp,
1061 size_t len,
1062 uchar_t prot,
1063 uchar_t maxprot,
1064 uint_t flags,
1065 struct cred *cr,
1066 caller_context_t *ct)
1067 {
1068 vp = realvp(vp);
1069 return (VOP_MAP(vp, off, as, addrp, len, prot, maxprot, flags, cr, ct));
1070 }
1071
1072 static int
lo_addmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uchar_t prot,uchar_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)1073 lo_addmap(
1074 vnode_t *vp,
1075 offset_t off,
1076 struct as *as,
1077 caddr_t addr,
1078 size_t len,
1079 uchar_t prot,
1080 uchar_t maxprot,
1081 uint_t flags,
1082 struct cred *cr,
1083 caller_context_t *ct)
1084 {
1085 vp = realvp(vp);
1086 return (VOP_ADDMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
1087 ct));
1088 }
1089
1090 static int
lo_delmap(vnode_t * vp,offset_t off,struct as * as,caddr_t addr,size_t len,uint_t prot,uint_t maxprot,uint_t flags,struct cred * cr,caller_context_t * ct)1091 lo_delmap(
1092 vnode_t *vp,
1093 offset_t off,
1094 struct as *as,
1095 caddr_t addr,
1096 size_t len,
1097 uint_t prot,
1098 uint_t maxprot,
1099 uint_t flags,
1100 struct cred *cr,
1101 caller_context_t *ct)
1102 {
1103 vp = realvp(vp);
1104 return (VOP_DELMAP(vp, off, as, addr, len, prot, maxprot, flags, cr,
1105 ct));
1106 }
1107
1108 static int
lo_poll(vnode_t * vp,short events,int anyyet,short * reventsp,struct pollhead ** phpp,caller_context_t * ct)1109 lo_poll(
1110 vnode_t *vp,
1111 short events,
1112 int anyyet,
1113 short *reventsp,
1114 struct pollhead **phpp,
1115 caller_context_t *ct)
1116 {
1117 vp = realvp(vp);
1118 return (VOP_POLL(vp, events, anyyet, reventsp, phpp, ct));
1119 }
1120
1121 static int
lo_dump(vnode_t * vp,caddr_t addr,offset_t bn,offset_t count,caller_context_t * ct)1122 lo_dump(vnode_t *vp, caddr_t addr, offset_t bn, offset_t count,
1123 caller_context_t *ct)
1124 {
1125 vp = realvp(vp);
1126 return (VOP_DUMP(vp, addr, bn, count, ct));
1127 }
1128
1129 static int
lo_pathconf(vnode_t * vp,int cmd,ulong_t * valp,struct cred * cr,caller_context_t * ct)1130 lo_pathconf(
1131 vnode_t *vp,
1132 int cmd,
1133 ulong_t *valp,
1134 struct cred *cr,
1135 caller_context_t *ct)
1136 {
1137 vp = realvp(vp);
1138 return (VOP_PATHCONF(vp, cmd, valp, cr, ct));
1139 }
1140
1141 static int
lo_pageio(vnode_t * vp,struct page * pp,u_offset_t io_off,size_t io_len,int flags,cred_t * cr,caller_context_t * ct)1142 lo_pageio(
1143 vnode_t *vp,
1144 struct page *pp,
1145 u_offset_t io_off,
1146 size_t io_len,
1147 int flags,
1148 cred_t *cr,
1149 caller_context_t *ct)
1150 {
1151 vp = realvp(vp);
1152 return (VOP_PAGEIO(vp, pp, io_off, io_len, flags, cr, ct));
1153 }
1154
1155 static void
lo_dispose(vnode_t * vp,page_t * pp,int fl,int dn,cred_t * cr,caller_context_t * ct)1156 lo_dispose(
1157 vnode_t *vp,
1158 page_t *pp,
1159 int fl,
1160 int dn,
1161 cred_t *cr,
1162 caller_context_t *ct)
1163 {
1164 vp = realvp(vp);
1165 if (vp != NULL && !VN_ISKAS(vp))
1166 VOP_DISPOSE(vp, pp, fl, dn, cr, ct);
1167 }
1168
1169 static int
lo_setsecattr(vnode_t * vp,vsecattr_t * secattr,int flags,struct cred * cr,caller_context_t * ct)1170 lo_setsecattr(
1171 vnode_t *vp,
1172 vsecattr_t *secattr,
1173 int flags,
1174 struct cred *cr,
1175 caller_context_t *ct)
1176 {
1177 if (vn_is_readonly(vp))
1178 return (EROFS);
1179 vp = realvp(vp);
1180 return (VOP_SETSECATTR(vp, secattr, flags, cr, ct));
1181 }
1182
1183 static int
lo_getsecattr(vnode_t * vp,vsecattr_t * secattr,int flags,struct cred * cr,caller_context_t * ct)1184 lo_getsecattr(
1185 vnode_t *vp,
1186 vsecattr_t *secattr,
1187 int flags,
1188 struct cred *cr,
1189 caller_context_t *ct)
1190 {
1191 vp = realvp(vp);
1192 return (VOP_GETSECATTR(vp, secattr, flags, cr, ct));
1193 }
1194
1195 static int
lo_shrlock(vnode_t * vp,int cmd,struct shrlock * shr,int flag,cred_t * cr,caller_context_t * ct)1196 lo_shrlock(
1197 vnode_t *vp,
1198 int cmd,
1199 struct shrlock *shr,
1200 int flag,
1201 cred_t *cr,
1202 caller_context_t *ct)
1203 {
1204 vp = realvp(vp);
1205 return (VOP_SHRLOCK(vp, cmd, shr, flag, cr, ct));
1206 }
1207
1208 /*
1209 * Loopback vnode operations vector.
1210 */
1211
1212 struct vnodeops *lo_vnodeops;
1213
1214 const fs_operation_def_t lo_vnodeops_template[] = {
1215 VOPNAME_OPEN, { .vop_open = lo_open },
1216 VOPNAME_CLOSE, { .vop_close = lo_close },
1217 VOPNAME_READ, { .vop_read = lo_read },
1218 VOPNAME_WRITE, { .vop_write = lo_write },
1219 VOPNAME_IOCTL, { .vop_ioctl = lo_ioctl },
1220 VOPNAME_SETFL, { .vop_setfl = lo_setfl },
1221 VOPNAME_GETATTR, { .vop_getattr = lo_getattr },
1222 VOPNAME_SETATTR, { .vop_setattr = lo_setattr },
1223 VOPNAME_ACCESS, { .vop_access = lo_access },
1224 VOPNAME_LOOKUP, { .vop_lookup = lo_lookup },
1225 VOPNAME_CREATE, { .vop_create = lo_create },
1226 VOPNAME_REMOVE, { .vop_remove = lo_remove },
1227 VOPNAME_LINK, { .vop_link = lo_link },
1228 VOPNAME_RENAME, { .vop_rename = lo_rename },
1229 VOPNAME_MKDIR, { .vop_mkdir = lo_mkdir },
1230 VOPNAME_RMDIR, { .vop_rmdir = lo_rmdir },
1231 VOPNAME_READDIR, { .vop_readdir = lo_readdir },
1232 VOPNAME_SYMLINK, { .vop_symlink = lo_symlink },
1233 VOPNAME_READLINK, { .vop_readlink = lo_readlink },
1234 VOPNAME_FSYNC, { .vop_fsync = lo_fsync },
1235 VOPNAME_INACTIVE, { .vop_inactive = lo_inactive },
1236 VOPNAME_FID, { .vop_fid = lo_fid },
1237 VOPNAME_RWLOCK, { .vop_rwlock = lo_rwlock },
1238 VOPNAME_RWUNLOCK, { .vop_rwunlock = lo_rwunlock },
1239 VOPNAME_SEEK, { .vop_seek = lo_seek },
1240 VOPNAME_CMP, { .vop_cmp = lo_cmp },
1241 VOPNAME_FRLOCK, { .vop_frlock = lo_frlock },
1242 VOPNAME_SPACE, { .vop_space = lo_space },
1243 VOPNAME_REALVP, { .vop_realvp = lo_realvp },
1244 VOPNAME_GETPAGE, { .vop_getpage = lo_getpage },
1245 VOPNAME_PUTPAGE, { .vop_putpage = lo_putpage },
1246 VOPNAME_MAP, { .vop_map = lo_map },
1247 VOPNAME_ADDMAP, { .vop_addmap = lo_addmap },
1248 VOPNAME_DELMAP, { .vop_delmap = lo_delmap },
1249 VOPNAME_POLL, { .vop_poll = lo_poll },
1250 VOPNAME_DUMP, { .vop_dump = lo_dump },
1251 VOPNAME_DUMPCTL, { .error = fs_error }, /* XXX - why? */
1252 VOPNAME_PATHCONF, { .vop_pathconf = lo_pathconf },
1253 VOPNAME_PAGEIO, { .vop_pageio = lo_pageio },
1254 VOPNAME_DISPOSE, { .vop_dispose = lo_dispose },
1255 VOPNAME_SETSECATTR, { .vop_setsecattr = lo_setsecattr },
1256 VOPNAME_GETSECATTR, { .vop_getsecattr = lo_getsecattr },
1257 VOPNAME_SHRLOCK, { .vop_shrlock = lo_shrlock },
1258 NULL, NULL
1259 };
1260