summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-03-25 12:10:32 +0100
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-03-26 15:53:50 +0100
commita9899ff3588801b825322d40564b271c7216fe46 (patch)
tree59f03b231fe7b7b6ae871b00f25a7b085ae846a3
parentca79564309e87f1cd92f7c79a03fccb792cca274 (diff)
downloadsystemd-a9899ff3588801b825322d40564b271c7216fe46.tar.gz
basic/fileio: optimize buffer sizes in read_full_virtual_file()
We'd proceed rather inefficiently: the initial buffer size was LINE_MAX/2, i.e. only 1k. We can read 4k at the same cost. Also, we'd try to allocate 1025, 2049, 4097 bytes, i.e. always one higher than the power-of-two size. Effectively the allocation would be bigger, and we'd waste the additional space. So let's allocate aligned to the power-of-two size. size=4095, 8191, 16383, so we allocate 4k, 8k, 16k.
-rw-r--r--src/basic/fileio.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 46ab5db79f..7c370d4fc3 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -27,7 +27,8 @@
#include "string-util.h"
#include "tmpfile-util.h"
-#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
+/* The maximum size of the file we'll read in one go. */
+#define READ_FULL_BYTES_MAX (4U*1024U*1024U - 1)
int fopen_unlocked(const char *path, const char *options, FILE **ret) {
assert(ret);
@@ -386,8 +387,10 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
/* Start size for files in /proc/ which usually report a file size of 0. (Files in /sys/ report a
* file size of 4K, which is probably OK for sizing our initial buffer, and sysfs attributes can't be
- * larger anyway.) */
- size = LINE_MAX / 2;
+ * larger anyway.)
+ *
+ * It's one less than 4k, so that the malloc() below allocates exactly 4k. */
+ size = 4095;
/* Limit the number of attempts to read the number of bytes returned by fstat(). */
n_retries = 3;
@@ -414,10 +417,10 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
/* Double the buffer size */
if (size >= READ_FULL_BYTES_MAX)
return -E2BIG;
- if (size > READ_FULL_BYTES_MAX / 2)
+ if (size > READ_FULL_BYTES_MAX / 2 - 1)
size = READ_FULL_BYTES_MAX; /* clamp to max */
else
- size *= 2;
+ size = size * 2 + 1; /* Stay always one less than page size, so we malloc evenly */
}
buf = malloc(size + 1);
@@ -466,16 +469,13 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
buf = TAKE_PTR(p);
}
- if (!ret_size) {
- /* Safety check: if the caller doesn't want to know the size of what we
- * just read it will rely on the trailing NUL byte. But if there's an
- * embedded NUL byte, then we should refuse operation as otherwise
- * there'd be ambiguity about what we just read. */
-
- if (memchr(buf, 0, n))
- return -EBADMSG;
- } else
+ if (ret_size)
*ret_size = n;
+ else if (memchr(buf, 0, n))
+ /* Safety check: if the caller doesn't want to know the size of what we just read it will
+ * rely on the trailing NUL byte. But if there's an embedded NUL byte, then we should refuse
+ * operation as otherwise there'd be ambiguity about what we just read. */
+ return -EBADMSG;
buf[n] = 0;
*ret_contents = TAKE_PTR(buf);