summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2013-06-19 01:14:17 +0000
committerBryan Cantrill <bryan@joyent.com>2013-06-19 01:14:17 +0000
commit419a2474236e929c11570353e419e8882e2516ac (patch)
tree04f0283ae8a044b7429e4b49197b42c3ba558301
parentb378a448a6a0c61f7225dbf2a70cb153acea1b29 (diff)
downloadillumos-joyent-419a2474236e929c11570353e419e8882e2516ac.tar.gz
OS-2271 'tail -F ...' not resetting the offset of file rotation properly
-rw-r--r--usr/src/cmd/tail/tests/tailtests.sh79
-rw-r--r--usr/src/uts/common/fs/portfs/port_fop.c17
2 files changed, 87 insertions, 9 deletions
diff --git a/usr/src/cmd/tail/tests/tailtests.sh b/usr/src/cmd/tail/tests/tailtests.sh
index 1ce5f5df02..c0ae3afcc4 100644
--- a/usr/src/cmd/tail/tests/tailtests.sh
+++ b/usr/src/cmd/tail/tests/tailtests.sh
@@ -13,7 +13,7 @@
#
# Copyright 2010 Chris Love. All rights reserved.
-# Copyright (c) 2012, Joyent, Inc. All rights reserved.
+# Copyright (c) 2013, Joyent, Inc. All rights reserved.
#
checktest()
@@ -312,8 +312,14 @@ sleep 2
mv $follow $moved
echo -e "x\ny\nz" >> $moved
+
+#
+# At this point, tail is polling on stat'ing the missing file; we need to
+# be sure to sleep long enough after recreating it to know that it will pick
+# it up.
+#
echo -e "d\ne\nf" > $follow
-sleep 1
+sleep 5
kill $child
sleep 1
@@ -361,6 +367,75 @@ a=`cat $out`
checktest "$a" "$o" 27
rm $follow $moved
+if [[ `uname -s` == "SunOS" ]]; then
+ #
+ # Use DTrace to truncate the file between the return from port_get()
+ # and the reassociation of the file object with the port, exposing
+ # any race conditions whereby FILE_TRUNC events are lost.
+ #
+ cat /dev/null > $follow
+ dtrace -c "$PROG -f $follow" -s /dev/stdin > $out <<EOF
+ #pragma D option destructive
+ #pragma D option quiet
+
+ pid\$target::port_get:return
+ /++i == 5/
+ {
+ stop();
+ system("cat /dev/null > $follow");
+ system("prun %d", pid);
+ }
+
+ tick-1sec
+ {
+ system("echo %d >> $follow", j++);
+ }
+
+ tick-1sec
+ /j == 10/
+ {
+ exit(0);
+ }
+EOF
+
+ o=`echo -e "0\n1\n2\n3\n5\n6\n7\n8\n9\n"`
+ a=`cat $out`
+ checktest "$a" "$o" 27a
+ rm $follow
+
+ cat /dev/null > $follow
+ dtrace -c "$PROG -f $follow" -s /dev/stdin > $out <<EOF
+ #pragma D option destructive
+ #pragma D option quiet
+
+ pid\$target::port_get:return
+ /++i == 5/
+ {
+ stop();
+ system("mv $follow $moved");
+ system("cat /dev/null > $moved");
+ system("prun %d", pid);
+ }
+
+ tick-1sec
+ {
+ system("echo %d >> %s", j++,
+ i < 5 ? "$follow" : "$moved");
+ }
+
+ tick-1sec
+ /j == 10/
+ {
+ exit(0);
+ }
+EOF
+
+ o=`echo -e "0\n1\n2\n3\n5\n6\n7\n8\n9\n"`
+ a=`cat $out`
+ checktest "$a" "$o" 27b
+ rm $moved
+fi
+
echo "$CMD: completed"
exit $errs
diff --git a/usr/src/uts/common/fs/portfs/port_fop.c b/usr/src/uts/common/fs/portfs/port_fop.c
index 48792394a5..1094dc160c 100644
--- a/usr/src/uts/common/fs/portfs/port_fop.c
+++ b/usr/src/uts/common/fs/portfs/port_fop.c
@@ -24,7 +24,7 @@
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
/*
@@ -1259,7 +1259,7 @@ port_associate_fop(port_t *pp, int source, uintptr_t object, int events,
void *user)
{
portfop_cache_t *pfcp;
- vnode_t *vp, *dvp, *oldvp = NULL, *olddvp = NULL;
+ vnode_t *vp, *dvp, *oldvp = NULL, *olddvp = NULL, *orig;
portfop_t *pfp;
int error = 0;
file_obj_t fobj;
@@ -1316,8 +1316,7 @@ port_associate_fop(port_t *pp, int source, uintptr_t object, int events,
goto errout;
}
- vp = port_resolve_vp(vp);
-
+ vp = port_resolve_vp(orig = vp);
if (vp != NULL && vnevent_support(vp, NULL)) {
error = ENOTSUP;
@@ -1325,10 +1324,14 @@ port_associate_fop(port_t *pp, int source, uintptr_t object, int events,
}
/*
- * If dvp belongs to a different filesystem just ignore it.
- * Hardlinks cannot exist across filesystems.
+ * If dvp belongs to a different filesystem just ignore it, as hard
+ * links cannot exist across filesystems. We make an exception for
+ * procfs, however, the magic of which we treat semantically as a hard
+ * link, allowing one to use /proc/[pid]/fd/[fd] for PORT_SOURCE_FILE
+ * and avoid spurious FILE_RENAME_FROM/FILE_RENAME_TO events.
*/
- if (dvp != NULL && dvp->v_vfsp != vp->v_vfsp) {
+ if (dvp != NULL && dvp->v_vfsp != vp->v_vfsp &&
+ !(orig->v_type == VPROC && vp != NULL && vp->v_type != VPROC)) {
VN_RELE(dvp);
dvp = NULL;
}