Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Feb 2009 09:42:28 GMT
From:      Yoshihiro Ota <ota@j.email.ne.jp>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/131356: [tmpfs][patch] unlink(2) on tmpfs removs wrong files with hard-links
Message-ID:  <200902040942.n149gS0g045796@www.freebsd.org>
Resent-Message-ID: <200902040950.n149o2K1010296@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         131356
>Category:       kern
>Synopsis:       [tmpfs][patch] unlink(2) on tmpfs removs wrong files with hard-links
>Confidential:   no
>Severity:       non-critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Feb 04 09:50:02 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Yoshihiro Ota
>Release:        7.1-RELEASE
>Organization:
>Environment:
%uname -a
FreeBSD xxxx 7.1-RELEASE-p2 FreeBSD 7.1-RELEASE-p2 #455: Sun Jan 18 14:49:21 EST 2009     root@xxxx:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
rm/unlink removes the first i-node entry specified but not by the same.  In the case below, "rm b" deletes file "a" where "a" and "b" are hard-linked and "a" is created first.
>How-To-Repeat:
% cat unlink.sh          
#!/bin/sh

echo @ cleaning
rm -rf a b
echo @ file is created and linked
echo "123" > a
ln a b
echo @ a and b should exist
ls -lsa
head a b
echo @ b is removed
#unlink b
rm b
echo @ only a should exist
ls -lsa
head a b


On TMPFS:
% cd /mnt/tmpfs
% sh unlink.sh
@ cleaning
@ file is created and linked
@ a and b should exist
total 18
4 drwxrwxrwx   3 root  wheel   80  1 31 04:26 .
2 drwxr-xr-x  19 root  wheel  512 12 29 10:07 ..
4 -rw-r--r--   2 uyota wheel    4  1 31 04:26 a
4 -rw-r--r--   2 uyota wheel    4  1 31 04:26 b
==> a <==
123

==> b <==
123
@ b is removed
@ only a should exist
total 14
4 drwxrwxrwx   3 root  wheel   60  1 31 04:26 .
2 drwxr-xr-x  19 root  wheel  512 12 29 10:07 ..
4 -rw-r--r--   1 uyota wheel    4  1 31 04:26 b
==> a <==
123

==> b <==
123

On UFS:
% cd /mnt/ufs
% sh unlink.sh
@ cleaning
@ file is created and linked
@ a and b should exist
total 8
2 drwxr-xr-x   2 uyota wheel  512  1 31 04:27 .
2 drwxrwxrwt  15 root  wheel  512  1 31 04:27 ..
2 -rw-r--r--   2 uyota wheel    4  1 31 04:27 a
2 -rw-r--r--   2 uyota wheel    4  1 31 04:27 b
==> a <==
123

==> b <==
123
@ b is removed
@ only a should exist
total 6
2 drwxr-xr-x   2 uyota wheel  512  1 31 04:27 .
2 drwxrwxrwt  15 root  wheel  512  1 31 04:27 ..
2 -rw-r--r--   1 uyota wheel    4  1 31 04:27 a
==> a <==
123



>Fix:
Patch is attached.  It replaces tmpfs_dir_search with a new version of tmpfs_dir_lookup.

Patch attached with submission follows:

Index: sys/fs/tmpfs/tmpfs.h
===================================================================
RCS file: /home/ncvs/src/sys/fs/tmpfs/tmpfs.h,v
retrieving revision 1.11.2.3.2.1
diff -u -u -r1.11.2.3.2.1 tmpfs.h
--- sys/fs/tmpfs/tmpfs.h	25 Nov 2008 02:59:29 -0000	1.11.2.3.2.1
+++ sys/fs/tmpfs/tmpfs.h	4 Feb 2009 07:14:05 -0000
@@ -408,9 +408,8 @@
 void	tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *);
 void	tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *);
 struct tmpfs_dirent *	tmpfs_dir_lookup(struct tmpfs_node *node,
+			    struct tmpfs_node *f,
 			    struct componentname *cnp);
-struct tmpfs_dirent *tmpfs_dir_search(struct tmpfs_node *node,
-    struct tmpfs_node *f);
 int	tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *);
 int	tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *);
 struct tmpfs_dirent *	tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t);
