diff --git a/share/man/man9/namei.9 b/share/man/man9/namei.9 index f98646725fb3..807c68bbae02 100644 --- a/share/man/man9/namei.9 +++ b/share/man/man9/namei.9 @@ -1,368 +1,319 @@ .\" .\" Copyright (c) 1998, 1999 Eivind Eklund .\" Copyright (c) 2003 Hiten M. Pandya .\" Copyright (c) 2005 Robert N. M. Watson .\" .\" All rights reserved. .\" .\" This program is free software. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" .\" If you integrate this manpage in another OS, I'd appreciate a note .\" - eivind@FreeBSD.org .\" .\" $FreeBSD$ .\" -.Dd May 23, 2015 +.Dd July 8, 2023 .Dt NAMEI 9 .Os .Sh NAME .Nm namei , .Nm NDINIT , .Nm NDFREE .Nd pathname translation and lookup operations .Sh SYNOPSIS .In sys/param.h .In sys/fcntl.h .In sys/namei.h .Ft int .Fn namei "struct nameidata *ndp" .Ft void .Fo NDINIT .Fa "struct nameidata *ndp" "u_long op" "u_long flags" .Fa "enum uio_seg segflg" "const char *namep" "struct thread *td" .Fc .Ft void .Fn NDFREE "struct nameidata *ndp" "const uint flags" .Sh DESCRIPTION The .Nm facility allows the client to perform pathname translation and lookup operations. The .Nm functions will increment the reference count for the vnode in question. The reference count has to be decremented after use of the vnode, by using either .Xr vrele 9 or .Xr vput 9 , depending on whether the .Dv LOCKLEAF flag was specified or not. .Pp The .Fn NDINIT function is used to initialize .Nm components. It takes the following arguments: .Bl -tag -width ".Fa segflg" .It Fa ndp The .Vt "struct nameidata" to initialize. .It Fa op The operation which .Fn namei will perform. The following operations are valid: .Dv LOOKUP , CREATE , DELETE , and .Dv RENAME . The latter three are just setup for those effects; just calling .Fn namei will not result in .Fn VOP_RENAME being called. .It Fa flags Operation flags. Several of these can be effective at the same time. .It Fa segflg UIO segment indicator. This indicates if the name of the object is in userspace .Pq Dv UIO_USERSPACE or in the kernel address space .Pq Dv UIO_SYSSPACE . .It Fa namep Pointer to the component's pathname buffer (the file or directory name that will be looked up). .It Fa td The thread context to use for .Nm operations and locks. .El .Sh NAMEI OPERATION FLAGS The .Fn namei function takes the following set of .Dq "operation flags" that influence its operation: .Bl -tag -width ".Dv WANTPARENT" .It Dv LOCKLEAF Lock vnode on return with .Dv LK_EXCLUSIVE unless .Dv LOCKSHARED is also set. The .Xr VOP_UNLOCK 9 should be used to release the lock (or .Xr vput 9 which is equivalent to calling .Xr VOP_UNLOCK 9 followed by .Xr vrele 9 , all in one). .It Dv LOCKPARENT This flag lets the .Fn namei function return the parent (directory) vnode, .Va ni_dvp in locked state, unless it is identical to .Va ni_vp , in which case .Va ni_dvp is not locked per se (but may be locked due to .Dv LOCKLEAF ) . If a lock is enforced, it should be released using .Xr vput 9 or .Xr VOP_UNLOCK 9 and .Xr vrele 9 . .It Dv LOCKSHARED Lock vnode on return with .Dv LK_SHARED . The .Xr VOP_UNLOCK 9 should be used to release the lock (or .Xr vput 9 which is equivalent to calling .Xr VOP_UNLOCK 9 followed by .Xr vrele 9 , all in one). .It Dv WANTPARENT This flag allows the .Fn namei function to return the parent (directory) vnode in an unlocked state. The parent vnode must be released separately by using .Xr vrele 9 . .It Dv NOCACHE Avoid .Fn namei creating this entry in the namecache if it is not already present. Normally, .Fn namei will add entries to the name cache if they are not already there. .It Dv FOLLOW With this flag, .Fn namei will follow the symbolic link if the last part of the path supplied is a symbolic link (i.e., it will return a vnode for whatever the link points at, instead for the link itself). .It Dv NOFOLLOW Do not follow symbolic links (pseudo). This flag is not looked for by the actual code, which looks for .Dv FOLLOW . .Dv NOFOLLOW is used to indicate to the source code reader that symlinks are intentionally not followed. .It Dv SAVENAME Do not free the pathname buffer at the end of the .Fn namei invocation; instead, free it later in .Fn NDFREE so that the caller may access the pathname buffer. See below for details. .It Dv SAVESTART Retain an additional reference to the parent directory; do not free the pathname buffer. See below for details. .El .Sh ALLOCATED ELEMENTS The .Vt nameidata structure is composed of the following fields: .Bl -tag -width ".Va ni_cnd.cn_pnbuf" .It Va ni_startdir In the normal case, this is either the current directory or the root. It is the current directory if the name passed in does not start with .Ql / and we have not gone through any symlinks with an absolute path, and the root otherwise. .Pp In this case, it is only used by -.Fn lookup , +.Fn vfs_lookup , and should not be considered valid after a call to .Fn namei . -If -.Dv SAVESTART -is set, this is set to the same as -.Va ni_dvp , -with an extra -.Xr vref 9 . -To block -.Fn NDFREE -from releasing -.Va ni_startdir , -the -.Dv NDF_NO_STARTDIR_RELE -can be set. .It Va ni_dvp Vnode pointer to directory of the object on which lookup is performed. This is available on successful return if .Dv LOCKPARENT or .Dv WANTPARENT is set. It is locked if .Dv LOCKPARENT is set. -Freeing this in -.Fn NDFREE -can be inhibited by -.Dv NDF_NO_DVP_RELE , NDF_NO_DVP_PUT , -or -.Dv NDF_NO_DVP_UNLOCK -(with the obvious effects). .It Va ni_vp Vnode pointer to the resulting object, .Dv NULL otherwise. The .Va v_usecount field of this vnode is incremented. If .Dv LOCKLEAF is set, it is also locked. .Pp -Freeing this in -.Fn NDFREE -can be inhibited by -.Dv NDF_NO_VP_RELE , NDF_NO_VP_PUT , -or -.Dv NDF_NO_VP_UNLOCK -(with the obvious effects). .It Va ni_cnd.cn_pnbuf The pathname buffer contains the location of the file or directory that will be used by the .Nm operations. It is managed by the .Xr uma 9 zone allocation interface. -If the -.Dv SAVESTART -or -.Dv SAVENAME -flag is set, then the pathname buffer is available -after calling the -.Fn namei -function. -.Pp -To only deallocate resources used by the pathname buffer, -.Va ni_cnd.cn_pnbuf , -then -.Dv NDF_ONLY_PNBUF -flag can be passed to the -.Fn NDFREE -function. -To keep the pathname buffer intact, -the -.Dv NDF_NO_FREE_PNBUF -flag can be passed to the -.Fn NDFREE -function. .El .Sh RETURN VALUES If successful, .Fn namei will return 0, otherwise it will return an error. .Sh FILES .Bl -tag -width Pa .It Pa src/sys/kern/vfs_lookup.c .El .Sh ERRORS Errors which .Fn namei may return: .Bl -tag -width Er .It Bq Er ENOTDIR A component of the specified pathname is not a directory when a directory is expected. .It Bq Er ENAMETOOLONG A component of a pathname exceeded 255 characters, or an entire pathname exceeded 1023 characters. .It Bq Er ENOENT A component of the specified pathname does not exist, or the pathname is an empty string. .It Bq Er EACCES An attempt is made to access a file in a way forbidden by its file access permissions. .It Bq Er ELOOP Too many symbolic links were encountered in translating the pathname. .It Bq Er EISDIR An attempt is made to open a directory with write mode specified. .It Bq Er EINVAL The last component of the pathname specified for a .Dv DELETE or .Dv RENAME operation is .Ql \&. . .It Bq Er EROFS An attempt is made to modify a file or directory on a read-only file system. .El .Sh SEE ALSO .Xr uio 9 , .Xr uma 9 , .Xr VFS 9 , .Xr vnode 9 , .Xr vput 9 , .Xr vref 9 .Sh AUTHORS .An -nosplit This manual page was written by .An Eivind Eklund Aq Mt eivind@FreeBSD.org and later significantly revised by .An Hiten M. Pandya Aq Mt hmp@FreeBSD.org . .Sh BUGS The .Dv LOCKPARENT flag does not always result in the parent vnode being locked. This results in complications when the .Dv LOCKPARENT is used. In order to solve this for the cases where both .Dv LOCKPARENT and .Dv LOCKLEAF are used, it is necessary to resort to recursive locking. diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 88ddb0f13458..547b337c7e32 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -1,321 +1,312 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1985, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)namei.h 8.5 (Berkeley) 1/9/95 * $FreeBSD$ */ #ifndef _SYS_NAMEI_H_ #define _SYS_NAMEI_H_ #include #include #include #include #include enum nameiop { LOOKUP, CREATE, DELETE, RENAME }; struct componentname { /* * Arguments to lookup. */ u_int64_t cn_flags; /* flags to namei */ struct ucred *cn_cred; /* credentials */ enum nameiop cn_nameiop; /* namei operation */ int cn_lkflags; /* Lock flags LK_EXCLUSIVE or LK_SHARED */ /* * Shared between lookup and commit routines. */ char *cn_pnbuf; /* pathname buffer */ char *cn_nameptr; /* pointer to looked up name */ long cn_namelen; /* length of looked up component */ }; struct nameicap_tracker; TAILQ_HEAD(nameicap_tracker_head, nameicap_tracker); /* * Encapsulation of namei parameters. */ struct nameidata { /* * Arguments to namei/lookup. */ const char *ni_dirp; /* pathname pointer */ enum uio_seg ni_segflg; /* location of pathname */ cap_rights_t *ni_rightsneeded; /* rights required to look up vnode */ /* * Arguments to lookup. */ struct vnode *ni_startdir; /* starting directory */ struct vnode *ni_rootdir; /* logical root directory */ struct vnode *ni_topdir; /* logical top directory */ int ni_dirfd; /* starting directory for *at functions */ int ni_lcf; /* local call flags */ /* * Results: returned from namei */ struct filecaps ni_filecaps; /* rights the *at base has */ /* * Results: returned from/manipulated by lookup */ struct vnode *ni_vp; /* vnode of result */ struct vnode *ni_dvp; /* vnode of intermediate directory */ /* * Results: flags returned from namei */ u_int ni_resflags; /* * Debug for validating API use by the callers. */ u_short ni_debugflags; /* * Shared between namei and lookup/commit routines. */ u_short ni_loopcnt; /* count of symlinks encountered */ size_t ni_pathlen; /* remaining chars in path */ char *ni_next; /* next location in pathname */ /* * Lookup parameters: this structure describes the subset of * information from the nameidata structure that is passed * through the VOP interface. */ struct componentname ni_cnd; struct nameicap_tracker_head ni_cap_tracker; /* * Private helper data for UFS, must be at the end. See * NDINIT_PREFILL(). */ seqc_t ni_dvp_seqc; seqc_t ni_vp_seqc; }; #ifdef _KERNEL enum cache_fpl_status { CACHE_FPL_STATUS_DESTROYED, CACHE_FPL_STATUS_ABORTED, CACHE_FPL_STATUS_PARTIAL, CACHE_FPL_STATUS_HANDLED, CACHE_FPL_STATUS_UNSET }; int cache_fplookup(struct nameidata *ndp, enum cache_fpl_status *status, struct pwd **pwdp); /* * Flags for namei. * * If modifying the list make sure to check whether NDVALIDATE needs updating. */ /* * Debug. */ #define NAMEI_DBG_INITED 0x0001 #define NAMEI_DBG_CALLED 0x0002 #define NAMEI_DBG_HADSTARTDIR 0x0004 /* * namei operational modifier flags, stored in ni_cnd.flags */ #define NC_NOMAKEENTRY 0x0001 /* name must not be added to cache */ #define NC_KEEPPOSENTRY 0x0002 /* don't evict a positive entry */ #define NOCACHE NC_NOMAKEENTRY /* for compatibility with older code */ #define LOCKLEAF 0x0004 /* lock vnode on return */ #define LOCKPARENT 0x0008 /* want parent vnode returned locked */ #define WANTPARENT 0x0010 /* want parent vnode returned unlocked */ #define FAILIFEXISTS 0x0020 /* return EEXIST if found */ #define FOLLOW 0x0040 /* follow symbolic links */ #define EMPTYPATH 0x0080 /* Allow empty path for *at */ #define LOCKSHARED 0x0100 /* Shared lock leaf */ #define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */ #define RBENEATH 0x100000000ULL /* No escape, even tmp, from start dir */ #define MODMASK 0xf000001ffULL /* mask of operational modifiers */ /* * Namei parameter descriptors. */ #define RDONLY 0x00000200 /* lookup with read-only semantics */ #define ISRESTARTED 0x00000400 /* restarted namei */ /* UNUSED 0x00000800 */ #define ISWHITEOUT 0x00001000 /* found whiteout */ #define DOWHITEOUT 0x00002000 /* do whiteouts */ #define WILLBEDIR 0x00004000 /* new files will be dirs; allow trailing / */ #define ISOPEN 0x00008000 /* caller is opening; return a real vnode. */ #define NOCROSSMOUNT 0x00010000 /* do not cross mount points */ #define NOMACCHECK 0x00020000 /* do not perform MAC checks */ #define AUDITVNODE1 0x00040000 /* audit the looked up vnode information */ #define AUDITVNODE2 0x00080000 /* audit the looked up vnode information */ #define NOCAPCHECK 0x00100000 /* do not perform capability checks */ #define OPENREAD 0x00200000 /* open for reading */ #define OPENWRITE 0x00400000 /* open for writing */ #define WANTIOCTLCAPS 0x00800000 /* leave ioctl caps for the caller */ /* UNUSED 0x01000000 */ #define NOEXECCHECK 0x02000000 /* do not perform exec check on dir */ #define MAKEENTRY 0x04000000 /* entry is to be added to name cache */ #define ISSYMLINK 0x08000000 /* symlink needs interpretation */ #define ISLASTCN 0x10000000 /* this is last component of pathname */ #define ISDOTDOT 0x20000000 /* current component name is .. */ #define TRAILINGSLASH 0x40000000 /* path ended in a slash */ #define PARAMASK 0x7ffffe00 /* mask of parameter descriptors */ /* * Flags which must not be passed in by callers. */ #define NAMEI_INTERNAL_FLAGS \ (NOEXECCHECK | MAKEENTRY | ISSYMLINK | ISLASTCN | ISDOTDOT | \ TRAILINGSLASH | ISRESTARTED) /* * Namei results flags */ #define NIRES_ABS 0x00000001 /* Path was absolute */ #define NIRES_STRICTREL 0x00000002 /* Restricted lookup result */ #define NIRES_EMPTYPATH 0x00000004 /* EMPTYPATH used */ /* * Flags in ni_lcf, valid for the duration of the namei call. */ #define NI_LCF_STRICTRELATIVE 0x0001 /* relative lookup only */ #define NI_LCF_CAP_DOTDOT 0x0002 /* ".." in strictrelative case */ /* * Initialization of a nameidata structure. */ #define NDINIT(ndp, op, flags, segflg, namep) \ NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, NULL, &cap_no_rights) #define NDINIT_AT(ndp, op, flags, segflg, namep, dirfd) \ NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, &cap_no_rights) #define NDINIT_ATRIGHTS(ndp, op, flags, segflg, namep, dirfd, rightsp) \ NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, NULL, rightsp) #define NDINIT_ATVP(ndp, op, flags, segflg, namep, vp) \ NDINIT_ALL(ndp, op, flags, segflg, namep, AT_FDCWD, vp, &cap_no_rights) /* * Note the constant pattern may *hide* bugs. * Note also that we enable debug checks for non-TIED KLDs * so that they can run on an INVARIANTS kernel without tripping over * assertions on ni_debugflags state. */ #if defined(INVARIANTS) || (defined(KLD_MODULE) && !defined(KLD_TIED)) #define NDINIT_PREFILL(arg) memset(arg, 0xff, offsetof(struct nameidata, \ ni_dvp_seqc)) #define NDINIT_DBG(arg) { (arg)->ni_debugflags = NAMEI_DBG_INITED; } #define NDREINIT_DBG(arg) { \ if (((arg)->ni_debugflags & NAMEI_DBG_INITED) == 0) \ panic("namei data not inited"); \ if (((arg)->ni_debugflags & NAMEI_DBG_HADSTARTDIR) != 0) \ panic("NDREINIT on namei data with NAMEI_DBG_HADSTARTDIR"); \ (arg)->ni_debugflags = NAMEI_DBG_INITED; \ } #else #define NDINIT_PREFILL(arg) do { } while (0) #define NDINIT_DBG(arg) do { } while (0) #define NDREINIT_DBG(arg) do { } while (0) #endif #define NDINIT_ALL(ndp, op, flags, segflg, namep, dirfd, startdir, rightsp) \ do { \ struct nameidata *_ndp = (ndp); \ cap_rights_t *_rightsp = (rightsp); \ MPASS(_rightsp != NULL); \ NDINIT_PREFILL(_ndp); \ NDINIT_DBG(_ndp); \ _ndp->ni_cnd.cn_nameiop = op; \ _ndp->ni_cnd.cn_flags = flags; \ _ndp->ni_segflg = segflg; \ _ndp->ni_dirp = namep; \ _ndp->ni_dirfd = dirfd; \ _ndp->ni_startdir = startdir; \ _ndp->ni_resflags = 0; \ filecaps_init(&_ndp->ni_filecaps); \ _ndp->ni_rightsneeded = _rightsp; \ } while (0) #define NDREINIT(ndp) do { \ struct nameidata *_ndp = (ndp); \ NDREINIT_DBG(_ndp); \ filecaps_free(&_ndp->ni_filecaps); \ _ndp->ni_resflags = 0; \ _ndp->ni_startdir = NULL; \ } while (0) #define NDPREINIT(ndp) do { \ (ndp)->ni_dvp_seqc = SEQC_MOD; \ (ndp)->ni_vp_seqc = SEQC_MOD; \ } while (0) -#define NDF_NO_DVP_RELE 0x00000001 -#define NDF_NO_DVP_UNLOCK 0x00000002 -#define NDF_NO_DVP_PUT 0x00000003 -#define NDF_NO_VP_RELE 0x00000004 -#define NDF_NO_VP_UNLOCK 0x00000008 -#define NDF_NO_VP_PUT 0x0000000c -#define NDF_NO_STARTDIR_RELE 0x00000010 -#define NDF_NO_FREE_PNBUF 0x00000020 - #define NDFREE_IOCTLCAPS(ndp) do { \ struct nameidata *_ndp = (ndp); \ filecaps_free(&_ndp->ni_filecaps); \ } while (0) #define NDFREE_PNBUF(ndp) do { \ struct nameidata *_ndp = (ndp); \ MPASS(_ndp->ni_cnd.cn_pnbuf != NULL); \ uma_zfree(namei_zone, _ndp->ni_cnd.cn_pnbuf); \ _ndp->ni_cnd.cn_pnbuf = NULL; \ } while (0) int namei(struct nameidata *ndp); int vfs_lookup(struct nameidata *ndp); int vfs_relookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, bool refstart); #define namei_setup_rootdir(ndp, cnp, pwd) do { \ if (__predict_true((cnp->cn_flags & ISRESTARTED) == 0)) \ ndp->ni_rootdir = pwd->pwd_adir; \ else \ ndp->ni_rootdir = pwd->pwd_rdir; \ } while (0) #endif /* * Stats on usefulness of namei caches. */ struct nchstats { long ncs_goodhits; /* hits that we can really use */ long ncs_neghits; /* negative hits that we can use */ long ncs_badhits; /* hits we must drop */ long ncs_falsehits; /* hits with id mismatch */ long ncs_miss; /* misses */ long ncs_long; /* long names that ignore cache */ long ncs_pass2; /* names found with passes == 2 */ long ncs_2passes; /* number of times we attempt it */ }; extern struct nchstats nchstats; #endif /* !_SYS_NAMEI_H_ */