Delete snapshot after opening it when running fsck_ffs(9) in background.

When fsck_ffs(8) runs in background, it creates a snapshot named
fsck_snapshot in the filesystem's .snap directory. The fsck_snapshot
file was removed when the background fsck finished. If the system
crashed or the fsck exited unexpectedly, the fsck_snapshot file
would remain. The snapshot would consume ever more space as the
filesystem changed over time until it was removed by a system
administrator or a future run of background fsck removed it to
create a new snapshot file.

This commit unlinks the .snap/fsck_snapshot file immediately after
opening it so that it will be reclaimed when fsck closes it at the
conclusion of its run. After a system crash, it will be removed as
part of the filesystem cleanup because of its zero reference count.
As only a few milliseconds pass between its creation and unlinking,
there is far less opportunity for it to be accidentally left behind.

PR:           106107
MFC-after:    1 week
This commit is contained in:
Kirk McKusick 2023-10-25 15:36:45 -07:00
parent 575878a533
commit d3a36e4b74
5 changed files with 9 additions and 11 deletions

View file

@ -376,7 +376,6 @@ extern long secsize; /* actual disk sector size */
extern char skipclean; /* skip clean file systems if preening */
extern int snapcnt; /* number of active snapshots */
extern struct inode snaplist[FSMAXSNAP + 1]; /* list of active snapshots */
extern char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
extern int sujrecovery; /* 1 => doing check using the journal */
extern int surrender; /* Give up if reads fail */
extern char usedsoftdep; /* just fix soft dependency inconsistencies */

View file

@ -616,7 +616,6 @@ ckfini(int markclean)
int ofsmodified, cnt, cg;
if (bkgrdflag) {
unlink(snapname);
if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) {
cmd.value = FS_UNCLEAN;
cmd.size = markclean ? -1 : 1;

View file

@ -71,7 +71,6 @@ int freefiles[MIBSIZE]; /* MIB cmd to free a set of files */
int freedirs[MIBSIZE]; /* MIB cmd to free a set of directories */
int freeblks[MIBSIZE]; /* MIB cmd to free a set of data blocks */
struct fsck_cmd cmd; /* sysctl file system update commands */
char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
char *cdevname; /* name of device being checked */
long dev_bsize; /* computed value of DEV_BSIZE */
long secsize; /* actual disk sector size */
@ -144,7 +143,6 @@ fsckinit(void)
bzero(freedirs, sizeof(int) * MIBSIZE);
bzero(freeblks, sizeof(int) * MIBSIZE);
bzero(&cmd, sizeof(struct fsck_cmd));
bzero(snapname, sizeof(char) * BUFSIZ);
cdevname = NULL;
dev_bsize = 0;
secsize = 0;

View file

@ -68,7 +68,8 @@ static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/14/95";
#include "fsck.h"
static int restarts;
static int restarts;
static char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
static void usage(void) __dead2;
static intmax_t argtoimax(int flag, const char *req, const char *str, int base);
@ -664,8 +665,7 @@ setup_bkgrdchk(struct statfs *mntp, int sbreadfailed, char **filesys)
"SUPPORT\n");
}
/* Find or create the snapshot directory */
snprintf(snapname, sizeof snapname, "%s/.snap",
mntp->f_mntonname);
snprintf(snapname, sizeof snapname, "%s/.snap", mntp->f_mntonname);
if (stat(snapname, &snapdir) < 0) {
if (errno != ENOENT) {
pwarn("CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT "
@ -713,6 +713,8 @@ setup_bkgrdchk(struct statfs *mntp, int sbreadfailed, char **filesys)
"BACKGROUND\n", snapname, strerror(errno));
return (0);
}
/* Immediately unlink snapshot so that it will be deleted when closed */
unlink(snapname);
free(sblock.fs_csp);
free(sblock.fs_si);
if (readsb() == 0) {

View file

@ -380,14 +380,14 @@ openfilesys(char *dev)
if ((statb.st_mode & S_IFMT) != S_IFCHR &&
(statb.st_mode & S_IFMT) != S_IFBLK) {
if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) {
pfatal("BACKGROUND FSCK LACKS A SNAPSHOT\n");
exit(EEXIT);
pwarn("BACKGROUND FSCK LACKS A SNAPSHOT\n");
return (0);
}
if (bkgrdflag != 0) {
cursnapshot = statb.st_ino;
} else {
pfatal("%s IS NOT A DISK DEVICE\n", dev);
if (reply("CONTINUE") == 0)
pwarn("%s IS NOT A DISK DEVICE\n", dev);
if (preen || reply("CONTINUE") == 0)
return (0);
}
}