diff options
author | Bryan Cantrill <bryan@joyent.com> | 2013-09-05 06:46:02 +0000 |
---|---|---|
committer | Bryan Cantrill <bryan@joyent.com> | 2013-09-05 06:46:02 +0000 |
commit | 64af696dbea3e718e4c758e173de5fa35826dd41 (patch) | |
tree | e68a6fe823b0d3026055cddd50e1bed589ea9727 /usr/src | |
parent | 1c485ea3760aeec397cb5b579d3feaf1c097ee4b (diff) | |
download | illumos-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.c | 30 | ||||
-rw-r--r-- | usr/src/cmd/tail/tests/tailtests.sh | 42 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs3_vnops.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs4_vnops.c | 13 | ||||
-rw-r--r-- | usr/src/uts/common/fs/nfs/nfs_vnops.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/fs/pcfs/pc_vnops.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/fs/portfs/port_fop.c | 16 | ||||
-rw-r--r-- | usr/src/uts/common/fs/tmpfs/tmp_vnops.c | 7 | ||||
-rw-r--r-- | usr/src/uts/common/fs/udfs/udf_vnops.c | 10 | ||||
-rw-r--r-- | usr/src/uts/common/fs/ufs/ufs_vnops.c | 7 | ||||
-rw-r--r-- | usr/src/uts/common/fs/vnode.c | 11 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_vnops.c | 6 | ||||
-rw-r--r-- | usr/src/uts/common/sys/vnode.h | 5 |
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 */ |