lofs_vnops.c revision 52782930452a219339a03491668e436bcef2efd9
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/pathname.h>
/*
* 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
*/
/*
* Copy over any looping flags to the new lnode.
*/
}
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);
return (0);
}
static int
int flags,
{
#ifdef LODEBUG
#endif
}
static int
{
#ifdef LODEBUG
#endif
return (EROFS);
}
}
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. Whichever
* the vnode returned is the vnode covered by the autonode
* "net" and this 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 autoloop = 0;
int doingdotdot = 0;
int nosub = 0;
int mkflag = 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;
/*
* In the standard case if the looping flag is set and
* performing dotdot we would be returning from a
* covered vnode, implying vfsp could not be null. The
* exceptions being if we have looping and overlay
* mounts or looping and covered file systems.
*/
/*
* Overlay mount or covered file system,
* so just make the shadow node.
*/
return (0);
}
/*
* When 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.
*
* has been set then we are encountering the
* cover of Y (Y being any directory vnode
* When performing a dotdot set the
* returned vp to the vnode covered
*/
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.
*
* identified any directory vnode contained within
* dvp will be set to the vnode covered by the
* mounted autofs. Thus all directories within dvp
* will appear empty hence teminating the looping.
* The LO_AUTOLOOP flag is set on the returned lonode
* looping. This is required for the correct behaviour
* when performing a dotdot.
*/
}
if (error)
goto out;
/*
* tvp now contains the rootvp of the vfs of the
* real vnode of dvp. The directory vnode vp is set
* to the covered vnode to terminate looping. No
* distinction is made between any vp as all directory
* vnodes contained in dvp are returned as the covered
* vnode.
*/
/*
* Need to find the covered vnode
*/
/*
* We don't have a covered vnode so this isn't
* an autonode. To find the autonode simply
* find the vnode covered by the lofs rootvp.
*/
if (error)
goto out;
/*
* Still can't find a covered vnode.
* Fail the lookup, or we'd loop.
*/
goto out;
}
}
/*
* Force the creation of a new lnode even if the hash
* table contains a lnode that references this vnode.
*/
autoloop++;
}
}
if ((looping) ||
}
if (autoloop) {
}
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 (!error) {
else
}
}
return (error);
}
static int
{
#ifdef LODEBUG
#endif
}
static int
{
#ifdef LODEBUG
#endif
}
}
return (EXDEV);
}
static int
char *onm,
char *nnm,
{
#ifdef LODEBUG
#endif
/*
* If we are coming from a loop back mounted fs, that has been
* mounted in the same filesystem as where we want to move to,
* read only, we don't want to allow a rename of the file. The
* so that is not necessary here. However, consider the following
* example:
* / - regular root fs
* /foo - directory in root
* /baz - directory in root
* mount -F lofs -o ro /foo /baz - all still in root
* directory
* The fact that we mounted /foo on /baz read only should stop us
* in the same filesystem, it is just that we do not check to see
* if the filesystem we are coming from in this case is read only.
*/
return (EROFS);
/*
* 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.
*/
} else {
/*
* We can go fast here
*/
}
return (EXDEV);
}
}
static int
char *nm,
{
int error;
#ifdef LODEBUG
#endif
if (!error)
return (error);
}
static int
{
#ifdef LODEBUG
#endif
return (0);
}
static int
char *nm,
{
#ifdef LODEBUG
#endif
/* if cdir is lofs vnode ptr get its real vnode ptr */
}
static int
char *lnm,
char *tnm,
{
#ifdef LODEBUG
#endif
}
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[] = {
};