fallocate: new command

The fallocate(1) utility is used to preallocate blocks to a file.

This can be useful for virtual images, database files, testing, etc.
Normally we'd hope that various tools will start using preallocation
internally, but until then such a utility may be useful, and could be
scripted as well.

The original Eric's version is available at:
http://thread.gmane.org/gmane.linux.utilities.util-linux-ng/2490

This version:
 - checks for fallocate glibc function and kernel syscall
 - does not provide a fallback and does not call posix_fallocate()
 - adds long options
 - uses err.h for errro messages
 - adds NLS support
 - cleanups man page

Co-Author: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2009-08-18 13:33:27 +02:00
parent 34fa5bc8e8
commit d46a54994e
6 changed files with 234 additions and 0 deletions

View File

@ -31,6 +31,7 @@ AUTHORS (merged projects & commands):
simpleinit: Richard Gooch <rgooch@atnf.csiro.au>
switch_root: Peter Jones <pjones@redhat.com>
Jeremy Katz <katzj@redhat.com>
fallocate: Eric Sandeen <sandeen@redhat.com>
CONTRIBUTORS:

View File

@ -558,6 +558,9 @@ UTIL_CHECK_SYSCALL([ioprio_get],
[sh*], [289],
[x86_64*], [252])
dnl fallocate could be available as libc function or as syscall only
UTIL_CHECK_SYSCALL([fallocate])
AC_CHECK_FUNCS([fallocate])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <time.h>

View File

@ -2,6 +2,7 @@ arch
ctrlaltdel
cytune
dmesg
fallocate
flock
i386.8
ia64.8

View File

@ -23,6 +23,11 @@ tunelp_SOURCES = tunelp.c lp.h
info_TEXINFOS = ipc.texi
if HAVE_FALLOCATE
usrbin_exec_PROGRAMS += fallocate
dist_man_MANS += fallocate.1
endif
if HAVE_PIVOT_ROOT
sbin_PROGRAMS += pivot_root
dist_man_MANS += pivot_root.8

51
sys-utils/fallocate.1 Normal file
View File

@ -0,0 +1,51 @@
.\" -*- nroff -*-
.TH FALLOCATE 1 "Jul 2009" "Version 1.0"
.SH NAME
fallocate \- preallocate space to a file.
.SH SYNOPSIS
.B fallocate
.RB [ \-n ]
.RB [ \-o
.IR offset ]
.B \-l
.IR length
.I filename
.SH DESCRIPTION
.B fallocate
is used to preallocate blocks to a file. For filesystems which support the
fallocate system call, this is done quickly by allocating blocks and marking
them as uninitialized, requiring no IO to the data blocks. This is much faster
than creating a file by filling it with zeros.
.PP
As of the Linux Kernel v2.6.31, the fallocate system call is supported by the
btrfs, ext4, ocfs2, and xfs filesystems.
.PP
The exit code returned by
.B fallocate
is 0 on success and 1 on failure.
.PP
.SH OPTIONS
.IP "\fB\-h, \-\-help\fP"
Print help and exit.
.IP "\fB\-n, \-\-keep-size\fP"
Do not modify the apparent length of the file. This may effectively allocate
blocks past EOF, which can be removed with a truncate.
.IP "\fB\-o, \-\-offset\fP \fIoffset\fP
Specifies the beginning offset of the allocation, in bytes. Suffixes of k, m,
g, t, p, e may be specified to denote KiB, MiB, GiB, etc.
.IP "\fB\-l, \-\-length\fP \fIlength\fP
Specifies the length of the allocation, in bytes. Suffixes of k, m, g, t, p, e
may be specified to denote KiB, MiB, GiB, etc.
.SH AUTHORS
.nf
Eric Sandeen <sandeen@redhat.com>
Karel Zak <kzak@redhat.com>
.fi
.SH SEE ALSO
.BR fallocate (2),
.BR posix_fallocate (3),
.BR truncate (1)
.SH AVAILABILITY
The fallocate command is part of the util-linux-ng package and is available from
ftp://ftp.kernel.org/pub/linux/utils/util-linux-ng/.

