From 3c74f736c657d007770fe866842b08d0a74772ca Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Wed, 9 Dec 2020 15:21:11 -0500
Subject: [PATCH 6/6] Issue 4414 - disk monitoring - prevent division by zero
crash
Bug Description: If a disk mount has zero total space or zero used
space then a division by zero can occur and the
server will crash.
It has also been observed that sometimes a system
can return the wrong disk entirely, and when that
happens the incorrect disk also has zero available
space which triggers the disk monitioring thread to
immediately shut the server down.
Fix Description: Check the total and used space for zero and do not
divide, just ignore it. As a preemptive measure
ignore disks from /dev, /proc, /sys (except /dev/shm).
Yes it's a bit hacky, but the true underlying cause
is not known yet. So better to be safe than sorry.
Relates: https://github.com/389ds/389-ds-base/issues/4414
Reviewed by: firstyear(Thanks!)
---
ldap/servers/slapd/daemon.c | 22 +++++++++++++++++++++-
ldap/servers/slapd/monitor.c | 13 +++++--------
2 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 691f77570..bfd965263 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -221,7 +221,27 @@ disk_mon_get_mount_point(char *dir)
}
if (s.st_dev == dev_id) {
endmntent(fp);
- return (slapi_ch_strdup(mnt->mnt_dir));
+
+ if ((strncmp(mnt->mnt_dir, "/dev", 4) == 0 && strncmp(mnt->mnt_dir, "/dev/shm", 8) != 0) ||
+ strncmp(mnt->mnt_dir, "/proc", 4) == 0 ||
+ strncmp(mnt->mnt_dir, "/sys", 4) == 0)
+ {
+ /*
+ * Ignore "mount directories" starting with /dev (except
+ * /dev/shm), /proc, /sys For some reason these mounts are
+ * occasionally/incorrectly returned. Only seen this at a
+ * customer site once. When it happens it causes disk
+ * monitoring to think the server has 0 disk space left, and
+ * it abruptly/unexpectedly shuts the server down. At this
+ * point it looks like a bug in stat(), setmntent(), or
+ * getmntent(), but there is no way to prove that since there
+ * is no way to reproduce the original issue. For now just
+ * return NULL to be safe.
+ */
+ return NULL;
+ } else {
+ return (slapi_ch_strdup(mnt->mnt_dir));
+ }
}
}
endmntent(fp);
diff --git a/ldap/servers/slapd/monitor.c b/ldap/servers/slapd/monitor.c
index 562721bed..65f082986 100644
--- a/ldap/servers/slapd/monitor.c
+++ b/ldap/servers/slapd/monitor.c
@@ -131,7 +131,6 @@ monitor_disk_info (Slapi_PBlock *pb __attribute__((unused)),
{
int32_t rc = LDAP_SUCCESS;
char **dirs = NULL;
- char buf[BUFSIZ];
struct berval val;
struct berval *vals[2];
uint64_t total_space;
@@ -143,15 +142,13 @@ monitor_disk_info (Slapi_PBlock *pb __attribute__((unused)),
disk_mon_get_dirs(&dirs);
- for (uint16_t i = 0; dirs && dirs[i]; i++) {
+ for (size_t i = 0; dirs && dirs[i]; i++) {
+ char buf[BUFSIZ] = {0};
rc = disk_get_info(dirs[i], &total_space, &avail_space, &used_space);
- if (rc) {
- slapi_log_err(SLAPI_LOG_WARNING, "monitor_disk_info",
- "Unable to get 'cn=disk space,cn=monitor' stats for %s\n", dirs[i]);
- } else {
+ if (rc == 0 && total_space > 0 && used_space > 0) {
val.bv_len = snprintf(buf, sizeof(buf),
- "partition=\"%s\" size=\"%" PRIu64 "\" used=\"%" PRIu64 "\" available=\"%" PRIu64 "\" use%%=\"%" PRIu64 "\"",
- dirs[i], total_space, used_space, avail_space, used_space * 100 / total_space);
+ "partition=\"%s\" size=\"%" PRIu64 "\" used=\"%" PRIu64 "\" available=\"%" PRIu64 "\" use%%=\"%" PRIu64 "\"",
+ dirs[i], total_space, used_space, avail_space, used_space * 100 / total_space);
val.bv_val = buf;
attrlist_merge(&e->e_attrs, "dsDisk", vals);
}
--
2.26.2