Module Name:    src
Committed By:   riastradh
Date:           Wed May  1 18:56:49 UTC 2013

Added Files:
        src/share/man/man9: genfs_rename.9

Log Message:
First draft of a long-awaited man page for genfs_rename(9).


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/share/man/man9/genfs_rename.9

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/share/man/man9/genfs_rename.9
diff -u /dev/null src/share/man/man9/genfs_rename.9:1.1
--- /dev/null	Wed May  1 18:56:49 2013
+++ src/share/man/man9/genfs_rename.9	Wed May  1 18:56:48 2013
@@ -0,0 +1,621 @@
+.\"	$NetBSD: genfs_rename.9,v 1.1 2013/05/01 18:56:48 riastradh Exp $
+.\"
+.\" Copyright (c) 2013 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This documentation is derived from text contributed to The NetBSD
+.\" Foundation by Taylor R. Campbell.
+.\"
+.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.Dd May 1, 2013
+.Dt GENFS_RENAME 9
+.Os
+.Sh NAME
+.Nm genfs_rename ,
+.Nm genfs_insane_rename ,
+.Nm genfs_sane_rename
+.Nd generic framework for implementing
+.Xr VOP_RENAME 9
+.Sh SYNOPSIS
+.Ft int
+.Fo genfs_insane_rename
+.Fa "struct vop_rename_args *v"
+.Fa "int (*sane_rename)(struct vnode *fdvp, struct componentname *fcnp, struct vnode *tdvp, struct componentname *tcnp, kauth_cred_t, bool)"
+.Fc
+.Ft int
+.Fo genfs_sane_rename
+.Fa "const struct genfs_rename_ops *gro"
+.Fa "struct vnode *fdvp"
+.Fa "struct componentname *fcnp"
+.Fa "void *fde"
+.Fa "struct vnode *tdvp"
+.Fa "struct componentname *tcnp"
+.Fa "void *tde"
+.Fa "kauth_cred_t cred"
+.Fa "bool posixly_correct"
+.Fc
+.Ft int
+.Fo genfs_rename_knote
+.Fa "struct vnode *fdvp"
+.Fa "struct vnode *fvp"
+.Fa "struct vnode *tdvp"
+.Fa "struct vnode *tvp"
+.Fc
+.Ft void
+.Fo genfs_rename_cache_purge
+.Fa "struct vnode *fdvp"
+.Fa "struct vnode *fvp"
+.Fa "struct vnode *tdvp"
+.Fa "struct vnode *tvp"
+.Fc
+.Ft int
+.Fo genfs_ufslike_rename_check_possible
+.Fa "unsigned long fdflags"
+.Fa "unsigned long fflags"
+.Fa "unsigned long tdflags"
+.Fa "unsigned long tflags"
+.Fa "bool clobber"
+.Fa "unsigned long immutable"
+.Fa "unsigned long append"
+.Fc
+.Ft int
+.Fo genfs_ufslike_rename_check_permitted
+.Fa "kauth_cred_t cred"
+.Fa "struct vnode *fdvp"
+.Fa "mode_t fdmode"
+.Fa "uid_t fduid"
+.Fa "struct vnode *fvp"
+.Fa "uid_t fuid"
+.Fa "struct vnode *tdvp"
+.Fa "mode_t tdmode"
+.Fa "uid_t tduid"
+.Fa "struct vnode *tvp"
+.Fa "uid_t tuid"
+.Fc
+.Ft int
+.Fo genfs_ufslike_remove_check_possible
+.Fa "unsigned long dflags"
+.Fa "unsigned long flags"
+.Fa "unsigned long immutable"
+.Fa "unsigned long append"
+.Fc
+.Ft int
+.Fo genfs_ufslike_remove_check_permitted
+.Fa "kauth_cred_t cred"
+.Fa "struct vnode *dvp"
+.Fa "mode_t dmode"
+.Fa "uid_t duid"
+.Fa "struct vnode *vp"
+.Fa "uid_t uid"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm
+functions provide a file-system-independent framework for implementing
+.Xr VOP_RENAME 9
+with correct locking and error-checking.
+.Pp
+Implementing rename is nontrivial.
+If you are doing it for a new file system, you should consider starting
+from
+.Fn tmpfs_rename
+as implemented in
+.Pa sys/fs/tmpfs/tmpfs_rename.c
+and adapting it to your file system's physical operations.
+.Pp
+Because there are so many moving parts to a rename operation,
+.Nm
+uses the following naming conventions:
+.Bl -tag -width indent
+.It Fa mp Pq "mount point"
+mount point of the file system in question
+.It Fa fdvp Pq "from directory vnode pointer"
+directory from which we are removing an entry
+.It Fa fcnp Pq "from componentname pointer"
+name of entry to remove from
+.Fa fdvp
+.It Fa fde Pq "from directory entry"
+fs-specific data about the entry in
+.Fa fdvp
+.It Fa fvp Pq "from vnode pointer"
+file at the entry named
+.Fa fcnp
+in
+.Fa fdvp
+.It Fa tdvp Pq "to directory vnode pointer"
+directory to which we are adding an entry
+.It Fa tcnp Pq "to componentname pointer"
+name of entry to add to
+.Fa tdvp
+.It Fa tde Pq "to directory entry"
+fs-specific data about the entry in
+.Fa tdvp
+.It Fa tvp Pq "to vnode pointer"
+file previously at the entry named
+.Fa tcnp
+in
+.Fa tdvp ,
+to be replaced, if any, or
+.Dv NULL
+if there was no entry before
+.It Fa vp Pq "vnode pointer"
+any file
+.It Fa dvp Pq "directory vnode pointer"
+any directory with an entry for
+.Fa vp
+.El
+.Pp
+A file system mumblefs should implement various file-system-dependent
+parts of the rename operation in a
+.Vt struct genfs_rename_ops ,
+and use
+.Nm
+to implement
+.Fn mumblefs_rename
+for
+.Xr VOP_RENAME 9
+as follows:
+.Bd -literal -offset indent
+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);
+}
+.Ed
+.Pp
+The split between
+.Fn mumblefs_rename
+and
+.Fn mumblefs_sane_rename
+is designed to enable us to easily change the
+.Xr VOP_RENAME 9
+interface, which is currently designed for a broken (hence
+.Sq insane )
+locking scheme, to a more sensible locking scheme once all the file
+systems have their rename operations split up thus.
+.Pp
+The
+.Vt struct mumblefs_lookup_results
+structure is storage for information about directory entries which
+needs to pass from the lookups of the children (see the
+.Fa gro_lookup
+member of
+.Vt "struct genfs_rename_ops" )
+to the physical on-disk rename or remove operations (see the
+.Fa gro_rename
+and
+.Fa gro_remove
+members of
+.Vt "struct genfs_rename_ops" ) .
+.Pp
+Callers must implement the following operations as members in a
+.Vt struct genfs_rename_ops
+structure passed to
+.Nm :
+.Bl -tag -width indent
+.It Ft int Fn "(*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
+.Fa tdvp
+until hitting either
+.Fa fdvp
+or the root.
+If
+.Fa fdvp
+is hit, store the child of
+.Fa fdvp
+through which the path from
+.Fa tdvp
+passed in
+.Fa *intermediate_node_ret ,
+referenced but unlocked.
+If
+.Fa fdvp
+is not hit, store
+.Dv NULL
+in
+.Fa *intermediate_node_ret .
+Return zero on success or error on failure.
+(Failure means file-system-specific failures, not hitting or missing
+.Fa fdvp . )
+.Pp
+.Fa fdvp
+and
+.Fa 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,
+.Fa gro_genealogy
+may take any locks it pleases.
+.It Ft int Fn "(*gro_lock_directory)" "struct mount *mp" "struct vnode *vp"
+Lock the directory vnode
+.Fa vp ,
+but fail if it has been rmdired already.
+Return zero on success or error on failure.
+.It Ft int Fn "(*gro_lookup)" "struct mount *mp" "struct vnode *dvp" "struct componentname *cnp" "void *de" "struct vnode **vpp"
+Look up the entry in
+.Fa dvp
+for
+.Fa cnp ,
+storing the vnode in
+.Fa "*vpp"
+and using
+.Fa de ,
+one of the pointers passed to
+.Nm genfs_sane_rename ,
+to store information about the directory entry as needed by the file
+system's
+.Fa gro_rename
+operation, and return zero.
+If there is no such entry, return error.
+.Pp
+.Fa dvp
+is guaranteed to be locked, and the vnode returned in
+.Fa "*vpp"
+must be unlocked.
+However,
+.Fa gro_lookup
+may temporarily lock the vnode without causing deadlock.
+.It Ft bool Fn "(*gro_directory_empty_p)" "struct mount *mp" "kauth_cred_t cred" "struct vnode *vp" "struct vnode *dvp"
+Return true if the directory vnode
+.Fa vp
+is empty.
+The argument
+.Fa dvp
+is the parent of
+.Fa vp ,
+as required for this check by some file systems.
+.Pp
+.Fa dvp
+and
+.Fa vp
+are guaranteed to be distinct, nonnull, referenced, and locked.
+.It Ft int Fn "(*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
+.Fn genfs_ufslike_rename_check_possible
+for file systems similar to UFS/FFS.
+.Pp
+.Fa fdvp
+and
+.Fa tdvp
+may be the same; every other pair of vnodes is guaranteed to be
+distinct.
+.Fa tvp
+may be
+.Dv NULL ;
+every other vnode is guaranteed to be nonnull.
+All three or four vnodes are guaranteed to be referenced and locked.
+.It Ft int Fn "(*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 credentials
+.Fa cred ,
+or error if not.
+This should check, for example, the ownership and permissions bits of
+the vnodes in question, and should use
+.Fn genfs_ufslike_rename_check_permitted
+for file systems similar to UFS/FFS.
+.Pp
+.Fa fdvp
+and
+.Fa tdvp
+may be the same; every other pair of vnodes is guaranteed to be
+distinct.
+.Fa tvp
+may be
+.Dv NULL ;
+every other vnode is guaranteed to be nonnull.
+All three or four vnodes are guaranteed to be referenced and locked.
+.It Ft int Fn "(*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.
+.Pp
+File systems using
+.Xr fstrans 9
+should use
+.Xr fstrans_start 9
+and
+.Xr fstrans_done 9
+here.
+.Fa fde
+and
+.Fa tde
+are the pointers that were supplied to
+.Fn genfs_sane_rename
+and got passed to the
+.Fa gro_lookup
+operation to find information about directory entries.
+.Pp
+This may use
+.Fn 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
+.Fn genfs_rename_cache_purge
+to purge the namecache.
+.Pp
+.Fa fdvp
+and
+.Fa tdvp
+may be the same; every other pair of vnodes is guaranteed to be
+distinct.
+.Fa tvp
+may be null; every other vnode is guaranteed to be nonnull.
+All three or four vnodes are guaranteed to be referenced and locked.
+.It Ft int Fn "(*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
+.Fa dvp
+for
+.Fa vp
+independent of credentials, or error if not.
+This should use
+.Fn genfs_ufslike_remove_check_possible
+for file systems similar to UFS/FFS.
+.Pp
+.Fa dvp
+and
+.Fa vp
+are guaranteed to be distinct, nonnull, referenced, and locked.
+.Pp
+This, and
+.Fa 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,
+.Nm
+cannot simply call
+.Xr VOP_REMOVE 9
+instead.
+.It Ft int Fn "(*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
+.Fa dvp
+for
+.Fa vp
+given the credentials
+.Fa cred ,
+or error if not.
+This should use
+.Fn genfs_ufslike_remove_check_permitted
+for file systems similar to UFS/FFS.
+.Pp
+.Fa dvp
+and
+.Fa vp
+are guaranteed to be distinct, nonnull, referenced, and locked.
+.It Ft int Fn "(*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.
+.Pp
+File systems using
+.Xr fstrans 9
+should use
+.Xr fstrans_start 9
+and
+.Xr fstrans_done 9
+here.
+.Fa de
+is one of the pointers that were supplied to
+.Fn genfs_sane_rename
+and got passed to the
+.Fa gro_lookup
+operation to find information about directory entries.
+.Pp
+This should signal a
+.Dv NOTE_WRITE
+knote for
+.Fa dvp ,
+and either a
+.Dv NOTE_DELETE
+or a
+.Dv NOTE_LINK
+knote for
+.Fa vp ,
+depending on whether this removed the last link to it or not.
+.Pp
+.Fa dvp
+and
+.Fa vp
+are guaranteed to be distinct, nonnull, referenced, and locked.
+.El
+.Pp
+The following utilities are provided for implementing the
+.Vt struct genfs_rename_ops
+operations:
+.Bl -tag -width indent
+.It Fn genfs_rename_knote fdvp fvp tdvp tvp
+Signal all the knotes relevant for the rename operation.
+.It Fn genfs_rename_cache_purge fdvp fvp tdvp tvp
+Purge any namecache entries that the rename operation invalidates.
+.It Fn 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.
+.Pp
+.Bl -tag -width immutable -compact
+.It Fa fdflags
+flags of source directory
+.It Fa fflags
+flags of source file
+.It Fa tdflags
+flags of target directory
+.It Fa tflags
+flags of target file, if there is one and
+.Fa clobber
+is true, or ignored otherwise
+.It Fa clobber
+true if there is a target file whose entry will be clobbered or false
+if not
+.It Fa immutable
+bit mask for the file system's immutable bit, like the UFS/FFS
+.Dv IMMUTABLE
+.It Fa append
+bit mask for the file system's append-only bit, like the UFS/FFS
+.Dv APPEND
+.El
+.It Fn genfs_ufslike_rename_check_permitted cred fdvp fdmode fduid fvp fuid tdvp tdmode tduid tvp tuid
+Check whether the credentials
+.Fa cred
+are permitted by the file ownership and permissions bits to perform a
+rename.
+Return zero if permitted or error if not.
+.Pp
+.Bl -tag -width fdmode -compact
+.It Fa cred
+caller's credentials
+.It Fa fdvp
+source directory
+.It Fa fdmode
+file permissions bits of
+.Fa fdvp
+.It Fa fduid
+uid of the owner of
+.Fa fdvp
+.It Fa fvp
+source file
+.It Fa fuid
+uid of owner of
+.Fa fvp
+.It Fa tdvp
+target directory
+.It Fa tdmode
+file permissions bits of
+.Fa tdvp
+.It Fa tduid
+uid of owner of
+.Fa tdvp
+.It Fa tvp
+target file, if there is one, or
+.Dv NULL
+if not
+.It Fa tuid
+uid of owner of
+.Fa tvp ,
+if there is a target file, or ignored otherwise
+.El
+.It Fn 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.
+.Pp
+.Bl -tag -width immutable -compact
+.It Fa dflags
+flags of the directory
+.It Fa flags
+flags of the file in the directory
+.It Fa immutable
+bit mask for the file system's immutable bit, like the UFS/FFS
+.Dv IMMUTABLE
+.It Fa append
+bit mask for the file system's append-only bit, like the UFS/FFS
+.Dv APPEND
+.El
+.It Fn genfs_ufslike_remove_check_permitted cred dvp dmode duid vp uid
+Check whether the credentials
+.Fa cred
+are permitted by the file ownership and permissions bits to perform a
+remove.
+Return zero if permitted or error if not.
+.Pp
+.Bl -tag -width fdmode -compact
+.It Fa cred
+caller's credentials
+.It Fa dvp
+directory
+.It Fa dmode
+file permissions bits of
+.Fa dvp
+.It Fa duid
+uid of owner of
+.Fa dvp
+.It Fa vp
+file in
+.Fa dvp
+.It Fa uid
+uid of owner of
+.Fa vp
+.El
+.El
+.Sh NOTES
+Because there are so many cases of rename, it cannot be assumed a
+priori that any pairs of
+.Fa fdvp ,
+.Fa fvp ,
+.Fa tdvp ,
+or
+.Fa fvp
+are distinct:
+.Bl -column -offset indent \
+"fdvp = tdvp" "rename(\*qa/b\*q, \*qa/c\*q)"
+.It Li "fdvp = fvp"     Ta Li "rename(\*qa/.\*q, \*qb\*q)"
+.It Li "fdvp = tdvp"    Ta Li "rename(\*qa/b\*q, \*qa/c\*q)"
+.It Li "fdvp = tvp"     Ta Li "rename(\*qa/b\*q, \*qa\*q)"
+.It Li "fvp = tdvp"     Ta Li "rename(\*qa\*q, \*qa/b\*q)"
+.It Li "fvp = tvp"      Ta Li "rename(\*qa\*q, \*qa\*q)"
+.It Li "tdvp = tvp"     Ta Li "rename(\*qa\*q, \*qb/.\*q)"
+.El
+.Pp
+Handling all these cases correctly, and getting the locking correct and
+deadlock-free, is very tricky, which is why
+.Nm
+exists.
+The interface to
+.Nm
+is very complicated because it must fit the insane
+.Xr VOP_RENAME 9
+and
+.Xr VOP_LOOKUP 9
+protocols until we can fix them, and because it must accomodate a
+variety of crufty file systems.
+.Sh SEE ALSO
+.Xr genfs 9 ,
+.Xr vfs 9 ,
+.Xr vnodeops 9
+.Sh HISTORY
+.Nm
+was designed and implemented by
+.An Taylor R. Campbell Aq riastr...@netbsd.org
+after many discussions with
+.An David Holland Aq dholl...@netbsd.org ,
+and first appeared in
+.Nx 6.0 .

Reply via email to