| 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, non-null, 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, non-null, 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 non-null. 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 non-null. 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 non-null. 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, non-null, 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, non-null, 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, non-null, 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)IMMUTABLEAPPENDgenfs_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)IMMUTABLEAPPENDgenfs_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 10.0 |