[LTP] [PATCH] Use fallocate() to create loop device backing file

Martin Doucha mdoucha@suse.cz
Thu Jul 2 16:15:03 CEST 2020


Creating large loop device backing files using tst_fill_file() on shared
testing machines  may lead to performance issues and timeouts. Preallocating
space using fallocate() is fast and sufficient.

Space allocation will fall back to tst_fill_file() if fallocate() fails for any
other reason than lack of space.

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
 doc/test-writing-guidelines.txt | 20 +++++++++++++++++
 include/tst_fs.h                | 17 ++++++++++++++
 lib/tst_device.c                |  2 +-
 lib/tst_fill_file.c             | 40 +++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/doc/test-writing-guidelines.txt b/doc/test-writing-guidelines.txt
index 6e466ed0f..4e7ee1628 100644
--- a/doc/test-writing-guidelines.txt
+++ b/doc/test-writing-guidelines.txt
@@ -1225,11 +1225,31 @@ Fill a file with specified pattern using file descriptor.
 -------------------------------------------------------------------------------
 #include "tst_test.h"
 
+int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount);
+-------------------------------------------------------------------------------
+
+Preallocate the specified amount of space using 'fallocate()'. Falls back to
+'tst_fill_fd()' if 'fallocate()' fails.
+
+[source,c]
+-------------------------------------------------------------------------------
+#include "tst_test.h"
+
 int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount);
 -------------------------------------------------------------------------------
 
 Creates/overwrites a file with specified pattern using file path.
 
+[source,c]
+-------------------------------------------------------------------------------
+#include "tst_test.h"
+
+int tst_prealloc_file(const char *path, size_t bs, size_t bcount);
+-------------------------------------------------------------------------------
+
+Create/overwrite a file and preallocate the specified amount of space for it.
+The allocated space will not be initialized to any particular content.
+
 2.2.19 Getting an unused PID number
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/include/tst_fs.h b/include/tst_fs.h
index bcef87a40..fc0390582 100644
--- a/include/tst_fs.h
+++ b/include/tst_fs.h
@@ -140,6 +140,15 @@ int tst_get_path(const char *prog_name, char *buf, size_t buf_len);
  */
 int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount);
 
+/*
+ * Preallocate space in open file. If fallocate() fails, falls back to
+ * using tst_fill_fd().
+ * @fd: file descriptor
+ * @bs: block size
+ * @bcount: blocks count
+ */
+int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount);
+
 /*
  * Creates/ovewrites a file with specified pattern
  * @path: path to file
@@ -149,6 +158,14 @@ int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount);
  */
 int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount);
 
+/*
+ * Creates file of specified size. Space will be only preallocated if possible.
+ * @path: path to file
+ * @bs: block size
+ * @bcount: blocks amount
+ */
+int tst_prealloc_file(const char *path, size_t bs, size_t bcount);
+
 #define TST_FS_SKIP_FUSE 0x01
 
 /*
diff --git a/lib/tst_device.c b/lib/tst_device.c
index 67fe90ed6..b46ae722e 100644
--- a/lib/tst_device.c
+++ b/lib/tst_device.c
@@ -232,7 +232,7 @@ const char *tst_acquire_loop_device(unsigned int size, const char *filename)
 {
 	unsigned int acq_dev_size = MAX(size, DEV_SIZE_MB);
 
-	if (tst_fill_file(filename, 0, 1024 * 1024, acq_dev_size)) {
+	if (tst_prealloc_file(filename, 1024 * 1024, acq_dev_size)) {
 		tst_resm(TWARN | TERRNO, "Failed to create %s", filename);
 		return NULL;
 	}
diff --git a/lib/tst_fill_file.c b/lib/tst_fill_file.c
index f2bc52d42..80472007f 100644
--- a/lib/tst_fill_file.c
+++ b/lib/tst_fill_file.c
@@ -19,12 +19,14 @@
  *
  */
 
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include "lapi/fallocate.h"
 
 #include "test.h"
 
@@ -54,6 +56,22 @@ int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount)
 	return 0;
 }
 
+int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount)
+{
+	int ret;
+
+	errno = 0;
+	ret = fallocate(fd, 0, 0, bs * bcount);
+
+	if (ret && errno == ENOSPC)
+		return ret;
+
+	if (ret)
+		ret = tst_fill_fd(fd, 0, bs, bcount);
+
+	return ret;
+}
+
 int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount)
 {
 	int fd;
@@ -76,3 +94,25 @@ int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount)
 
 	return 0;
 }
+
+int tst_prealloc_file(const char *path, size_t bs, size_t bcount)
+{
+	int fd;
+
+	fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
+	if (fd < 0)
+		return -1;
+
+	if (tst_prealloc_size_fd(fd, bs, bcount)) {
+		close(fd);
+		unlink(path);
+		return -1;
+	}
+
+	if (close(fd) < 0) {
+		unlink(path);
+		return -1;
+	}
+
+	return 0;
+}
-- 
2.26.2



More information about the ltp mailing list