From nobody Wed Aug 17 21:21:44 2022 X-Original-To: dev-commits-src-all@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 4M7LYh28Nkz4ZJTb; Wed, 17 Aug 2022 21:21:44 +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 4M7LYh1f3Lz3M2K; Wed, 17 Aug 2022 21:21:44 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1660771304; 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=UCpaBqSIwsf0vgCr7en6HkxnUrENchbXvf+Drlibnes=; b=fbMzbzon4gYdojRt4TNxyr9LNFulk4RZMNgUPd65Noy0D6mNCIXxeO4JJc6ktE2kZOVwQv Bp41IOwWhAnNgEj8sjwXLy42GG6HCJNd3XTPKkI7af+jk2+HkMbamMcKWu5naEGirBb54N uIQl65Ml4rWUp0379N2Nvvfj7hL+Sic2AGYzf9rXu5DufDnFzIAAJoXW6IjNNZZB+0vcQD uA0DABGYHMkF3LP7vLB22YxIg5UqFenq+pwWIzUPgv1H2RsgeJcm1w/+sMmwtPLgRrbxqc Qr6MeuhI+3Vu2PYD1XqSm9gcBbTpzv60XAcI/LCnDg8T+az4zrNdef5cnrMzgA== 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 4M7LYh0m11z14T5; Wed, 17 Aug 2022 21:21:44 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 27HLLiE2024154; Wed, 17 Aug 2022 21:21:44 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 27HLLiP7024153; Wed, 17 Aug 2022 21:21:44 GMT (envelope-from git) Date: Wed, 17 Aug 2022 21:21:44 GMT Message-Id: <202208172121.27HLLiP7024153@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: 6bae6625e0e0 - main - Improve handling of missing '.' and '..' in UFS directories. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@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: 6bae6625e0e06816c80ac4971dfccf0643abe3f0 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1660771304; 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=UCpaBqSIwsf0vgCr7en6HkxnUrENchbXvf+Drlibnes=; b=SvVv3ZfF6YNO3iM4Xoybt8icXH1yfTxJgNlO5eCupehJ3ceS1fNHGAWx29PrzCnxgfVMx2 qwp2fsD/xt9CvysFQqgVX7OijttL/IOWzF0XgZdm8Yoz4dIq4UPyGUY7x0IjuHszVRWbDI FN0yfYC7gUPbxnmotdltWKN4B9cW17WSXyxczuNydrBiSDF48y7OlXTDmgYpQGmgvAbmYY Ip50SiEUB8F/0IVGnySWo1/dj1aILBA7oXER2ChUg1UKOsxOhklp0neIA/W7OcZ0kNDLGl p3udlcxP2UJCHE4Appw4TQB7P5sjjkKvK1nXOdfOklKt4FL3ijmfJ7WOodpn3Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1660771304; a=rsa-sha256; cv=none; b=ViOwu3MyWzhYXszpabVVg1x8k7PpewCVlZMQdI8Vdlu4wrjocrexlOSX19PyM5EXTBIq1v tGyMpXTlvajW8FbfHJDHnCniKscwUNfzYnyF2vwyTd2NL2TluyVroC9rDUpT/b9e/SGEk1 G8pfsm1cCY4EI5wxVL3SMdO67DmwZw8GUsPARBzaLPfYM42Ffk6tomzGAZ2KCuXvlJAYei 2Xt3jU+yMDJsU1tNZCHx9KBxkLyQbCtyZrwT2eZVRnybc7SWoG8l2k9LhUoQLEJ4h7OjBv 0DxElVPRfy3MyszIXhpEhX1RaBuuO9c3FLR1hIX4GTOrdmRgu2uKURYLPglg+A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by mckusick: URL: https://cgit.FreeBSD.org/src/commit/?id=6bae6625e0e06816c80ac4971dfccf0643abe3f0 commit 6bae6625e0e06816c80ac4971dfccf0643abe3f0 Author: Kirk McKusick AuthorDate: 2022-08-17 21:19:59 +0000 Commit: Kirk McKusick CommitDate: 2022-08-17 21:19:59 +0000 Improve handling of missing '.' and '..' in UFS directories. The UFS filesystem expects to find '.' and '..' as the first two entries in a directory. The kernel's UFS name cache can become quite confused when these two entries are not present as the first two entries. Prior to this change, when the fsck_ffs(8) utility detected that '.' and/or '..' were missing, it would report them, but only offered to replace them if the space at the beginning of the directory was available. Otherwise it was left to the system administrator to move the offending file(s) out of the way and then rerun fsck_ffs(8) to create the '.' and '..' entries. With this change, fsck_ffs(8) will always be able to create the '.' and/or '..' entries. It moves any files in the way elsewhere in the directory block. If there is no room in the directory block to which to move them, they are placed in the lost+found directory. Reported by: Peter Holm Sponsored by: The FreeBSD Foundation --- sbin/fsck_ffs/pass2.c | 127 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/sbin/fsck_ffs/pass2.c b/sbin/fsck_ffs/pass2.c index 8632cf4878b1..78815493fba8 100644 --- a/sbin/fsck_ffs/pass2.c +++ b/sbin/fsck_ffs/pass2.c @@ -217,9 +217,9 @@ pass2(void) continue; if (inp->i_dotdot == 0) { inp->i_dotdot = inp->i_parent; - fileerror(inp->i_parent, inp->i_number, "MISSING '..'"); - if (reply("FIX") == 0) - continue; + if (debug) + fileerror(inp->i_parent, inp->i_number, + "DEFERRED MISSING '..' FIX"); (void)makeentry(inp->i_number, inp->i_parent, ".."); inoinfo(inp->i_parent)->ino_linkcnt--; continue; @@ -289,7 +289,7 @@ pass2check(struct inodesc *idesc) struct inode ip; union dinode *dp; const char *errmsg; - struct direct proto; + struct direct proto, *newdirp; /* * check for "." @@ -301,45 +301,52 @@ pass2check(struct inodesc *idesc) if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { if (dirp->d_ino != idesc->id_number) { direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'"); - dirp->d_ino = idesc->id_number; - if (reply("FIX") == 1) + if (reply("FIX") == 1) { + dirp->d_ino = idesc->id_number; ret |= ALTERED; + } } if (dirp->d_type != DT_DIR) { direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'"); - dirp->d_type = DT_DIR; - if (reply("FIX") == 1) + if (reply("FIX") == 1) { + dirp->d_type = DT_DIR; ret |= ALTERED; + } } goto chk1; } - direrror(idesc->id_number, "MISSING '.'"); proto.d_ino = idesc->id_number; proto.d_type = DT_DIR; proto.d_namlen = 1; (void)strcpy(proto.d_name, "."); entrysize = DIRSIZ(0, &proto); - if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { - pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", - dirp->d_name); - } else if (dirp->d_reclen < entrysize) { - pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); - } else if (dirp->d_reclen < 2 * entrysize) { + direrror(idesc->id_number, "MISSING '.'"); + errmsg = "ADD '.' ENTRY"; + if (dirp->d_reclen < entrysize + DIRSIZ(0, dirp)) { + /* Not enough space to add '.', replace first entry with '.' */ + if (dirp->d_ino != 0) { + pwarn("\nFIRST ENTRY IN DIRECTORY CONTAINS %s\n", + dirp->d_name); + errmsg = "REPLACE WITH '.'"; + } + if (reply(errmsg) == 0) + goto chk1; proto.d_reclen = dirp->d_reclen; memmove(dirp, &proto, (size_t)entrysize); - if (reply("FIX") == 1) - ret |= ALTERED; + ret |= ALTERED; } else { - n = dirp->d_reclen - entrysize; + /* Move over first entry and add '.' entry */ + if (reply(errmsg) == 0) + goto chk1; + newdirp = (struct direct *)((char *)(dirp) + entrysize); + dirp->d_reclen -= entrysize; + memmove(newdirp, dirp, dirp->d_reclen); proto.d_reclen = entrysize; memmove(dirp, &proto, (size_t)entrysize); idesc->id_entryno++; - inoinfo(dirp->d_ino)->ino_linkcnt--; - dirp = (struct direct *)((char *)(dirp) + entrysize); - memset(dirp, 0, (size_t)n); - dirp->d_reclen = n; - if (reply("FIX") == 1) - ret |= ALTERED; + inoinfo(idesc->id_number)->ino_linkcnt--; + dirp = newdirp; + ret |= ALTERED; } chk1: if (idesc->id_entryno > 1) @@ -372,30 +379,60 @@ chk1: } goto chk2; } - if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { - fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); - pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", - dirp->d_name); - inp->i_dotdot = (ino_t)-1; - } else if (dirp->d_reclen < entrysize) { - fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); - pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); - inp->i_dotdot = (ino_t)-1; - } else if (inp->i_parent != 0) { - /* - * We know the parent, so fix now. - */ - inp->i_dotdot = inp->i_parent; - fileerror(inp->i_parent, idesc->id_number, "MISSING '..'"); + fileerror(inp->i_parent != 0 ? inp->i_parent : idesc->id_number, + idesc->id_number, "MISSING '..'"); + errmsg = "ADD '..' ENTRY"; + if (dirp->d_reclen < entrysize + DIRSIZ(0, dirp)) { + /* No space to add '..', replace second entry with '..' */ + if (dirp->d_ino != 0) { + pfatal("SECOND ENTRY IN DIRECTORY CONTAINS %s\n", + dirp->d_name); + errmsg = "REPLACE WITH '..'"; + } + if (reply(errmsg) == 0) { + inp->i_dotdot = (ino_t)-1; + goto chk2; + } + if (proto.d_ino == 0) { + /* Defer processing until parent known */ + idesc->id_entryno++; + if (debug) + printf("(FIX DEFERRED)\n"); + } + inp->i_dotdot = proto.d_ino; proto.d_reclen = dirp->d_reclen; memmove(dirp, &proto, (size_t)entrysize); - if (reply("FIX") == 1) - ret |= ALTERED; + ret |= ALTERED; + } else { + /* Move over second entry and add '..' entry */ + if (reply(errmsg) == 0) { + inp->i_dotdot = (ino_t)-1; + goto chk2; + } + if (proto.d_ino == 0) { + /* Defer processing until parent known */ + idesc->id_entryno++; + if (debug) + printf("(FIX DEFERRED)\n"); + } + inp->i_dotdot = proto.d_ino; + if (dirp->d_ino == 0) { + proto.d_reclen = dirp->d_reclen; + memmove(dirp, &proto, (size_t)entrysize); + } else { + newdirp = (struct direct *)((char *)(dirp) + entrysize); + dirp->d_reclen -= entrysize; + memmove(newdirp, dirp, dirp->d_reclen); + proto.d_reclen = entrysize; + memmove(dirp, &proto, (size_t)entrysize); + if (dirp->d_ino != 0) { + idesc->id_entryno++; + inoinfo(dirp->d_ino)->ino_linkcnt--; + } + dirp = newdirp; + } + ret |= ALTERED; } - idesc->id_entryno++; - if (dirp->d_ino != 0) - inoinfo(dirp->d_ino)->ino_linkcnt--; - return (ret|KEEPON); chk2: if (dirp->d_ino == 0) return (ret|KEEPON);