Home | History | Annotate | Line # | Download | only in genfs
genfs_rename.c revision 1.1.8.1
      1 /*	$NetBSD: genfs_rename.c,v 1.1.8.1 2014/08/20 00:04:31 tls Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Taylor R Campbell.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Generic rename abstraction.
     34  *
     35  * Rename is unbelievably hairy.  Try to use this if you can --
     36  * otherwise you are practically guaranteed to get it wrong.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: genfs_rename.c,v 1.1.8.1 2014/08/20 00:04:31 tls Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/kauth.h>
     44 #include <sys/mount.h>
     45 #include <sys/namei.h>
     46 #include <sys/stat.h>
     47 #include <sys/vnode.h>
     48 #include <sys/fstrans.h>
     49 #include <sys/types.h>
     50 
     51 #include <miscfs/genfs/genfs.h>
     52 
     53 /*
     54  * Sample copypasta for implementing VOP_RENAME via genfs_rename.
     55  * Don't change this template without carefully considering whether
     56  * every other file system that already uses it needs to change too.
     57  * That way, once we have changed all the file systems to use it, we
     58  * can easily replace mumblefs_rename by mumblefs_sane_rename and
     59  * eliminate the insane API altogether.
     60  */
     61 
     62 /* begin sample copypasta */
     63 #if 0
     64 
     65 static const struct genfs_rename_ops mumblefs_genfs_rename_ops;
     66 
     67 /*
     68  * mumblefs_sane_rename: The hairiest vop, with the saner API.
     69  *
     70  * Arguments:
     71  *
     72  * . fdvp (from directory vnode),
     73  * . fcnp (from component name),
     74  * . tdvp (to directory vnode),
     75  * . tcnp (to component name),
     76  * . cred (credentials structure), and
     77  * . posixly_correct (flag for behaviour if target & source link same file).
     78  *
     79  * fdvp and tdvp may be the same, and must be referenced and unlocked.
     80  */
     81 static int
     82 mumblefs_sane_rename(
     83     struct vnode *fdvp, struct componentname *fcnp,
     84     struct vnode *tdvp, struct componentname *tcnp,
     85     kauth_cred_t cred, bool posixly_correct)
     86 {
     87 	struct mumblefs_lookup_results fulr, tulr;
     88 
     89 	return genfs_sane_rename(&mumblefs_genfs_rename_ops,
     90 	    fdvp, fcnp, &fulr, tdvp, tcnp, &tulr,
     91 	    cred, posixly_correct);
     92 }
     93 
     94 /*
     95  * mumblefs_rename: The hairiest vop, with the insanest API.  Defer to
     96  * genfs_insane_rename immediately.
     97  */
     98 int
     99 mumblefs_rename(void *v)
    100 {
    101 
    102 	return genfs_insane_rename(v, &mumblefs_sane_rename);
    103 }
    104 
    105 #endif
    106 /* end sample copypasta */
    107 
    108 /*
    109  * Forward declarations
    110  */
    111 
    112 static int genfs_rename_enter(const struct genfs_rename_ops *, struct mount *,
    113     kauth_cred_t,
    114     struct vnode *, struct componentname *, void *, struct vnode **,
    115     struct vnode *, struct componentname *, void *, struct vnode **);
    116 static int genfs_rename_enter_common(const struct genfs_rename_ops *,
    117     struct mount *, kauth_cred_t, struct vnode *,
    118     struct componentname *, void *, struct vnode **,
    119     struct componentname *, void *, struct vnode **);
    120 static int genfs_rename_enter_separate(const struct genfs_rename_ops *,
    121     struct mount *, kauth_cred_t,
    122     struct vnode *, struct componentname *, void *, struct vnode **,
    123     struct vnode *, struct componentname *, void *, struct vnode **);
    124 static int genfs_rename_lock(const struct genfs_rename_ops *, struct mount *,
    125     kauth_cred_t, int, int, int,
    126     struct vnode *, struct componentname *, bool, void *, struct vnode **,
    127     struct vnode *, struct componentname *, bool, void *, struct vnode **);
    128 static void genfs_rename_exit(const struct genfs_rename_ops *, struct mount *,
    129     struct vnode *, struct vnode *,
    130     struct vnode *, struct vnode *);
    131 static int genfs_rename_remove(const struct genfs_rename_ops *, struct mount *,
    132     kauth_cred_t,
    133     struct vnode *, struct componentname *, void *, struct vnode *);
    134 
    135 /*
    136  * genfs_insane_rename: Generic implementation of the insane API for
    137  * the rename vop.
    138  *
    139  * Arguments:
    140  *
    141  * . fdvp (from directory vnode),
    142  * . fvp (from vnode),
    143  * . fcnp (from component name),
    144  * . tdvp (to directory vnode),
    145  * . tvp (to vnode, or NULL), and
    146  * . tcnp (to component name).
    147  *
    148  * Any pair of vnode parameters may have the same vnode.
    149  *
    150  * On entry,
    151  *
    152  * . fdvp, fvp, tdvp, and tvp are referenced,
    153  * . fdvp and fvp are unlocked, and
    154  * . tdvp and tvp (if nonnull) are locked.
    155  *
    156  * On exit,
    157  *
    158  * . fdvp, fvp, tdvp, and tvp (if nonnull) are unreferenced, and
    159  * . tdvp and tvp (if nonnull) are unlocked.
    160  */
    161 int
    162 genfs_insane_rename(void *v,
    163     int (*sane_rename)(struct vnode *fdvp, struct componentname *fcnp,
    164 	struct vnode *tdvp, struct componentname *tcnp,
    165 	kauth_cred_t cred, bool posixly_correct))
    166 {
    167 	struct vop_rename_args	/* {
    168 		struct vnode *a_fdvp;
    169 		struct vnode *a_fvp;
    170 		struct componentname *a_fcnp;
    171 		struct vnode *a_tdvp;
    172 		struct vnode *a_tvp;
    173 		struct componentname *a_tcnp;
    174 	} */ *ap = v;
    175 	struct vnode *fdvp = ap->a_fdvp;
    176 	struct vnode *fvp = ap->a_fvp;
    177 	struct componentname *fcnp = ap->a_fcnp;
    178 	struct vnode *tdvp = ap->a_tdvp;
    179 	struct vnode *tvp = ap->a_tvp;
    180 	struct mount *mp = fdvp->v_mount;
    181 	struct componentname *tcnp = ap->a_tcnp;
    182 	kauth_cred_t cred;
    183 	int error;
    184 
    185 	KASSERT(fdvp != NULL);
    186 	KASSERT(fvp != NULL);
    187 	KASSERT(fcnp != NULL);
    188 	KASSERT(fcnp->cn_nameptr != NULL);
    189 	KASSERT(tdvp != NULL);
    190 	KASSERT(tcnp != NULL);
    191 	KASSERT(fcnp->cn_nameptr != NULL);
    192 	/* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
    193 	/* KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
    194 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    195 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    196 	KASSERT(fdvp->v_type == VDIR);
    197 	KASSERT(tdvp->v_type == VDIR);
    198 
    199 	fstrans_start(mp, FSTRANS_SHARED);
    200 
    201 	cred = fcnp->cn_cred;
    202 
    203 	/*
    204 	 * XXX Want a better equality test.  `tcnp->cn_cred == cred'
    205 	 * hoses p2k because puffs transmits the creds separately and
    206 	 * allocates distinct but equivalent structures for them.
    207 	 */
    208 	KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
    209 
    210 	/*
    211 	 * Sanitize our world from the VFS insanity.  Unlock the target
    212 	 * directory and node, which are locked.  Release the children,
    213 	 * which are referenced, since we'll be looking them up again
    214 	 * later.
    215 	 */
    216 
    217 	VOP_UNLOCK(tdvp);
    218 	if ((tvp != NULL) && (tvp != tdvp))
    219 		VOP_UNLOCK(tvp);
    220 
    221 	vrele(fvp);
    222 	if (tvp != NULL)
    223 		vrele(tvp);
    224 
    225 	error = (*sane_rename)(fdvp, fcnp, tdvp, tcnp, cred, false);
    226 
    227 	/*
    228 	 * All done, whether with success or failure.  Release the
    229 	 * directory nodes now, as the caller expects from the VFS
    230 	 * protocol.
    231 	 */
    232 	vrele(fdvp);
    233 	vrele(tdvp);
    234 
    235 	fstrans_done(mp);
    236 
    237 	return error;
    238 }
    239 
    240 /*
    241  * genfs_sane_rename: Generic implementation of the saner API for the
    242  * rename vop.  Handles ancestry checks, locking, and permissions
    243  * checks.  Caller is responsible for implementing the genfs rename
    244  * operations.
    245  *
    246  * fdvp and tdvp must be referenced and unlocked.
    247  */
    248 int
    249 genfs_sane_rename(const struct genfs_rename_ops *ops,
    250     struct vnode *fdvp, struct componentname *fcnp, void *fde,
    251     struct vnode *tdvp, struct componentname *tcnp, void *tde,
    252     kauth_cred_t cred, bool posixly_correct)
    253 {
    254 	struct mount *mp;
    255 	struct vnode *fvp = NULL, *tvp = NULL;
    256 	int error;
    257 
    258 	KASSERT(ops != NULL);
    259 	KASSERT(fdvp != NULL);
    260 	KASSERT(fcnp != NULL);
    261 	KASSERT(tdvp != NULL);
    262 	KASSERT(tcnp != NULL);
    263 	/* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
    264 	/* KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
    265 	KASSERT(fdvp->v_type == VDIR);
    266 	KASSERT(tdvp->v_type == VDIR);
    267 	KASSERT(fdvp->v_mount == tdvp->v_mount);
    268 	KASSERT(fcnp != tcnp);
    269 	KASSERT(fcnp->cn_nameiop == DELETE);
    270 	KASSERT(tcnp->cn_nameiop == RENAME);
    271 
    272         /* XXX Want a better equality test.  */
    273 	KASSERT(kauth_cred_uidmatch(cred, fcnp->cn_cred));
    274 	KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
    275 
    276 	mp = fdvp->v_mount;
    277 	KASSERT(mp != NULL);
    278 	KASSERT(mp == tdvp->v_mount);
    279 	/* XXX How can we be sure this stays true?  */
    280 	KASSERT((mp->mnt_flag & MNT_RDONLY) == 0);
    281 
    282 	/* Reject rename("x/..", ...) and rename(..., "x/..") early.  */
    283 	if ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)
    284 		return EINVAL;	/* XXX EISDIR?  */
    285 
    286 	error = genfs_rename_enter(ops, mp, cred,
    287 	    fdvp, fcnp, fde, &fvp,
    288 	    tdvp, tcnp, tde, &tvp);
    289 	if (error)
    290 		return error;
    291 
    292 	/*
    293 	 * Check that everything is locked and looks right.
    294 	 */
    295 	KASSERT(fvp != NULL);
    296 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    297 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    298 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    299 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    300 
    301 	/*
    302 	 * If the source and destination are the same object, we need
    303 	 * only at most delete the source entry.  We are guaranteed at
    304 	 * this point that the entries are distinct.
    305 	 */
    306 	if (fvp == tvp) {
    307 		KASSERT(tvp != NULL);
    308 		if (fvp->v_type == VDIR)
    309 			/* XXX This shouldn't be possible.  */
    310 			error = EINVAL;
    311 		else if (posixly_correct)
    312 			/* POSIX sez to leave them alone.  */
    313 			error = 0;
    314 		else if ((fdvp == tdvp) &&
    315 		    (fcnp->cn_namelen == tcnp->cn_namelen) &&
    316 		    (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr,
    317 			fcnp->cn_namelen) == 0))
    318 			/* Renaming an entry over itself does nothing.  */
    319 			error = 0;
    320 		else
    321 			/* XXX Can't use VOP_REMOVE because of locking.  */
    322 			error = genfs_rename_remove(ops, mp, cred,
    323 			    fdvp, fcnp, fde, fvp);
    324 		goto out;
    325 	}
    326 	KASSERT(fvp != tvp);
    327 	KASSERT((fdvp != tdvp) ||
    328 	    (fcnp->cn_namelen != tcnp->cn_namelen) ||
    329 	    (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen)
    330 		!= 0));
    331 
    332 	/*
    333 	 * If the target exists, refuse to rename a directory over a
    334 	 * non-directory or vice versa, or to clobber a non-empty
    335 	 * directory.
    336 	 */
    337 	if (tvp != NULL) {
    338 		if (fvp->v_type == VDIR && tvp->v_type == VDIR)
    339 			error =
    340 			    (ops->gro_directory_empty_p(mp, cred, tvp, tdvp)?
    341 				0 : ENOTEMPTY);
    342 		else if (fvp->v_type == VDIR && tvp->v_type != VDIR)
    343 			error = ENOTDIR;
    344 		else if (fvp->v_type != VDIR && tvp->v_type == VDIR)
    345 			error = EISDIR;
    346 		else
    347 			error = 0;
    348 		if (error)
    349 			goto out;
    350 		KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR));
    351 	}
    352 
    353 	/*
    354 	 * Authorize the rename.
    355 	 */
    356 	error = ops->gro_rename_check_possible(mp, fdvp, fvp, tdvp, tvp);
    357 	if (error)
    358 		goto out;
    359 	error = ops->gro_rename_check_permitted(mp, cred, fdvp, fvp, tdvp, tvp);
    360 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, fvp, fdvp,
    361 	    error);
    362 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_RENAME, tvp, tdvp,
    363 	    error);
    364 	if (error)
    365 		goto out;
    366 
    367 	/*
    368 	 * Everything is hunky-dory.  Shuffle the directory entries.
    369 	 */
    370 	error = ops->gro_rename(mp, cred,
    371 	    fdvp, fcnp, fde, fvp,
    372 	    tdvp, tcnp, tde, tvp);
    373 	if (error)
    374 		goto out;
    375 
    376 	/* Success!  */
    377 
    378 out:	genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
    379 	return error;
    380 }
    381 
    382 /*
    383  * genfs_rename_knote: Note events about the various vnodes in a
    384  * rename.  To be called by gro_rename on success.  The only pair of
    385  * vnodes that may be identical is {fdvp, tdvp}.  deleted_p is true iff
    386  * the rename overwrote the last link to tvp.
    387  */
    388 void
    389 genfs_rename_knote(struct vnode *fdvp, struct vnode *fvp,
    390     struct vnode *tdvp, struct vnode *tvp, bool deleted_p)
    391 {
    392 	long fdvp_events, tdvp_events;
    393 	bool directory_p, reparent_p, replaced_p;
    394 
    395 	KASSERT(fdvp != NULL);
    396 	KASSERT(fvp != NULL);
    397 	KASSERT(tdvp != NULL);
    398 	KASSERT(fdvp != fvp);
    399 	KASSERT(fdvp != tvp);
    400 	KASSERT(tdvp != fvp);
    401 	KASSERT(tdvp != tvp);
    402 	KASSERT(fvp != tvp);
    403 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    404 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    405 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    406 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    407 
    408 	directory_p = (fvp->v_type == VDIR);
    409 	reparent_p = (fdvp != tdvp);
    410 	replaced_p = (tvp != NULL);
    411 
    412 	KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR)));
    413 	KASSERT(!deleted_p || replaced_p);
    414 
    415 	fdvp_events = NOTE_WRITE;
    416 	if (directory_p && reparent_p)
    417 		fdvp_events |= NOTE_LINK;
    418 	VN_KNOTE(fdvp, fdvp_events);
    419 
    420 	VN_KNOTE(fvp, NOTE_RENAME);
    421 
    422 	if (reparent_p) {
    423 		tdvp_events = NOTE_WRITE;
    424 		if (!replaced_p) {
    425 			tdvp_events |= NOTE_EXTEND;
    426 			if (directory_p)
    427 				tdvp_events |= NOTE_LINK;
    428 		}
    429 		VN_KNOTE(tdvp, tdvp_events);
    430 	}
    431 
    432 	if (replaced_p)
    433 		VN_KNOTE(tvp, (deleted_p? NOTE_DELETE : NOTE_LINK));
    434 }
    435 
    436 /*
    437  * genfs_rename_cache_purge: Purge the name cache.  To be called by
    438  * gro_rename on success.  The only pair of vnodes that may be
    439  * identical is {fdvp, tdvp}.
    440  */
    441 void
    442 genfs_rename_cache_purge(struct vnode *fdvp, struct vnode *fvp,
    443     struct vnode *tdvp, struct vnode *tvp)
    444 {
    445 
    446 	KASSERT(fdvp != NULL);
    447 	KASSERT(fvp != NULL);
    448 	KASSERT(tdvp != NULL);
    449 	KASSERT(fdvp != fvp);
    450 	KASSERT(fdvp != tvp);
    451 	KASSERT(tdvp != fvp);
    452 	KASSERT(tdvp != tvp);
    453 	KASSERT(fvp != tvp);
    454 	KASSERT(fdvp->v_type == VDIR);
    455 	KASSERT(tdvp->v_type == VDIR);
    456 
    457 	/*
    458 	 * XXX What actually needs to be purged?
    459 	 */
    460 
    461 	cache_purge(fdvp);
    462 
    463 	if (fvp->v_type == VDIR)
    464 		cache_purge(fvp);
    465 
    466 	if (tdvp != fdvp)
    467 		cache_purge(tdvp);
    468 
    469 	if ((tvp != NULL) && (tvp->v_type == VDIR))
    470 		cache_purge(tvp);
    471 }
    472 
    473 /*
    474  * genfs_rename_enter: Look up fcnp in fdvp, and store the lookup
    475  * results in *fde_ret and the associated vnode in *fvp_ret; fail if
    476  * not found.  Look up tcnp in tdvp, and store the lookup results in
    477  * *tde_ret and the associated vnode in *tvp_ret; store null instead if
    478  * not found.  Fail if anything has been mounted on any of the nodes
    479  * involved.
    480  *
    481  * fdvp and tdvp must be referenced.
    482  *
    483  * On entry, nothing is locked.
    484  *
    485  * On success, everything is locked, and *fvp_ret, and *tvp_ret if
    486  * nonnull, are referenced.  The only pairs of vnodes that may be
    487  * identical are {fdvp, tdvp} and {fvp, tvp}.
    488  *
    489  * On failure, everything remains as was.
    490  *
    491  * Locking everything including the source and target nodes is
    492  * necessary to make sure that, e.g., link count updates are OK.  The
    493  * locking order is, in general, ancestor-first, matching the order you
    494  * need to use to look up a descendant anyway.
    495  */
    496 static int
    497 genfs_rename_enter(const struct genfs_rename_ops *ops,
    498     struct mount *mp, kauth_cred_t cred,
    499     struct vnode *fdvp, struct componentname *fcnp,
    500     void *fde_ret, struct vnode **fvp_ret,
    501     struct vnode *tdvp, struct componentname *tcnp,
    502     void *tde_ret, struct vnode **tvp_ret)
    503 {
    504 	int error;
    505 
    506 	KASSERT(mp != NULL);
    507 	KASSERT(fdvp != NULL);
    508 	KASSERT(fcnp != NULL);
    509 	KASSERT(fvp_ret != NULL);
    510 	KASSERT(tdvp != NULL);
    511 	KASSERT(tcnp != NULL);
    512 	KASSERT(tvp_ret != NULL);
    513 	KASSERT(fvp_ret != tvp_ret);
    514 	KASSERT(fdvp->v_type == VDIR);
    515 	KASSERT(tdvp->v_type == VDIR);
    516 	KASSERT(fdvp->v_mount == mp);
    517 	KASSERT(tdvp->v_mount == mp);
    518 
    519 	if (fdvp == tdvp)
    520 		error = genfs_rename_enter_common(ops, mp, cred, fdvp,
    521 		    fcnp, fde_ret, fvp_ret,
    522 		    tcnp, tde_ret, tvp_ret);
    523 	else
    524 		error = genfs_rename_enter_separate(ops, mp, cred,
    525 		    fdvp, fcnp, fde_ret, fvp_ret,
    526 		    tdvp, tcnp, tde_ret, tvp_ret);
    527 
    528 	if (error)
    529 		return error;
    530 
    531 	KASSERT(*fvp_ret != NULL);
    532 	KASSERT(VOP_ISLOCKED(*fvp_ret) == LK_EXCLUSIVE);
    533 	KASSERT((*tvp_ret == NULL) || (VOP_ISLOCKED(*tvp_ret) == LK_EXCLUSIVE));
    534 	KASSERT(*fvp_ret != fdvp);
    535 	KASSERT(*fvp_ret != tdvp);
    536 	KASSERT(*tvp_ret != fdvp);
    537 	KASSERT(*tvp_ret != tdvp);
    538 	return 0;
    539 }
    540 
    541 /*
    542  * genfs_rename_enter_common: Lock and look up with a common
    543  * source/target directory.
    544  */
    545 static int
    546 genfs_rename_enter_common(const struct genfs_rename_ops *ops,
    547     struct mount *mp, kauth_cred_t cred, struct vnode *dvp,
    548     struct componentname *fcnp,
    549     void *fde_ret, struct vnode **fvp_ret,
    550     struct componentname *tcnp,
    551     void *tde_ret, struct vnode **tvp_ret)
    552 {
    553 	struct vnode *fvp, *tvp;
    554 	int error;
    555 
    556 	KASSERT(ops != NULL);
    557 	KASSERT(mp != NULL);
    558 	KASSERT(dvp != NULL);
    559 	KASSERT(fcnp != NULL);
    560 	KASSERT(fvp_ret != NULL);
    561 	KASSERT(tcnp != NULL);
    562 	KASSERT(tvp_ret != NULL);
    563 	KASSERT(dvp->v_type == VDIR);
    564 	KASSERT(dvp->v_mount == mp);
    565 
    566 	error = ops->gro_lock_directory(mp, dvp);
    567 	if (error)
    568 		goto fail0;
    569 
    570 	/* Did we lose a race with mount?  */
    571 	if (dvp->v_mountedhere != NULL) {
    572 		error = EBUSY;
    573 		goto fail1;
    574 	}
    575 
    576 	KASSERT(fcnp->cn_nameiop == DELETE);
    577 	error = ops->gro_lookup(mp, dvp, fcnp, fde_ret, &fvp);
    578 	if (error)
    579 		goto fail1;
    580 
    581 	KASSERT(fvp != NULL);
    582 
    583 	/* Refuse to rename `.'.  */
    584 	if (fvp == dvp) {
    585 		error = EINVAL;
    586 		goto fail2;
    587 	}
    588 	KASSERT(fvp != dvp);
    589 
    590 	KASSERT(tcnp->cn_nameiop == RENAME);
    591 	error = ops->gro_lookup(mp, dvp, tcnp, tde_ret, &tvp);
    592 	if (error == ENOENT) {
    593 		tvp = NULL;
    594 	} else if (error) {
    595 		goto fail2;
    596 	} else {
    597 		KASSERT(tvp != NULL);
    598 
    599 		/* Refuse to rename over `.'.  */
    600 		if (tvp == dvp) {
    601 			error = EISDIR; /* XXX EINVAL?  */
    602 			goto fail2;
    603 		}
    604 	}
    605 	KASSERT(tvp != dvp);
    606 
    607 	/*
    608 	 * We've looked up both nodes.  Now lock them and check them.
    609 	 */
    610 
    611 	vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
    612 	KASSERT(fvp->v_mount == mp);
    613 	/* Refuse to rename a mount point.  */
    614 	if ((fvp->v_type == VDIR) && (fvp->v_mountedhere != NULL)) {
    615 		error = EBUSY;
    616 		goto fail3;
    617 	}
    618 
    619 	if ((tvp != NULL) && (tvp != fvp)) {
    620 		vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
    621 		KASSERT(tvp->v_mount == mp);
    622 		/* Refuse to rename over a mount point.  */
    623 		if ((tvp->v_type == VDIR) && (tvp->v_mountedhere != NULL)) {
    624 			error = EBUSY;
    625 			goto fail4;
    626 		}
    627 	}
    628 
    629 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    630 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    631 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    632 
    633 	*fvp_ret = fvp;
    634 	*tvp_ret = tvp;
    635 	return 0;
    636 
    637 fail4:	if ((tvp != NULL) && (tvp != fvp))
    638 		VOP_UNLOCK(tvp);
    639 fail3:	VOP_UNLOCK(fvp);
    640 	if (tvp != NULL)
    641 		vrele(tvp);
    642 fail2:	vrele(fvp);
    643 fail1:	VOP_UNLOCK(dvp);
    644 fail0:	return error;
    645 }
    646 
    647 /*
    648  * genfs_rename_enter_separate: Lock and look up with separate source
    649  * and target directories.
    650  */
    651 static int
    652 genfs_rename_enter_separate(const struct genfs_rename_ops *ops,
    653     struct mount *mp, kauth_cred_t cred,
    654     struct vnode *fdvp, struct componentname *fcnp,
    655     void *fde_ret, struct vnode **fvp_ret,
    656     struct vnode *tdvp, struct componentname *tcnp,
    657     void *tde_ret, struct vnode **tvp_ret)
    658 {
    659 	struct vnode *intermediate_node;
    660 	struct vnode *fvp, *tvp;
    661 	int error;
    662 
    663 	KASSERT(ops != NULL);
    664 	KASSERT(mp != NULL);
    665 	KASSERT(fdvp != NULL);
    666 	KASSERT(fcnp != NULL);
    667 	KASSERT(fvp_ret != NULL);
    668 	KASSERT(tdvp != NULL);
    669 	KASSERT(tcnp != NULL);
    670 	KASSERT(tvp_ret != NULL);
    671 	KASSERT(fdvp != tdvp);
    672 	KASSERT(fcnp != tcnp);
    673 	KASSERT(fcnp->cn_nameiop == DELETE);
    674 	KASSERT(tcnp->cn_nameiop == RENAME);
    675 	KASSERT(fvp_ret != tvp_ret);
    676 	KASSERT(fdvp->v_type == VDIR);
    677 	KASSERT(tdvp->v_type == VDIR);
    678 	KASSERT(fdvp->v_mount == mp);
    679 	KASSERT(tdvp->v_mount == mp);
    680 
    681 	error = ops->gro_genealogy(mp, cred, fdvp, tdvp, &intermediate_node);
    682 	if (error)
    683 		return error;
    684 
    685 	/*
    686 	 * intermediate_node == NULL means fdvp is not an ancestor of tdvp.
    687 	 */
    688 	if (intermediate_node == NULL)
    689 		error = genfs_rename_lock(ops, mp, cred,
    690 		    ENOTEMPTY, EISDIR, EINVAL,
    691 		    tdvp, tcnp, true, tde_ret, &tvp,
    692 		    fdvp, fcnp, false, fde_ret, &fvp);
    693 	else
    694 		error = genfs_rename_lock(ops, mp, cred,
    695 		    EINVAL, EISDIR, EINVAL,
    696 		    fdvp, fcnp, false, fde_ret, &fvp,
    697 		    tdvp, tcnp, true, tde_ret, &tvp);
    698 	if (error)
    699 		goto out;
    700 
    701 	KASSERT(fvp != NULL);
    702 
    703 	/*
    704 	 * Reject rename("foo/bar", "foo/bar/baz/quux/zot").
    705 	 */
    706 	if (fvp == intermediate_node) {
    707 		genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
    708 		error = EINVAL;
    709 		goto out;
    710 	}
    711 
    712 	*fvp_ret = fvp;
    713 	*tvp_ret = tvp;
    714 	error = 0;
    715 
    716 out:	if (intermediate_node != NULL)
    717 		vrele(intermediate_node);
    718 	return error;
    719 }
    720 
    721 /*
    722  * genfs_rename_lock: Lock directories a and b, which must be distinct,
    723  * and look up and lock nodes a and b.  Do a first and then b.
    724  * Directory b may not be an ancestor of directory a, although
    725  * directory a may be an ancestor of directory b.  Fail with
    726  * overlap_error if node a is directory b.  Neither componentname may
    727  * be `.' or `..'.
    728  *
    729  * a_dvp and b_dvp must be referenced.
    730  *
    731  * On entry, a_dvp and b_dvp are unlocked.
    732  *
    733  * On success,
    734  * . a_dvp and b_dvp are locked,
    735  * . *a_dirent_ret is filled with a directory entry whose node is
    736  *     locked and referenced,
    737  * . *b_vp_ret is filled with the corresponding vnode,
    738  * . *b_dirent_ret is filled either with null or with a directory entry
    739  *     whose node is locked and referenced,
    740  * . *b_vp is filled either with null or with the corresponding vnode,
    741  *     and
    742  * . the only pair of vnodes that may be identical is a_vp and b_vp.
    743  *
    744  * On failure, a_dvp and b_dvp are left unlocked, and *a_dirent_ret,
    745  * *a_vp, *b_dirent_ret, and *b_vp are left alone.
    746  */
    747 static int
    748 genfs_rename_lock(const struct genfs_rename_ops *ops,
    749     struct mount *mp, kauth_cred_t cred,
    750     int overlap_error, int a_dot_error, int b_dot_error,
    751     struct vnode *a_dvp, struct componentname *a_cnp, bool a_missing_ok,
    752     void *a_de_ret, struct vnode **a_vp_ret,
    753     struct vnode *b_dvp, struct componentname *b_cnp, bool b_missing_ok,
    754     void *b_de_ret, struct vnode **b_vp_ret)
    755 {
    756 	struct vnode *a_vp, *b_vp;
    757 	int error;
    758 
    759 	KASSERT(ops != NULL);
    760 	KASSERT(mp != NULL);
    761 	KASSERT(a_dvp != NULL);
    762 	KASSERT(a_cnp != NULL);
    763 	KASSERT(a_vp_ret != NULL);
    764 	KASSERT(b_dvp != NULL);
    765 	KASSERT(b_cnp != NULL);
    766 	KASSERT(b_vp_ret != NULL);
    767 	KASSERT(a_dvp != b_dvp);
    768 	KASSERT(a_vp_ret != b_vp_ret);
    769 	KASSERT(a_dvp->v_type == VDIR);
    770 	KASSERT(b_dvp->v_type == VDIR);
    771 	KASSERT(a_dvp->v_mount == mp);
    772 	KASSERT(b_dvp->v_mount == mp);
    773 	KASSERT(a_missing_ok != b_missing_ok);
    774 
    775 	error = ops->gro_lock_directory(mp, a_dvp);
    776 	if (error)
    777 		goto fail0;
    778 
    779 	/* Did we lose a race with mount?  */
    780 	if (a_dvp->v_mountedhere != NULL) {
    781 		error = EBUSY;
    782 		goto fail1;
    783 	}
    784 
    785 	error = ops->gro_lookup(mp, a_dvp, a_cnp, a_de_ret, &a_vp);
    786 	if (error) {
    787 		if (a_missing_ok && (error == ENOENT))
    788 			a_vp = NULL;
    789 		else
    790 			goto fail1;
    791 	} else {
    792 		KASSERT(a_vp != NULL);
    793 
    794 		/* Refuse to rename (over) `.'.  */
    795 		if (a_vp == a_dvp) {
    796 			error = a_dot_error;
    797 			goto fail2;
    798 		}
    799 
    800 		if (a_vp == b_dvp) {
    801 			error = overlap_error;
    802 			goto fail2;
    803 		}
    804 	}
    805 
    806 	KASSERT(a_vp != a_dvp);
    807 	KASSERT(a_vp != b_dvp);
    808 
    809 	error = ops->gro_lock_directory(mp, b_dvp);
    810 	if (error)
    811 		goto fail2;
    812 
    813 	/* Did we lose a race with mount?  */
    814 	if (b_dvp->v_mountedhere != NULL) {
    815 		error = EBUSY;
    816 		goto fail3;
    817 	}
    818 
    819 	error = ops->gro_lookup(mp, b_dvp, b_cnp, b_de_ret, &b_vp);
    820 	if (error) {
    821 		if (b_missing_ok && (error == ENOENT))
    822 			b_vp = NULL;
    823 		else
    824 			goto fail3;
    825 	} else {
    826 		KASSERT(b_vp != NULL);
    827 
    828 		/* Refuse to rename (over) `.'.  */
    829 		if (b_vp == b_dvp) {
    830 			error = b_dot_error;
    831 			goto fail4;
    832 		}
    833 
    834 		/* b is not an ancestor of a.  */
    835 		if (b_vp == a_dvp) {
    836 			/*
    837 			 * We have a directory hard link before us.
    838 			 * XXX What error should this return?  EDEADLK?
    839 			 * Panic?
    840 			 */
    841 			error = EIO;
    842 			goto fail4;
    843 		}
    844 	}
    845 	KASSERT(b_vp != b_dvp);
    846 	KASSERT(b_vp != a_dvp);
    847 
    848 	/*
    849 	 * We've looked up both nodes.  Now lock them and check them.
    850 	 */
    851 
    852 	if (a_vp != NULL) {
    853 		vn_lock(a_vp, LK_EXCLUSIVE | LK_RETRY);
    854 		KASSERT(a_vp->v_mount == mp);
    855 		/* Refuse to rename (over) a mount point.  */
    856 		if ((a_vp->v_type == VDIR) && (a_vp->v_mountedhere != NULL)) {
    857 			error = EBUSY;
    858 			goto fail5;
    859 		}
    860 	}
    861 
    862 	if ((b_vp != NULL) && (b_vp != a_vp)) {
    863 		vn_lock(b_vp, LK_EXCLUSIVE | LK_RETRY);
    864 		KASSERT(b_vp->v_mount == mp);
    865 		/* Refuse to rename (over) a mount point.  */
    866 		if ((b_vp->v_type == VDIR) && (b_vp->v_mountedhere != NULL)) {
    867 			error = EBUSY;
    868 			goto fail6;
    869 		}
    870 	}
    871 
    872 	KASSERT(VOP_ISLOCKED(a_dvp) == LK_EXCLUSIVE);
    873 	KASSERT(VOP_ISLOCKED(b_dvp) == LK_EXCLUSIVE);
    874 	KASSERT(a_missing_ok || (a_vp != NULL));
    875 	KASSERT(b_missing_ok || (b_vp != NULL));
    876 	KASSERT((a_vp == NULL) || (VOP_ISLOCKED(a_vp) == LK_EXCLUSIVE));
    877 	KASSERT((b_vp == NULL) || (VOP_ISLOCKED(b_vp) == LK_EXCLUSIVE));
    878 
    879 	*a_vp_ret = a_vp;
    880 	*b_vp_ret = b_vp;
    881 	return 0;
    882 
    883 fail6:	if ((b_vp != NULL) && (b_vp != a_vp))
    884 		VOP_UNLOCK(b_vp);
    885 fail5:	if (a_vp != NULL)
    886 		VOP_UNLOCK(a_vp);
    887 fail4:	if (b_vp != NULL)
    888 		vrele(b_vp);
    889 fail3:	VOP_UNLOCK(b_dvp);
    890 fail2:	if (a_vp != NULL)
    891 		vrele(a_vp);
    892 fail1:	VOP_UNLOCK(a_dvp);
    893 fail0:	return error;
    894 }
    895 
    896 /*
    897  * genfs_rename_exit: Unlock everything we locked for rename.
    898  *
    899  * fdvp and tdvp must be referenced.
    900  *
    901  * On entry, everything is locked, and fvp and tvp referenced.
    902  *
    903  * On exit, everything is unlocked, and fvp and tvp are released.
    904  */
    905 static void
    906 genfs_rename_exit(const struct genfs_rename_ops *ops,
    907     struct mount *mp,
    908     struct vnode *fdvp, struct vnode *fvp,
    909     struct vnode *tdvp, struct vnode *tvp)
    910 {
    911 
    912 	(void)ops;
    913 	KASSERT(ops != NULL);
    914 	KASSERT(mp != NULL);
    915 	KASSERT(fdvp != NULL);
    916 	KASSERT(fvp != NULL);
    917 	KASSERT(fdvp != fvp);
    918 	KASSERT(fdvp != tvp);
    919 	KASSERT(tdvp != tvp);
    920 	KASSERT(tdvp != fvp);
    921 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    922 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    923 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    924 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    925 
    926 	if ((tvp != NULL) && (tvp != fvp))
    927 		VOP_UNLOCK(tvp);
    928 	VOP_UNLOCK(fvp);
    929 	if (tvp != NULL)
    930 		vrele(tvp);
    931 	if (tdvp != fdvp)
    932 		VOP_UNLOCK(tdvp);
    933 	vrele(fvp);
    934 	VOP_UNLOCK(fdvp);
    935 }
    936 
    937 /*
    938  * genfs_rename_remove: Remove the entry for the non-directory vp with
    939  * componentname cnp from the directory dvp, using the lookup results
    940  * de.  It is the responsibility of gro_remove to purge the name cache
    941  * and note kevents.
    942  *
    943  * Everything must be locked and referenced.
    944  */
    945 static int
    946 genfs_rename_remove(const struct genfs_rename_ops *ops,
    947     struct mount *mp, kauth_cred_t cred,
    948     struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
    949 {
    950 	int error;
    951 
    952 	KASSERT(ops != NULL);
    953 	KASSERT(mp != NULL);
    954 	KASSERT(dvp != NULL);
    955 	KASSERT(cnp != NULL);
    956 	KASSERT(vp != NULL);
    957 	KASSERT(dvp != vp);
    958 	KASSERT(dvp->v_type == VDIR);
    959 	KASSERT(vp->v_type != VDIR);
    960 	KASSERT(dvp->v_mount == mp);
    961 	KASSERT(vp->v_mount == mp);
    962 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    963 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
    964 
    965 	error = ops->gro_remove_check_possible(mp, dvp, vp);
    966 	if (error)
    967 		return error;
    968 
    969 	error = ops->gro_remove_check_permitted(mp, cred, dvp, vp);
    970 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, vp, dvp,
    971 	    error);
    972 	if (error)
    973 		return error;
    974 
    975 	error = ops->gro_remove(mp, cred, dvp, cnp, de, vp);
    976 	if (error)
    977 		return error;
    978 
    979 	return 0;
    980 }
    981 
    982 static int
    983 genfs_ufslike_check_sticky(kauth_cred_t, mode_t, uid_t, struct vnode *, uid_t);
    984 
    985 /*
    986  * genfs_ufslike_rename_check_possible: Check whether a rename is
    987  * possible independent of credentials, assuming UFS-like inode flag
    988  * semantics.  clobber_p is true iff the target node already exists.
    989  */
    990 int
    991 genfs_ufslike_rename_check_possible(
    992     unsigned long fdflags, unsigned long fflags,
    993     unsigned long tdflags, unsigned long tflags, bool clobber_p,
    994     unsigned long immutable, unsigned long append)
    995 {
    996 
    997 	if ((fdflags | fflags) & (immutable | append))
    998 		return EPERM;
    999 
   1000 	if (tdflags & (immutable | (clobber_p? append : 0)))
   1001 		return EPERM;
   1002 
   1003 	if (clobber_p && (tflags & (immutable | append)))
   1004 		return EPERM;
   1005 
   1006 	return 0;
   1007 }
   1008 
   1009 /*
   1010  * genfs_ufslike_rename_check_permitted: Check whether a rename is
   1011  * permitted given our credentials, assuming UFS-like permission and
   1012  * ownership semantics.
   1013  *
   1014  * The only pair of vnodes that may be identical is {fdvp, tdvp}.
   1015  *
   1016  * Everything must be locked and referenced.
   1017  */
   1018 int
   1019 genfs_ufslike_rename_check_permitted(kauth_cred_t cred,
   1020     struct vnode *fdvp, mode_t fdmode, uid_t fduid,
   1021     struct vnode *fvp, uid_t fuid,
   1022     struct vnode *tdvp, mode_t tdmode, uid_t tduid,
   1023     struct vnode *tvp, uid_t tuid)
   1024 {
   1025 	int error;
   1026 
   1027 	KASSERT(fdvp != NULL);
   1028 	KASSERT(fvp != NULL);
   1029 	KASSERT(tdvp != NULL);
   1030 	KASSERT(fdvp != fvp);
   1031 	KASSERT(fdvp != tvp);
   1032 	KASSERT(tdvp != fvp);
   1033 	KASSERT(tdvp != tvp);
   1034 	KASSERT(fvp != tvp);
   1035 	KASSERT(fdvp->v_type == VDIR);
   1036 	KASSERT(tdvp->v_type == VDIR);
   1037 	KASSERT(fdvp->v_mount == fvp->v_mount);
   1038 	KASSERT(fdvp->v_mount == tdvp->v_mount);
   1039 	KASSERT((tvp == NULL) || (fdvp->v_mount == tvp->v_mount));
   1040 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
   1041 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
   1042 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
   1043 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
   1044 
   1045 	/*
   1046 	 * We need to remove or change an entry in the source directory.
   1047 	 */
   1048 	error = VOP_ACCESS(fdvp, VWRITE, cred);
   1049 	if (error)
   1050 		return error;
   1051 
   1052 	/*
   1053 	 * If we are changing directories, then we need to write to the
   1054 	 * target directory to add or change an entry.  Also, if fvp is
   1055 	 * a directory, we need to write to it to change its `..'
   1056 	 * entry.
   1057 	 */
   1058 	if (fdvp != tdvp) {
   1059 		error = VOP_ACCESS(tdvp, VWRITE, cred);
   1060 		if (error)
   1061 			return error;
   1062 		if (fvp->v_type == VDIR) {
   1063 			error = VOP_ACCESS(fvp, VWRITE, cred);
   1064 			if (error)
   1065 				return error;
   1066 		}
   1067 	}
   1068 
   1069 	error = genfs_ufslike_check_sticky(cred, fdmode, fduid, fvp, fuid);
   1070 	if (error)
   1071 		return error;
   1072 
   1073 	error = genfs_ufslike_check_sticky(cred, tdmode, tduid, tvp, tuid);
   1074 	if (error)
   1075 		return error;
   1076 
   1077 	return 0;
   1078 }
   1079 
   1080 /*
   1081  * genfs_ufslike_remove_check_possible: Check whether a remove is
   1082  * possible independent of credentials, assuming UFS-like inode flag
   1083  * semantics.
   1084  */
   1085 int
   1086 genfs_ufslike_remove_check_possible(unsigned long dflags, unsigned long flags,
   1087     unsigned long immutable, unsigned long append)
   1088 {
   1089 
   1090 	/*
   1091 	 * We want to delete the entry.  If the directory is immutable,
   1092 	 * we can't write to it to delete the entry.  If the directory
   1093 	 * is append-only, the only change we can make is to add
   1094 	 * entries, so we can't delete entries.  If the node is
   1095 	 * immutable, we can't change the links to it, so we can't
   1096 	 * delete the entry.  If the node is append-only...well, this
   1097 	 * is what UFS does.
   1098 	 */
   1099 	if ((dflags | flags) & (immutable | append))
   1100 		return EPERM;
   1101 
   1102 	return 0;
   1103 }
   1104 
   1105 /*
   1106  * genfs_ufslike_remove_check_permitted: Check whether a remove is
   1107  * permitted given our credentials, assuming UFS-like permission and
   1108  * ownership semantics.
   1109  *
   1110  * Everything must be locked and referenced.
   1111  */
   1112 int
   1113 genfs_ufslike_remove_check_permitted(kauth_cred_t cred,
   1114     struct vnode *dvp, mode_t dmode, uid_t duid,
   1115     struct vnode *vp, uid_t uid)
   1116 {
   1117 	int error;
   1118 
   1119 	KASSERT(dvp != NULL);
   1120 	KASSERT(vp != NULL);
   1121 	KASSERT(dvp != vp);
   1122 	KASSERT(dvp->v_type == VDIR);
   1123 	KASSERT(vp->v_type != VDIR);
   1124 	KASSERT(dvp->v_mount == vp->v_mount);
   1125 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
   1126 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
   1127 
   1128 	/*
   1129 	 * We need to write to the directory to remove from it.
   1130 	 */
   1131 	error = VOP_ACCESS(dvp, VWRITE, cred);
   1132 	if (error)
   1133 		return error;
   1134 
   1135 	error = genfs_ufslike_check_sticky(cred, dmode, duid, vp, uid);
   1136 	if (error)
   1137 		return error;
   1138 
   1139 	return 0;
   1140 }
   1141 
   1142 /*
   1143  * genfs_ufslike_check_sticky: Check whether a party with credentials
   1144  * cred may change an entry in a sticky directory, assuming UFS-like
   1145  * permission, ownership, and stickiness semantics: If the directory is
   1146  * sticky and the entry exists, the user must own either the directory
   1147  * or the entry's node in order to change the entry.
   1148  *
   1149  * Everything must be locked and referenced.
   1150  */
   1151 int
   1152 genfs_ufslike_check_sticky(kauth_cred_t cred, mode_t dmode, uid_t duid,
   1153     struct vnode *vp, uid_t uid)
   1154 {
   1155 
   1156 	if ((dmode & S_ISTXT) && (vp != NULL))
   1157 		return genfs_can_sticky(cred, duid, uid);
   1158 
   1159 	return 0;
   1160 }
   1161