[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] New fallocate module
From: |
Pádraig Brady |
Subject: |
Re: [PATCH] New fallocate module |
Date: |
Wed, 27 May 2009 17:20:31 +0100 |
User-agent: |
Thunderbird 2.0.0.6 (X11/20071008) |
Take 2 attached.
Still outstanding from the gnulib portion is support for solaris.
I may get time to set this up, but I've very little time lately,
so I would like not to require this for merging.
Also I didn't yet implement the optimization to coreutils
that Paul mentioned, to cache whether the filesystem will
just return ENOSYS all the time.
cheers,
Pádraig.
>From bd55931dd6286ff952fdcadd25d0bef263be4de2 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?P=C3=A1draig=20Brady?= <address@hidden>
Date: Thu, 21 May 2009 08:03:00 +0100
Subject: [PATCH] fallocate: New module to ensure this interface is available
fallocate() allows one to associate a unit of space
with a (portion of a) file before writing. This info can
then be used to immediately determine if enough space is available,
and also allow efficient allocation on the storage device.
* m4/fallocate.m4: check we can link to fallocate()
* lib/fcntl.in.h: replacement stub if missing
* modules/fallocate: dependencies for new module
* MODULES.html.sh (File system functions): add it
---
MODULES.html.sh | 1 +
lib/fcntl.in.h | 17 +++++++++++++++++
m4/fallocate.m4 | 26 ++++++++++++++++++++++++++
modules/fallocate | 23 +++++++++++++++++++++++
4 files changed, 67 insertions(+), 0 deletions(-)
create mode 100644 m4/fallocate.m4
create mode 100644 modules/fallocate
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 06afa2d..6a1e058 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2438,6 +2438,7 @@ func_all_modules ()
func_module dirfd
func_module double-slash-root
func_module euidaccess
+ func_module fallocate
func_module file-type
func_module fileblocks
func_module filemode
diff --git a/lib/fcntl.in.h b/lib/fcntl.in.h
index fd7520e..709db88 100644
--- a/lib/fcntl.in.h
+++ b/lib/fcntl.in.h
@@ -63,6 +63,23 @@ extern int open (const char *filename, int flags, ...);
extern void _gl_register_fd (int fd, const char *filename);
#endif
+#ifdef REPLACE_FALLOCATE
+# undef fallocate
+# define fallocate rpl_fallocate
+#include <sys/types.h>
+#include <errno.h>
+#undef FALLOC_FL_KEEP_SIZE /* Ensure this name is available. */
+#define FALLOC_FL_KEEP_SIZE 0x01
+static inline int fallocate (int fd, int mode, off_t offset, off_t len)
+{
+ /* This is a valid replacement for missing glibc fallocate(),
+ because code calling fallocate() must also handle this error
+ in the case that the kernel or filesystem don't support this. */
+ return ENOSYS;
+ /* FIXME: support fcntl(fd, F_ALLOCSP, ...) on solaris. */
+}
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/m4/fallocate.m4 b/m4/fallocate.m4
new file mode 100644
index 0000000..b218253
--- /dev/null
+++ b/m4/fallocate.m4
@@ -0,0 +1,26 @@
+# fallocate.m4 serial 1
+dnl Copyright (C) 2009 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_FALLOCATE],
+[
+ AC_CHECK_HEADERS_ONCE([linux/falloc.h])
+
+ dnl Persuade glibc <fcntl.h> to declare fallocate().
+ AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+ AC_CACHE_CHECK([for fallocate], [gl_cv_func_fallocate], [
+ AC_TRY_LINK([#include <fcntl.h> /* fallocate() declaration */
+ #include <linux/falloc.h> /* FALLOC_FL_KEEP_SIZE define */],
+ [fallocate(-1, FALLOC_FL_KEEP_SIZE, 0, 0);],
+ gl_cv_func_fallocate=yes, gl_cv_func_fallocate=no)])
+
+ if test $gl_cv_func_fallocate = yes; then
+ AC_DEFINE([HAVE_FALLOCATE], [1], [Defined if fallocate() exists])
+ else
+ AC_REQUIRE([AC_C_INLINE])
+ AC_DEFINE([REPLACE_FALLOCATE], [1], [Include replacement])
+ fi
+])
diff --git a/modules/fallocate b/modules/fallocate
new file mode 100644
index 0000000..bbcb5db
--- /dev/null
+++ b/modules/fallocate
@@ -0,0 +1,23 @@
+Description:
+Ensure fallocate() is available
+
+Files:
+m4/fallocate.m4
+
+Depends-on:
+errno
+extensions
+fcntl
+
+configure.ac:
+gl_FUNC_FALLOCATE
+
+Makefile.am:
+
+Include:
+
+License:
+LGPL
+
+Maintainer:
+Pádraig Brady
--
1.5.3.6
>From 7202ea62e6f6358931c50327df4a7b70b84332b7 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?P=C3=A1draig=20Brady?= <address@hidden>
Date: Mon, 18 May 2009 08:38:18 +0100
Subject: [PATCH] cp,mv,install: Try to fallocate() the destination file
This will allocate the file efficiently and also
give immediate indication of insufficient space for the copy.
* bootstrap.conf: include fallocate module from gnulib.
* src/copy.c (copy_reg): call fallocate() for non sparse files.
* NEWS: mention the change.
---
NEWS | 6 ++++++
bootstrap.conf | 1 +
src/copy.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 62 insertions(+), 1 deletions(-)
diff --git a/NEWS b/NEWS
index 31f1b1a..80bc22b 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,12 @@ GNU coreutils NEWS -*-
outline -*-
truncate -s failed to skip all whitespace in the option argument in
some locales.
+** Changes in behavior
+
+ cp, install, mv: now try to allocate the destination file as an extent.
+ This will give immediate feedback if there is not enough space for the
+ copy, and allow more efficient layout of the file on the storage device.
+
* Noteworthy changes in release 7.4 (2009-05-07) [stable]
** Bug fixes
diff --git a/bootstrap.conf b/bootstrap.conf
index d34e908..d044b7e 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -79,6 +79,7 @@ gnulib_modules="
euidaccess
exclude
exitfail
+ fallocate
fchdir
fcntl
fcntl-safer
diff --git a/src/copy.c b/src/copy.c
index 511f705..eb00fac 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -54,6 +54,10 @@
#include "areadlink.h"
#include "yesno.h"
+#if HAVE_LINUX_FALLOC_H
+#include <linux/falloc.h>
+#endif
+
#if USE_XATTR
# include <attr/error_context.h>
# include <attr/libattr.h>
@@ -603,6 +607,9 @@ copy_reg (char const *src_name, char const *dst_name,
bool last_write_made_hole = false;
bool make_holes = false;
+ /* Size to fallocate. */
+ off_t alloc_size = 0;
+
if (S_ISREG (sb.st_mode))
{
/* Even with --sparse=always, try to create holes only
@@ -615,10 +622,41 @@ copy_reg (char const *src_name, char const *dst_name,
blocks. If the file has fewer blocks than would normally be
needed for a file of its size, then at least one of the blocks in
the file is a hole. */
- if (x->sparse_mode == SPARSE_AUTO && S_ISREG (src_open_sb.st_mode)
+ else if (x->sparse_mode == SPARSE_AUTO && S_ISREG (src_open_sb.st_mode)
&& ST_NBLOCKS (src_open_sb) < src_open_sb.st_size / ST_NBLOCKSIZE)
make_holes = true;
#endif
+
+ /* If not making a sparse file, try to fallocate() the destination.
+ I.E. tell the system that this amount of space should be treated
+ as a unit. This will allow the system to inform us immediately
+ if there is not enough space available. The info can also be used
+ to lay out the blocks more efficiently on the storage device. */
+ else
+ {
+ /* Get the maximum space needed for a file.
+ If the current st_blocks is smaller than size, then
+ sparse_mode must be SPARSE_NEVER, so we allocate the full
+ st_size. If the allocation is larger than size due to
+ a previous fallocate call, then we maintain this allocation. */
+ alloc_size = src_open_sb.st_size;
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+ alloc_size = MAX (ST_NBLOCKS (src_open_sb) * ST_NBLOCKSIZE,
+ alloc_size);
+#endif
+ /* FIXME: Should we use ioctl(BLKGETSIZE64) on block devices? */
+
+ /* FALLOC_FL_KEEP_SIZE means st_size is not updated. */
+ int err = fallocate (dest_desc, FALLOC_FL_KEEP_SIZE, 0, alloc_size);
+ if (err != 0)
+ alloc_size = 0; /* reset for truncation test later on. */
+ if (err != ENOTSUP && err != ENOSYS)
+ {
+ error (0, err, _("allocating %s"), quote (dst_name));
+ return_val = false;
+ goto close_src_and_dst_desc;
+ }
+ }
}
/* If not making a sparse file, try to use a more-efficient
@@ -753,6 +791,22 @@ copy_reg (char const *src_name, char const *dst_name,
goto close_src_and_dst_desc;
}
}
+
+ /* If we fallocated space for the destination, check that
+ we were able to copy at least st_size bytes. Otherwise
+ the source was probably truncated, so we'll truncate
+ the destination to match. */
+
+ if (alloc_size && n_read_total < src_open_sb.st_size)
+ {
+ /* Assume we have ftruncate() if we have fallocate() */
+ if (ftruncate (dest_desc, n_read_total) < 0)
+ {
+ error (0, errno, _("truncating %s"), quote (dst_name));
+ return_val = false;
+ goto close_src_and_dst_desc;
+ }
+ }
}
if (x->preserve_timestamps)
--
1.5.3.6