summaryrefslogtreecommitdiffstats
path: root/sys-utils/fallocate.c
diff options
context:
space:
mode:
authorKarel Zak2014-02-19 10:48:16 +0100
committerKarel Zak2014-02-19 10:48:16 +0100
commitc4172cc3bb1702b7d4fc929877990753f3252a99 (patch)
tree18ab34604813c2cdf939380440817fc8e3642477 /sys-utils/fallocate.c
parentfallocate: use POSIX_FADV_DONTNEED to discard cached data (diff)
downloadkernel-qcow2-util-linux-c4172cc3bb1702b7d4fc929877990753f3252a99.tar.gz
kernel-qcow2-util-linux-c4172cc3bb1702b7d4fc929877990753f3252a99.tar.xz
kernel-qcow2-util-linux-c4172cc3bb1702b7d4fc929877990753f3252a99.zip
fallocate: code optimalizations
Based on Pádraig Brady review: * use is_nul() from coreutils rather then memcmp() * always call skip_hole() (SEEK_DATA) * fix possible overflows Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/fallocate.c')
-rw-r--r--sys-utils/fallocate.c47
1 files changed, 29 insertions, 18 deletions
diff --git a/sys-utils/fallocate.c b/sys-utils/fallocate.c
index a2545039e..e6dac1993 100644
--- a/sys-utils/fallocate.c
+++ b/sys-utils/fallocate.c
@@ -130,6 +130,27 @@ static int skip_hole(int fd, off_t *off)
return -1; /* no hole */
}
+static int is_nul(void const *buf, size_t bufsize)
+{
+ typedef uintptr_t word;
+ void const *vp;
+ char const *cbuf = buf, *cp;
+ word const *wp = buf;
+
+ /* Find first nonzero *word*, or the word with the sentinel. */
+ while (*wp++ == 0)
+ continue;
+
+ /* Find the first nonzero *byte*, or the sentinel. */
+ vp = wp - 1;
+ cp = vp;
+
+ while (*cp++ == 0)
+ continue;
+
+ return cbuf + bufsize < cp;
+}
+
static void dig_holes(int fd, off_t off, off_t len)
{
off_t end = len ? off + len : 0;
@@ -137,9 +158,8 @@ static void dig_holes(int fd, off_t off, off_t len)
off_t cache_start = 0;
uintmax_t ct = 0;
size_t bufsz, cachesz;
- char *buf, *empty;
+ char *buf;
struct stat st;
- int sparse = 0;
if (fstat(fd, &st) != 0)
err(EXIT_FAILURE, _("stat failed %s"), filename);
@@ -156,16 +176,10 @@ static void dig_holes(int fd, off_t off, off_t len)
*/
cachesz = getpagesize() * 256;
- if (st.st_blocks * 512 < st.st_size) {
- if (verbose)
- fprintf(stdout, _("%s: already has holes.\n"), filename);
- sparse = 1;
- }
if (lseek(fd, off, SEEK_SET) < 0)
err(EXIT_FAILURE, _("seek on %s failed"), filename);
buf = xmalloc(bufsz);
- empty = xcalloc(1, bufsz);
cache_start = off;
#if defined(POSIX_FADV_SEQUENTIAL) && defined(HAVE_POSIX_FADVISE)
@@ -178,20 +192,18 @@ static void dig_holes(int fd, off_t off, off_t len)
rsz = pread(fd, buf, bufsz, off);
if (rsz < 0 && errno)
err(EXIT_FAILURE, _("%s: read failed"), filename);
- if (end && rsz > 0 && off + rsz > end)
+ if (end && rsz > 0 && off > end - rsz)
rsz = end - off;
if (rsz <= 0)
break;
- if (memcmp(buf, empty, rsz) == 0) {
+ if (is_nul(buf, rsz)) {
if (!hole_sz) { /* new hole detected */
- if (sparse) {
- int rc = skip_hole(fd, &off);
- if (rc == 0)
- continue; /* hole skipped */
- else if (rc == 1)
- break; /* end of file */
- }
+ int rc = skip_hole(fd, &off);
+ if (rc == 0)
+ continue; /* hole skipped */
+ else if (rc == 1)
+ break; /* end of file */
hole_start = off;
}
hole_sz += rsz;
@@ -222,7 +234,6 @@ static void dig_holes(int fd, off_t off, off_t len)
}
free(buf);
- free(empty);
if (verbose) {
char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE, ct);