From nobody@FreeBSD.org  Tue May 10 17:14:40 2011
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 8D0B1106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 10 May 2011 17:14:40 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 625338FC13
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 10 May 2011 17:14:40 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p4AHEdrH074977
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 10 May 2011 17:14:39 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id p4AHEdX2074976;
	Tue, 10 May 2011 17:14:39 GMT
	(envelope-from nobody)
Message-Id: <201105101714.p4AHEdX2074976@red.freebsd.org>
Date: Tue, 10 May 2011 17:14:39 GMT
From: "D. Secret" <org_freebsd@L93.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: ZFS receive after read on readonly=on filesystem is corrupted without warning
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         156933
>Category:       kern
>Synopsis:       [zfs] ZFS receive after read on readonly=on filesystem is corrupted without warning
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-fs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue May 10 17:20:10 UTC 2011
>Closed-Date:    Fri Sep 02 08:23:59 UTC 2011
>Last-Modified:  Fri Sep 02 08:23:59 UTC 2011
>Originator:     D. Secret
>Release:        8.2-RELEASE
>Organization:
>Environment:
FreeBSD z0.L93.com 8.2-RELEASE FreeBSD 8.2-RELEASE #0: Thu Feb 17 02:41:51 UTC 2011     root@mason.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64

>Description:
If you read from a readonly=on ZFS filesystem before receiving a ZFS -i send for new snapshots it will receive the new snapshot and have a corrupted filesystem(that ZFS scrub does not detect!)  The one file on the filesystem I've included will show this corruption.  It should simply be a file of consecutive numbers, yet the last like will have some messed up data.

The ZFS 'images' were created as such:
13.zfs: A snapshot export of the filesystem
 -=- Append "14" to the replicate.dat file
 -=- Create snapshot @14
diff.zfs : a -i snapshot between @13 and @14.  It properly re-creates the file assuming you haven't read from the filesystem.  Note: Reading from the filesystem in this manner is present in some FAQ's about ZFS replication.


>How-To-Repeat:
1. Create a new zfs filesystem
zfs set readonly=on (my new filesystem)
cat zimg/13.zfs | zfs receive -F (my new filesystem)

OPTIONAL: cat (my new filesystem)/replicate.dat    
[This will cause the corruption if you do it]

cat zimg/diff.zfs | zfs receive (my new filesystem)

Now inspect (my new filesystem)/replicate.dat .. 

BUG file SHA1 is b3af2ae0f05cceb7efbcfc747750f56f53e4a69e
Proper file SHA1 is 42f9e9bf4534b43b57faaed39194115bf3517898

You'll notice it'll be different depending on if you performed the "optional" step.  I'm pretty sure this isn't proper.  I've verified that the atime of the file isn't changing, but there must be some subtle change going on that isn't being caught.  Also the zfs receive is allowed in both cases, but in one case the file is corrupted (vi shows 3x ^@ at the end, rather than the expected 14\n)

I can offer you access to a machine if you have difficulty reproducing this issue.  My scripts & sample filesystems are at:
http://sov.L93.com/bug.tgz
SHA1: 62b700d95096474ed7f3ae0b9249f9ec77e9a747
MD5: 9b9aa38b322cedd3e1223fc50f18a55b

There are no executables, just a very simple 5 or so line (rather basic) script to automate things if you choose to use them.  Please note it will destroy filesystem "z0/rdata_rcv" if you happen to have a ZFS filesystem by that name. ;)

A shar archive of the 11k TGZ is 711k, beyond what i can attach to this.  Hopefully the web link suffices.

>Fix:
I do not have a fix, but I do have what I believe is a 100% reproduction so I imagine a fix shouldn't be too difficult.   I would look for what change is being made to the ZFS filesystem while readonly=on is set and a file is read...It should be none, as far as I know.

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-fs 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Tue May 10 19:30:17 UTC 2011 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=156933 

