GENFS_RENAME(9) | Kernel Developer's Manual | GENFS_RENAME(9) |
genfs_rename
,
genfs_insane_rename
,
genfs_sane_rename
—
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);
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:
NULL
if there was no entry beforeA 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 children (see the gro_lookup member of struct genfs_rename_ops) to the physical 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
:
(*gro_genealogy)
(struct mount
*mp, kauth_cred_t cred, struct
vnode *fdvp, struct vnode *tdvp,
struct vnode **intermediate_node_ret)NULL
in *intermediate_node_ret. Return zero on success 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.
(*gro_lock_directory)
(struct mount
*mp, struct vnode *vp)(*gro_lookup)
(struct mount
*mp, struct vnode *dvp, struct
componentname *cnp, void *de,
struct vnode **vpp)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.
(*gro_directory_empty_p)
(struct
mount *mp, kauth_cred_t cred,
struct vnode *vp, struct vnode
*dvp)dvp and vp are guaranteed to be distinct, nonnull, referenced, and locked.
(*gro_rename_check_possible)
(struct
mount *mp, struct vnode *fdvp,
struct vnode *fvp, struct vnode
*tdvp, struct vnode *tvp)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
guaranteed to be referenced and locked.
(*gro_rename_check_permitted)
(struct
mount *mp, kauth_cred_t cred,
struct vnode *fdvp, struct vnode
*fvp, struct vnode *tdvp, struct
vnode *tvp)genfs_ufslike_rename_check_permitted
()
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
guaranteed to be referenced and locked.
(*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)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 guaranteed to be referenced and locked.
(*gro_remove_check_possible)
(struct
mount *mp, struct vnode *dvp,
struct vnode *vp)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.
(*gro_remove_check_permitted)
(struct
mount *mp, kauth_cred_t cred,
struct vnode *dvp, struct vnode
*vp)genfs_ufslike_remove_check_permitted
() for file
systems similar to UFS/FFS.
dvp and vp are guaranteed to be distinct, nonnull, referenced, and locked.
(*gro_remove)
(struct mount
*mp, kauth_cred_t cred, struct
vnode *dvp, struct componentname *cnp,
void *de, struct vnode *vp)File systems using
fstrans(9) should use
fstrans_start(9)
and fstrans_done(9)
here. de is one of the pointers that were supplied
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)genfs_rename_cache_purge
(fdvp,
fvp, tdvp,
tvp)genfs_ufslike_rename_check_possible
(fdflags,
fflags, tdflags,
tflags, clobber,
immutable, append)IMMUTABLE
APPEND
genfs_ufslike_rename_check_permitted
(cred,
fdvp, fdmode,
fduid, fvp,
fuid, tdvp,
tdmode, tduid,
tvp, tuid)NULL
if
notgenfs_ufslike_remove_check_possible
(dflags,
flags, immutable,
append)IMMUTABLE
APPEND
genfs_ufslike_remove_check_permitted
(cred,
dvp, dmode,
duid, vp,
uid)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.
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.
May 1, 2013 | NetBSD 9.0 |