summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2013-09-05 06:46:02 +0000
committerBryan Cantrill <bryan@joyent.com>2013-09-05 06:46:02 +0000
commit64af696dbea3e718e4c758e173de5fa35826dd41 (patch)
treee68a6fe823b0d3026055cddd50e1bed589ea9727 /usr/src
parent1c485ea3760aeec397cb5b579d3feaf1c097ee4b (diff)
downloadillumos-joyent-64af696dbea3e718e4c758e173de5fa35826dd41.tar.gz
OS-2432 tail -f/-F missing some truncation events
OS-2433 tail -f/-F can produce duplicate output after a truncation
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/tail/forward.c30
-rw-r--r--usr/src/cmd/tail/tests/tailtests.sh42
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_vnops.c12
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c13
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_vnops.c12
-rw-r--r--usr/src/uts/common/fs/pcfs/pc_vnops.c8
-rw-r--r--usr/src/uts/common/fs/portfs/port_fop.c16
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vnops.c7
-rw-r--r--usr/src/uts/common/fs/udfs/udf_vnops.c10
-rw-r--r--usr/src/uts/common/fs/ufs/ufs_vnops.c7
-rw-r--r--usr/src/uts/common/fs/vnode.c11
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vnops.c6
-rw-r--r--usr/src/uts/common/sys/vnode.h5
13 files changed, 154 insertions, 25 deletions
diff --git a/usr/src/cmd/tail/forward.c b/usr/src/cmd/tail/forward.c
index 54ac882ec8..8b87dfff06 100644
--- a/usr/src/cmd/tail/forward.c
+++ b/usr/src/cmd/tail/forward.c
@@ -328,25 +328,31 @@ associate(file_info_t *file, boolean_t assoc, port_event_t *ev)
/*
* To assure that we cannot possibly drop a FILE_TRUNC event,
* we have two different PORT_SOURCE_FILE associations with the
- * port: one to get either FILE_MODIFIED or FILE_TRUNC events,
- * and another to get only FILE_TRUNC events. This assures that
- * we always have an active association for FILE_TRUNC events.
- * (Without the second association, there is a window where a
- * file truncation could occur after a port_get() but before
- * the port_associate() call to re-associate the object --
- * resulting in loss of the truncation event.)
+ * port: one to get only FILE_MODIFIED events and another to
+ * get only FILE_TRUNC events. This assures that we always
+ * have an active association for FILE_TRUNC events when the
+ * seek offset is non-zero. Note that the association order
+ * _must_ be FILE_TRUNC followed by FILE_MODIFIED: if a single
+ * event induces both a FILE_TRUNC and a FILE_MODIFIED (as
+ * a VE_CREATE vnode event does), we must process the
+ * FILE_TRUNC before FILE_MODIFIED -- and the order in which
+ * these are processed will be the association order. So
+ * if we see a FILE_TRUNC, we dissociate/reassociate the
+ * FILE_MODIFIED association.
*/
- if (ev == NULL || (ev->portev_events & FILE_MODIFIED) ||
+ if (ev == NULL || (ev->portev_events & FILE_TRUNC) ||
!(ev->portev_events & (FILE_MODIFIED | FILE_TRUNC))) {
(void) port_associate(port, PORT_SOURCE_FILE,
- (uintptr_t)&file->fobj[0],
- FILE_MODIFIED | FILE_TRUNC, file);
+ (uintptr_t)&file->fobj[0], FILE_TRUNC, file);
+ (void) port_dissociate(port, PORT_SOURCE_FILE,
+ (uintptr_t)&file->fobj[1]);
+ ev = NULL;
}
- if (ev == NULL || (ev->portev_events & FILE_TRUNC) ||
+ if (ev == NULL || (ev->portev_events & FILE_MODIFIED) ||
!(ev->portev_events & (FILE_MODIFIED | FILE_TRUNC))) {
(void) port_associate(port, PORT_SOURCE_FILE,
- (uintptr_t)&file->fobj[1], FILE_TRUNC, file);
+ (uintptr_t)&file->fobj[1], FILE_MODIFIED, file);
}
} else {
for (i = 0; i <= 1; i++) {
diff --git a/usr/src/cmd/tail/tests/tailtests.sh b/usr/src/cmd/tail/tests/tailtests.sh
index c0ae3afcc4..d3a8bb1cf2 100644
--- a/usr/src/cmd/tail/tests/tailtests.sh
+++ b/usr/src/cmd/tail/tests/tailtests.sh
@@ -24,8 +24,8 @@ checktest()
if [[ "$actual" != "$output" ]]; then
echo "$CMD: test $test: FAIL"
- echo -e "$CMD: test $test: expected output:\n$o"
- echo -e "$CMD: test $test: actual output:\n$a"
+ echo -e "$CMD: test $test: expected output:\n$output"
+ echo -e "$CMD: test $test: actual output:\n$actual"
else
echo "$CMD: test $test: pass"
fi
@@ -177,6 +177,7 @@ checktest "$a" "$o" 19
# Now we want to do a series of follow tests.
#
if [[ $DIR == "" ]]; then
+ export TMPDIR=/var/tmp
tdir=$(mktemp -d -t tailtest.XXXXXXXX || exit 1)
else
tdir=$(mktemp -d $DIR/tailtest.XXXXXXXX || exit 1)
@@ -434,8 +435,45 @@ EOF
a=`cat $out`
checktest "$a" "$o" 27b
rm $moved
+
+ #
+ # Verify that -F will deal properly with the file being truncated
+ # not by truncation, but rather via an ftruncate() from logadm.
+ #
+ cat /dev/null > $follow
+ ( $PROG -F $follow > $out ) &
+ child=$!
+ echo -e "a\nb\nc\nd\ne\nf" >> $follow
+ logadm -c $follow
+ sleep 2
+ echo -e "g\nh\ni" >> $follow
+ sleep 2
+ kill $child
+ sleep 1
+
+ o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
+ a=`cat $out`
+ checktest "$a" "$o" 27c
fi
+#
+# We're now going to test that while we may miss output due to truncations
+# occurring faster than tail can read, we don't ever repeat output.
+#
+cat /dev/null > $follow
+( $PROG -f $follow > $out ) &
+tchild=$!
+( let i=0 ; while true; do echo $i > $follow ; sleep 0.1; let i=i+1 ; done ) &
+child=$!
+sleep 10
+kill $tchild
+kill $child
+
+a=`sort $out | uniq -c | sort -n | tail -1 | awk '{ print $1 }'`
+o=1
+
+checktest "$a" "$o" 28
+
echo "$CMD: completed"
exit $errs
diff --git a/usr/src/uts/common/fs/nfs/nfs3_vnops.c b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
index 4e5882ad7c..fd1595b9f5 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
@@ -29,7 +29,7 @@
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -1331,7 +1331,12 @@ nfs3_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
if (error)
return (error);
- return (nfs3setattr(vp, vap, flags, cr));
+ error = nfs3setattr(vp, vap, flags, cr);
+
+ if (error == 0 && (vap->va_mask & AT_SIZE) && vap->va_size == 0)
+ vnevent_truncate(vp, ct);
+
+ return (error);
}
static int
@@ -5521,6 +5526,9 @@ nfs3_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
va.va_mask = AT_SIZE;
va.va_size = bfp->l_start;
error = nfs3setattr(vp, &va, 0, cr);
+
+ if (error == 0 && bfp->l_start == 0)
+ vnevent_truncate(vp, ct);
} else
error = EINVAL;
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
index f05a0717d9..0c97fcc176 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
@@ -32,7 +32,7 @@
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -3716,6 +3716,8 @@ static int
nfs4_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
caller_context_t *ct)
{
+ int error;
+
if (vap->va_mask & AT_NOSET)
return (EINVAL);
@@ -3731,8 +3733,12 @@ nfs4_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
* to setattr (e.g. basic without chmod) then we will
* need to add a check here before calling the server.
*/
+ error = nfs4setattr(vp, vap, flags, cr, NULL);
+
+ if (error == 0 && (vap->va_mask & AT_SIZE) && vap->va_size == 0)
+ vnevent_truncate(vp, ct);
- return (nfs4setattr(vp, vap, flags, cr, NULL));
+ return (error);
}
/*
@@ -10999,6 +11005,9 @@ nfs4_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
va.va_mask = AT_SIZE;
va.va_size = bfp->l_start;
error = nfs4setattr(vp, &va, 0, cr, NULL);
+
+ if (error == 0 && bfp->l_start == 0)
+ vnevent_truncate(vp, ct);
} else
error = EINVAL;
}
diff --git a/usr/src/uts/common/fs/nfs/nfs_vnops.c b/usr/src/uts/common/fs/nfs/nfs_vnops.c
index fa31e3693f..df128f4bc6 100644
--- a/usr/src/uts/common/fs/nfs/nfs_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs_vnops.c
@@ -26,7 +26,7 @@
*/
/*
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -1171,7 +1171,12 @@ nfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
if (error)
return (error);
- return (nfssetattr(vp, vap, flags, cr));
+ error = nfssetattr(vp, vap, flags, cr);
+
+ if (error == 0 && (mask & AT_SIZE) && vap->va_size == 0)
+ vnevent_truncate(vp, ct);
+
+ return (error);
}
static int
@@ -4618,6 +4623,9 @@ nfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
va.va_mask = AT_SIZE;
va.va_size = bfp->l_start;
error = nfssetattr(vp, &va, 0, cr);
+
+ if (error == 0 && bfp->l_start == 0)
+ vnevent_truncate(vp, ct);
} else
error = EINVAL;
}
diff --git a/usr/src/uts/common/fs/pcfs/pc_vnops.c b/usr/src/uts/common/fs/pcfs/pc_vnops.c
index ce9711140b..e2c6f3a371 100644
--- a/usr/src/uts/common/fs/pcfs/pc_vnops.c
+++ b/usr/src/uts/common/fs/pcfs/pc_vnops.c
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/t_lock.h>
#include <sys/systm.h>
@@ -772,8 +776,12 @@ pcfs_setattr(
goto out;
}
error = pc_truncate(pcp, (uint_t)vap->va_size);
+
if (error)
goto out;
+
+ if (vap->va_size == 0)
+ vnevent_truncate(vp, ct);
}
/*
* Change file modified times.
diff --git a/usr/src/uts/common/fs/portfs/port_fop.c b/usr/src/uts/common/fs/portfs/port_fop.c
index 1094dc160c..03a03dd2a6 100644
--- a/usr/src/uts/common/fs/portfs/port_fop.c
+++ b/usr/src/uts/common/fs/portfs/port_fop.c
@@ -1828,12 +1828,19 @@ port_fop_sendevent(vnode_t *vp, int events, vnode_t *dvp, char *cname)
if (!removeall) {
/*
* All the active ones are in the beginning of the list.
+ * Note that we process this list in reverse order to assure
+ * that events are delivered in the order that they were
+ * associated.
*/
- for (pfp = (portfop_t *)list_head(&pvp->pvp_pfoplist);
- pfp && pfp->pfop_flags & PORT_FOP_ACTIVE; pfp = npfp) {
+ for (pfp = (portfop_t *)list_tail(&pvp->pvp_pfoplist);
+ pfp && !(pfp->pfop_flags & PORT_FOP_ACTIVE); pfp = npfp) {
+ npfp = list_prev(&pvp->pvp_pfoplist, pfp);
+ }
+
+ for (; pfp != NULL; pfp = npfp) {
int levents = events;
- npfp = list_next(&pvp->pvp_pfoplist, pfp);
+ npfp = list_prev(&pvp->pvp_pfoplist, pfp);
/*
* Hard links case - If the file is being
* removed/renamed, and the name matches
@@ -2348,6 +2355,9 @@ port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name,
case VE_MOUNTEDOVER:
port_fop_sendevent(vp, MOUNTEDOVER, NULL, NULL);
break;
+ case VE_TRUNCATE:
+ port_fop_sendevent(vp, FILE_TRUNC, NULL, NULL);
+ break;
default:
break;
}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
index a2074f284f..602c61602c 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
@@ -792,6 +792,10 @@ tmp_setattr(
error = tmpnode_trunc(tm, tp, (ulong_t)vap->va_size);
rw_exit(&tp->tn_contents);
rw_exit(&tp->tn_rwlock);
+
+ if (error == 0 && vap->va_size == 0)
+ vnevent_truncate(vp, ct);
+
goto out1;
}
out:
@@ -2368,6 +2372,9 @@ tmp_space(
if ((bfp->l_start > MAXOFF_T) || (bfp->l_len > MAXOFF_T))
return (EFBIG);
error = tmp_freesp(vp, bfp, flag);
+
+ if (error == 0 && bfp->l_start == 0)
+ vnevent_truncate(vp, ct);
}
return (error);
}
diff --git a/usr/src/uts/common/fs/udfs/udf_vnops.c b/usr/src/uts/common/fs/udfs/udf_vnops.c
index 90ad1b8d48..307d3987ed 100644
--- a/usr/src/uts/common/fs/udfs/udf_vnops.c
+++ b/usr/src/uts/common/fs/udfs/udf_vnops.c
@@ -23,6 +23,10 @@
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
*/
+/*
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ */
+
#include <sys/types.h>
#include <sys/t_lock.h>
#include <sys/param.h>
@@ -564,6 +568,9 @@ udf_setattr(
if (error = ud_itrunc(ip, vap->va_size, 0, cr)) {
goto update_inode;
}
+
+ if (vap->va_size == 0)
+ vnevent_truncate(vp, ct);
}
/*
* Change file access or modified times.
@@ -1621,6 +1628,9 @@ udf_space(
error = EINVAL;
} else if ((error = convoff(vp, bfp, 0, offset)) == 0) {
error = ud_freesp(vp, bfp, flag, cr);
+
+ if (error == 0 && bfp->l_start == 0)
+ vnevent_truncate(vp, ct);
}
return (error);
diff --git a/usr/src/uts/common/fs/ufs/ufs_vnops.c b/usr/src/uts/common/fs/ufs/ufs_vnops.c
index e210339dfb..92bdb0d0a7 100644
--- a/usr/src/uts/common/fs/ufs/ufs_vnops.c
+++ b/usr/src/uts/common/fs/ufs/ufs_vnops.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1984, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -2191,6 +2192,9 @@ again:
rw_enter(&ip->i_contents, RW_WRITER);
goto update_inode;
}
+
+ if (error == 0 && vap->va_size)
+ vnevent_truncate(vp, ct);
}
if (ulp) {
@@ -4460,6 +4464,9 @@ ufs_space(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
if (error)
return (error);
error = ufs_freesp(vp, bfp, flag, cr);
+
+ if (error == 0 && bfp->l_start == 0)
+ vnevent_truncate(vp, ct);
} else if (cmd == F_ALLOCSP) {
error = ufs_lockfs_begin(ufsvfsp, &ulp,
ULOCKFS_FALLOCATE_MASK);
diff --git a/usr/src/uts/common/fs/vnode.c b/usr/src/uts/common/fs/vnode.c
index 67f21866ec..679940cf5e 100644
--- a/usr/src/uts/common/fs/vnode.c
+++ b/usr/src/uts/common/fs/vnode.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Joyent Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -2589,6 +2589,15 @@ vnevent_mountedover(vnode_t *vp, caller_context_t *ct)
(void) VOP_VNEVENT(vp, VE_MOUNTEDOVER, NULL, NULL, ct);
}
+void
+vnevent_truncate(vnode_t *vp, caller_context_t *ct)
+{
+ if (vp == NULL || vp->v_femhead == NULL) {
+ return;
+ }
+ (void) VOP_VNEVENT(vp, VE_TRUNCATE, NULL, NULL, ct);
+}
+
/*
* Vnode accessors.
*/
diff --git a/usr/src/uts/common/fs/zfs/zfs_vnops.c b/usr/src/uts/common/fs/zfs/zfs_vnops.c
index 84960c9a13..f1b5abc1f1 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c
@@ -2757,6 +2757,9 @@ top:
ZFS_EXIT(zfsvfs);
return (err);
}
+
+ if (vap->va_size == 0)
+ vnevent_truncate(ZTOV(zp), ct);
}
if (mask & (AT_ATIME|AT_MTIME) ||
@@ -4748,6 +4751,9 @@ zfs_space(vnode_t *vp, int cmd, flock64_t *bfp, int flag,
error = zfs_freesp(zp, off, len, flag, TRUE);
+ if (error == 0 && off == 0 && len == 0)
+ vnevent_truncate(ZTOV(zp), ct);
+
ZFS_EXIT(zfsvfs);
return (error);
}
diff --git a/usr/src/uts/common/sys/vnode.h b/usr/src/uts/common/sys/vnode.h
index d29152346e..af9516fe52 100644
--- a/usr/src/uts/common/sys/vnode.h
+++ b/usr/src/uts/common/sys/vnode.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -733,7 +734,8 @@ typedef enum vnevent {
VE_CREATE = 5, /* Create with vnode's name which exists */
VE_LINK = 6, /* Link with vnode's name as source */
VE_RENAME_DEST_DIR = 7, /* Rename with vnode as target dir */
- VE_MOUNTEDOVER = 8 /* File or Filesystem got mounted over vnode */
+ VE_MOUNTEDOVER = 8, /* File or Filesystem got mounted over vnode */
+ VE_TRUNCATE = 9 /* Truncate */
} vnevent_t;
/*
@@ -1290,6 +1292,7 @@ void vnevent_create(vnode_t *, caller_context_t *);
void vnevent_link(vnode_t *, caller_context_t *);
void vnevent_rename_dest_dir(vnode_t *, caller_context_t *ct);
void vnevent_mountedover(vnode_t *, caller_context_t *);
+void vnevent_truncate(vnode_t *, caller_context_t *);
int vnevent_support(vnode_t *, caller_context_t *);
/* Vnode specific data */