lofs_vnops.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/pathname.h>
#define IS_ZONEDEVFS(vp) \
/*
* These are the vnode ops routines which implement the vnode interface to
* the looped-back file system. These routines just take their parameters,
* and then calling the appropriate real vnode routine(s) to do the work.
*/
static int
{
int error;
#ifdef LODEBUG
#endif
/*
* Need to hold new reference to vp since VOP_OPEN() may
* decide to release it.
*/
/*
* the FS which we called should have released the
* new reference on vp
*/
else
}
} else {
}
return (error);
}
static int
int flag,
int count,
{
#ifdef LODEBUG
#endif
}
static int
{
#ifdef LODEBUG
#endif
}
static int
{
#ifdef LODEBUG
#endif
}
static int
int cmd,
int flag,
int *rvalp)
{
#ifdef LODEBUG
#endif
}
static int
{
}
static int
int flags,
{
int error;
#ifdef LODEBUG
#endif
return (error);
/*
* In zonedevfs mode, we pull a nasty trick; we make sure that
* the dev_t does *not* reflect the underlying device, so that
* no renames can occur to or from the /dev hierarchy.
*/
if (IS_ZONEDEVFS(vp)) {
}
return (0);
}
static int
int flags,
{
#ifdef LODEBUG
#endif
return (EACCES);
}
}
static int
{
#ifdef LODEBUG
#endif
return (EROFS);
return (EACCES);
}
}
static int
{
#ifdef LODEBUG
#endif
}
/*ARGSUSED*/
static void
{
#ifdef LODEBUG
#endif
}
/* ARGSUSED */
static int
{
#ifdef LODEBUG
#endif
}
/*
* Given a vnode of lofs type, lookup nm name and
* return a shadow vnode (of lofs type) of the
* real vnode found.
*
* Due to the nature of lofs, there is a potential
* looping in path traversal.
*
* starting from the mount point of an lofs;
* a loop is defined to be a traversal path
* where the mount point or the real vnode of
* the root of this lofs is encountered twice.
* Once at the start of traversal and second
* when the looping is found.
*
* When a loop is encountered, a shadow of the
* covered vnode is returned to stop the looping.
*
* This normally works, but with the advent of
* the new automounter, returning the shadow of the
* covered vnode (autonode, in this case) does not
* stop the loop. Because further lookup on this
* lonode will cause the autonode to call lo_lookup()
* on the lonode covering it.
*
* returning the shadow of the autonode corresponding to
* loop. To solve this problem we allow the loop to go
* through one more level component lookup. If it hit
* then returning the vnode covered by the autonode "net"
* will terminate the loop.
*
* Lookup for dot dot has to be dealt with separately.
* It will be nice to have a "one size fits all" kind
* of solution, so that we don't have so many ifs statement
* in the lo_lookup() to handle dotdot. But, since
* there are so many special cases to handle different
* kinds looping above, we need special codes to handle
* dotdot lookup as well.
*/
static int
char *nm,
int flags,
{
int error, is_indirectloop;
int looping = 0;
int doingdotdot = 0;
int nosub = 0;
/*
* If name is empty and no XATTR flags are set, then return
* dvp (empty name == lookup "."). If an XATTR flag is set
* then we need to call VOP_LOOKUP to get the xattr dir.
*/
return (0);
}
doingdotdot++;
/*
* Handle ".." out of mounted filesystem
*/
}
}
/*
* Do the normal lookup
*/
goto out;
/*
* We do this check here to avoid returning a stale file handle to the
* caller.
*/
return (0);
}
if (doingdotdot) {
if (error)
goto out;
/*
* if looping get the actual found vnode
* instead of the vnode covered
* Here we have to hold the lock for realdvp
* since an unmount during the traversal to the
* root vnode would turn *vfsp into garbage
* which would be fatal.
*/
if (error)
goto out;
/*
* we're back at the real vnode
* of the rootvp
*
* return the rootvp
* where / has been lofs-mounted
* onto /mnt. Return the lofs
* node mounted at /mnt.
*/
return (0);
} else {
/*
* We are returning from a covered
* node whose vfs_mountedhere is
* not pointing to vfs of the current
* root vnode.
* This is a condn where in we
* returned a covered node say Zc
* but Zc is not the cover of current
* root.
* i.e.., if X is the root vnode
* lookup(Zc,"..") is taking us to
* X.
* We are encountering cover of net.
* doing a dotdot from here means we
* to take the lookup to the same state
* that would have happened when we do
*/
return (0);
}
}
} else {
/*
* We are returning from a looping dvp.
* If we are returning to rootvp return
* the covered node with looping bit set.
*
* This means we are not returning from cover
* but we should return to the root node by
* giving the covered node with looping flag
* set. We are returning from a non-covernode
* with looping bit set means we couldn't stop
* by giving the cover of root vnode.
*
* Say X is the root vnode and lookup of
* X again under X returns Xc(due to looping
* condn). let Z=lookup(Xc,"path") and
* if lookup(Z,"..") returns the root vp X
* return Xc with looping bit set or if a new
* node Z.. is returned make a shadow with a
* looping flag.
*
* In the first case we are returning to root
* we will return the cover of root with
* looping bit set.
*/
}
return (0);
}
} else {
/*
* No frills just make the shadow node.
*/
return (0);
}
}
/*
* If this vnode is mounted on, then we
* traverse to the vnode which is the root of
* the mounted file system.
*/
goto out;
/*
* Make a lnode for the real vnode.
*/
else
}
return (error);
}
/*
* if the found vnode (vp) is not of type lofs
* then we're just going to make a shadow of that
* vp and get out.
*
* If the found vnode (vp) is of lofs type, and
* we're not doing dotdot, check if we are
* looping.
*/
/*
* Check if we're looping, i.e.
* vp equals the root vp of the lofs, directly
* or indirectly, return the covered node.
*/
/*
* Direct looping condn.
* Ex:- X is / mounted directory so lookup of
* /X/X is a direct looping condn.
*/
looping++;
} else {
/*
* Indirect looping can be defined as
* real lookup returning rootvp of the current
* tree in any level of recursion.
*
* This check is useful if there are multiple
* levels of lofs indirections. Suppose vnode X
* in the current lookup has as its real vnode
* another lofs node. Y = realvp(X) Y should be
* a lofs node for the check to continue or Y
* is not the rootvp of X.
* Ex:- say X and Y are two vnodes
* say real(Y) is X and real(X) is Z
* parent vnode for X and Y is Z
* lookup(Y,"path") say we are looking for Y
* again under Y and we have to return Yc.
* but the lookup of Y under Y doesnot return
* Y the root vnode again here is why.
* 1. lookup(Y,"path of Y") will go to
* 2. lookup(real(Y),"path of Y") and then to
* 3. lookup(real(X),"path of Y").
* and now what lookup level 1 sees is the
* outcome of 2 but the vnode Y is due to
* lookup(Z,"path of Y") so we have to skip
* intermediate levels to find if in any level
* there is a looping.
*/
is_indirectloop = 0;
while (
!(is_indirectloop)) {
break;
}
}
if (is_indirectloop) {
looping++;
}
}
} else {
/*
* come here only because of the interaction between
* the autofs and lofs.
*
* an autonode X_a which we call X_l.
*
* Lookup of anything under X_l, will trigger a call to
* auto_lookup(X_a,nm) which will eventually call
* lo_lookup(X_lr,nm) where X_lr is the root vnode of
* the current lofs.
*
* We come here only when we are called with X_l as dvp
* and look for something underneath.
*
* We need to find out if the vnode, which vp is
* shadowing, is the rootvp of the autofs.
*
*/
}
if (error)
goto out;
/*
* tvp now contains the rootvp of the vfs of the
* real vnode of dvp
*/
/*
* vp is the shadow of "net",
* the rootvp of autofs
*/
/*
* Need to find the covered vnode
*/
} else {
}
}
}
}
out:
#ifdef LODEBUG
lo_dprint(4,
"lo_lookup dvp %x realdvp %x nm '%s' newvp %x real vp %x error %d\n",
#endif
return (error);
}
/*ARGSUSED*/
static int
char *nm,
int mode,
int flag)
{
int error;
#ifdef LODEBUG
#endif
if (*nm == '\0') {
}
if (IS_ZONEDEVFS(dvp)) {
/* Is this truly a create? If so, fail */
return (EACCES);
/* Is this an open of a non-special for writing? If so, fail */
return (EACCES);
}
if (!error) {
else
}
}
return (error);
}
static int
{
#ifdef LODEBUG
#endif
if (IS_ZONEDEVFS(dvp))
return (EACCES);
}
static int
{
#ifdef LODEBUG
#endif
if (IS_ZONEDEVFS(vp))
return (EACCES);
}
if (IS_ZONEDEVFS(tdvp))
return (EACCES);
}
return (EXDEV);
}
static int
char *onm,
char *nnm,
{
#ifdef LODEBUG
#endif
if (IS_ZONEDEVFS(odvp))
return (EACCES);
/*
* We need to make sure we're not trying to remove a mount point for a
* filesystem mounted on top of lofs, which only we know about.
*/
goto rename;
goto rename;
goto rename;
}
if (vn_mountedvfs(tnvp)) {
return (EBUSY);
}
/*
* Since the case we're dealing with above can happen at any layer in
* the stack of lofs filesystems, we need to recurse down the stack,
* checking to see if there are any instances of a filesystem mounted on
* top of lofs. In order to keep on using the lofs version of
* VOP_RENAME(), we make sure that while the target directory is of type
* lofs, the source directory (the one used for getting the fs-specific
* version of VOP_RENAME()) is also of type lofs.
*/
if (IS_ZONEDEVFS(ndvp))
return (EACCES);
} else {
/*
* We can go fast here
*/
if (IS_ZONEDEVFS(odvp))
return (EACCES);
}
return (EXDEV);
}
}
static int
char *nm,
{
int error;
#ifdef LODEBUG
#endif
if (IS_ZONEDEVFS(dvp))
return (EACCES);
if (!error)
return (error);
}
static int
{
#ifdef LODEBUG
#endif
return (0);
}
static int
char *nm,
{
#ifdef LODEBUG
#endif
if (IS_ZONEDEVFS(dvp))
return (EACCES);
/* if cdir is lofs vnode ptr get its real vnode ptr */
}
static int
char *lnm,
char *tnm,
{
#ifdef LODEBUG
#endif
if (IS_ZONEDEVFS(dvp))
return (EACCES);
}
static int
{
}
static int
{
#ifdef LODEBUG
#endif
}
static int
{
}
static void
{
}
static int
{
}
static int
{
}
static int
int cmd,
int flag,
struct flk_callback *flk_cbp,
{
}
static int
int cmd,
int flag,
{
}
static int
{
}
static int
{
}
static int
{
}
static int
{
}
static int
{
}
static int
short events,
int anyyet,
short *reventsp,
{
}
static int
{
}
static int
{
}
static int
int flags,
{
}
static void
{
}
static int
{
if (vn_is_readonly(vp))
return (EROFS);
}
static int
{
}
static int
{
}
/*
* Loopback vnode operations vector.
*/
struct vnodeops *lo_vnodeops;
const fs_operation_def_t lo_vnodeops_template[] = {
};