genfs_rename(9)
- NetBSD Manual Pages
GENFS_RENAME(9) NetBSD Kernel Developer's Manual GENFS_RENAME(9)
NAME
genfs_rename, genfs_insane_rename, genfs_sane_rename -- generic framework
for implementing VOP_RENAME(9)
SYNOPSIS
int
genfs_insane_rename(struct vop_rename_args *v,
int (*sane_rename)(struct vnode *fdvp, struct componentname *fcnp, struct vnode *tdvp, struct componentname *tcnp, kauth_cred_t, bool));
int
genfs_sane_rename(const struct genfs_rename_ops *gro, struct vnode *fdvp,
struct componentname *fcnp, void *fde, struct vnode *tdvp,
struct componentname *tcnp, void *tde, kauth_cred_t cred,
bool posixly_correct);
int
genfs_rename_knote(struct vnode *fdvp, struct vnode *fvp,
struct vnode *tdvp, struct vnode *tvp);
void
genfs_rename_cache_purge(struct vnode *fdvp, struct vnode *fvp,
struct vnode *tdvp, struct vnode *tvp);
int
genfs_ufslike_rename_check_possible(unsigned long fdflags,
unsigned long fflags, unsigned long tdflags, unsigned long tflags,
bool clobber, unsigned long immutable, unsigned long append);
int
genfs_ufslike_rename_check_permitted(kauth_cred_t cred,
struct vnode *fdvp, mode_t fdmode, uid_t fduid, struct vnode *fvp,
uid_t fuid, struct vnode *tdvp, mode_t tdmode, uid_t tduid,
struct vnode *tvp, uid_t tuid);
int
genfs_ufslike_remove_check_possible(unsigned long dflags,
unsigned long flags, unsigned long immutable, unsigned long append);
int
genfs_ufslike_remove_check_permitted(kauth_cred_t cred,
struct vnode *dvp, mode_t dmode, uid_t duid, struct vnode *vp,
uid_t uid);
DESCRIPTION
The genfs_rename functions provide a file-system-independent framework
for implementing VOP_RENAME(9) with correct locking and error-checking.
Implementing rename is nontrivial. If you are doing it for a new file
system, you should consider starting from tmpfs_rename() as implemented
in sys/fs/tmpfs/tmpfs_rename.c and adapting it to your file system's
physical operations.
Because there are so many moving parts to a rename operation,
genfs_rename uses the following naming conventions:
mp (mount point)
mount point of the file system in question
fdvp (from directory vnode pointer)
directory from which we are removing an entry
fcnp (from componentname pointer)
name of entry to remove from fdvp
fde (from directory entry)
fs-specific data about the entry in fdvp
fvp (from vnode pointer)
file at the entry named fcnp in fdvp
tdvp (to directory vnode pointer)
directory to which we are adding an entry
tcnp (to componentname pointer)
name of entry to add to tdvp
tde (to directory entry)
fs-specific data about the entry in tdvp
tvp (to vnode pointer)
file previously at the entry named tcnp in tdvp, to be replaced,
if any, or NULL if there was no entry before
vp (vnode pointer)
any file
dvp (directory vnode pointer)
any directory with an entry for vp
A file system mumblefs should implement various file-system-dependent
parts of the rename operation in a struct genfs_rename_ops, and use
genfs_rename to implement mumblefs_rename() for VOP_RENAME(9) as follows:
static const struct genfs_rename_ops mumblefs_genfs_rename_ops;
static int
mumblefs_sane_rename(
struct vnode *fdvp, struct componentname *fcnp,
struct vnode *tdvp, struct componentname *tcnp,
kauth_cred_t cred, bool posixly_correct)
{
struct mumblefs_lookup_results fulr, tulr;
return genfs_sane_rename(&mumblefs_genfs_rename_ops,
fdvp, fcnp, &fulr, tdvp, tcnp, &tulr,
cred, posixly_correct);
}
int
mumblefs_rename(void *v)
{
return genfs_insane_rename(v, &mumblefs_sane_rename);
}
The split between mumblefs_rename() and mumblefs_sane_rename() is
designed to enable us to easily change the VOP_RENAME(9) interface, which
is currently designed for a broken (hence `insane') locking scheme, to a
more sensible locking scheme once all the file systems have their rename
operations split up thus.
The struct mumblefs_lookup_results structure is storage for information
about directory entries which needs to pass from the lookups of the chil-
dren (see the gro_lookup member of struct genfs_rename_ops) to the physi-
cal on-disk rename or remove operations (see the gro_rename and
gro_remove members of struct genfs_rename_ops).
Callers must implement the following operations as members in a struct
genfs_rename_ops structure passed to genfs_rename:
int (*gro_genealogy)(struct mount *mp, kauth_cred_t cred, struct vnode
*fdvp, struct vnode *tdvp, struct vnode **intermediate_node_ret)
Walk up the directory tree from the directory vnode tdvp until
hitting either fdvp or the root. If fdvp is hit, store the child
of fdvp through which the path from tdvp passed in
*intermediate_node_ret, referenced but unlocked. If fdvp is not
hit, store NULL in *intermediate_node_ret. Return zero on suc-
cess or error on failure. (Failure means file-system-specific
failures, not hitting or missing fdvp.)
fdvp and tdvp are guaranteed to be distinct, nonnull, referenced,
and unlocked. Since no locks are held on entry except for the
file-system-wide rename lock, gro_genealogy may take any locks it
pleases.
int (*gro_lock_directory)(struct mount *mp, struct vnode *vp)
Lock the directory vnode vp, but fail if it has been rmdired
already. Return zero on success or error on failure.
int (*gro_lookup)(struct mount *mp, struct vnode *dvp, struct
componentname *cnp, void *de, struct vnode **vpp)
Look up the entry in dvp for cnp, storing the vnode in *vpp and
using de, one of the pointers passed to genfs_sane_rename, to
store information about the directory entry as needed by the file
system's gro_rename operation, and return zero. If there is no
such entry, return error.
dvp is guaranteed to be locked, and the vnode returned in *vpp
must be unlocked. However, gro_lookup may temporarily lock the
vnode without causing deadlock.
bool (*gro_directory_empty_p)(struct mount *mp, kauth_cred_t cred, struct
vnode *vp, struct vnode *dvp)
Return true if the directory vnode vp is empty. The argument dvp
is the parent of vp, as required for this check by some file sys-
tems.
dvp and vp are guaranteed to be distinct, nonnull, referenced,
and locked.
int (*gro_rename_check_possible)(struct mount *mp, struct vnode *fdvp,
struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp)
Return zero if the file system might allow the rename independent
of credentials, or error if not. This should check, for example,
any immutability flags in the vnodes in question, and should use
genfs_ufslike_rename_check_possible() for file systems similar to
UFS/FFS.
fdvp and tdvp may be the same; every other pair of vnodes is
guaranteed to be distinct. tvp may be NULL; every other vnode is
guaranteed to be nonnull. All three or four vnodes are guaran-
teed to be referenced and locked.
int (*gro_rename_check_permitted)(struct mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, struct
vnode *tvp)
Return zero if the file system allows the rename given the cre-
dentials cred, or error if not. This should check, for example,
the ownership and permissions bits of the vnodes in question, and
should use genfs_ufslike_rename_check_permitted() for file sys-
tems similar to UFS/FFS.
fdvp and tdvp may be the same; every other pair of vnodes is
guaranteed to be distinct. tvp may be NULL; every other vnode is
guaranteed to be nonnull. All three or four vnodes are guaran-
teed to be referenced and locked.
int (*gro_rename)(struct mount *mp, kauth_cred_t cred, struct vnode
*fdvp, struct componentname *fcnp, void *fde, struct vnode *fvp,
struct vnode *tdvp, struct componentname *tcnp, void *tde, struct
vnode *tvp)
Perform the physical file system rename operation, report any
knotes, and purge the namecache entries. Return zero on success
or error on failure. All file-system-independent error cases
have been handled already.
File systems using fstrans(9) should use fstrans_start(9) and
fstrans_done(9) here. fde and tde are the pointers that were
supplied to genfs_sane_rename() and got passed to the gro_lookup
operation to find information about directory entries.
This may use genfs_rename_knote() to report any knotes, if the
various file-system-dependent routines it uses to edit links
don't do that already. This should use
genfs_rename_cache_purge() to purge the namecache.
fdvp and tdvp may be the same; every other pair of vnodes is
guaranteed to be distinct. tvp may be null; every other vnode is
guaranteed to be nonnull. All three or four vnodes are guaran-
teed to be referenced and locked.
int (*gro_remove_check_possible)(struct mount *mp, struct vnode *dvp,
struct vnode *vp)
Return zero if the file system might allow removing an entry in
dvp for vp independent of credentials, or error if not. This
should use genfs_ufslike_remove_check_possible() for file systems
similar to UFS/FFS.
dvp and vp are guaranteed to be distinct, nonnull, referenced,
and locked.
This, and gro_remove_check_permitted below, are for renames that
reduce to a remove; that is, renaming one entry to another when
both entries refer to the same file. For reasons of locking
insanity, genfs_rename cannot simply call VOP_REMOVE(9) instead.
int (*gro_remove_check_permitted)(struct mount *mp, kauth_cred_t cred,
struct vnode *dvp, struct vnode *vp)
Return zero if the file system allows removing an entry in dvp
for vp given the credentials cred, or error if not. This should
use genfs_ufslike_remove_check_permitted() for file systems simi-
lar to UFS/FFS.
dvp and vp are guaranteed to be distinct, nonnull, referenced,
and locked.
int (*gro_remove)(struct mount *mp, kauth_cred_t cred, struct vnode *dvp,
struct componentname *cnp, void *de, struct vnode *vp)
For a rename that is effectively a remove, perform the physical
file system remove operation, report any knotes, and purge the
namecache entries. Return zero on success or error on failure.
All file-system-independent error cases have been handled
already.
File systems using fstrans(9) should use fstrans_start(9) and
fstrans_done(9) here. de is one of the pointers that were sup-
plied to genfs_sane_rename() and got passed to the gro_lookup
operation to find information about directory entries.
This should signal a NOTE_WRITE knote for dvp, and either a
NOTE_DELETE or a NOTE_LINK knote for vp, depending on whether
this removed the last link to it or not.
dvp and vp are guaranteed to be distinct, nonnull, referenced,
and locked.
The following utilities are provided for implementing the struct
genfs_rename_ops operations:
genfs_rename_knote(fdvp, fvp, tdvp, tvp)
Signal all the knotes relevant for the rename operation.
genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp)
Purge any namecache entries that the rename operation invali-
dates.
genfs_ufslike_rename_check_possible(fdflags, fflags, tdflags, tflags,
clobber, immutable, append)
Check whether the UFS/FFS-like flags of the files involved a
rename allow it. Return zero if allowed or error if not.
fdflags flags of source directory
fflags flags of source file
tdflags flags of target directory
tflags flags of target file, if there is one and clobber is
true, or ignored otherwise
clobber true if there is a target file whose entry will be
clobbered or false if not
immutable bit mask for the file system's immutable bit, like the
UFS/FFS IMMUTABLE
append bit mask for the file system's append-only bit, like
the UFS/FFS APPEND
genfs_ufslike_rename_check_permitted(cred, fdvp, fdmode, fduid, fvp,
fuid, tdvp, tdmode, tduid, tvp, tuid)
Check whether the credentials cred are permitted by the file own-
ership and permissions bits to perform a rename. Return zero if
permitted or error if not.
cred caller's credentials
fdvp source directory
fdmode file permissions bits of fdvp
fduid uid of the owner of fdvp
fvp source file
fuid uid of owner of fvp
tdvp target directory
tdmode file permissions bits of tdvp
tduid uid of owner of tdvp
tvp target file, if there is one, or NULL if not
tuid uid of owner of tvp, if there is a target file, or
ignored otherwise
genfs_ufslike_remove_check_possible(dflags, flags, immutable, append)
Check whether the UFS/FFS-like flags of the files involved a
remove allow it. Return zero if allowed or error if not.
dflags flags of the directory
flags flags of the file in the directory
immutable bit mask for the file system's immutable bit, like the
UFS/FFS IMMUTABLE
append bit mask for the file system's append-only bit, like
the UFS/FFS APPEND
genfs_ufslike_remove_check_permitted(cred, dvp, dmode, duid, vp, uid)
Check whether the credentials cred are permitted by the file own-
ership and permissions bits to perform a remove. Return zero if
permitted or error if not.
cred caller's credentials
dvp directory
dmode file permissions bits of dvp
duid uid of owner of dvp
vp file in dvp
uid uid of owner of vp
NOTES
Because there are so many cases of rename, it cannot be assumed a priori
that any pairs of fdvp, fvp, tdvp, or fvp are distinct:
fdvp = fvp rename("a/.", "b")
fdvp = tdvp rename("a/b", "a/c")
fdvp = tvp rename("a/b", "a")
fvp = tdvp rename("a", "a/b")
fvp = tvp rename("a", "a")
tdvp = tvp rename("a", "b/.")
Handling all these cases correctly, and getting the locking correct and
deadlock-free, is very tricky, which is why genfs_rename exists. The
interface to genfs_rename is very complicated because it must fit the
insane VOP_RENAME(9) and VOP_LOOKUP(9) protocols until we can fix them,
and because it must accommodate a variety of crufty file systems.
SEE ALSO
genfs(9), vfs(9), vnodeops(9)
HISTORY
genfs_rename was designed and implemented by Taylor R. Campbell
<riastradh@NetBSD.org> after many discussions with David Holland
<dholland@NetBSD.org>, and first appeared in NetBSD 6.0.
NetBSD 9.0 May 1, 2013 NetBSD 9.0
Powered by man-cgi (2024-03-20).
Maintained for NetBSD
by Kimmo Suominen.
Based on man-cgi by Panagiotis Christias.