DF-2635 / fix.diff
--- a/sys/vfs/hammer2/hammer2_inode.c +++ b/sys/vfs/hammer2/hammer2_inode.c @@ -621,13 +621,32 @@ KKASSERT(hammer2_mtx_refs(&ip->lock) == 0); if (ip->flags & HAMMER2_INODE_ONHASH) { xipp = &hash->base; - while (*xipp != ip) + /* + * DF-2635: meta.inum can be + * overwritten from media after the + * inode was hashed (iroot in + * hammer2_pfsalloc/hammer2_vfs_root). + * Never walk off the end of the + * (possibly wrong) bucket. + */ + while (*xipp && *xipp != ip) xipp = &(*xipp)->next; - *xipp = ip->next; - ip->next = NULL; - atomic_add_long(&pmp->inum_count, -1); - atomic_clear_int(&ip->flags, + if (*xipp == ip) { + *xipp = ip->next; + ip->next = NULL; + atomic_add_long( + &pmp->inum_count, -1); + atomic_clear_int(&ip->flags, HAMMER2_INODE_ONHASH); + } else { + kprintf("hammer2: inode %p " + "inum %ld not on " + "inum hash\n", + ip, + (long)ip->meta.inum); + atomic_clear_int(&ip->flags, + HAMMER2_INODE_ONHASH); + } } hammer2_spin_unex(&hash->spin); --- a/sys/vfs/hammer2/hammer2_vfsops.c +++ b/sys/vfs/hammer2/hammer2_vfsops.c @@ -452,8 +452,11 @@ */ if ((iroot = pmp->iroot) == NULL) { iroot = hammer2_inode_get(pmp, NULL, 1, -1); - if (ripdata) + if (ripdata) { iroot->meta = ripdata->meta; + /* DF-2635: iroot is hashed under inum 1; keep it */ + iroot->meta.inum = 1; + } pmp->iroot = iroot; hammer2_inode_ref(iroot); hammer2_inode_unlock(iroot); @@ -1974,6 +1977,8 @@ if (error == 0) { meta = &hammer2_xop_gdata(&xop->head)->ipdata.meta; pmp->iroot->meta = *meta; + /* DF-2635: iroot is hashed under inum 1; keep it */ + pmp->iroot->meta.inum = 1; pmp->inode_tid = meta->pfs_inum + 1; hammer2_xop_pdata(&xop->head); /* meta invalid */ |