UFS: unaligned read from GELI with 8k sectorsize
Konstantin Belousov
kostikbel at gmail.com
Sun Oct 2 19:14:03 UTC 2016
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);
+}
More information about the freebsd-fs
mailing list