summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Cantrill <bryan@joyent.com>2012-08-03 19:23:29 +0000
committerBryan Cantrill <bryan@joyent.com>2012-08-03 19:23:29 +0000
commit12ef7bd6596eedcaafd544ec675d6b72dfd15998 (patch)
tree36806bf6158fa7ba2f411f590c8d66f25c58d8b5
parent9e857228fdc0128410f9aec8c9e410612e8bd96e (diff)
downloadillumos-joyent-12ef7bd6596eedcaafd544ec675d6b72dfd15998.tar.gz
OS-1429 `tail -f ...` doesn't notice file truncation
-rw-r--r--usr/src/cmd/tail/forward.c94
-rw-r--r--usr/src/cmd/tail/tests/tailtests.sh266
-rw-r--r--usr/src/man/man3c/port_associate.3c30
-rw-r--r--usr/src/uts/common/fs/nfs/nfs3_vnops.c15
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_vnops.c16
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_vnops.c16
-rw-r--r--usr/src/uts/common/fs/portfs/port_fop.c14
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vnops.c11
-rw-r--r--usr/src/uts/common/sys/port.h7
-rw-r--r--usr/src/uts/common/sys/port_impl.h12
10 files changed, 398 insertions, 83 deletions
diff --git a/usr/src/cmd/tail/forward.c b/usr/src/cmd/tail/forward.c
index e4f22582f3..63e3c46e5b 100644
--- a/usr/src/cmd/tail/forward.c
+++ b/usr/src/cmd/tail/forward.c
@@ -31,9 +31,7 @@
*/
/*
- * Solaris porting notes: the original FreeBSD version made use of the
- * BSD kqueue event notification framework; this
- * was changed to use usleep()
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
*/
#include <sys/param.h>
@@ -53,6 +51,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <unistd.h>
#include "extern.h"
@@ -63,9 +62,11 @@ static void set_events(file_info_t *files);
/* defines for inner loop actions */
#define USE_SLEEP 0
+#define USE_PORT 1
#define ADD_EVENTS 2
-int action = USE_SLEEP;
+int port;
+int action = USE_PORT;
static const file_info_t *last;
@@ -261,6 +262,58 @@ show(file_info_t *file)
}
static void
+associate(file_info_t *file, boolean_t assoc)
+{
+ char buf[64];
+ file_obj_t fobj;
+
+ if (action != USE_PORT || file->fp == NULL)
+ return;
+
+ if (!S_ISREG(file->st.st_mode)) {
+ /*
+ * For FIFOs, we use PORT_SOURCE_FD as our port event source.
+ */
+ if (assoc) {
+ (void) port_associate(port, PORT_SOURCE_FD,
+ fileno(file->fp), POLLIN, file);
+ } else {
+ (void) port_dissociate(port, PORT_SOURCE_FD,
+ fileno(file->fp));
+ }
+
+ return;
+ }
+
+ bzero(&fobj, sizeof (fobj));
+
+ /*
+ * We pull a bit of a stunt here. PORT_SOURCE_FILE only allows us to
+ * specify a file name -- not a file descriptor. If we were to specify
+ * the name of the file to port_associate() and that file were moved
+ * aside, we would not be able to reassociate an event because we would
+ * not know a name that would resolve to the new file (indeed, there
+ * might not be such a name -- the file may have been unlinked). But
+ * there _is_ a name that we know maps to the file and doesn't change:
+ * the name of the representation of the open file descriptor in /proc.
+ * We therefore associate with this name (and the underlying file),
+ * not the name of the file as specified at the command line.
+ */
+ (void) snprintf(buf,
+ sizeof (buf), "/proc/self/fd/%d", fileno(file->fp));
+
+ fobj.fo_name = buf;
+
+ if (assoc) {
+ (void) port_associate(port, PORT_SOURCE_FILE,
+ (uintptr_t)&fobj, FILE_MODIFIED | FILE_TRUNC, file);
+ } else {
+ (void) port_dissociate(port, PORT_SOURCE_FILE,
+ (uintptr_t)&fobj);
+ }
+}
+
+static void
set_events(file_info_t *files)
{
int i;
@@ -271,6 +324,8 @@ set_events(file_info_t *files)
continue;
(void) fstat(fileno(file->fp), &file->st);
+
+ associate(file, B_TRUE);
}
}
@@ -284,6 +339,8 @@ follow(file_info_t *files, enum STYLE style, off_t off)
int active, ev_change, i, n = -1;
struct stat sb2;
file_info_t *file;
+ struct timespec ts;
+ port_event_t ev;
/* Position each of the files */
@@ -307,6 +364,10 @@ follow(file_info_t *files, enum STYLE style, off_t off)
return;
last = --file;
+
+ if (action == USE_PORT && (port = port_create()) == -1)
+ action = USE_SLEEP;
+
set_events(files);
for (;;) {
@@ -341,12 +402,13 @@ follow(file_info_t *files, enum STYLE style, off_t off)
sb2.st_dev != file->st.st_dev ||
sb2.st_nlink == 0) {
(void) show(file);
+ associate(file, B_FALSE);
file->fp = freopen(file->file_name, "r",
file->fp);
- if (file->fp != NULL)
+ if (file->fp != NULL) {
(void) memcpy(&file->st, &sb2,
sizeof (struct stat));
- else if (errno != ENOENT)
+ } else if (errno != ENOENT)
ierr(file->file_name);
ev_change++;
}
@@ -361,6 +423,26 @@ follow(file_info_t *files, enum STYLE style, off_t off)
set_events(files);
switch (action) {
+ case USE_PORT:
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+
+ /*
+ * In the -F case we set a timeout to ensure that
+ * we re-stat the file at least once every second.
+ */
+ n = port_get(port, &ev, Fflag ? &ts : NULL);
+
+ if (n == 0) {
+ file = (file_info_t *)ev.portev_user;
+ associate(file, B_TRUE);
+
+ if (ev.portev_events & FILE_TRUNC)
+ (void) fseek(file->fp, 0, SEEK_SET);
+ }
+
+ break;
+
case USE_SLEEP:
(void) usleep(250000);
break;
diff --git a/usr/src/cmd/tail/tests/tailtests.sh b/usr/src/cmd/tail/tests/tailtests.sh
index 57ec1c46cc..f9591c8ad1 100644
--- a/usr/src/cmd/tail/tests/tailtests.sh
+++ b/usr/src/cmd/tail/tests/tailtests.sh
@@ -13,14 +13,34 @@
#
# Copyright 2010 Chris Love. All rights reserved.
+# Copyright (c) 2012, Joyent, Inc. All rights reserved.
#
+checktest()
+{
+ local actual=$1
+ local output=$2
+ local test=$3
+
+ if [[ "$a" != "$o" ]]; then
+ echo "$CMD: test $test: FAIL"
+ echo -e "$CMD: test $test: expected output:\n$o"
+ echo -e "$CMD: test $test: actual output:\n$a"
+ else
+ echo "$CMD: test $test: pass"
+ fi
+}
#
# Test cases for 'tail', some based on CoreUtils test cases (validated
-# with legacy Solaris 'tail' and/or xpg4 'tail')
+# with legacy Solaris 'tail' and/or xpg4 'tail'). Note that this is designed
+# to be able to run on BSD systems as well to check our behavior against
+# theirs (some behavior that is known to be idiosyncratic to illumos is
+# skipped on non-illumos systems).
#
PROG=/usr/bin/tail
+CMD=`basename $0`
+DIR=""
case $1 in
-x)
@@ -29,113 +49,273 @@ case $1 in
-o)
PROG=$2
;;
+ -d)
+ DIR=$2
+ ;;
-?)
echo "Usage: tailtests.sh [-x][-o <override tail executable>]"
exit 1
;;
esac
-echo "Using $PROG"
+#
+# Shut bash up upon receiving a term so we can drop it on our children
+# without disrupting the output.
+#
+trap "exit 0" TERM
+
+echo "$CMD: program is $PROG"
+
+if [[ $DIR != "" ]]; then
+ echo "$CMD: directory is $DIR"
+fi
o=`echo -e "bcd"`
a=`echo -e "abcd" | $PROG +2c`
-[[ "$a" != "$o" ]] && echo "Fail test 1 - $a"
+checktest "$a" "$o" 1
o=`echo -e ""`
a=`echo "abcd" | $PROG +8c`
-[[ "$a" != "$o" ]] && echo "Fail test 2 - $a"
+checktest "$a" "$o" 2
o=`echo -e "abcd"`
a=`echo "abcd" | $PROG -9c`
-[[ "$a" != "$o" ]] && echo "Fail test 3 - $a"
+checktest "$a" "$o" 3
o=`echo -e "x"`
a=`echo -e "x" | $PROG -1l`
-[[ "$a" != "x" ]] && echo "Fail test 4 - $a"
+checktest "$a" "$o" 4
o=`echo -e "\n"`
a=`echo -e "x\ny\n" | $PROG -1l`
-[[ "$a" != "$o" ]] && echo "Fail test 5 - $a"
+checktest "$a" "$o" 5
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG -2l`
-[[ "$a" != "$o" ]] && echo "Fail test 6 - $a"
+checktest "$a" "$o" 6
o=`echo -e "y"`
a=`echo -e "x\ny" | $PROG -1l`
-[[ "$a" != "$o" ]] && echo "Fail test 7 - $a"
+checktest "$a" "$o" 7
o=`echo -e "x\ny\n"`
a=`echo -e "x\ny\n" | $PROG +1l`
-[[ "$a" != "$o" ]] && echo "Fail test 8 - $a"
+checktest "$a" "$o" 8
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG +2l`
-[[ "$a" != "$o" ]] && echo "Fail test 9 - $a"
+checktest "$a" "$o" 9
o=`echo -e "x"`
a=`echo -e "x" | $PROG -1`
-[[ "$a" != "$o" ]] && echo "Fail test 10 - $a"
+checktest "$a" "$o" 10
o=`echo -e "\n"`
a=`echo -e "x\ny\n" | $PROG -1`
-[[ "$a" != "$o" ]] && echo "Fail test 11 - $a"
+checktest "$a" "$o" 11
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG -2`
-[[ "$a" != "$o" ]] && echo "Fail test 12 - $a"
+checktest "$a" "$o" 12
o=`echo -e "y"`
a=`echo -e "x\ny" | $PROG -1`
-[[ "$a" != "$o" ]] && echo "Fail test 13 - $a"
+checktest "$a" "$o" 13
o=`echo -e "x\ny\n"`
a=`echo -e "x\ny\n" | $PROG +1`
-[[ "$a" != "$o" ]] && echo "Fail test 14 - $a"
+checktest "$a" "$o" 14
o=`echo -e "y\n"`
a=`echo -e "x\ny\n" | $PROG +2`
-[[ "$a" != "$o" ]] && echo "Fail test 15 - $a"
+checktest "$a" "$o" 15
-# For compatibility with Legacy Solaris tail this should also work as '+c'
o=`echo -e "yyz"`
a=`echo -e "xyyyyyyyyyyz" | $PROG +10c`
-[[ "$a" != "$o" ]] && echo "Fail test 16 - $a"
+checktest "$a" "$o" 16
-o=`echo -e "yyz"`
-a=`echo -e "xyyyyyyyyyyz" | $PROG +c`
-[[ "$a" != "$o" ]] && echo "Fail test 16a - $a"
-
-
-# For compatibility with Legacy Solaris tail this should also work as '+l'
o=`echo -e "y\ny\nz"`
a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG +10l`
-[[ "$a" != "$o" ]] && echo "Fail test 17 - $a"
-
-o=`echo -e "y\ny\nz"`
-a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG +l`
-[[ "$a" != "$o" ]] && echo "Fail test 17a - $a"
-
+checktest "$a" "$o" 17
-# For compatibility with Legacy Solaris tail this should also work as '-l'
o=`echo -e "y\ny\ny\ny\ny\ny\ny\ny\ny\nz"`
a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG -10l`
-[[ "$a" != "$o" ]] && echo "Fail test 18 - $a"
+checktest "$a" "$o" 18
-o=`echo -e "y\ny\ny\ny\ny\ny\ny\ny\ny\nz"`
-a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG -l`
-[[ "$a" != "$o" ]] && echo "Fail test 18a - $a"
+#
+# For reasons that are presumably as accidental as they are ancient, legacy
+# (and closed) Solaris tail(1) allows +c, +l and -l to be aliases for +10c,
+# +10l and -10l, respectively. If we are on SunOS, verify that this silly
+# behavior is functional.
+#
+if [[ `uname -s` == "SunOS" ]]; then
+ o=`echo -e "yyz"`
+ a=`echo -e "xyyyyyyyyyyz" | $PROG +c`
+ checktest "$a" "$o" 16a
+
+ o=`echo -e "y\ny\nz"`
+ a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG +l`
+ checktest "$a" "$o" 17a
+
+ o=`echo -e "y\ny\ny\ny\ny\ny\ny\ny\ny\nz"`
+ a=`echo -e "x\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\nz" | $PROG -l`
+ checktest "$a" "$o" 18a
+fi
o=`echo -e "c\nb\na"`
a=`echo -e "a\nb\nc" | $PROG -r`
-[[ "$a" != "$o" ]] && echo "Fail test 19 - $a"
+checktest "$a" "$o" 19
+
+#
+# Now we want to do a series of follow tests.
+#
+if [[ $DIR == "" ]]; then
+ tdir=$(mktemp -d -t tailtest.XXXXXXXX || exit 1)
+else
+ tdir=$(mktemp -d $DIR/tailtest.XXXXXXXX || exit 1)
+fi
+
+follow=$tdir/follow
+moved=$tdir/follow.moved
+out=$tdir/out
+
+#
+# First, verify that following works in its most basic sense.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\n"`
+a=`cat $out`
+checktest "$a" "$o" 20
+rm $follow
+
+#
+# Now verify that following correctly follows the file being moved.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+mv $follow $moved
+
+echo -e "d\ne\nf" >> $moved
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\n"`
+a=`cat $out`
+checktest "$a" "$o" 21
+rm $moved
+
+#
+# And now truncation with the new offset being less than the old offset.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+echo -e "g\nh\ni" > $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
+a=`cat $out`
+checktest "$a" "$o" 22
+rm $follow
+
+#
+# And truncation with the new offset being greater than the old offset.
+#
+echo -e "a\nb\nc" > $follow
+sleep 1
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+echo -e "g\nh\ni\nj\nk\nl\nm\no\np\nq" > $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\no\np\nq"`
+a=`cat $out`
+checktest "$a" "$o" 23
+rm $follow
+
+#
+# Verify that we can follow the moved file and correctly see a truncation.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -f $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+mv $follow $moved
+
+echo -e "d\ne\nf" >> $moved
+sleep 1
+echo -e "g\nh\ni\nj\nk\nl\nm\no\np\nq" > $moved
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\no\np\nq"`
+a=`cat $out`
+checktest "$a" "$o" 24
+rm $moved
+
+#
+# Verify that capital-F follow properly deals with truncation
+#
+echo -e "a\nb\nc" > $follow
+$PROG -F $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+echo -e "d\ne\nf" >> $follow
+sleep 1
+echo -e "g\nh\ni" > $follow
+sleep 1
+kill $child
+sleep 1
+
+o=`echo -e "a\nb\nc\nd\ne\nf\ng\nh\ni\n"`
+a=`cat $out`
+checktest "$a" "$o" 25
+rm $follow
+
+#
+# Verify that capital-F follow _won't_ follow the moved file and will
+# correctly deal with recreation of the original file.
+#
+echo -e "a\nb\nc" > $follow
+$PROG -F $follow > $out 2> /dev/null &
+child=$!
+sleep 2
+mv $follow $moved
+
+echo -e "x\ny\nz" >> $moved
+echo -e "d\ne\nf" > $follow
+sleep 1
+kill $child
+sleep 1
+o=`echo -e "a\nb\nc\nd\ne\nf\n"`
+a=`cat $out`
+checktest "$a" "$o" 26
+rm $moved
-echo "Completed"
+echo "$CMD: completed"
-exit 0
+exit $errs
-# Template for additional test cases
-#o=`echo -e ""`
-#a=`echo -e "" | $PROG `
-#[[ "$a" != "$o" ]] && echo "Fail test - $a"
diff --git a/usr/src/man/man3c/port_associate.3c b/usr/src/man/man3c/port_associate.3c
index d876b5c9d7..f6e66b0d65 100644
--- a/usr/src/man/man3c/port_associate.3c
+++ b/usr/src/man/man3c/port_associate.3c
@@ -73,21 +73,21 @@ the port.
.LP
Objects of type \fBPORT_SOURCE_FILE\fR are pointer to the structure
\fBfile_obj\fR defined in \fB<sys/port.h>\fR. This event source provides event
-notification when the specified file/directory is accessed or modified or when
-its status changes. The path name of the file/directory to be watched is passed
-in the \fBstruct file_obj\fR along with the \fBaccess\fR, \fBmodification\fR,
-and \fBchange\fR time stamps acquired from a \fBstat\fR(2) call. If the file
-name is a symbolic links, it is followed by default. The \fBFILE_NOFOLLOW\fR
-needs to be passed in along with the specified events if the symbolic link
-itself needs to be watched and \fBlstat()\fR needs to be used to get the file
-status of the symbolic link file.
+notification when the specified file/directory is accessed, modified,
+truncated or when its status changes. The path name of the file/directory to
+be watched is passed in the \fBstruct file_obj\fR along with the \fBaccess\fR,
+\fBmodification\fR, and \fBchange\fR time stamps acquired from a \fBstat\fR(2)
+call. If the file name is a symbolic link, it is followed by default. The
+\fBFILE_NOFOLLOW\fR needs to be passed in along with the specified events if
+the symbolic link itself needs to be watched and \fBlstat()\fR needs to be
+used to get the file status of the symbolic link file.
.sp
.LP
The \fBstruct file_obj\fR contains the following elements:
.sp
.in +2
.nf
-timestruc_t fo_atime; /* Access time got from stat() */
+timestruc_t fo_atime; /* Access time from stat() */
timestruc_t fo_mtime; /* Modification time from stat() */
timestruc_t fo_ctime; /* Change time from stat() */
char *fo_name; /* Pointer to a null terminated path name */
@@ -104,11 +104,13 @@ occurs.
.sp
.LP
The event types that can be specified at \fBport_associate()\fR time for
-\fBPORT_SOURCE_FILE\fR are \fBFILE_ACCESS\fR, \fBFILE_MODIFIED\fR, and
-\fBFILE_ATTRIB\fR, corresponding to the three time stamps. An \fBfo_atime\fR
-change results in the \fBFILE_ACCESS\fR event, an \fBfo_mtime\fR change results
-in the \fBFILE_MODIFIED\fR event, and an \fBfo_time\fR change results in the
-\fBFILE_ATTRIB\fR event.
+\fBPORT_SOURCE_FILE\fR are \fBFILE_ACCESS\fR, \fBFILE_MODIFIED\fR,
+\fBFILE_ATTRIB\fR, and \fbFILE_TRUNC\fR. The first three of these correspond
+to the three time stamps: an \fBfo_atime\fR change results in the
+\fBFILE_ACCESS\fR event, an \fBfo_mtime\fR change results in the
+\fBFILE_MODIFIED\fR event, and an \fBfo_ctime\fR change results in the
+\fBFILE_ATTRIB\fR event. If the operation that induced the time stamp update
+also truncated the file, \fBFILE_TRUNC\fR will be set in the resulting event.
.sp
.LP
The following exception events are delivered when they occur. These event types
diff --git a/usr/src/uts/common/fs/nfs/nfs3_vnops.c b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
index d31b53d2e9..4e5882ad7c 100644
--- a/usr/src/uts/common/fs/nfs/nfs3_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs3_vnops.c
@@ -28,6 +28,10 @@
* All rights reserved.
*/
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
@@ -2298,6 +2302,12 @@ top:
vattr.va_mask = AT_SIZE;
error = nfs3setattr(vp,
&vattr, 0, cr);
+
+ /*
+ * Existing file was truncated;
+ * emit a create event.
+ */
+ vnevent_create(vp, ct);
}
}
}
@@ -2306,12 +2316,9 @@ top:
if (error) {
VN_RELE(vp);
} else {
- /*
- * existing file got truncated, notify.
- */
- vnevent_create(vp, ct);
*vpp = vp;
}
+
return (error);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs4_vnops.c b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
index 97521f8e3a..a5b6bbfdc1 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_vnops.c
@@ -28,6 +28,10 @@
* All Rights Reserved
*/
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
@@ -6651,16 +6655,20 @@ top:
} else {
vnode_t *tvp;
rnode4_t *trp;
- /*
- * existing file got truncated, notify.
- */
tvp = vp;
if (vp->v_type == VREG) {
trp = VTOR4(vp);
if (IS_SHADOW(vp, trp))
tvp = RTOV4(trp);
}
- vnevent_create(tvp, ct);
+
+ if (must_trunc) {
+ /*
+ * existing file got truncated, notify.
+ */
+ vnevent_create(tvp, ct);
+ }
+
*vpp = vp;
}
return (error);
diff --git a/usr/src/uts/common/fs/nfs/nfs_vnops.c b/usr/src/uts/common/fs/nfs/nfs_vnops.c
index a3f43a4e95..fa31e3693f 100644
--- a/usr/src/uts/common/fs/nfs/nfs_vnops.c
+++ b/usr/src/uts/common/fs/nfs/nfs_vnops.c
@@ -25,6 +25,10 @@
* All rights reserved.
*/
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
@@ -2030,6 +2034,14 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
vp->v_type == VREG) {
vattr.va_mask = AT_SIZE;
error = nfssetattr(vp, &vattr, 0, cr);
+
+ if (!error) {
+ /*
+ * Existing file was truncated;
+ * emit a create event.
+ */
+ vnevent_create(vp, ct);
+ }
}
}
}
@@ -2037,10 +2049,6 @@ nfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
if (error) {
VN_RELE(vp);
} else {
- /*
- * existing file got truncated, notify.
- */
- vnevent_create(vp, ct);
*vpp = vp;
}
return (error);
diff --git a/usr/src/uts/common/fs/portfs/port_fop.c b/usr/src/uts/common/fs/portfs/port_fop.c
index 2852a98f52..48792394a5 100644
--- a/usr/src/uts/common/fs/portfs/port_fop.c
+++ b/usr/src/uts/common/fs/portfs/port_fop.c
@@ -23,6 +23,9 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
/*
* File Events Notification
@@ -1965,7 +1968,9 @@ port_fop(vnode_t *vp, int op, int retval)
if (op & FOP_ATTRIB_MASK) {
event |= FILE_ATTRIB;
}
-
+ if (op & FOP_TRUNC_MASK) {
+ event |= FILE_TRUNC;
+ }
if (event) {
port_fop_sendevent(vp, event, NULL, NULL);
}
@@ -2147,6 +2152,9 @@ port_fop_setattr(femarg_t *vf, vattr_t *vap, int flags, cred_t *cr,
int events = 0;
retval = vnext_setattr(vf, vap, flags, cr, ct);
+ if (vap->va_mask & AT_SIZE) {
+ events |= FOP_FILE_TRUNC;
+ }
if (vap->va_mask & (AT_SIZE|AT_MTIME)) {
events |= FOP_FILE_SETATTR_MTIME;
}
@@ -2322,8 +2330,8 @@ port_fop_vnevent(femarg_t *vf, vnevent_t vnevent, vnode_t *dvp, char *name,
port_fop_sendevent(vp, FILE_DELETE, dvp, name);
break;
case VE_CREATE:
- port_fop_sendevent(vp, FILE_MODIFIED|FILE_ATTRIB,
- NULL, NULL);
+ port_fop_sendevent(vp,
+ FILE_MODIFIED|FILE_ATTRIB|FILE_TRUNC, NULL, NULL);
break;
case VE_LINK:
port_fop_sendevent(vp, FILE_ATTRIB, NULL, NULL);
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
index 61d72a4015..461016aa52 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vnops.c
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
#include <sys/types.h>
#include <sys/param.h>
#include <sys/t_lock.h>
@@ -978,6 +982,8 @@ again:
}
if (error == 0) { /* name found */
+ boolean_t trunc = B_FALSE;
+
ASSERT(oldtp);
rw_enter(&oldtp->tn_rwlock, RW_WRITER);
@@ -1005,6 +1011,7 @@ again:
rw_enter(&oldtp->tn_contents, RW_WRITER);
(void) tmpnode_trunc(tm, oldtp, 0);
rw_exit(&oldtp->tn_contents);
+ trunc = B_TRUE;
}
rw_exit(&oldtp->tn_rwlock);
if (IS_DEVVP(*vpp)) {
@@ -1019,9 +1026,9 @@ again:
*vpp = newvp;
}
- if (error == 0) {
+ if (trunc)
vnevent_create(*vpp, ct);
- }
+
return (0);
}
diff --git a/usr/src/uts/common/sys/port.h b/usr/src/uts/common/sys/port.h
index ccb0308255..d4d74d55ea 100644
--- a/usr/src/uts/common/sys/port.h
+++ b/usr/src/uts/common/sys/port.h
@@ -24,11 +24,13 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
#ifndef _SYS_PORT_H
#define _SYS_PORT_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -106,6 +108,7 @@ typedef struct port_notify32 {
#define FILE_ACCESS 0x00000001
#define FILE_MODIFIED 0x00000002
#define FILE_ATTRIB 0x00000004
+#define FILE_TRUNC 0x00100000
#define FILE_NOFOLLOW 0x10000000
/*
diff --git a/usr/src/uts/common/sys/port_impl.h b/usr/src/uts/common/sys/port_impl.h
index 9f3f291874..504fb9ece1 100644
--- a/usr/src/uts/common/sys/port_impl.h
+++ b/usr/src/uts/common/sys/port_impl.h
@@ -24,6 +24,10 @@
* Use is subject to license terms.
*/
+/*
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ */
+
#ifndef _SYS_PORT_IMPL_H
#define _SYS_PORT_IMPL_H
@@ -311,6 +315,7 @@ typedef struct portfop_vp {
#define FOP_FILE_SETATTR_MTIME 0x00080000
#define FOP_FILE_SETATTR_CTIME 0x00100000
#define FOP_FILE_LINK_SRC 0x00200000
+#define FOP_FILE_TRUNC 0x00400000
/*
* File modification event.
@@ -339,10 +344,15 @@ typedef struct portfop_vp {
/*
+ * File trunc event
+ */
+#define FOP_TRUNC_MASK (FOP_FILE_TRUNC|FOP_FILE_CREATE)
+
+/*
* valid watchable events
*/
#define FILE_EVENTS_MASK (FILE_ACCESS|FILE_MODIFIED|FILE_ATTRIB \
- |FILE_NOFOLLOW)
+ |FILE_NOFOLLOW|FILE_TRUNC)
/* --- End file events --- */
/*