From nobody Mon Aug 7 23:28:39 2023 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4RKXZH3CJlz4mWmV; Mon, 7 Aug 2023 23:28:39 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4RKXZH2mXKz4V2S; Mon, 7 Aug 2023 23:28:39 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1691450919; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=JO24kFJa/Pksdu+S9FbIZJPh7g8YkO1i3NoDaWnccOQ=; b=XBQWuGgQlHN6Ckh1DLbvfAwAruqgpDgthc+JZKBwpnPKQLcLlzrO2f1abGGE83z2B0Q18l YV9FcdFaK6X4IgsJH3AQCLe4QImeBY5zyMkefRzYEqs/iIRDIK7ijZQMFdzsWTU3R4zoLJ e+tr4YasZolYv2sLe1VGG1bLn0/Kv92o7ixzBX1UFk6CDUeOZqLZHjhNjW/blBDU7B7OgP adivuJNMqi/bxzZJShfynJUHMoW6X4/nQ3X4U29NEf+SML8TOpi/4gzYHSHhLMr9eelR9p f7U960e5DMd3rDsLTFsDRagkN57VhDMKkyTzegXhaHM9TUJh4wR0EkzhpofNng== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1691450919; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=JO24kFJa/Pksdu+S9FbIZJPh7g8YkO1i3NoDaWnccOQ=; b=BB+q3kzto95X77sSgRljZir5YHssAzfm86yt2JVYpnLaXfm0uX080BNH0/ivHw8oK0vQX+ 7lQ91nXCT3FGtBhphc9TNHlXIUWxnLyWiEgi6mVNc+tugWvKt1jLQkVG8Or+VSf5m1w0jx vAbgXsRn/nY5eNHdyWLwtz6KvEbXL0vl5zfB4/E/xnSOULvQl4UyCeWfMcdKgPcYU605S+ nGr+y27lpdNWpfjdfdZCEJCAC+hSy78E35LsOXNuPc+qtrWoKVuebbx/az9JlQgXA3hoPr nTbRMCnRaKBbsv3ZQsIpI6MwydMgD8XyKavP4iQAXbZBVhR1kBfUBuNLv/xhVg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1691450919; a=rsa-sha256; cv=none; b=wcxb3FCfBUj3+2D3rMuQNm/dWD+8Klbsq6jTx+jfwxTyZ/26W3gf5S2M7W/jIkm/omq3Q5 3j3cBJ5T+BrIKM7m5AAK2mQSIlPkYyD7rOmRKvY3UqWfQQzdBDaXWhBa8OEKvf1jOZPA+/ 0srO5tpk/aPRcMuQi7OqIappWrC5K2ah8sVpFgwgpYhhA1JR55wd1uJjuEiwaASG4V5tBs Pj/QDsYxoK7/AgR1XZUZYIuZ8SSeV36FcrdxpI+HB5L1fI9zYroZePsLJbpjmVfyeDYrMv i46AdEwE/w9MwjIeekP0PhXEUUVz7IEPIArBKFuVDMsQhrkbIWRmDQQhaHpeTQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4RKXZH1qGpz1B9N; Mon, 7 Aug 2023 23:28:39 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 377NSdsq026542; Mon, 7 Aug 2023 23:28:39 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 377NSdc6026541; Mon, 7 Aug 2023 23:28:39 GMT (envelope-from git) Date: Mon, 7 Aug 2023 23:28:39 GMT Message-Id: <202308072328.377NSdc6026541@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kirk McKusick Subject: git: d4a8f5bf1339 - main - Handle UFS/FFS file deletion from cylinder groups with check-hash failure. List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mckusick X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: d4a8f5bf133956e71c05edff6fa20b156e5f1bbf Auto-Submitted: auto-generated The branch main has been updated by mckusick: URL: https://cgit.FreeBSD.org/src/commit/?id=d4a8f5bf133956e71c05edff6fa20b156e5f1bbf commit d4a8f5bf133956e71c05edff6fa20b156e5f1bbf Author: Kirk McKusick AuthorDate: 2023-08-07 23:27:39 +0000 Commit: Kirk McKusick CommitDate: 2023-08-07 23:28:11 +0000 Handle UFS/FFS file deletion from cylinder groups with check-hash failure. When a file is deleted, its blocks need to be put back in the free block list and its inode needs to be put back in the inode free list. These lists reside in cylinder-group maps. If either some of its blocks or its inode reside in a cylinder-group map with a bad check hash it is not possible to free the associated resource. Since the cylinder group cannot be repaired until the filesystem is unmounted these resources cannot be freed. They simply accumulate in memory. And any attempt to unmount the filesystem loops forever trying to flush them. With this change, the resource update claims to succeed so that the file deletion can successfully complete. The filesystem is marked as requiring an fsck so that before the next time that the filesystem is mounted, the offending cylinder groups are reconstructed causing the lost resources to be reclaimed. A better solution would be to downgrade the filesystem to read-only, but that capability is not currently implemented. Reported-by: Peter Holm Tested-by: Peter Holm MFC-after: 1 week Sponsored-by: The FreeBSD Foundation --- sys/ufs/ffs/ffs_alloc.c | 27 ++++++++++++++------ sys/ufs/ffs/ffs_extern.h | 4 +-- sys/ufs/ffs/ffs_softdep.c | 65 +++++++++++++++++++++++++---------------------- 3 files changed, 55 insertions(+), 41 deletions(-) diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index c5e2a706a128..e173253720c6 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -2295,9 +2295,14 @@ ffs_blkfree_cg(struct ufsmount *ump, return; } if ((error = ffs_getcg(fs, devvp, cg, GB_CVTENXIO, &bp, &cgp)) != 0) { - if (!ffs_fsfail_cleanup(ump, error) || - !MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR) + if (!MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR) return; + /* + * Would like to just downgrade to read-only. Until that + * capability is available, just toss the cylinder group + * update and mark the filesystem as needing to run fsck. + */ + fs->fs_flags |= FS_NEEDSFSCK; if (devvp->v_type == VREG) dbn = fragstoblks(fs, cgtod(fs, cg)); else @@ -2305,7 +2310,7 @@ ffs_blkfree_cg(struct ufsmount *ump, error = getblkx(devvp, dbn, dbn, fs->fs_cgsize, 0, 0, 0, &bp); KASSERT(error == 0, ("getblkx failed")); softdep_setup_blkfree(UFSTOVFS(ump), bp, bno, - numfrags(fs, size), dephd); + numfrags(fs, size), dephd, true); bp->b_flags |= B_RELBUF | B_NOCACHE; bp->b_flags &= ~B_CACHE; bawrite(bp); @@ -2380,7 +2385,7 @@ ffs_blkfree_cg(struct ufsmount *ump, mp = UFSTOVFS(ump); if (MOUNTEDSOFTDEP(mp) && devvp->v_type == VCHR) softdep_setup_blkfree(UFSTOVFS(ump), bp, bno, - numfrags(fs, size), dephd); + numfrags(fs, size), dephd, false); bdwrite(bp); } @@ -2841,16 +2846,21 @@ ffs_freefile(struct ufsmount *ump, panic("ffs_freefile: range: dev = %s, ino = %ju, fs = %s", devtoname(dev), (uintmax_t)ino, fs->fs_fsmnt); if ((error = ffs_getcg(fs, devvp, cg, GB_CVTENXIO, &bp, &cgp)) != 0) { - if (!ffs_fsfail_cleanup(ump, error) || - !MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR) + if (!MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR) return (error); + /* + * Would like to just downgrade to read-only. Until that + * capability is available, just toss the cylinder group + * update and mark the filesystem as needing to run fsck. + */ + fs->fs_flags |= FS_NEEDSFSCK; if (devvp->v_type == VREG) dbn = fragstoblks(fs, cgtod(fs, cg)); else dbn = fsbtodb(fs, cgtod(fs, cg)); error = getblkx(devvp, dbn, dbn, fs->fs_cgsize, 0, 0, 0, &bp); KASSERT(error == 0, ("getblkx failed")); - softdep_setup_inofree(UFSTOVFS(ump), bp, ino, wkhd); + softdep_setup_inofree(UFSTOVFS(ump), bp, ino, wkhd, true); bp->b_flags |= B_RELBUF | B_NOCACHE; bp->b_flags &= ~B_CACHE; bawrite(bp); @@ -2880,7 +2890,7 @@ ffs_freefile(struct ufsmount *ump, ACTIVECLEAR(fs, cg); UFS_UNLOCK(ump); if (MOUNTEDSOFTDEP(UFSTOVFS(ump)) && devvp->v_type == VCHR) - softdep_setup_inofree(UFSTOVFS(ump), bp, ino, wkhd); + softdep_setup_inofree(UFSTOVFS(ump), bp, ino, wkhd, false); bdwrite(bp); return (0); } @@ -2888,6 +2898,7 @@ ffs_freefile(struct ufsmount *ump, /* * Check to see if a file is free. * Used to check for allocated files in snapshots. + * Return 1 if file is free. */ int ffs_checkfreefile(struct fs *fs, diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index 46f1a71ed585..97213bc20d7c 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -194,9 +194,9 @@ void softdep_setup_allocindir_meta(struct buf *, struct inode *, void softdep_setup_allocindir_page(struct inode *, ufs_lbn_t, struct buf *, int, ufs2_daddr_t, ufs2_daddr_t, struct buf *); void softdep_setup_blkfree(struct mount *, struct buf *, ufs2_daddr_t, int, - struct workhead *); + struct workhead *, bool); void softdep_setup_inofree(struct mount *, struct buf *, ino_t, - struct workhead *); + struct workhead *, bool); void softdep_setup_sbupdate(struct ufsmount *, struct fs *, struct buf *); void softdep_fsync_mountdev(struct vnode *); int softdep_sync_metadata(struct vnode *); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 2606c17f7295..f671f529a04b 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -300,7 +300,8 @@ softdep_setup_blkfree(struct mount *mp, struct buf *bp, ufs2_daddr_t blkno, int frags, - struct workhead *wkhd) + struct workhead *wkhd, + bool doingrecovery) { panic("%s called", __FUNCTION__); @@ -310,7 +311,8 @@ void softdep_setup_inofree(struct mount *mp, struct buf *bp, ino_t ino, - struct workhead *wkhd) + struct workhead *wkhd, + bool doingrecovery) { panic("%s called", __FUNCTION__); @@ -10926,30 +10928,26 @@ void softdep_setup_inofree(struct mount *mp, struct buf *bp, ino_t ino, - struct workhead *wkhd) + struct workhead *wkhd, + bool doingrecovery) { struct worklist *wk, *wkn; - struct inodedep *inodedep; struct ufsmount *ump; - uint8_t *inosused; - struct cg *cgp; - struct fs *fs; +#ifdef INVARIANTS + struct inodedep *inodedep; +#endif KASSERT(MOUNTEDSOFTDEP(mp) != 0, ("softdep_setup_inofree called on non-softdep filesystem")); ump = VFSTOUFS(mp); ACQUIRE_LOCK(ump); - if (!ffs_fsfail_cleanup(ump, 0)) { - fs = ump->um_fs; - cgp = (struct cg *)bp->b_data; - inosused = cg_inosused(cgp); - if (isset(inosused, ino % fs->fs_ipg)) - panic("softdep_setup_inofree: inode %ju not freed.", - (uintmax_t)ino); - } - if (inodedep_lookup(mp, ino, 0, &inodedep)) - panic("softdep_setup_inofree: ino %ju has existing inodedep %p", - (uintmax_t)ino, inodedep); + KASSERT(doingrecovery || ffs_fsfail_cleanup(ump, 0) || + isclr(cg_inosused((struct cg *)bp->b_data), + ino % ump->um_fs->fs_ipg), + ("softdep_setup_inofree: inode %ju not freed.", (uintmax_t)ino)); + KASSERT(inodedep_lookup(mp, ino, 0, &inodedep) == 0, + ("softdep_setup_inofree: ino %ju has existing inodedep %p", + (uintmax_t)ino, inodedep)); if (wkhd) { LIST_FOREACH_SAFE(wk, wkhd, wk_list, wkn) { if (wk->wk_type != D_JADDREF) @@ -10980,7 +10978,8 @@ softdep_setup_blkfree( struct buf *bp, ufs2_daddr_t blkno, int frags, - struct workhead *wkhd) + struct workhead *wkhd, + bool doingrecovery) { struct bmsafemap *bmsafemap; struct jnewblk *jnewblk; @@ -11027,18 +11026,22 @@ softdep_setup_blkfree( KASSERT(jnewblk->jn_state & GOINGAWAY, ("softdep_setup_blkfree: jnewblk not canceled.")); #ifdef INVARIANTS - /* - * Assert that this block is free in the bitmap - * before we discard the jnewblk. - */ - cgp = (struct cg *)bp->b_data; - blksfree = cg_blksfree(cgp); - bno = dtogd(fs, jnewblk->jn_blkno); - for (i = jnewblk->jn_oldfrags; - i < jnewblk->jn_frags; i++) { - if (isset(blksfree, bno + i)) - continue; - panic("softdep_setup_blkfree: not free"); + if (!doingrecovery && !ffs_fsfail_cleanup(ump, 0)) { + /* + * Assert that this block is free in the + * bitmap before we discard the jnewblk. + */ + cgp = (struct cg *)bp->b_data; + blksfree = cg_blksfree(cgp); + bno = dtogd(fs, jnewblk->jn_blkno); + for (i = jnewblk->jn_oldfrags; + i < jnewblk->jn_frags; i++) { + if (isset(blksfree, bno + i)) + continue; + panic("softdep_setup_blkfree: block " + "%ju not freed.", + (uintmax_t)jnewblk->jn_blkno); + } } #endif /*