|
|
05ad79 |
From 9f2a32a8fd08bb1b48f29c88bfa398fa4eb5f2a4 Mon Sep 17 00:00:00 2001
|
|
|
05ad79 |
From: Karel Zak <kzak@redhat.com>
|
|
|
05ad79 |
Date: Wed, 6 Jun 2018 11:59:16 +0200
|
|
|
05ad79 |
Subject: [PATCH 159/173] fallocate: backport v2.32-164-g641af90dc
|
|
|
05ad79 |
|
|
|
05ad79 |
* add --dig-holes
|
|
|
05ad79 |
* add --collapse-range
|
|
|
05ad79 |
* add --insert-range
|
|
|
05ad79 |
* add --zero-range
|
|
|
05ad79 |
|
|
|
05ad79 |
For backward compatibility with previous RHEL7 versions we keep
|
|
|
05ad79 |
O_CREAT for open(). The current upstream uses O_CREAT only when
|
|
|
05ad79 |
necessary.
|
|
|
05ad79 |
|
|
|
05ad79 |
Addresses: http://bugzilla.redhat.com/show_bug.cgi?id=1528567
|
|
|
05ad79 |
Signed-off-by: Karel Zak <kzak@redhat.com>
|
|
|
05ad79 |
---
|
|
|
05ad79 |
sys-utils/fallocate.1 | 195 ++++++++++++++++++++++------
|
|
|
05ad79 |
sys-utils/fallocate.c | 349 +++++++++++++++++++++++++++++++++++++++-----------
|
|
|
05ad79 |
2 files changed, 428 insertions(+), 116 deletions(-)
|
|
|
05ad79 |
|
|
|
05ad79 |
diff --git a/sys-utils/fallocate.1 b/sys-utils/fallocate.1
|
|
|
05ad79 |
index 376353013..d4821dcd1 100644
|
|
|
05ad79 |
--- a/sys-utils/fallocate.1
|
|
|
05ad79 |
+++ b/sys-utils/fallocate.1
|
|
|
05ad79 |
@@ -1,72 +1,185 @@
|
|
|
05ad79 |
-.\" -*- nroff -*-
|
|
|
05ad79 |
-.TH FALLOCATE 1 "September 2011" "util-linux" "User Commands"
|
|
|
05ad79 |
+.TH FALLOCATE 1 "April 2014" "util-linux" "User Commands"
|
|
|
05ad79 |
.SH NAME
|
|
|
05ad79 |
-fallocate \- preallocate space to a file
|
|
|
05ad79 |
+fallocate \- preallocate or deallocate space to a file
|
|
|
05ad79 |
.SH SYNOPSIS
|
|
|
05ad79 |
.B fallocate
|
|
|
05ad79 |
-.RB [ \-n ]
|
|
|
05ad79 |
-.RB [ \-p ]
|
|
|
05ad79 |
+.RB [ \-c | \-p | \-z ]
|
|
|
05ad79 |
.RB [ \-o
|
|
|
05ad79 |
.IR offset ]
|
|
|
05ad79 |
.B \-l
|
|
|
05ad79 |
-.IR length
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
+.RB [ \-n ]
|
|
|
05ad79 |
+.I filename
|
|
|
05ad79 |
+.PP
|
|
|
05ad79 |
+.B fallocate \-d
|
|
|
05ad79 |
+.RB [ \-o
|
|
|
05ad79 |
+.IR offset ]
|
|
|
05ad79 |
+.RB [ \-l
|
|
|
05ad79 |
+.IR length ]
|
|
|
05ad79 |
.I filename
|
|
|
05ad79 |
.PP
|
|
|
05ad79 |
.B fallocate \-x
|
|
|
05ad79 |
.RB [ \-o
|
|
|
05ad79 |
.IR offset ]
|
|
|
05ad79 |
-.RB \-l
|
|
|
05ad79 |
-.IR length
|
|
|
05ad79 |
+.B \-l
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
.I filename
|
|
|
05ad79 |
.SH DESCRIPTION
|
|
|
05ad79 |
.B fallocate
|
|
|
05ad79 |
-is used to preallocate blocks to a file. For filesystems which support the
|
|
|
05ad79 |
-fallocate system call, this is done quickly by allocating blocks and marking
|
|
|
05ad79 |
-them as uninitialized, requiring no IO to the data blocks. This is much faster
|
|
|
05ad79 |
-than creating a file by filling it with zeros.
|
|
|
05ad79 |
-.PP
|
|
|
05ad79 |
-As of the Linux Kernel v2.6.31, the fallocate system call is supported by the
|
|
|
05ad79 |
-btrfs, ext4, ocfs2, and xfs filesystems.
|
|
|
05ad79 |
+is used to manipulate the allocated disk space for a file,
|
|
|
05ad79 |
+either to deallocate or preallocate it.
|
|
|
05ad79 |
+For filesystems which support the fallocate system call,
|
|
|
05ad79 |
+preallocation is done quickly by allocating blocks and marking them as
|
|
|
05ad79 |
+uninitialized, requiring no IO to the data blocks.
|
|
|
05ad79 |
+This is much faster than creating a file by filling it with zeroes.
|
|
|
05ad79 |
.PP
|
|
|
05ad79 |
The exit code returned by
|
|
|
05ad79 |
.B fallocate
|
|
|
05ad79 |
is 0 on success and 1 on failure.
|
|
|
05ad79 |
-.PP
|
|
|
05ad79 |
.SH OPTIONS
|
|
|
05ad79 |
-The \fIlength\fR and \fIoffset\fR arguments may be followed by the multiplicative
|
|
|
05ad79 |
-suffixes KiB=1024, MiB=1024*1024, and so on for GiB, TiB, PiB, EiB, ZiB and YiB
|
|
|
05ad79 |
-(the "iB" is optional, e.g. "K" has the same meaning as "KiB") or the suffixes
|
|
|
05ad79 |
-KB=1000, MB=1000*1000, and so on for GB, TB, PB, EB, ZB and YB.
|
|
|
05ad79 |
-.IP "\fB\-n, \-\-keep-size\fP"
|
|
|
05ad79 |
+The
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
+and
|
|
|
05ad79 |
+.I offset
|
|
|
05ad79 |
+arguments may be followed by the multiplicative suffixes KiB (=1024),
|
|
|
05ad79 |
+MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB, and YiB (the "iB" is
|
|
|
05ad79 |
+optional, e.g., "K" has the same meaning as "KiB") or the suffixes
|
|
|
05ad79 |
+KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB, and YB.
|
|
|
05ad79 |
+.PP
|
|
|
05ad79 |
+The options
|
|
|
05ad79 |
+.BR \-\-collapse\-range ", " \-\-dig\-holes ", " \-\-punch\-hole ,
|
|
|
05ad79 |
+and
|
|
|
05ad79 |
+.B \-\-zero\-range
|
|
|
05ad79 |
+are mutually exclusive.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-c ", " \-\-collapse\-range
|
|
|
05ad79 |
+Removes a byte range from a file, without leaving a hole.
|
|
|
05ad79 |
+The byte range to be collapsed starts at
|
|
|
05ad79 |
+.I offset
|
|
|
05ad79 |
+and continues for
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
+bytes.
|
|
|
05ad79 |
+At the completion of the operation,
|
|
|
05ad79 |
+the contents of the file starting at the location
|
|
|
05ad79 |
+.IR offset + length
|
|
|
05ad79 |
+will be appended at the location
|
|
|
05ad79 |
+.IR offset ,
|
|
|
05ad79 |
+and the file will be
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
+bytes smaller.
|
|
|
05ad79 |
+The option
|
|
|
05ad79 |
+.B \-\-keep\-size
|
|
|
05ad79 |
+may not be specified for the collapse-range operation.
|
|
|
05ad79 |
+.sp
|
|
|
05ad79 |
+Available since Linux 3.15 for ext4 (only for extent-based files) and XFS.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-d ", " \-\-dig\-holes
|
|
|
05ad79 |
+Detect and dig holes.
|
|
|
05ad79 |
+This makes the file sparse in-place, without using extra disk space.
|
|
|
05ad79 |
+The minimum size of the hole depends on filesystem I/O block size
|
|
|
05ad79 |
+(usually 4096 bytes).
|
|
|
05ad79 |
+Also, when using this option,
|
|
|
05ad79 |
+.B \-\-keep\-size
|
|
|
05ad79 |
+is implied. If no range is specified by
|
|
|
05ad79 |
+.B \-\-offset
|
|
|
05ad79 |
+and
|
|
|
05ad79 |
+.BR \-\-length ,
|
|
|
05ad79 |
+then the entire file is analyzed for holes.
|
|
|
05ad79 |
+.sp
|
|
|
05ad79 |
+You can think of this option as doing a
|
|
|
05ad79 |
+.RB """" "cp \-\-sparse" """"
|
|
|
05ad79 |
+and then renaming the destination file to the original,
|
|
|
05ad79 |
+without the need for extra disk space.
|
|
|
05ad79 |
+.sp
|
|
|
05ad79 |
+See \fB\-\-punch\-hole\fP for a list of supported filesystems.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-i ", " \-\-insert\-range
|
|
|
05ad79 |
+Insert a hole of
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
+bytes from
|
|
|
05ad79 |
+.IR offset ,
|
|
|
05ad79 |
+shifting existing data.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-l ", " "\-\-length " \fIlength
|
|
|
05ad79 |
+Specifies the length of the range, in bytes.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-n ", " \-\-keep\-size
|
|
|
05ad79 |
Do not modify the apparent length of the file. This may effectively allocate
|
|
|
05ad79 |
blocks past EOF, which can be removed with a truncate.
|
|
|
05ad79 |
-.IP "\fB\-p, \-\-punch-hole\fP"
|
|
|
05ad79 |
-Punch holes in the file, the range should not exceed the length of the file.
|
|
|
05ad79 |
-.IP "\fB\-o, \-\-offset\fP \fIoffset\fP
|
|
|
05ad79 |
-Specifies the beginning offset of the allocation, in bytes.
|
|
|
05ad79 |
-.IP "\fB\-l, \-\-length\fP \fIlength\fP
|
|
|
05ad79 |
-Specifies the length of the allocation, in bytes.
|
|
|
05ad79 |
-.IP "\fB\-x , \-\-posix\fP
|
|
|
05ad79 |
-Enable POSIX operation mode. In that mode allocation operation always completes,
|
|
|
05ad79 |
-but it may take longer time when fast allocation is not supported by the underlying filesystem.
|
|
|
05ad79 |
-.IP "\fB\-h, \-\-help\fP"
|
|
|
05ad79 |
-Print help and exit.
|
|
|
05ad79 |
-.IP "\fB-V, \-\-version"
|
|
|
05ad79 |
-Print version and exit.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-o ", " "\-\-offset " \fIoffset
|
|
|
05ad79 |
+Specifies the beginning offset of the range, in bytes.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-p ", " \-\-punch\-hole
|
|
|
05ad79 |
+Deallocates space (i.e., creates a hole) in the byte range starting at
|
|
|
05ad79 |
+.I offset
|
|
|
05ad79 |
+and continuing for
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
+bytes.
|
|
|
05ad79 |
+Within the specified range, partial filesystem blocks are zeroed,
|
|
|
05ad79 |
+and whole filesystem blocks are removed from the file.
|
|
|
05ad79 |
+After a successful call,
|
|
|
05ad79 |
+subsequent reads from this range will return zeroes.
|
|
|
05ad79 |
+This option may not be specified at the same time as the
|
|
|
05ad79 |
+.B \-\-zero\-range
|
|
|
05ad79 |
+option.
|
|
|
05ad79 |
+Also, when using this option,
|
|
|
05ad79 |
+.B \-\-keep\-size
|
|
|
05ad79 |
+is implied.
|
|
|
05ad79 |
+.sp
|
|
|
05ad79 |
+Supported for XFS (since Linux 2.6.38), ext4 (since Linux 3.0),
|
|
|
05ad79 |
+Btrfs (since Linux 3.7) and tmpfs (since Linux 3.5).
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-v ", " \-\-verbose
|
|
|
05ad79 |
+Enable verbose mode.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-x ", " \-\-posix
|
|
|
05ad79 |
+Enable POSIX operation mode.
|
|
|
05ad79 |
+In that mode allocation operation always completes,
|
|
|
05ad79 |
+but it may take longer time when fast allocation is not supported by
|
|
|
05ad79 |
+the underlying filesystem.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-z ", " \-\-zero\-range
|
|
|
05ad79 |
+Zeroes space in the byte range starting at
|
|
|
05ad79 |
+.I offset
|
|
|
05ad79 |
+and continuing for
|
|
|
05ad79 |
+.I length
|
|
|
05ad79 |
+bytes.
|
|
|
05ad79 |
+Within the specified range, blocks are preallocated for the regions
|
|
|
05ad79 |
+that span the holes in the file.
|
|
|
05ad79 |
+After a successful call,
|
|
|
05ad79 |
+subsequent reads from this range will return zeroes.
|
|
|
05ad79 |
+.sp
|
|
|
05ad79 |
+Zeroing is done within the filesystem preferably by converting the
|
|
|
05ad79 |
+range into unwritten extents. This approach means that the specified
|
|
|
05ad79 |
+range will not be physically zeroed out on the device (except for
|
|
|
05ad79 |
+partial blocks at the either end of the range), and I/O is
|
|
|
05ad79 |
+(otherwise) required only to update metadata.
|
|
|
05ad79 |
+.sp
|
|
|
05ad79 |
+Option \fB\-\-keep\-size\fP can be specified to prevent file length
|
|
|
05ad79 |
+modification.
|
|
|
05ad79 |
+.sp
|
|
|
05ad79 |
+Available since Linux 3.14 for ext4 (only for extent-based files) and XFS.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-V ", " \-\-version
|
|
|
05ad79 |
+Display version information and exit.
|
|
|
05ad79 |
+.TP
|
|
|
05ad79 |
+.BR \-h ", " \-\-help
|
|
|
05ad79 |
+Display help text and exit.
|
|
|
05ad79 |
.SH AUTHORS
|
|
|
05ad79 |
-.UR sandeen@redhat.com
|
|
|
05ad79 |
+.MT sandeen@redhat.com
|
|
|
05ad79 |
Eric Sandeen
|
|
|
05ad79 |
-.UE
|
|
|
05ad79 |
+.ME
|
|
|
05ad79 |
.br
|
|
|
05ad79 |
-.UR kzak@redhat.com
|
|
|
05ad79 |
+.MT kzak@redhat.com
|
|
|
05ad79 |
Karel Zak
|
|
|
05ad79 |
-.UE
|
|
|
05ad79 |
+.ME
|
|
|
05ad79 |
.SH SEE ALSO
|
|
|
05ad79 |
+.BR truncate (1),
|
|
|
05ad79 |
.BR fallocate (2),
|
|
|
05ad79 |
-.BR posix_fallocate (3),
|
|
|
05ad79 |
-.BR truncate (1)
|
|
|
05ad79 |
+.BR posix_fallocate (3)
|
|
|
05ad79 |
.SH AVAILABILITY
|
|
|
05ad79 |
The fallocate command is part of the util-linux package and is available from
|
|
|
05ad79 |
-.UR ftp://\:ftp.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
|
|
|
05ad79 |
+.UR https://\:www.kernel.org\:/pub\:/linux\:/utils\:/util-linux/
|
|
|
05ad79 |
Linux Kernel Archive
|
|
|
05ad79 |
.UE .
|
|
|
05ad79 |
diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c
|
|
|
05ad79 |
index 17ae5fe69..75d89a7a9 100644
|
|
|
05ad79 |
--- a/sys-utils/fallocate.c
|
|
|
05ad79 |
+++ b/sys-utils/fallocate.c
|
|
|
05ad79 |
@@ -23,6 +23,7 @@
|
|
|
05ad79 |
*/
|
|
|
05ad79 |
#include <sys/stat.h>
|
|
|
05ad79 |
#include <sys/types.h>
|
|
|
05ad79 |
+#include <sys/mman.h>
|
|
|
05ad79 |
#include <ctype.h>
|
|
|
05ad79 |
#include <errno.h>
|
|
|
05ad79 |
#include <fcntl.h>
|
|
|
05ad79 |
@@ -31,50 +32,110 @@
|
|
|
05ad79 |
#include <unistd.h>
|
|
|
05ad79 |
#include <getopt.h>
|
|
|
05ad79 |
#include <limits.h>
|
|
|
05ad79 |
+#include <string.h>
|
|
|
05ad79 |
|
|
|
05ad79 |
#ifndef HAVE_FALLOCATE
|
|
|
05ad79 |
# include <sys/syscall.h>
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
|
|
|
05ad79 |
-#ifdef HAVE_LINUX_FALLOC_H
|
|
|
05ad79 |
-# include <linux/falloc.h> /* for FALLOC_FL_* flags */
|
|
|
05ad79 |
+#if defined(HAVE_LINUX_FALLOC_H) && \
|
|
|
05ad79 |
+ (!defined(FALLOC_FL_KEEP_SIZE) || !defined(FALLOC_FL_PUNCH_HOLE) || \
|
|
|
05ad79 |
+ !defined(FALLOC_FL_COLLAPSE_RANGE) || !defined(FALLOC_FL_ZERO_RANGE) || \
|
|
|
05ad79 |
+ !defined(FALLOC_FL_INSERT_RANGE))
|
|
|
05ad79 |
+# include <linux/falloc.h> /* non-libc fallback for FALLOC_FL_* flags */
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
|
|
|
05ad79 |
+
|
|
|
05ad79 |
#ifndef FALLOC_FL_KEEP_SIZE
|
|
|
05ad79 |
-# define FALLOC_FL_KEEP_SIZE 1
|
|
|
05ad79 |
+# define FALLOC_FL_KEEP_SIZE 0x1
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
|
|
|
05ad79 |
#ifndef FALLOC_FL_PUNCH_HOLE
|
|
|
05ad79 |
-# define FALLOC_FL_PUNCH_HOLE 2
|
|
|
05ad79 |
+# define FALLOC_FL_PUNCH_HOLE 0x2
|
|
|
05ad79 |
+#endif
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+#ifndef FALLOC_FL_COLLAPSE_RANGE
|
|
|
05ad79 |
+# define FALLOC_FL_COLLAPSE_RANGE 0x8
|
|
|
05ad79 |
+#endif
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+#ifndef FALLOC_FL_ZERO_RANGE
|
|
|
05ad79 |
+# define FALLOC_FL_ZERO_RANGE 0x10
|
|
|
05ad79 |
+#endif
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+#ifndef FALLOC_FL_INSERT_RANGE
|
|
|
05ad79 |
+# define FALLOC_FL_INSERT_RANGE 0x20
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
|
|
|
05ad79 |
#include "nls.h"
|
|
|
05ad79 |
#include "strutils.h"
|
|
|
05ad79 |
#include "c.h"
|
|
|
05ad79 |
#include "closestream.h"
|
|
|
05ad79 |
+#include "xalloc.h"
|
|
|
05ad79 |
#include "optutils.h"
|
|
|
05ad79 |
|
|
|
05ad79 |
-static void __attribute__((__noreturn__)) usage(FILE *out)
|
|
|
05ad79 |
+static int verbose;
|
|
|
05ad79 |
+static char *filename;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+static void __attribute__((__noreturn__)) usage(void)
|
|
|
05ad79 |
{
|
|
|
05ad79 |
+ FILE *out = stdout;
|
|
|
05ad79 |
fputs(USAGE_HEADER, out);
|
|
|
05ad79 |
fprintf(out,
|
|
|
05ad79 |
_(" %s [options] <filename>\n"), program_invocation_short_name);
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ fputs(USAGE_SEPARATOR, out);
|
|
|
05ad79 |
+ fputs(_("Preallocate space to, or deallocate space from a file.\n"), out);
|
|
|
05ad79 |
+
|
|
|
05ad79 |
fputs(USAGE_OPTIONS, out);
|
|
|
05ad79 |
- fputs(_(" -n, --keep-size don't modify the length of the file\n"
|
|
|
05ad79 |
- " -p, --punch-hole punch holes in the file\n"
|
|
|
05ad79 |
- " -o, --offset <num> offset of the allocation, in bytes\n"
|
|
|
05ad79 |
- " -l, --length <num> length of the allocation, in bytes\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -c, --collapse-range remove a range from the file\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -d, --dig-holes detect zeroes and replace with holes\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -i, --insert-range insert a hole at range, shifting existing data\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -l, --length <num> length for range operations, in bytes\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -n, --keep-size maintain the apparent size of the file\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -o, --offset <num> offset for range operations, in bytes\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -p, --punch-hole replace a range with a hole (implies -n)\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -z, --zero-range zero and ensure allocation of a range\n"), out);
|
|
|
05ad79 |
#ifdef HAVE_POSIX_FALLOCATE
|
|
|
05ad79 |
- fputs(_(" -x, --posix use posix_fallocate(3) instead of fallocate(2)\n"), out);
|
|
|
05ad79 |
+ fputs(_(" -x, --posix use posix_fallocate(3) instead of fallocate(2)\n"), out);
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
+ fputs(_(" -v, --verbose verbose mode\n"), out);
|
|
|
05ad79 |
+
|
|
|
05ad79 |
fputs(USAGE_SEPARATOR, out);
|
|
|
05ad79 |
- fputs(USAGE_HELP, out);
|
|
|
05ad79 |
- fputs(USAGE_VERSION, out);
|
|
|
05ad79 |
- fprintf(out, USAGE_MAN_TAIL("fallocate(1)"));
|
|
|
05ad79 |
+ printf(USAGE_HELP_OPTIONS(22));
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ printf(USAGE_MAN_TAIL("fallocate(1)"));
|
|
|
05ad79 |
|
|
|
05ad79 |
- exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
|
|
05ad79 |
+ exit(EXIT_SUCCESS);
|
|
|
05ad79 |
}
|
|
|
05ad79 |
|
|
|
05ad79 |
+static loff_t cvtnum(char *s)
|
|
|
05ad79 |
+{
|
|
|
05ad79 |
+ uintmax_t x;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ if (strtosize(s, &x))
|
|
|
05ad79 |
+ return -1LL;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ return x;
|
|
|
05ad79 |
+}
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+static void xfallocate(int fd, int mode, off_t offset, off_t length)
|
|
|
05ad79 |
+{
|
|
|
05ad79 |
+ int error;
|
|
|
05ad79 |
+#ifdef HAVE_FALLOCATE
|
|
|
05ad79 |
+ error = fallocate(fd, mode, offset, length);
|
|
|
05ad79 |
+#else
|
|
|
05ad79 |
+ error = syscall(SYS_fallocate, fd, mode, offset, length);
|
|
|
05ad79 |
+#endif
|
|
|
05ad79 |
+ /*
|
|
|
05ad79 |
+ * EOPNOTSUPP: The FALLOC_FL_KEEP_SIZE is unsupported
|
|
|
05ad79 |
+ * ENOSYS: The filesystem does not support sys_fallocate
|
|
|
05ad79 |
+ */
|
|
|
05ad79 |
+ if (error < 0) {
|
|
|
05ad79 |
+ if ((mode & FALLOC_FL_KEEP_SIZE) && errno == EOPNOTSUPP)
|
|
|
05ad79 |
+ errx(EXIT_FAILURE, _("fallocate failed: keep size mode is unsupported"));
|
|
|
05ad79 |
+ err(EXIT_FAILURE, _("fallocate failed"));
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+}
|
|
|
05ad79 |
|
|
|
05ad79 |
#ifdef HAVE_POSIX_FALLOCATE
|
|
|
05ad79 |
static void xposix_fallocate(int fd, off_t offset, off_t length)
|
|
|
05ad79 |
@@ -86,41 +147,163 @@ static void xposix_fallocate(int fd, off_t offset, off_t length)
|
|
|
05ad79 |
}
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
|
|
|
05ad79 |
+/* The real buffer size has to be bufsize + sizeof(uintptr_t) */
|
|
|
05ad79 |
+static int is_nul(void *buf, size_t bufsize)
|
|
|
05ad79 |
+{
|
|
|
05ad79 |
+ typedef uintptr_t word;
|
|
|
05ad79 |
+ void const *vp;
|
|
|
05ad79 |
+ char const *cbuf = buf, *cp;
|
|
|
05ad79 |
+ word const *wp = buf;
|
|
|
05ad79 |
|
|
|
05ad79 |
-static loff_t cvtnum(char *s)
|
|
|
05ad79 |
+ /* set sentinel */
|
|
|
05ad79 |
+ memset((char *) buf + bufsize, '\1', sizeof(word));
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ /* Find first nonzero *word*, or the word with the sentinel. */
|
|
|
05ad79 |
+ while (*wp++ == 0)
|
|
|
05ad79 |
+ continue;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ /* Find the first nonzero *byte*, or the sentinel. */
|
|
|
05ad79 |
+ vp = wp - 1;
|
|
|
05ad79 |
+ cp = vp;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ while (*cp++ == 0)
|
|
|
05ad79 |
+ continue;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ return cbuf + bufsize < cp;
|
|
|
05ad79 |
+}
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+static void dig_holes(int fd, off_t file_off, off_t len)
|
|
|
05ad79 |
{
|
|
|
05ad79 |
- uintmax_t x;
|
|
|
05ad79 |
+ off_t file_end = len ? file_off + len : 0;
|
|
|
05ad79 |
+ off_t hole_start = 0, hole_sz = 0;
|
|
|
05ad79 |
+ uintmax_t ct = 0;
|
|
|
05ad79 |
+ size_t bufsz;
|
|
|
05ad79 |
+ char *buf;
|
|
|
05ad79 |
+ struct stat st;
|
|
|
05ad79 |
+#if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
|
|
|
05ad79 |
+ off_t cache_start = file_off;
|
|
|
05ad79 |
+ /*
|
|
|
05ad79 |
+ * We don't want to call POSIX_FADV_DONTNEED to discard cached
|
|
|
05ad79 |
+ * data in PAGE_SIZE steps. IMHO it's overkill (too many syscalls).
|
|
|
05ad79 |
+ *
|
|
|
05ad79 |
+ * Let's assume that 1MiB (on system with 4K page size) is just
|
|
|
05ad79 |
+ * a good compromise.
|
|
|
05ad79 |
+ * -- kzak Feb-2014
|
|
|
05ad79 |
+ */
|
|
|
05ad79 |
+ const size_t cachesz = getpagesize() * 256;
|
|
|
05ad79 |
+#endif
|
|
|
05ad79 |
|
|
|
05ad79 |
- if (strtosize(s, &x))
|
|
|
05ad79 |
- return -1LL;
|
|
|
05ad79 |
+ if (fstat(fd, &st) != 0)
|
|
|
05ad79 |
+ err(EXIT_FAILURE, _("stat of %s failed"), filename);
|
|
|
05ad79 |
|
|
|
05ad79 |
- return x;
|
|
|
05ad79 |
+ bufsz = st.st_blksize;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ if (lseek(fd, file_off, SEEK_SET) < 0)
|
|
|
05ad79 |
+ err(EXIT_FAILURE, _("seek on %s failed"), filename);
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ /* buffer + extra space for is_nul() sentinel */
|
|
|
05ad79 |
+ buf = xmalloc(bufsz + sizeof(uintptr_t));
|
|
|
05ad79 |
+ while (file_end == 0 || file_off < file_end) {
|
|
|
05ad79 |
+ /*
|
|
|
05ad79 |
+ * Detect data area (skip holes)
|
|
|
05ad79 |
+ */
|
|
|
05ad79 |
+ off_t end, off;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ off = lseek(fd, file_off, SEEK_DATA);
|
|
|
05ad79 |
+ if ((off == -1 && errno == ENXIO) ||
|
|
|
05ad79 |
+ (file_end && off >= file_end))
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ end = lseek(fd, off, SEEK_HOLE);
|
|
|
05ad79 |
+ if (file_end && end > file_end)
|
|
|
05ad79 |
+ end = file_end;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+#if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
|
|
|
05ad79 |
+ posix_fadvise(fd, off, end, POSIX_FADV_SEQUENTIAL);
|
|
|
05ad79 |
+#endif
|
|
|
05ad79 |
+ /*
|
|
|
05ad79 |
+ * Dig holes in the area
|
|
|
05ad79 |
+ */
|
|
|
05ad79 |
+ while (off < end) {
|
|
|
05ad79 |
+ ssize_t rsz = pread(fd, buf, bufsz, off);
|
|
|
05ad79 |
+ if (rsz < 0 && errno)
|
|
|
05ad79 |
+ err(EXIT_FAILURE, _("%s: read failed"), filename);
|
|
|
05ad79 |
+ if (end && rsz > 0 && off > end - rsz)
|
|
|
05ad79 |
+ rsz = end - off;
|
|
|
05ad79 |
+ if (rsz <= 0)
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ if (is_nul(buf, rsz)) {
|
|
|
05ad79 |
+ if (!hole_sz) /* new hole detected */
|
|
|
05ad79 |
+ hole_start = off;
|
|
|
05ad79 |
+ hole_sz += rsz;
|
|
|
05ad79 |
+ } else if (hole_sz) {
|
|
|
05ad79 |
+ xfallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE,
|
|
|
05ad79 |
+ hole_start, hole_sz);
|
|
|
05ad79 |
+ ct += hole_sz;
|
|
|
05ad79 |
+ hole_sz = hole_start = 0;
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+#if defined(POSIX_FADV_DONTNEED) && defined(HAVE_POSIX_FADVISE)
|
|
|
05ad79 |
+ /* discard cached data */
|
|
|
05ad79 |
+ if (off - cache_start > (off_t) cachesz) {
|
|
|
05ad79 |
+ size_t clen = off - cache_start;
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ clen = (clen / cachesz) * cachesz;
|
|
|
05ad79 |
+ posix_fadvise(fd, cache_start, clen, POSIX_FADV_DONTNEED);
|
|
|
05ad79 |
+ cache_start = cache_start + clen;
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+#endif
|
|
|
05ad79 |
+ off += rsz;
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+ if (hole_sz) {
|
|
|
05ad79 |
+ xfallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE,
|
|
|
05ad79 |
+ hole_start, hole_sz);
|
|
|
05ad79 |
+ ct += hole_sz;
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+ file_off = off;
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ free(buf);
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ if (verbose) {
|
|
|
05ad79 |
+ char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE, ct);
|
|
|
05ad79 |
+ fprintf(stdout, _("%s: %s (%ju bytes) converted to sparse holes.\n"),
|
|
|
05ad79 |
+ filename, str, ct);
|
|
|
05ad79 |
+ free(str);
|
|
|
05ad79 |
+ }
|
|
|
05ad79 |
}
|
|
|
05ad79 |
|
|
|
05ad79 |
int main(int argc, char **argv)
|
|
|
05ad79 |
{
|
|
|
05ad79 |
- char *fname;
|
|
|
05ad79 |
int c;
|
|
|
05ad79 |
- int error = 0;
|
|
|
05ad79 |
int fd;
|
|
|
05ad79 |
int mode = 0;
|
|
|
05ad79 |
- int posix = 0;
|
|
|
05ad79 |
+ int dig = 0;
|
|
|
05ad79 |
+ int posix = 0;
|
|
|
05ad79 |
loff_t length = -2LL;
|
|
|
05ad79 |
loff_t offset = 0;
|
|
|
05ad79 |
|
|
|
05ad79 |
static const struct option longopts[] = {
|
|
|
05ad79 |
- { "help", 0, 0, 'h' },
|
|
|
05ad79 |
- { "version", 0, 0, 'V' },
|
|
|
05ad79 |
- { "keep-size", 0, 0, 'n' },
|
|
|
05ad79 |
- { "punch-hole", 0, 0, 'p' },
|
|
|
05ad79 |
- { "offset", 1, 0, 'o' },
|
|
|
05ad79 |
- { "length", 1, 0, 'l' },
|
|
|
05ad79 |
- { "posix", 0, 0, 'x' },
|
|
|
05ad79 |
- { NULL, 0, 0, 0 }
|
|
|
05ad79 |
+ { "help", no_argument, NULL, 'h' },
|
|
|
05ad79 |
+ { "version", no_argument, NULL, 'V' },
|
|
|
05ad79 |
+ { "keep-size", no_argument, NULL, 'n' },
|
|
|
05ad79 |
+ { "punch-hole", no_argument, NULL, 'p' },
|
|
|
05ad79 |
+ { "collapse-range", no_argument, NULL, 'c' },
|
|
|
05ad79 |
+ { "dig-holes", no_argument, NULL, 'd' },
|
|
|
05ad79 |
+ { "insert-range", no_argument, NULL, 'i' },
|
|
|
05ad79 |
+ { "zero-range", no_argument, NULL, 'z' },
|
|
|
05ad79 |
+ { "offset", required_argument, NULL, 'o' },
|
|
|
05ad79 |
+ { "length", required_argument, NULL, 'l' },
|
|
|
05ad79 |
+ { "posix", no_argument, NULL, 'x' },
|
|
|
05ad79 |
+ { "verbose", no_argument, NULL, 'v' },
|
|
|
05ad79 |
+ { NULL, 0, NULL, 0 }
|
|
|
05ad79 |
};
|
|
|
05ad79 |
|
|
|
05ad79 |
- static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
|
|
|
05ad79 |
- { 'x', 'n', 'p' },
|
|
|
05ad79 |
+ static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
|
|
|
05ad79 |
+ { 'c', 'd', 'p', 'z' },
|
|
|
05ad79 |
+ { 'c', 'n' },
|
|
|
05ad79 |
+ { 'x', 'c', 'd', 'i', 'n', 'p', 'z'},
|
|
|
05ad79 |
{ 0 }
|
|
|
05ad79 |
};
|
|
|
05ad79 |
int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
|
|
|
05ad79 |
@@ -130,29 +313,39 @@ int main(int argc, char **argv)
|
|
|
05ad79 |
textdomain(PACKAGE);
|
|
|
05ad79 |
atexit(close_stdout);
|
|
|
05ad79 |
|
|
|
05ad79 |
- while ((c = getopt_long(argc, argv, "hVnpl:o:x", longopts, NULL)) != -1) {
|
|
|
05ad79 |
+ while ((c = getopt_long(argc, argv, "hvVncpdizxl:o:", longopts, NULL))
|
|
|
05ad79 |
+ != -1) {
|
|
|
05ad79 |
|
|
|
05ad79 |
err_exclusive_options(c, longopts, excl, excl_st);
|
|
|
05ad79 |
|
|
|
05ad79 |
switch(c) {
|
|
|
05ad79 |
case 'h':
|
|
|
05ad79 |
- usage(stdout);
|
|
|
05ad79 |
+ usage();
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
- case 'V':
|
|
|
05ad79 |
- printf(UTIL_LINUX_VERSION);
|
|
|
05ad79 |
- return EXIT_SUCCESS;
|
|
|
05ad79 |
- case 'p':
|
|
|
05ad79 |
- mode |= FALLOC_FL_PUNCH_HOLE;
|
|
|
05ad79 |
- /* fall through */
|
|
|
05ad79 |
- case 'n':
|
|
|
05ad79 |
- mode |= FALLOC_FL_KEEP_SIZE;
|
|
|
05ad79 |
+ case 'c':
|
|
|
05ad79 |
+ mode |= FALLOC_FL_COLLAPSE_RANGE;
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
+ case 'd':
|
|
|
05ad79 |
+ dig = 1;
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
+ case 'i':
|
|
|
05ad79 |
+ mode |= FALLOC_FL_INSERT_RANGE;
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
case 'l':
|
|
|
05ad79 |
length = cvtnum(optarg);
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
+ case 'n':
|
|
|
05ad79 |
+ mode |= FALLOC_FL_KEEP_SIZE;
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
case 'o':
|
|
|
05ad79 |
offset = cvtnum(optarg);
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
+ case 'p':
|
|
|
05ad79 |
+ mode |= FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
+ case 'z':
|
|
|
05ad79 |
+ mode |= FALLOC_FL_ZERO_RANGE;
|
|
|
05ad79 |
+ break;
|
|
|
05ad79 |
case 'x':
|
|
|
05ad79 |
#ifdef HAVE_POSIX_FALLOCATE
|
|
|
05ad79 |
posix = 1;
|
|
|
05ad79 |
@@ -160,53 +353,59 @@ int main(int argc, char **argv)
|
|
|
05ad79 |
#else
|
|
|
05ad79 |
errx(EXIT_FAILURE, _("posix_fallocate support is not compiled"))
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
- default:
|
|
|
05ad79 |
- usage(stderr);
|
|
|
05ad79 |
+ case 'v':
|
|
|
05ad79 |
+ verbose++;
|
|
|
05ad79 |
break;
|
|
|
05ad79 |
+ case 'V':
|
|
|
05ad79 |
+ printf(UTIL_LINUX_VERSION);
|
|
|
05ad79 |
+ return EXIT_SUCCESS;
|
|
|
05ad79 |
+ default:
|
|
|
05ad79 |
+ errtryhelp(EXIT_FAILURE);
|
|
|
05ad79 |
}
|
|
|
05ad79 |
}
|
|
|
05ad79 |
|
|
|
05ad79 |
- if (length == -2LL)
|
|
|
05ad79 |
- errx(EXIT_FAILURE, _("no length argument specified"));
|
|
|
05ad79 |
- if (length <= 0)
|
|
|
05ad79 |
- errx(EXIT_FAILURE, _("invalid length value specified"));
|
|
|
05ad79 |
- if (offset < 0)
|
|
|
05ad79 |
- errx(EXIT_FAILURE, _("invalid offset value specified"));
|
|
|
05ad79 |
if (optind == argc)
|
|
|
05ad79 |
- errx(EXIT_FAILURE, _("no filename specified."));
|
|
|
05ad79 |
+ errx(EXIT_FAILURE, _("no filename specified"));
|
|
|
05ad79 |
+
|
|
|
05ad79 |
+ filename = argv[optind++];
|
|
|
05ad79 |
|
|
|
05ad79 |
- fname = argv[optind++];
|
|
|
05ad79 |
+ if (optind != argc)
|
|
|
05ad79 |
+ errx(EXIT_FAILURE, _("unexpected number of arguments"));
|
|
|
05ad79 |
|
|
|
05ad79 |
- if (optind != argc) {
|
|
|
05ad79 |
- warnx(_("unexpected number of arguments"));
|
|
|
05ad79 |
- usage(stderr);
|
|
|
05ad79 |
+ if (dig) {
|
|
|
05ad79 |
+ /* for --dig-holes the default is analyze all file */
|
|
|
05ad79 |
+ if (length == -2LL)
|
|
|
05ad79 |
+ length = 0;
|
|
|
05ad79 |
+ if (length < 0)
|
|
|
05ad79 |
+ errx(EXIT_FAILURE, _("invalid length value specified"));
|
|
|
05ad79 |
+ } else {
|
|
|
05ad79 |
+ /* it's safer to require the range specification (--length --offset) */
|
|
|
05ad79 |
+ if (length == -2LL)
|
|
|
05ad79 |
+ errx(EXIT_FAILURE, _("no length argument specified"));
|
|
|
05ad79 |
+ if (length <= 0)
|
|
|
05ad79 |
+ errx(EXIT_FAILURE, _("invalid length value specified"));
|
|
|
05ad79 |
}
|
|
|
05ad79 |
+ if (offset < 0)
|
|
|
05ad79 |
+ errx(EXIT_FAILURE, _("invalid offset value specified"));
|
|
|
05ad79 |
|
|
|
05ad79 |
- fd = open(fname, O_WRONLY|O_CREAT, 0644);
|
|
|
05ad79 |
+ /* O_CREAT makes sense only for the default fallocate(2) behavior
|
|
|
05ad79 |
+ * when mode is no specified and new space is allocated
|
|
|
05ad79 |
+ *
|
|
|
05ad79 |
+ * RHEL7.6: for backward compatibility in RHEL7 we keep O_CREAT there.
|
|
|
05ad79 |
+ */
|
|
|
05ad79 |
+ fd = open(filename, O_RDWR | O_CREAT,
|
|
|
05ad79 |
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
|
|
05ad79 |
if (fd < 0)
|
|
|
05ad79 |
- err(EXIT_FAILURE, _("cannot open %s"), fname);
|
|
|
05ad79 |
+ err(EXIT_FAILURE, _("cannot open %s"), filename);
|
|
|
05ad79 |
|
|
|
05ad79 |
+ if (dig)
|
|
|
05ad79 |
+ dig_holes(fd, offset, length);
|
|
|
05ad79 |
#ifdef HAVE_POSIX_FALLOCATE
|
|
|
05ad79 |
- if (posix)
|
|
|
05ad79 |
+ else if (posix)
|
|
|
05ad79 |
xposix_fallocate(fd, offset, length);
|
|
|
05ad79 |
- else
|
|
|
05ad79 |
#endif
|
|
|
05ad79 |
-
|
|
|
05ad79 |
-#ifdef HAVE_FALLOCATE
|
|
|
05ad79 |
- error = fallocate(fd, mode, offset, length);
|
|
|
05ad79 |
-#else
|
|
|
05ad79 |
- error = syscall(SYS_fallocate, fd, mode, offset, length);
|
|
|
05ad79 |
-#endif
|
|
|
05ad79 |
- /*
|
|
|
05ad79 |
- * EOPNOTSUPP: The FALLOC_FL_KEEP_SIZE is unsupported
|
|
|
05ad79 |
- * ENOSYS: The filesystem does not support sys_fallocate
|
|
|
05ad79 |
- */
|
|
|
05ad79 |
- if (error < 0) {
|
|
|
05ad79 |
- if ((mode & FALLOC_FL_KEEP_SIZE) && errno == EOPNOTSUPP)
|
|
|
05ad79 |
- errx(EXIT_FAILURE,
|
|
|
05ad79 |
- _("keep size mode (-n option) unsupported"));
|
|
|
05ad79 |
- err(EXIT_FAILURE, _("%s: fallocate failed"), fname);
|
|
|
05ad79 |
- }
|
|
|
05ad79 |
+ else
|
|
|
05ad79 |
+ xfallocate(fd, mode, offset, length);
|
|
|
05ad79 |
|
|
|
05ad79 |
close(fd);
|
|
|
05ad79 |
return EXIT_SUCCESS;
|
|
|
05ad79 |
--
|
|
|
05ad79 |
2.14.4
|
|
|
05ad79 |
|