summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-09-16 03:40:14 +0200
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-09-16 13:52:36 +0200
commitf6c13f9f9506a90f52b2cd76929c5e8e028183b9 (patch)
treec9b62c1dc0272ea89999aea436378ccd70dbf31f
parentuid-range: escape from loop earlier (diff)
downloadsystemd-f6c13f9f9506a90f52b2cd76929c5e8e028183b9.tar.xz
systemd-f6c13f9f9506a90f52b2cd76929c5e8e028183b9.zip
uid-range: optimize to load uid_map file
If uid_map contains many lines, then the previous logic takes O(n^2 log n), This makes O(n log n).
-rw-r--r--src/basic/uid-range.c58
-rw-r--r--src/basic/uid-range.h5
2 files changed, 27 insertions, 36 deletions
diff --git a/src/basic/uid-range.c b/src/basic/uid-range.c
index 73dd4b2892..8e68e0464c 100644
--- a/src/basic/uid-range.c
+++ b/src/basic/uid-range.c
@@ -69,10 +69,7 @@ static void uid_range_coalesce(UidRange **p, size_t *n) {
}
}
-int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
- bool found = false;
- UidRange *x;
-
+int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce) {
assert(p);
assert(n);
@@ -82,37 +79,16 @@ int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
if (start > UINT32_MAX - nr) /* overflow check */
return -ERANGE;
- for (size_t i = 0; i < *n; i++) {
- x = (*p) + i;
- if (uid_range_intersect(x, start, nr)) {
- found = true;
- break;
- }
- }
-
- if (found) {
- uid_t begin, end;
-
- begin = MIN(x->start, start);
- end = MAX(x->start + x->nr, start + nr);
+ if (!GREEDY_REALLOC(*p, *n + 1))
+ return -ENOMEM;
- x->start = begin;
- x->nr = end - begin;
- } else {
- UidRange *t;
+ (*p)[(*n)++] = (UidRange) {
+ .start = start,
+ .nr = nr,
+ };
- t = reallocarray(*p, *n + 1, sizeof(UidRange));
- if (!t)
- return -ENOMEM;
-
- *p = t;
- x = t + ((*n) ++);
-
- x->start = start;
- x->nr = nr;
- }
-
- uid_range_coalesce(p, n);
+ if (coalesce)
+ uid_range_coalesce(p, n);
return *n;
}
@@ -182,7 +158,9 @@ bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr) {
}
int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
+ _cleanup_free_ UidRange *q = NULL;
_cleanup_fclose_ FILE *f = NULL;
+ size_t m = 0;
int r;
/* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
@@ -191,6 +169,9 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
*
* To simplify things this will modify the passed array in case of later failure. */
+ assert(p);
+ assert(n);
+
if (!path)
path = "/proc/self/uid_map";
@@ -214,13 +195,20 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
if (ferror(f))
return errno_or_else(EIO);
- return 0;
+ break;
}
if (k != 3)
return -EBADMSG;
- r = uid_range_add(p, n, uid_base, uid_range);
+ r = uid_range_add_internal(&q, &m, uid_base, uid_range, /* coalesce = */ false);
if (r < 0)
return r;
}
+
+ uid_range_coalesce(&q, &m);
+
+ *p = TAKE_PTR(q);
+ *n = m;
+
+ return 0;
}
diff --git a/src/basic/uid-range.h b/src/basic/uid-range.h
index 7259c9e371..7e238409d1 100644
--- a/src/basic/uid-range.h
+++ b/src/basic/uid-range.h
@@ -8,7 +8,10 @@ typedef struct UidRange {
uid_t start, nr;
} UidRange;
-int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr);
+int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce);
+static inline int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
+ return uid_range_add_internal(p, n, start, nr, true);
+}
int uid_range_add_str(UidRange **p, size_t *n, const char *s);
int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);