git: 5ee2c35751ef - main - truncate(1): Add hole-punching support

Ka Ho Ng khng at FreeBSD.org
Thu Aug 19 10:31:45 UTC 2021


The branch main has been updated by khng:

URL: https://cgit.FreeBSD.org/src/commit/?id=5ee2c35751ef5d131222423bf3e25073f997c337

commit 5ee2c35751ef5d131222423bf3e25073f997c337
Author:     Ka Ho Ng <khng at FreeBSD.org>
AuthorDate: 2021-08-19 10:30:41 +0000
Commit:     Ka Ho Ng <khng at FreeBSD.org>
CommitDate: 2021-08-19 10:30:41 +0000

    truncate(1): Add hole-punching support
    
    This commit adds hole-punching support to the truncate(1) utility. If
    the option -d is specified, truncate(1) performs zeroing, and if
    possible hole-punching in case the operation is supported by the
    underlying file system of the specified files.
    
    Sponsored by:   The FreeBSD Foundation
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D31556
---
 usr.bin/truncate/truncate.1 | 63 +++++++++++++++++++++++++++++++-----
 usr.bin/truncate/truncate.c | 79 ++++++++++++++++++++++++++++++++++-----------
 2 files changed, 115 insertions(+), 27 deletions(-)

diff --git a/usr.bin/truncate/truncate.1 b/usr.bin/truncate/truncate.1
index 2058530162c5..54780ccbca83 100644
--- a/usr.bin/truncate/truncate.1
+++ b/usr.bin/truncate/truncate.1
@@ -1,6 +1,10 @@
 .\"
 .\" Copyright (c) 2000 Sheldon Hearn <sheldonh at FreeBSD.org>.
 .\" All rights reserved.
+.\" Copyright (c) 2021 The FreeBSD Foundation
+.\"
+.\" Portions of this manual page were written by Ka Ho Ng <khng at FreeBSD.org>
+.\" under sponsorship from the FreeBSD Foundation.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
 .\" modification, are permitted provided that the following conditions
@@ -25,12 +29,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 27, 2020
+.Dd August 18, 2021
 .Dt TRUNCATE 1
 .Os
 .Sh NAME
 .Nm truncate
-.Nd truncate or extend the length of files
+.Nd truncate, extend the length of files, or perform space management in files
 .Sh SYNOPSIS
 .Nm
 .Op Fl c
@@ -39,7 +43,7 @@
 .Sm off
 .Op Cm + | - | % | /
 .Ar size
-.Op Cm K | k | M | m | G | g | T | t
+.Op Cm SUFFIX
 .Sm on
 .Xc
 .Ek
@@ -50,10 +54,32 @@
 .Fl r Ar rfile
 .Ek
 .Ar
+.Nm
+.Op Fl c
+.Bk -words
+.Fl d
+.Oo
+.Fl o Xo
+.Sm off
+.Ar offset
+.Op Cm SUFFIX
+.Sm on
+.Xc
+.Oc
+.Fl l Xo
+.Sm off
+.Ar length
+.Op Cm SUFFIX
+.Sm on
+.Xc
+.Ek
+.Ar
 .Sh DESCRIPTION
 The
 .Nm
-utility adjusts the length of each regular file given on the command-line.
+utility adjusts the length of each regular file given on the command-line, or
+performs space management with the given offset and the length over a regular
+file given on the command-line.
 .Pp
 The following options are available:
 .Bl -tag -width indent
@@ -71,7 +97,7 @@ Truncate or extend files to the length of the file
 .Sm off
 .Op Cm + | - | % | /
 .Ar size
-.Op Cm K | k | M | m | G | g | T | t
+.Op Cm SUFFIX
 .Sm on
 .Xc
 If the
@@ -100,10 +126,28 @@ Otherwise, the
 .Ar size
 argument specifies an absolute length to which all files
 should be extended or reduced as appropriate.
+.It Fl d
+Zero a region in the specified file.
+If the underlying file system of the given file supports hole-punching,
+file system space deallocation may be performed in the operation region.
+.It Fl o Ar offset
+The space management operation is performed at the given
+.Ar offset
+bytes in the file.
+If this option is not specified, the operation is performed at the beginning of the file.
+.It Fl l Ar length
+The length of the operation range in bytes.
+This option must always be specified if option
+.Fl d
+is specified, and must be greater than 0.
+.El
 .Pp
 The
-.Ar size
-argument may be suffixed with one of
+.Ar size ,
+.Ar offset
+and
+.Ar length
+arguments may be suffixed with one of
 .Cm K ,
 .Cm M ,
 .Cm G
@@ -112,7 +156,6 @@ or
 (either upper or lower case) to indicate a multiple of
 Kilobytes, Megabytes, Gigabytes or Terabytes
 respectively.
-.El
 .Pp
 Exactly one of the
 .Fl r
@@ -183,6 +226,7 @@ ls -l test_file*
 .Sh SEE ALSO
 .Xr dd 1 ,
 .Xr touch 1 ,
+.Xr fspacectl 2 ,
 .Xr truncate 2
 .Sh STANDARDS
 The
@@ -198,3 +242,6 @@ The
 .Nm
 utility was written by
 .An Sheldon Hearn Aq Mt sheldonh at starjuice.net .