From: Martin Matuska <mm@FreeBSD.org>
To: bug-followup@FreeBSD.org, org_freebsd@L93.com
Cc:  
Subject: Re: kern/156933: [zfs] ZFS receive after read on readonly=on filesystem
 is corrupted without warning
Date: Mon, 18 Jul 2011 13:52:21 +0200

 I am unable to reproduce this on ZFS v28.
 Can you give me detailed instructions and necessary files?
 
 -- 
 Martin Matuska
 FreeBSD committer
 http://blog.vx.sk
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/156933: commit references a PR
Date: Thu, 25 Aug 2011 08:17:55 +0000 (UTC)

 Author: mm
 Date: Thu Aug 25 08:17:39 2011
 New Revision: 225166
 URL: http://svn.freebsd.org/changeset/base/225166
 
 Log:
   Generalize ffs_pages_remove() into vn_pages_remove().
   
   Remove mapped pages for all dataset vnodes in zfs_rezget() using
   new vn_pages_remove() to fix mmapped files changed by
   zfs rollback or zfs receive -F.
   
   PR:		kern/160035, kern/156933
   Reviewed by:	kib, pjd
   Approved by:	re (kib)
   MFC after:	1 week
 
 Modified:
   head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
   head/sys/kern/vfs_vnops.c
   head/sys/sys/vnode.h
   head/sys/ufs/ffs/ffs_extern.h
   head/sys/ufs/ffs/ffs_inode.c
   head/sys/ufs/ffs/ffs_softdep.c
 
 Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
 ==============================================================================
 --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Thu Aug 25 07:28:07 2011	(r225165)
 +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Thu Aug 25 08:17:39 2011	(r225166)
 @@ -1273,6 +1273,7 @@ zfs_rezget(znode_t *zp)
  	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
  	dmu_object_info_t doi;
  	dmu_buf_t *db;
 +	vnode_t *vp;
  	uint64_t obj_num = zp->z_id;
  	uint64_t mode, size;
  	sa_bulk_attr_t bulk[8];
 @@ -1348,8 +1349,9 @@ zfs_rezget(znode_t *zp)
  	 * that for example regular file was replaced with directory
  	 * which has the same object number.
  	 */
 -	if (ZTOV(zp) != NULL &&
 -	    ZTOV(zp)->v_type != IFTOVT((mode_t)zp->z_mode)) {
 +	vp = ZTOV(zp);
 +	if (vp != NULL &&
 +	    vp->v_type != IFTOVT((mode_t)zp->z_mode)) {
  		zfs_znode_dmu_fini(zp);
  		ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
  		return (EIO);
 @@ -1357,8 +1359,11 @@ zfs_rezget(znode_t *zp)
  
  	zp->z_unlinked = (zp->z_links == 0);
  	zp->z_blksz = doi.doi_data_block_size;
 -	if (zp->z_size != size && ZTOV(zp) != NULL)
 -		vnode_pager_setsize(ZTOV(zp), zp->z_size);
 +	if (vp != NULL) {
 +		vn_pages_remove(vp, 0, 0);
 +		if (zp->z_size != size)
 +			vnode_pager_setsize(vp, zp->z_size);
 +	}
  
  	ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
  
 
 Modified: head/sys/kern/vfs_vnops.c
 ==============================================================================
 --- head/sys/kern/vfs_vnops.c	Thu Aug 25 07:28:07 2011	(r225165)
 +++ head/sys/kern/vfs_vnops.c	Thu Aug 25 08:17:39 2011	(r225166)
 @@ -64,6 +64,9 @@ __FBSDID("$FreeBSD$");
  #include <security/audit/audit.h>
  #include <security/mac/mac_framework.h>
  
 +#include <vm/vm.h>
 +#include <vm/vm_object.h>
 +
  static fo_rdwr_t	vn_read;
  static fo_rdwr_t	vn_write;
  static fo_truncate_t	vn_truncate;
 @@ -1398,3 +1401,15 @@ vn_chown(struct file *fp, uid_t uid, gid
  	VFS_UNLOCK_GIANT(vfslocked);
  	return (error);
  }
 +
 +void
 +vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
 +{
 +	vm_object_t object;
 +
 +	if ((object = vp->v_object) == NULL)
 +		return;
 +	VM_OBJECT_LOCK(object);
 +	vm_object_page_remove(object, start, end, 0);
 +	VM_OBJECT_UNLOCK(object);
 +}
 
 Modified: head/sys/sys/vnode.h
 ==============================================================================
 --- head/sys/sys/vnode.h	Thu Aug 25 07:28:07 2011	(r225165)
 +++ head/sys/sys/vnode.h	Thu Aug 25 08:17:39 2011	(r225166)
 @@ -640,6 +640,7 @@ int	_vn_lock(struct vnode *vp, int flags
  int	vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp);
  int	vn_open_cred(struct nameidata *ndp, int *flagp, int cmode,
  	    u_int vn_open_flags, struct ucred *cred, struct file *fp);
 +void	vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end);
  int	vn_pollrecord(struct vnode *vp, struct thread *p, int events);
  int	vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base,
  	    int len, off_t offset, enum uio_seg segflg, int ioflg,
 
 Modified: head/sys/ufs/ffs/ffs_extern.h
 ==============================================================================
 --- head/sys/ufs/ffs/ffs_extern.h	Thu Aug 25 07:28:07 2011	(r225165)
 +++ head/sys/ufs/ffs/ffs_extern.h	Thu Aug 25 08:17:39 2011	(r225166)
 @@ -79,7 +79,6 @@ int	ffs_isfreeblock(struct fs *, u_char 
  void	ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t);
  int	ffs_mountroot(void);
  void	ffs_oldfscompat_write(struct fs *, struct ufsmount *);
 -void	ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end);
  int	ffs_reallocblks(struct vop_reallocblks_args *);
  int	ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
  	    ufs2_daddr_t, int, int, int, struct ucred *, struct buf **);
 
 Modified: head/sys/ufs/ffs/ffs_inode.c
 ==============================================================================
 --- head/sys/ufs/ffs/ffs_inode.c	Thu Aug 25 07:28:07 2011	(r225165)
 +++ head/sys/ufs/ffs/ffs_inode.c	Thu Aug 25 08:17:39 2011	(r225166)
 @@ -120,18 +120,6 @@ ffs_update(vp, waitfor)
  	}
  }
  
 -void
 -ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
 -{
 -	vm_object_t object;
 -
 -	if ((object = vp->v_object) == NULL)
 -		return;
 -	VM_OBJECT_LOCK(object);
 -	vm_object_page_remove(object, start, end, 0);
 -	VM_OBJECT_UNLOCK(object);
 -}
 -
  #define	SINGLE	0	/* index of single indirect block */
  #define	DOUBLE	1	/* index of double indirect block */
  #define	TRIPLE	2	/* index of triple indirect block */
 @@ -219,7 +207,7 @@ ffs_truncate(vp, length, flags, cred, td
  			(void) chkdq(ip, -extblocks, NOCRED, 0);
  #endif
  			vinvalbuf(vp, V_ALT, 0, 0);
 -			ffs_pages_remove(vp,
 +			vn_pages_remove(vp,
  			    OFF_TO_IDX(lblktosize(fs, -extblocks)), 0);
  			osize = ip->i_din2->di_extsize;
  			ip->i_din2->di_blocks -= extblocks;
 
 Modified: head/sys/ufs/ffs/ffs_softdep.c
 ==============================================================================
 --- head/sys/ufs/ffs/ffs_softdep.c	Thu Aug 25 07:28:07 2011	(r225165)
 +++ head/sys/ufs/ffs/ffs_softdep.c	Thu Aug 25 08:17:39 2011	(r225166)
 @@ -6541,7 +6541,7 @@ trunc_pages(ip, length, extblocks, flags
  	fs = ip->i_fs;
  	extend = OFF_TO_IDX(lblktosize(fs, -extblocks));
  	if ((flags & IO_EXT) != 0)
 -		ffs_pages_remove(vp, extend, 0);
 +		vn_pages_remove(vp, extend, 0);
  	if ((flags & IO_NORMAL) == 0)
  		return;
  	BO_LOCK(&vp->v_bufobj);
 @@ -6567,7 +6567,7 @@ trunc_pages(ip, length, extblocks, flags
  		end = OFF_TO_IDX(lblktosize(fs, lbn));
  	} else
  		end = extend;
 -	ffs_pages_remove(vp, OFF_TO_IDX(OFF_MAX), end);
 +	vn_pages_remove(vp, OFF_TO_IDX(OFF_MAX), end);
  }
  
  /*
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/156933: commit references a PR
Date: Fri,  2 Sep 2011 08:19:40 +0000 (UTC)

 Author: mm
 Date: Fri Sep  2 08:19:19 2011
 New Revision: 225326
 URL: http://svn.freebsd.org/changeset/base/225326
 
 Log:
   MFC r226155:
   
   Generalize ffs_pages_remove() into vn_pages_remove().
   
   Remove mapped pages for all dataset vnodes in zfs_rezget() using
   new vn_pages_remove() to fix mmapped files changed by
   zfs rollback or zfs receive -F.
   
   PR:		kern/160035, kern/156933
 
 Modified:
   stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
   stable/8/sys/kern/vfs_vnops.c
   stable/8/sys/sys/vnode.h
   stable/8/sys/ufs/ffs/ffs_inode.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
 
 Modified: stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
 ==============================================================================
 --- stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Fri Sep  2 08:15:48 2011	(r225325)
 +++ stable/8/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Fri Sep  2 08:19:19 2011	(r225326)
 @@ -1259,6 +1259,7 @@ zfs_rezget(znode_t *zp)
  	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
  	dmu_object_info_t doi;
  	dmu_buf_t *db;
 +	vnode_t *vp;
  	uint64_t obj_num = zp->z_id;
  	uint64_t mode, size;
  	sa_bulk_attr_t bulk[8];
 @@ -1334,8 +1335,9 @@ zfs_rezget(znode_t *zp)
  	 * that for example regular file was replaced with directory
  	 * which has the same object number.
  	 */
 -	if (ZTOV(zp) != NULL &&
 -	    ZTOV(zp)->v_type != IFTOVT((mode_t)zp->z_mode)) {
 +	vp = ZTOV(zp);
 +	if (vp != NULL &&
 +	    vp->v_type != IFTOVT((mode_t)zp->z_mode)) {
  		zfs_znode_dmu_fini(zp);
  		ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
  		return (EIO);
 @@ -1343,8 +1345,11 @@ zfs_rezget(znode_t *zp)
  
  	zp->z_unlinked = (zp->z_links == 0);
  	zp->z_blksz = doi.doi_data_block_size;
 -	if (zp->z_size != size && ZTOV(zp) != NULL)
 -		vnode_pager_setsize(ZTOV(zp), zp->z_size);
 +	if (vp != NULL) {
 +		vn_pages_remove(vp, 0, 0);
 +		if (zp->z_size != size)
 +			vnode_pager_setsize(vp, zp->z_size);
 +	}
  
  	ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
  
 
 Modified: stable/8/sys/kern/vfs_vnops.c
 ==============================================================================
 --- stable/8/sys/kern/vfs_vnops.c	Fri Sep  2 08:15:48 2011	(r225325)
 +++ stable/8/sys/kern/vfs_vnops.c	Fri Sep  2 08:19:19 2011	(r225326)
 @@ -63,6 +63,9 @@ __FBSDID("$FreeBSD$");
  
  #include <security/mac/mac_framework.h>
  
 +#include <vm/vm.h>
 +#include <vm/vm_object.h>
 +
  static fo_rdwr_t	vn_read;
  static fo_rdwr_t	vn_write;
  static fo_truncate_t	vn_truncate;
 @@ -1353,3 +1356,15 @@ vn_rlimit_fsize(const struct vnode *vp, 
  
  	return (0);
  }
 +
 +void
 +vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
 +{
 +	vm_object_t object;
 +
 +	if ((object = vp->v_object) == NULL)
 +		return;
 +	VM_OBJECT_LOCK(object);
 +	vm_object_page_remove(object, start, end, 0);
 +	VM_OBJECT_UNLOCK(object);
 +}
 
 Modified: stable/8/sys/sys/vnode.h
 ==============================================================================
 --- stable/8/sys/sys/vnode.h	Fri Sep  2 08:15:48 2011	(r225325)
 +++ stable/8/sys/sys/vnode.h	Fri Sep  2 08:19:19 2011	(r225326)
 @@ -644,6 +644,7 @@ int	_vn_lock(struct vnode *vp, int flags
  int	vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp);
  int	vn_open_cred(struct nameidata *ndp, int *flagp, int cmode,
  	    u_int vn_open_flags, struct ucred *cred, struct file *fp);
 +void	vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end);
  int	vn_pollrecord(struct vnode *vp, struct thread *p, int events);
  int	vn_rdwr(enum uio_rw rw, struct vnode *vp, void *base,
  	    int len, off_t offset, enum uio_seg segflg, int ioflg,
 
 Modified: stable/8/sys/ufs/ffs/ffs_inode.c
 ==============================================================================
 --- stable/8/sys/ufs/ffs/ffs_inode.c	Fri Sep  2 08:15:48 2011	(r225325)
 +++ stable/8/sys/ufs/ffs/ffs_inode.c	Fri Sep  2 08:19:19 2011	(r225326)
 @@ -129,18 +129,6 @@ ffs_update(vp, waitfor)
  	}
  }
  
 -static void
 -ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
 -{
 -	vm_object_t object;
 -
 -	if ((object = vp->v_object) == NULL)
 -		return;
 -	VM_OBJECT_LOCK(object);
 -	vm_object_page_remove(object, start, end, FALSE);
 -	VM_OBJECT_UNLOCK(object);
 -}
 -
  #define	SINGLE	0	/* index of single indirect block */
  #define	DOUBLE	1	/* index of double indirect block */
  #define	TRIPLE	2	/* index of triple indirect block */
 @@ -218,7 +206,7 @@ ffs_truncate(vp, length, flags, cred, td
  			(void) chkdq(ip, -extblocks, NOCRED, 0);
  #endif
  			vinvalbuf(vp, V_ALT, 0, 0);
 -			ffs_pages_remove(vp,
 +			vn_pages_remove(vp,
  			    OFF_TO_IDX(lblktosize(fs, -extblocks)), 0);
  			ip->i_din2->di_extsize = 0;
  			for (i = 0; i < NXADDR; i++) {
 @@ -297,7 +285,7 @@ ffs_truncate(vp, length, flags, cred, td
  			ASSERT_VOP_LOCKED(vp, "ffs_truncate1");
  			vinvalbuf(vp, needextclean ? 0 : V_NORMAL, 0, 0);
  			if (!needextclean)
 -				ffs_pages_remove(vp, 0,
 +				vn_pages_remove(vp, 0,
  				    OFF_TO_IDX(lblktosize(fs, -extblocks)));
  			vnode_pager_setsize(vp, 0);
  			ip->i_flag |= IN_CHANGE | IN_UPDATE;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: mm 
State-Changed-When: Fri Sep 2 08:23:57 UTC 2011 
State-Changed-Why:  
Resolved. Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=156933 
>Unformatted:
