NAMEI(9) | Kernel Developer's Manual | NAMEI(9) |
namei
, NDINIT
,
NDAT
, namei_simple_kernel
,
namei_simple_user
, relookup
,
lookup_for_nfsd
,
lookup_for_nfsd_index
—
#include <sys/namei.h>
#include <sys/uio.h>
#include <sys/vnode.h>
NDINIT
(struct
nameidata *ndp, u_long
op, u_long flags,
struct pathbuf
*pathbuf);
NDAT
(struct
nameidata *ndp, struct
vnode *dvp);
int
namei
(struct
nameidata *ndp);
int
namei_simple_kernel
(const
char *path,
namei_simple_flags_t
sflags, struct vnode
**ret);
int
namei_simple_user
(const
char *path,
namei_simple_flags_t
sflags, struct vnode
**ret);
int
relookup
(struct
vnode *dvp, struct vnode
**vpp, struct
componentname *cnp, int
dummy);
int
lookup_for_nfsd
(struct
nameidata *ndp, struct
vnode *startdir, int
neverfollow);
int
lookup_for_nfsd_index
(struct
nameidata *ndp, struct
vnode *startdir);
namei
interface is used to convert pathnames to file
system vnodes. The name of the interface is actually a contraction of the
words name and inode for name-to-inode
conversion, in the days before the
vfs(9) interface was implemented.
All access to the namei
interface must be
in process context. Pathname lookups cannot be done in interrupt
context.
In the general form of namei
, a caller
must:
NDINIT
()
and optionally NDAT
() to specify the arguments to
a lookup.namei
() and handle failure if it returns a
nonzero error code..ni_vp
. If requested with
LOCKPARENT
, read the directory vnode out of
nd.ni_dvp
..ni_cnd
.The other fields of struct nameidata should not be examined or altered directly.
Note that the nfs(4)
code misuses struct nameidata and currently has an
incestuous relationship with the namei
code. This is
gradually being cleaned up.
The struct componentname type has the following layout:
struct componentname { /* * Arguments to VOP_LOOKUP and directory VOP routines. */ uint32_t cn_nameiop; /* namei operation */ uint32_t cn_flags; /* flags to namei */ kauth_cred_t cn_cred; /* credentials */ const char *cn_nameptr; /* pointer to looked up name */ size_t cn_namelen; /* length of looked up comp */ /* * Side result from VOP_LOOKUP. */ size_t cn_consume; /* chars to consume in lookup */ };
This structure contains the information about a single directory component name, along with certain other information required by vnode operations. See vnodeops(9) for more information about these vnode operations.
The members:
LOOKUP
,
CREATE
, DELETE
, or
RENAME
. These modes are described below.namei
with NDINIT
() and
specified internally by namei
to
VOP_LOOKUP(9):
namei
specify the mode for the last
component of a lookup.namei
recursively calls
VOP_LOOKUP(9) in
LOOKUP
mode for each directory component, and then
finally calls
VOP_LOOKUP(9) in the
caller-specified mode for the last component.LOOKUP
mode fails with ENOENT
if no entry exists, but CREATE
mode succeeds with a
NULL
vnode.
LOOKUP
LOOKUP
for operations on existing vnodes:
stat(2),
open(2) without
O_CREATE
, etc.
File systems:
ENOENT
]CREATE
NULL
and hint that it will soon be created.
Callers specify CREATE
for operations that may
create directory entries:
mkdir(2),
open(2) with
O_CREATE
, etc.
File systems:
EPERM
]EPERM
]EROFS
]DELETE
DELETE
for operations
that delete directory entries:
unlink(2),
rmdir(2), etc.
File systems:
ENOENT
]EPERM
]EPERM
]EROFS
]RENAME
NULL
, and
hint that it will soon be created.
Callers specify RENAME
for an entry
that is about to be created or overwritten, namely for the target of
rename(2).
File systems:
EPERM
]EPERM
]EROFS
]If a caller decides not to perform an operation it hinted at by a
destructive operating mode (CREATE
,
DELETE
, or
RENAME
), it SHOULD call
VOP_ABORTOP(9) to release
the hints. If a file system fails to perform such an operation, it SHOULD
call VOP_ABORTOP(9) to
release the hints. However, the current code is inconsistent about this, and
every implementation of
VOP_ABORTOP(9) does
nothing.
namei
, and MUST NOT be used by file systems:
FOLLOW
NOFOLLOW
Note: The value of NOFOLLOW
is 0. We
define the constant to let callers say either
FOLLOW
or NOFOLLOW
explicitly.
LOCKLEAF
->ni_vp
. Without this
flag, it would be unlocked.LOCKPARENT
->ni_dvp
. Without this
flag, it is not returned at all.TRYEMULROOT
EMULROOTSET
->ni_erootdir
prior to
calling namei
. This is only useful or permitted
when the emulation in the current process is partway through being set
up.NOCHROOT
NOCROSSMOUNT
RDONLY
CREATEDIR
CREATE
mode and when creating a
directory.NOCACHE
RENAME
mode for the target; the
cache entry would be invalidated immediately.The following flag may be set by a caller of
namei
and tested by a file system in
VOP_LOOKUP(9) or other
subsequent directory operations:
DOWHITEOUT
The following flags are set by namei for calling VOP_LOOKUP(9):
ISDOTDOT
..
”. May be tested by subsequent
directory operations too.ISLASTCN
REQUIREDIR
MAKEENTRY
A file system may set the following flag on return from
VOP_LOOKUP(9) for use by
namei
,
namecache(9), and
subsequent directory operations:
ISWHITEOUT
The following additional historic flags have been removed from NetBSD and should be handled as follows if porting code from elsewhere:
INRENAME
VOP_RENAME
().INRELOOKUP
ISSYMLINK
SAVESTART
SAVENAME
namei
owns the
pathbuf structure and is always responsible for
destroying it.HASBUF
NDINIT
(ndp,
op, flags,
pathbuf)namei
interface. The operating mode
and flags (as documented above) are specified by op
and flags respectively. The pathname is passed as a
pathbuf structure, which should be initialized using one of the
pathbuf(9) operations.
Destroying the pathbuf is the responsibility of the caller; this must not
be done until the caller is finished with all of the
namei
results and all of the nameidata contents
except for the result vnode.
This routine stores the credentials of the calling thread
(curlwp) in ndp.
NDINIT
() sets the credentials using
kauth_cred_get(9).
In the rare case that another set of credentials is required for the
namei operation, ndp->ni_cnd.cn_cred must be set
manually after NDINIT
().
NDAT
(ndp,
dvp)NDINIT
() to set the
starting directory. This supersedes the current process's current working
directory as the initial point of departure for looking up relative paths.
This mechanism is used by
openat(2) and related
calls.namei
(ndp)NDINIT
() macro, and perhaps also the
NDAT
() macro. Direct initialization of members of
struct nameidata is not supported and may (will) break
silently in the future.
The vnode for the pathname is returned in
ndp->ni_vp. The parent directory is returned locked
in ndp->ni_dvp iff
LOCKPARENT
is specified.
Any or all of the flags documented above as set by the caller
can be enabled by passing them (OR'd together) as the
flags argument of
NDINIT
(). As discussed above every such call
should explicitly contain either FOLLOW
or
NOFOLLOW
to control the behavior regarding final
symbolic links.
namei_simple_kernel
(path,
sflags, ret)UIO_SYSSPACE
) pointer.
The sflags argument chooses the precise behavior. It
may be set to one of the following symbols:
These select (or not) the FOLLOW/NOFOLLOW
and
TRYEMULROOT
flags. Other flags are not available
through this interface, which is nonetheless sufficient for more than half
the namei
() usage in the kernel. Note that the
encoding of sflags has deliberately been arranged to
be type-incompatible with anything else. This prevents various possible
accidents while the namei
() interface is being
rototilled.namei_simple_user
(path,
sflags, ret)namei_simple_kernel
()
except that the path argument shall be a user
pointer (UIO_USERSPACE
) rather than a kernel
pointer.relookup
(dvp,
vpp, cnp,
dummy)relookup
() to repeat a lookup of a final path
component previously done by namei
, and one must
use the same componentname structure that call produced.
Otherwise the behavior is undefined and likely adverse.lookup_for_nfsd
(ndp,
startdir, neverfollow)namei
used by
the NFS server code. It looks up a path starting from
startdir. If neverfollow is
set, any symbolic link (not just at the end of the path)
will cause an error. Otherwise, it follows symlinks normally. It should
not be used by new code.lookup_for_nfsd_index
(ndp,
startdir)namei
used by the NFS server code. It looks up a single path component starting
from startdir. It should not be used by new
code.struct nameidata { /* * Arguments to namei. */ struct vnode *ni_atdir; /* startup dir, cwd if null */ struct pathbuf *ni_pathbuf; /* pathname container */ char *ni_pnbuf; /* extra pathname buffer ref (XXX) */ /* * Internal starting state. (But see notes.) */ struct vnode *ni_rootdir; /* logical root directory */ struct vnode *ni_erootdir; /* emulation root directory */ /* * Results from namei. */ struct vnode *ni_vp; /* vnode of result */ struct vnode *ni_dvp; /* vnode of intermediate directory */ /* * Internal current state. */ size_t ni_pathlen; /* remaining chars in path */ const char *ni_next; /* next location in pathname */ unsigned int ni_loopcnt; /* count of symlinks encountered */ /* * Lookup parameters: this structure describes the subset of * information from the nameidata structure that is passed * through the VOP interface. */ struct componentname ni_cnd; };
These fields are:
NULL
by NDINIT
() and set
by NDAT
().NDINIT
(). The name pointers that appear elsewhere,
such as in the componentname structure, point into this
buffer. It is owned by the caller and must not be destroyed until all
namei
operations are complete. See
pathbuf(9).namei
. It
points into ni_pathbuf. It is not initialized until
entry into namei
.namei
starts up. It is not initialized by
NDINIT
().namei
starts up and not initialized
by NDINIT
(). As described elsewhere, it may be set
by the caller if the EMULROOTSET
flag is used, but
this should only be done when the current process's emulation root
directory is not yet initialized. (And ideally in the future things would
be tidied so that this is not necessary.)namei
returns successfully.NDINIT
() and is used only internally.NDINIT
() and is used only internally.namei
fails with
ELOOP
. This is not initialized by
NDINIT
() and is used only internally.NDINIT
(); the rest is not initialized until
namei
runs.There is also a namei_state structure that is hidden within vfs_lookup.c. This contains the following additional state:
RDONLY
flag.The state in namei_state is genuinely private to
namei
. Note that much of the state in
nameidata should also be private, but is currently not
because it is misused in some fashion by outside code, usually
nfs(4).
The control flow within the namei
portions
of vfs_lookup.c is as follows.
namei
()namei_init
(),
namei_tryemulroot
(), and
namei_cleanup
().namei_init
()namei_cleanup
()namei_tryemulroot
()TRYEMULROOT
by calling
namei_oneroot
() once or twice as needed, and
attends to making sure the original pathname is preserved for the second
try.namei_oneroot
()namei_start
(), then calls
lookup_once
() (and if necessary,
namei_follow
()) repeatedly until done. It also
handles returning the result vnode(s) in the requested state.namei_start
()namei_getstartdir
().namei_getstartdir
()namei_getstartdir_for_nfsd
() is used for lookups
coming from nfsd(8) as those
are required to have different semantics.lookup_once
()VOP_LOOKUP
() for one path component, also
handling any needed crossing of mount points (either up or down) and
coping with locking requirements.lookup_parsepath
()lookup_once
() call to
examine the pathname and find where the next component starts.namei_follow
()As a final note be advised that the magic return value associated
with CREATE
mode is different for
namei
than it is for
VOP_LOOKUP
(). The latter “fails” with
EJUSTRETURN
. namei
translates this into succeeding and returning a null vnode.
LOOKUP
is actually needed. The behavior where removing
an object looks it up within namei
and then calls into
the file system (which must look it up again internally or cache state from
VOP_LOOKUP
()) is particularly contorted.
Most of the flags are equally bogus.
Most of the contents of the nameidata structure
should be private and hidden within namei
; currently
it cannot be because of abuse elsewhere.
The EMULROOTSET
flag is messy.
There is no good way to support file systems that want to use a more elaborate pathname schema than the customary slash-delimited components.
May 5, 2019 | NetBSD 9.0 |