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>