Index: sys/fs/tmpfs/tmpfs_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/tmpfs/tmpfs_subr.c,v
retrieving revision 1.12.2.3.2.1
diff -u -u -r1.12.2.3.2.1 tmpfs_subr.c
--- sys/fs/tmpfs/tmpfs_subr.c	25 Nov 2008 02:59:29 -0000	1.12.2.3.2.1
+++ sys/fs/tmpfs/tmpfs_subr.c	4 Feb 2009 07:14:07 -0000
@@ -572,7 +572,8 @@
  * Returns a pointer to the entry when found, otherwise NULL.
  */
 struct tmpfs_dirent *
-tmpfs_dir_lookup(struct tmpfs_node *node, struct componentname *cnp)
+tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f,
+    struct componentname *cnp)
 {
 	boolean_t found;
 	struct tmpfs_dirent *de;
@@ -584,6 +585,8 @@
 
 	found = 0;
 	TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) {
+		if (f != NULL && de->td_node != f)
+		    continue;
 		MPASS(cnp->cn_namelen < 0xffff);
 		if (de->td_namelen == (uint16_t)cnp->cn_namelen &&
 		    memcmp(de->td_name, cnp->cn_nameptr, de->td_namelen) == 0) {
@@ -596,20 +599,6 @@
 	return found ? de : NULL;
 }
 
-struct tmpfs_dirent *
-tmpfs_dir_search(struct tmpfs_node *node, struct tmpfs_node *f)
-{
-	struct tmpfs_dirent *de;
-
-	TMPFS_VALIDATE_DIR(node);
-	node->tn_status |= TMPFS_NODE_ACCESSED;
-	TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) {
-		if (de->td_node == f)
-			return (de);
-	}
-	return (NULL);
-}
-
 /* --------------------------------------------------------------------- */
 
 /*
Index: sys/fs/tmpfs/tmpfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/tmpfs/tmpfs_vnops.c,v
retrieving revision 1.11.2.4.2.1
diff -u -u -r1.11.2.4.2.1 tmpfs_vnops.c
--- sys/fs/tmpfs/tmpfs_vnops.c	25 Nov 2008 02:59:29 -0000	1.11.2.4.2.1
+++ sys/fs/tmpfs/tmpfs_vnops.c	4 Feb 2009 07:14:07 -0000
@@ -104,7 +104,7 @@
 		*vpp = dvp;
 		error = 0;
 	} else {
-		de = tmpfs_dir_lookup(dnode, cnp);
+		de = tmpfs_dir_lookup(dnode, NULL, cnp);
 		if (de == NULL) {
 			/* The entry was not found in the directory.
 			 * This is OK if we are creating or renaming an
@@ -775,7 +775,7 @@
 	dnode = VP_TO_TMPFS_DIR(dvp);
 	node = VP_TO_TMPFS_NODE(vp);
 	tmp = VFS_TO_TMPFS(vp->v_mount);
-	de = tmpfs_dir_search(dnode, node);
+	de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
 	MPASS(de != NULL);
 
 	/* Files marked as immutable or append-only cannot be deleted. */
@@ -922,7 +922,7 @@
 	}
 	fdnode = VP_TO_TMPFS_DIR(fdvp);
 	fnode = VP_TO_TMPFS_NODE(fvp);
-	de = tmpfs_dir_search(fdnode, fnode);
+	de = tmpfs_dir_lookup(fdnode, fnode, fcnp);
 
 	/* Avoid manipulating '.' and '..' entries. */
 	if (de == NULL) {
@@ -1034,7 +1034,7 @@
 	 * from the target directory. */
 	if (tvp != NULL) {
 		/* Remove the old entry from the target directory. */
-		de = tmpfs_dir_search(tdnode, tnode);
+		de = tmpfs_dir_lookup(tdnode, tnode, tcnp);
 		tmpfs_dir_detach(tdvp, de);
 
 		/* Free the directory entry we just deleted.  Note that the
@@ -1122,7 +1122,7 @@
 
 	/* Get the directory entry associated with node (vp).  This was
 	 * filled by tmpfs_lookup while looking up the entry. */
-	de = tmpfs_dir_search(dnode, node);
+	de = tmpfs_dir_lookup(dnode, node, v->a_cnp);
 	MPASS(TMPFS_DIRENT_MATCHES(de,
 	    v->a_cnp->cn_nameptr,
 	    v->a_cnp->cn_namelen));


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200902040942.n149gS0g045796>