diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h index 342b95f138e6..250fc1f9890f 100644 --- a/sbin/fsck_ffs/fsck.h +++ b/sbin/fsck_ffs/fsck.h @@ -274,6 +274,7 @@ char yflag; /* assume a yes response */ int bkgrdflag; /* use a snapshot to run on an active system */ int bflag; /* location of alternate super block */ int debug; /* output debugging info */ +int Eflag; /* zero out empty data blocks */ int inoopt; /* trim out unused inodes */ char ckclean; /* only do work if not cleanly unmounted */ int cvtlevel; /* convert to newer file system format */ @@ -337,6 +338,7 @@ char *blockcheck(char *name); int blread(int fd, char *buf, ufs2_daddr_t blk, long size); void bufinit(void); void blwrite(int fd, char *buf, ufs2_daddr_t blk, long size); +void blerase(int fd, ufs2_daddr_t blk, long size); void cacheino(union dinode *dp, ino_t inumber); void catch(int); void catchquit(int); diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8 index 2834149f97c8..523cb6543ed8 100644 --- a/sbin/fsck_ffs/fsck_ffs.8 +++ b/sbin/fsck_ffs/fsck_ffs.8 @@ -29,7 +29,7 @@ .\" @(#)fsck.8 8.4 (Berkeley) 5/9/95 .\" $FreeBSD$ .\" -.Dd January 25, 2009 +.Dd April 27, 2011 .Dt FSCK_FFS 8 .Os .Sh NAME @@ -38,7 +38,7 @@ .Nd file system consistency check and interactive repair .Sh SYNOPSIS .Nm -.Op Fl BFfnpry +.Op Fl BEFfnpry .Op Fl b Ar block .Op Fl c Ar level .Op Fl m Ar mode @@ -149,6 +149,24 @@ If unexpected errors are found, the file system is marked as needing a foreground check and .Nm exits without attempting any further cleaning. +.It Fl E +Clear unallocated blocks, notifying the underlying device that they +are not used and that their contents may be discarded. +This is useful for filesystems which have been mounted on systems +without TRIM support, or with TRIM support disabled, as well as +filesystems which have been copied from one device to another. +.Pp +See the +.Fl E +and +.Fl t +flags of +.Xr newfs 8 , +and +the +.Fl t +flag of +.Xr tunefs 8 . .It Fl F Determine whether the file system needs to be cleaned immediately in foreground, or if its cleaning can be deferred to background. diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c index 68d113a3f618..85ea03352685 100644 --- a/sbin/fsck_ffs/fsutil.c +++ b/sbin/fsck_ffs/fsutil.c @@ -39,9 +39,10 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include #include -#include #include #include @@ -421,6 +422,20 @@ blwrite(int fd, char *buf, ufs2_daddr_t blk, long size) return; } +void +blerase(int fd, ufs2_daddr_t blk, long size) +{ + off_t ioarg[2]; + + if (fd < 0) + return; + ioarg[0] = blk * dev_bsize; + ioarg[1] = size; + ioctl(fd, DIOCGDELETE, ioarg); + /* we don't really care if we succeed or not */ + return; +} + /* * Verify cylinder group's magic number and other parameters. If the * test fails, offer an option to rebuild the whole cylinder group. diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c index 127a612cae91..e26494d50574 100644 --- a/sbin/fsck_ffs/main.c +++ b/sbin/fsck_ffs/main.c @@ -82,7 +82,7 @@ main(int argc, char *argv[]) sync(); skipclean = 1; inoopt = 0; - while ((ch = getopt(argc, argv, "b:Bc:CdfFm:npry")) != -1) { + while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npry")) != -1) { switch (ch) { case 'b': skipclean = 0; @@ -106,6 +106,10 @@ main(int argc, char *argv[]) debug++; break; + case 'E': + Eflag++; + break; + case 'f': skipclean = 0; break; @@ -632,7 +636,7 @@ static void usage(void) { (void) fprintf(stderr, - "usage: %s [-BFprfny] [-b block] [-c level] [-m mode] " + "usage: %s [-BEFprfny] [-b block] [-c level] [-m mode] " "filesystem ...\n", getprogname()); exit(1); diff --git a/sbin/fsck_ffs/pass5.c b/sbin/fsck_ffs/pass5.c index 639ce0f8abdc..01ed8a54052d 100644 --- a/sbin/fsck_ffs/pass5.c +++ b/sbin/fsck_ffs/pass5.c @@ -51,6 +51,8 @@ __FBSDID("$FreeBSD$"); static void check_maps(u_char *, u_char *, int, ufs2_daddr_t, const char *, int *, int, int); +static void clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end); + void pass5(void) { @@ -58,7 +60,7 @@ pass5(void) int inomapsize, blkmapsize; struct fs *fs = &sblock; struct cg *cg = &cgrp; - ufs2_daddr_t d, dbase, dmax; + ufs2_daddr_t d, dbase, dmax, start; int excessdirs, rewritecg = 0; struct csum *cs; struct csum_total cstotal; @@ -242,13 +244,21 @@ pass5(void) setbit(cg_inosused(newcg), i); newcg->cg_cs.cs_nifree--; } + start = -1; for (i = 0, d = dbase; d < dmax; d += fs->fs_frag, i += fs->fs_frag) { frags = 0; for (j = 0; j < fs->fs_frag; j++) { - if (testbmap(d + j)) + if (testbmap(d + j)) { + if (Eflag && start != -1) { + clear_blocks(start, d + j - 1); + start = -1; + } continue; + } + if (start == -1) + start = d + j; setbit(cg_blksfree(newcg), i + j); frags++; } @@ -263,6 +273,8 @@ pass5(void) ffs_fragacct(fs, blk, newcg->cg_frsum, 1); } } + if (Eflag && start != -1) + clear_blocks(start, d - 1); if (fs->fs_contigsumsize > 0) { int32_t *sump = cg_clustersum(newcg); u_char *mapp = cg_clustersfree(newcg); @@ -551,3 +563,12 @@ check_maps( } } } + +static void clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end) +{ + + if (debug) + printf("Zero frags %jd to %jd\n", start, end); + blerase(fswritefd, fsbtodb(&sblock, start), + lfragtosize(&sblock, end - start + 1)); +}