Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 2 Oct 2016 22:13:49 +0300
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        Anton Yuzhaninov <citrin@citrin.ru>
Cc:        "freebsd-fs@freebsd.org" <freebsd-fs@freebsd.org>
Subject:   Re: UFS: unaligned read from GELI with 8k sectorsize
Message-ID:  <20161002191349.GH38409@kib.kiev.ua>
In-Reply-To: <999638f9-3fee-82e3-d67f-cffef53b74e8@citrin.ru>
References:  <f84b069b-aeee-ff3c-d4f9-e2fe3caaddb1@citrin.ru> <20161001114536.GX38409@kib.kiev.ua> <20161001115439.GY38409@kib.kiev.ua> <68a8ed6d-e302-799c-3d2c-1d85c48d07bf@citrin.ru> <20161001211025.GD38409@kib.kiev.ua> <999638f9-3fee-82e3-d67f-cffef53b74e8@citrin.ru>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, Oct 01, 2016 at 06:02:14PM -0400, Anton Yuzhaninov wrote:
> DDB backtrace for shell:
> https://imgur.com/a/JDLry

I see.  I was able to reproduce it with gnop -S 8k over swap-backed md.
The following patch worked for me.

diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
index 2af5383..c9cd4dc 100644
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -118,14 +118,14 @@ static vop_listextattr_t	ffs_listextattr;
 static vop_openextattr_t	ffs_openextattr;
 static vop_setextattr_t	ffs_setextattr;
 static vop_vptofh_t	ffs_vptofh;
-
+static vop_getpages_t	ffs_getpages;
 
 /* Global vfs data structures for ufs. */
 struct vop_vector ffs_vnodeops1 = {
 	.vop_default =		&ufs_vnodeops,
 	.vop_fsync =		ffs_fsync,
 	.vop_fdatasync =	ffs_fdatasync,
-	.vop_getpages =		vnode_pager_local_getpages,
+	.vop_getpages =		ffs_getpages,
 	.vop_getpages_async =	vnode_pager_local_getpages_async,
 	.vop_lock1 =		ffs_lock,
 	.vop_read =		ffs_read,
@@ -147,7 +147,7 @@ struct vop_vector ffs_vnodeops2 = {
 	.vop_default =		&ufs_vnodeops,
 	.vop_fsync =		ffs_fsync,
 	.vop_fdatasync =	ffs_fdatasync,
-	.vop_getpages =		vnode_pager_local_getpages,
+	.vop_getpages =		ffs_getpages,
 	.vop_getpages_async =	vnode_pager_local_getpages_async,
 	.vop_lock1 =		ffs_lock,
 	.vop_read =		ffs_read,
@@ -1784,3 +1787,95 @@ vop_vptofh {
 	ufhp->ufid_gen = ip->i_gen;
 	return (0);
 }
+
+static int
+ffs_getpages(struct vop_getpages_args *ap)
+{
+	struct vnode *vp;
+	vm_page_t *mm, m, m1;
+	vm_object_t object;
+	struct bufobj *bo;
+	struct buf *bp;
+	struct fs *fs;
+	vm_pindex_t pi;
+	ufs_lbn_t lbn, lbnp;
+	long bsize;
+	int count, error, i;
+	bool redo;
+
+	vp = ap->a_vp;
+	mm = ap->a_m;
+	count = ap->a_count;
+
+	bo = &VFSTOUFS(ap->a_vp->v_mount)->um_devvp->v_bufobj;
+	if (bo->bo_bsize <= PAGE_SIZE)
+		return (vnode_pager_generic_getpages(vp, mm, count,
+		    ap->a_rbehind, ap->a_rahead, NULL, NULL));
+
+	object = vp->v_object;
+	VM_OBJECT_WLOCK(object);
+	if (IDX_TO_OFF(mm[count - 1]->pindex) >= object->un_pager.vnp.vnp_size)
+		return (VM_PAGER_BAD);
+again:
+	for (i = 0; i < count; i++) {
+		vm_page_xunbusy(mm[i]);
+		vm_page_sbusy(mm[i]);
+	}
+	VM_OBJECT_WUNLOCK(object);
+
+	fs = VFSTOUFS(vp->v_mount)->um_fs;
+	lbnp = -1;
+	for (i = 0; i < count; i++) {
+		lbn = lblkno(fs, OFF_TO_IDX(mm[i]->pindex));
+		if (lbn != lbnp) {
+			bsize = blksize(fs, VTOI(vp), lbn);
+			error = bread_gb(vp, lbn, bsize, NOCRED, GB_UNMAPPED,
+			    &bp);
+			if (error == 0) {
+				if (LIST_EMPTY(&bp->b_dep)) {
+					bp->b_flags |= B_RELBUF;
+					brelse(bp);
+				} else {
+					/* XXX */
+					bqrelse(bp);
+				}
+				lbnp = lbn;
+			} else {
+				break;
+			}
+		}
+	}
+
+	VM_OBJECT_WLOCK(object);
+	if (error == 0)
+		vm_page_zero_invalid(mm[count - 1], TRUE);
+	redo = false;
+	for (i = 0; i < count; i++) {
+		KASSERT(mm[i]->valid == VM_PAGE_BITS_ALL,
+		    ("run %d %p invalid", i, mm[i]));
+		vm_page_sunbusy(mm[i]);
+wait:
+		while (vm_page_busied(mm[i])) {
+			pi = mm[i]->pindex;
+			vm_page_lock(mm[i]);
+			VM_OBJECT_WUNLOCK(object);
+			vm_page_busy_sleep(mm[i], "ffspgl");
+			VM_OBJECT_WLOCK(object);
+			m1 = vm_page_lookup(object, pi);
+			if (m1 != mm[i])
+				mm[i] = m1;
+			if (vm_page_busied(m1)) {
+				m = m1;
+				goto wait;
+			}
+			vm_page_xbusy(m1);
+			if (m1->valid != VM_PAGE_BITS_ALL)
+				redo = true;
+		}
+		vm_page_xbusy(mm[i]);
+	}
+	if (redo && error == 0)
+		goto again;
+	VM_OBJECT_WUNLOCK(object);
+	return (error != 0 ? VM_PAGER_ERROR : VM_PAGER_OK);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20161002191349.GH38409>