diff options
author | Bryan Cantrill <bryan@joyent.com> | 2012-08-03 19:23:29 +0000 |
---|---|---|
committer | Bryan Cantrill <bryan@joyent.com> | 2012-08-03 19:23:29 +0000 |
commit | 12ef7bd6596eedcaafd544ec675d6b72dfd15998 (patch) | |
tree | 36806bf6158fa7ba2f411f590c8d66f25c58d8b5 | |
parent | 9e857228fdc0128410f9aec8c9e410612e8bd96e (diff) | |
download | illumos-joyent-12ef7bd6596eedcaafd544ec675d6b72dfd15998.tar.gz |
OS-1429 `tail -f ...` doesn't notice file truncation
-rw-r--r-- | usr/src/cmd/tail/forward.c | 94 | ||||
-rw-r--r-- | usr/src/cmd/tail/tests/tailtests.sh | 266 | ||||
-rw-r--r-- | usr/src/man/man3c/port_associate.3c | 30 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs3_vnops.c | 15 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs4_vnops.c | 16 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs_vnops.c | 16 | ||||
-rw-r--r-- | usr/src/uts/common/fs/portfs/port_fop.c | 14 | ||||
-rw-r--r-- | usr/src/uts/common/fs/tmpfs/tmp_vnops.c | 11 | ||||
-rw-r--r-- | usr/src/uts/common/sys/port.h | 7 | ||||
-rw-r--r-- | usr/src/uts/common/sys/port_impl.h | 12 |
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 --- */ /* |