173
sys-utils/fallocate.c Normal file
View File

@ -0,0 +1,173 @@
/*
* fallocate - utility to use the fallocate system call
*
* Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
* Written by Eric Sandeen <sandeen@redhat.com>
* Karel Zak <kzak@redhat.com>
*
* cvtnum routine taken from xfsprogs,
* Copyright (c) 2003-2005 Silicon Graphics, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <err.h>
#ifndef HAVE_FALLOCATE
# include <sys/syscall.h>
#endif
#include <linux/falloc.h> /* for FALLOC_FL_* flags */
#include "nls.h"
static void __attribute__((__noreturn__)) usage(FILE *out)
{
fprintf(out, _("Usage: %s [options] <filename>\n\nOptions:\n"),
program_invocation_short_name);
fprintf(out, _(
" -h, --help this help\n"
" -n, --keep-size don't modify the length of the file\n"
" -o, --offset <num> offset of the allocation, in bytes\n"
" -l, --length <num> length of the allocation, in bytes\n"));
fprintf(out, _("\nFor more information see fallocate(1).\n"));
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}
#define EXABYTES(x) ((x) << 60)
#define PETABYTES(x) ((x) << 50)
#define TERABYTES(x) ((x) << 40)
#define GIGABYTES(x) ((x) << 30)
#define MEGABYTES(x) ((x) << 20)
#define KILOBYTES(x) ((x) << 10)
static loff_t cvtnum(char *s)
{
loff_t i;
char *sp;
i = strtoll(s, &sp, 0);
if (i == 0 && sp == s)
return -1LL;
if (*sp == '\0')
return i;
if (sp[1] != '\0')
return -1LL;
switch (tolower(*sp)) {
case 'k':
return KILOBYTES(i);
case 'm':
return MEGABYTES(i);
case 'g':
return GIGABYTES(i);
case 't':
return TERABYTES(i);
case 'p':
return PETABYTES(i);
case 'e':
return EXABYTES(i);
}
return -1LL;
}
int main(int argc, char **argv)
{
char *fname;
int c;
int error;
int fd;
int mode = 0;
loff_t length = -2LL;
loff_t offset = 0;
struct option longopts[] = {
{ "help", 0, 0, 'h' },
{ "keep-size", 0, 0, 'n' },
{ "offset", 1, 0, 'o' },
{ "lenght", 1, 0, 'l' },
{ NULL, 0, 0, 0 }
};
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
while ((c = getopt_long(argc, argv, "hnl:o:", longopts, NULL)) != -1) {
switch(c) {
case 'h':
usage(stdout);
break;
case 'n':
mode |= FALLOC_FL_KEEP_SIZE;
break;
case 'l':
length = cvtnum(optarg);
break;
case 'o':
offset = cvtnum(optarg);
break;
default:
usage(stderr);
break;
}
}
if (length == -2LL)
errx(EXIT_FAILURE, _("no length argument specified"));
if (length <= 0)
errx(EXIT_FAILURE, _("invalid length value specified"));
if (offset < 0)
errx(EXIT_FAILURE, _("invalid offset value specified"));
if (optind == argc)
errx(EXIT_FAILURE, _("no filename specified."));
fname = argv[optind++];
fd = open(fname, O_WRONLY|O_CREAT, 0644);
if (fd < 0)
err(EXIT_FAILURE, _("%s: open failed"), fname);
#ifdef HAVE_FALLOCATE
error = fallocate(fd, mode, offset, length);
#else
error = syscall(SYS_fallocate, fd, mode, offset, length);
#endif
/*
* EOPNOTSUPP: The FALLOC_FL_KEEP_SIZE is unsupported
* ENOSYS: The filesystem does not support sys_fallocate
*/
if (error < 0) {
if ((mode & FALLOC_FL_KEEP_SIZE) && errno == EOPNOTSUPP)
errx(EXIT_FAILURE,
_("keep size mode (-n option) unsupported"));
err(EXIT_FAILURE, _("%s: fallocate failed"), fname);
}
close(fd);
return EXIT_SUCCESS;
}