tmpfs_rename: handle hard-links correctly. Fixes PR/41236.

This commit is contained in:
rmind 2009-10-06 00:17:24 +00:00
parent b619d660f4
commit 9abdb3b71e

View File

@ -1,4 +1,4 @@
/* $NetBSD: tmpfs_vnops.c,v 1.62 2009/09/03 04:45:28 elad Exp $ */
/* $NetBSD: tmpfs_vnops.c,v 1.63 2009/10/06 00:17:24 rmind Exp $ */
/*
* Copyright (c) 2005, 2006, 2007 The NetBSD Foundation, Inc.
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.62 2009/09/03 04:45:28 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.63 2009/10/06 00:17:24 rmind Exp $");
#include <sys/param.h>
#include <sys/dirent.h>
@ -746,9 +746,7 @@ tmpfs_link(void *v)
/* Lock vp because we will need to run tmpfs_update over it, which
* needs the vnode to be locked. */
error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (error != 0)
goto out1;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
/* XXX: Why aren't the following two tests done by the caller? */
@ -795,16 +793,24 @@ tmpfs_link(void *v)
out:
VOP_UNLOCK(vp, 0);
out1:
PNBUF_PUT(cnp->cn_pnbuf);
vput(dvp);
return error;
}
/* --------------------------------------------------------------------- */
/*
* tmpfs_rename: rename routine.
*
* Arguments: fdvp (from-parent vnode), fvp (from-leaf), tdvp (to-parent)
* and tvp (to-leaf), if exists (NULL if not).
*
* => Caller holds a reference on fdvp and fvp, they are unlocked.
* Note: fdvp and fvp can refer to the same object (i.e. when it is root).
*
* => Both tdvp and tvp are referenced and locked. It is our responsibility
* to release the references and unlock them (or destroy).
*/
int
tmpfs_rename(void *v)
{
@ -857,9 +863,7 @@ tmpfs_rename(void *v)
/* XXX: this is a potential locking order violation! */
if (fdnode != tdnode) {
error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
if (error != 0)
goto out_unlocked;
vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
}
/*
@ -871,10 +875,16 @@ tmpfs_rename(void *v)
goto out;
}
/* If source and target are the same file, there is nothing to do. */
/* If source and target is the same vnode, remove the source link. */
if (fvp == tvp) {
error = 0;
goto out;
/*
* Detach and free the directory entry. Drops the link
* count on the node.
*/
tmpfs_dir_detach(fdvp, de);
tmpfs_free_dirent(VFS_TO_TMPFS(fvp->v_mount), de, true);
VN_KNOTE(fdvp, NOTE_WRITE);
goto out_ok;
}
/* If replacing an existing entry, ensure we can do the operation. */
@ -986,7 +996,7 @@ tmpfs_rename(void *v)
fnode->tn_status |= TMPFS_NODE_CHANGED;
tdnode->tn_status |= TMPFS_NODE_MODIFIED;
}
out_ok:
/* Notify listeners of tdvp about the change in the directory (either
* because a new entry was added or because one was removed) and
* listeners of fvp about the rename. */