+Hole-punching support of this
+utility was developed by
+.An Ka Ho Ng Aq Mt khng at FreeBSD.org .
diff --git a/usr.bin/truncate/truncate.c b/usr.bin/truncate/truncate.c
index a7579227f299..529d2c7e6dab 100644
--- a/usr.bin/truncate/truncate.c
+++ b/usr.bin/truncate/truncate.c
@@ -4,6 +4,11 @@
  * Copyright (c) 2000 Sheldon Hearn <sheldonh at FreeBSD.org>.
  * All rights reserved.
  *
+ * Copyright (c) 2021 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Ka Ho Ng <khng at FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -49,26 +54,36 @@ main(int argc, char **argv)
 {
 	struct stat sb;
 	mode_t omode;
-	off_t oflow, rsize, sz, tsize, round;
+	off_t oflow, rsize, sz, tsize, round, off, len;
 	uint64_t usz;
-	int ch, error, fd, oflags;
+	int ch, error, fd, oflags, r;
+	int do_dealloc;
+	int do_truncate;
 	int no_create;
 	int do_relative;
 	int do_round;
 	int do_refer;
 	int got_size;
 	char *fname, *rname;
+	struct spacectl_range sr;
 
 	fd = -1;
-	rsize = tsize = sz = 0;
-	no_create = do_relative = do_round = do_refer = got_size = 0;
-	error = 0;
+	rsize = tsize = sz = off = 0;
+	len = -1;
+	do_dealloc = no_create = do_relative = do_round = do_refer =
+	    got_size = 0;
+	do_truncate = 1;
+	error = r = 0;
 	rname = NULL;
-	while ((ch = getopt(argc, argv, "cr:s:")) != -1)
+	while ((ch = getopt(argc, argv, "cdr:s:o:l:")) != -1)
 		switch (ch) {
 		case 'c':
 			no_create = 1;
 			break;
+		case 'd':
+			do_dealloc = 1;
+			do_truncate = 0;
+			break;
 		case 'r':
 			do_refer = 1;
 			rname = optarg;
@@ -89,6 +104,22 @@ main(int argc, char **argv)
 				-(off_t)usz : (off_t)usz;
 			got_size = 1;
 			break;
+		case 'o':
+			if (expand_number(optarg, &usz) == -1 ||
+			    (off_t)usz < 0)
+				errx(EXIT_FAILURE,
+				    "invalid offset argument `%s'", optarg);
+
+			off = usz;
+			break;
+		case 'l':
+			if (expand_number(optarg, &usz) == -1 ||
+			    (off_t)usz <= 0)
+				errx(EXIT_FAILURE,
+				    "invalid length argument `%s'", optarg);
+
+			len = usz;
+			break;
 		default:
 			usage();
 			/* NOTREACHED */
@@ -98,19 +129,22 @@ main(int argc, char **argv)
 	argc -= optind;
 
 	/*
-	 * Exactly one of do_refer or got_size must be specified.  Since
-	 * do_relative implies got_size, do_relative and do_refer are
-	 * also mutually exclusive.  See usage() for allowed invocations.
+	 * Exactly one of do_refer, got_size or do_dealloc must be specified.
+	 * Since do_relative implies got_size, do_relative, do_refer and
+	 * do_dealloc are also mutually exclusive.  If do_dealloc is specified,
+	 * the length argument must be set.  See usage() for allowed
+	 * invocations.
 	 */
-	if (do_refer + got_size != 1 || argc < 1)
+	if (argc < 1 || do_refer + got_size + do_dealloc != 1 ||
+	    (do_dealloc == 1 && len == -1))
 		usage();
-	if (do_refer) {
+	if (do_refer == 1) {
 		if (stat(rname, &sb) == -1)
 			err(EXIT_FAILURE, "%s", rname);
 		tsize = sb.st_size;
-	} else if (do_relative || do_round)
+	} else if (do_relative == 1 || do_round == 1)
 		rsize = sz;
-	else
+	else if (do_dealloc == 0)
 		tsize = sz;
 
 	if (no_create)
@@ -129,7 +163,7 @@ main(int argc, char **argv)
 			}
 			continue;
 		}
-		if (do_relative) {
+		if (do_relative == 1) {
 			if (fstat(fd, &sb) == -1) {
 				warn("%s", fname);
 				error++;
@@ -144,7 +178,7 @@ main(int argc, char **argv)
 			}
 			tsize = oflow;
 		}
-		if (do_round) {
+		if (do_round == 1) {
 			if (fstat(fd, &sb) == -1) {
 				warn("%s", fname);
 				error++;
@@ -166,10 +200,16 @@ main(int argc, char **argv)
 		if (tsize < 0)
 			tsize = 0;
 
-		if (ftruncate(fd, tsize) == -1) {
+		if (do_dealloc == 1) {
+			sr.r_offset = off;
+			sr.r_len = len;
+			r = fspacectl(fd, SPACECTL_DEALLOC, &sr, 0, &sr);
+		}
+		if (do_truncate == 1)
+			r = ftruncate(fd, tsize);
+		if (r == -1) {
 			warn("%s", fname);
 			error++;
-			continue;
 		}
 	}
 	if (fd != -1)
@@ -181,8 +221,9 @@ main(int argc, char **argv)
 static void
 usage(void)
 {
-	fprintf(stderr, "%s\n%s\n",
+	fprintf(stderr, "%s\n%s\n%s\n",
 	    "usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ...",
-	    "       truncate [-c] -r rfile file ...");
+	    "       truncate [-c] -r rfile file ...",
+	    "       truncate [-c] -d [-o offset[K|k|M|m|G|g|T|t]] -l length[K|k|M|m|G|g|T|t] file ...");
 	exit(EXIT_FAILURE);
 }


More information about the dev-commits-src-all mailing list