From 8ee8fbefe0fb9861ce7a0dc6669826cb9cfe46d9 Mon Sep 17 00:00:00 2001
From: Conrad Lara - KG6JEI
Date: Thu, 12 Jan 2017 11:47:03 -0800
Subject: [PATCH] bugfix: Increase available memory during upgrade/install
process
It is possible for the system to run out of memory when dealing
with large file uploads and installs.
As part of the upgrade procedure shutdown services that are not
essential for node operations to allow more memory for install
to take place.
Includes changes to linkled to indicate this new state as it will
be shutdown as part of the cleanup process.
Memory gain (approximate)
dropbear 100kb
linkled 200kb
logd 200kb
odhcp 100kb
snmpd 500kb
xinetd 100kb
Total(approximate): 1200kb (around %4 on 32mb devices)
This is somewhat similar to files/usr/local/bin/upgrade_kill_prep
except that it kills only a select group of services
so that the system can handle the file upload while
upgrade_kill_prep does the final system cleanup to run the full
upgrade.
ref AREDN->ticket:204
Change-Id: Ic6d3aa028725064a97c4723f6d9b36e1e51d87a7
---
files/etc/crontabs.upgrademode/root | 3 ++
files/usr/local/bin/linkled | 53 +++++++++++++++----
files/usr/local/bin/uploadctlservices | 73 +++++++++++++++++++++++++++
files/www/cgi-bin/admin | 21 ++++++++
files/www/cgi-bin/perlfunc.pm | 4 +-
files/www/help.html | 7 +++
6 files changed, 149 insertions(+), 12 deletions(-)
create mode 100644 files/etc/crontabs.upgrademode/root
create mode 100755 files/usr/local/bin/uploadctlservices
diff --git a/files/etc/crontabs.upgrademode/root b/files/etc/crontabs.upgrademode/root
new file mode 100644
index 00000000..a2b4b396
--- /dev/null
+++ b/files/etc/crontabs.upgrademode/root
@@ -0,0 +1,3 @@
+*/5 * * * * /usr/local/bin/fccid
+* * * * * /usr/local/bin/rssi_monitor
+
diff --git a/files/usr/local/bin/linkled b/files/usr/local/bin/linkled
index 7d3c4bad..b1bf668f 100755
--- a/files/usr/local/bin/linkled
+++ b/files/usr/local/bin/linkled
@@ -30,13 +30,46 @@ case "$BOARD_TYPE" in
esac
-{
- while true; do
- sleep 5;
- if echo /neighbors | nc 127.0.0.1 2006 2>/dev/null | grep -q YES; then
- echo 1 > "$LINK1LED/brightness"
- else
- echo 0 > "$LINK1LED/brightness"
- fi
- done;
-} &
+firmware_upgrade_mode() {
+ # Put the LED in "upgrade" mode
+ echo timer > "$LINK1LED/trigger"
+ echo 100 > "$LINK1LED/delay_on"
+ echo 100 > "$LINK1LED/delay_off"
+ echo 1 > "$LINK1LED/brightness"
+
+}
+
+
+reset_led() {
+ # Reset the LED to a blank state
+ echo none > "$LINK1LED/trigger"
+ echo 0 > "$LINK1LED/brightness"
+}
+
+
+link_state() {
+ {
+ reset_led
+
+ while true; do
+ sleep 5;
+ if echo /neighbors | nc 127.0.0.1 2006 2>/dev/null | grep -q YES; then
+ echo 1 > "$LINK1LED/brightness"
+ else
+ echo 0 > "$LINK1LED/brightness"
+ fi
+ done;
+ } & # Push into the background
+}
+
+case $1 in
+ "upgrade" )
+ firmware_upgrade_mode
+ ;;
+ "restore" )
+ reset_led
+ ;;
+ *)
+ link_state
+ ;;
+esac
diff --git a/files/usr/local/bin/uploadctlservices b/files/usr/local/bin/uploadctlservices
new file mode 100755
index 00000000..d3cc7bc0
--- /dev/null
+++ b/files/usr/local/bin/uploadctlservices
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Alphabetical except where noted below
+# log needs to start before cron (and maybe others) to be detected for logging.
+serviceslist="log cron dropbear linkled odhcpd snmpd vtund vtundsrv xinetd"
+
+start_upgrade_mode() {
+
+ touch /tmp/.upgrade_mode
+
+ # drop the page cache to take pressure of tmps when uploading file
+ echo 3 > /proc/sys/vm/drop_caches
+
+ #Kill processes
+
+ for name in $serviceslist
+ do
+ "/etc/init.d/${name}" stop
+ done
+
+ # Switch to a limited crontab list
+ /usr/sbin/crond -b -c /etc/crontabs.upgrademode -l 5
+
+ # Some services need to kill the last remaining processes
+ killall -9 dropbear
+
+ # Put the LED in "upgrade" mode
+ /usr/local/bin/linkled upgrade
+
+ # Purge the /tmp/ filesystem of unneeded files.
+ rm -Rf /tmp/node.history /tmp/olsrd.log /tmp/olsrd.watchdog /tmp/snrlog/ /tmp/snr.dat /tmp/web/firmware.list /tmp/.uci
+
+}
+
+remove_opkg_lists() {
+ rm -Rf /tmp/opkg-lists/
+}
+
+return_to_operating_mode() {
+
+ killall -9 crond
+
+ # If anything goes wrong after this point return the error code to the calling process
+ # as we could be in an unstable state.
+ set -e
+
+ # Start up the services we stopped
+ for name in $serviceslist
+ do
+ "/etc/init.d/${name}" start
+ done
+
+ rm /tmp/.upgrade_mode
+
+}
+
+
+case $1 in
+ "upgrade" )
+ start_upgrade_mode
+ remove_opkg_lists
+ ;;
+ "opkginstall" )
+ start_upgrade_mode
+ ;;
+ "restore" )
+ return_to_operating_mode
+ ;;
+ *)
+ echo "This program is not intended to be called by users."
+ ;;
+esac
+
diff --git a/files/www/cgi-bin/admin b/files/www/cgi-bin/admin
index 37587363..9ee2806d 100755
--- a/files/www/cgi-bin/admin
+++ b/files/www/cgi-bin/admin
@@ -152,6 +152,8 @@ if($parms{button_ul_fw} and -f "/tmp/web/upload/file")
push @fw_output, "Firmware CANNOT be updated\n";
push @fw_output, "firmware file is not valid\n";
$fw_install = 0;
+ unlink("$tmpdir/firmware");
+ system("/usr/local/bin/uploadctlservices","restore") and push @fw_output, "Failed to restart all services, please reboot this node.\n";
}
}
elsif($parms{firmfile} =~ /^patch\S+\.tgz$/) # firmware patch
@@ -162,6 +164,8 @@ if($parms{button_ul_fw} and -f "/tmp/web/upload/file")
{
push @fw_output, "Firmware CANNOT be updated\n";
push @fw_output, "the uploaded file is not recognized\n";
+ unlink("$tmpdir/firmware");
+ system("/usr/local/bin/uploadctlservices","restore") and push @fw_output, "Failed to restart all services, please reboot this node.\n";
}
}
@@ -171,6 +175,7 @@ if($parms{button_dl_fw} and $parms{dl_fw} ne "default")
if(get_default_gw() ne "none")
{
unlink "$tmpdir/firmware";
+ system("/usr/local/bin/uploadctlservices","upgrade");
$ok = 0;
foreach $serverpath (@serverpaths)
{
@@ -196,6 +201,8 @@ if($parms{button_dl_fw} and $parms{dl_fw} ne "default")
push @fw_output, "Firmware CANNOT be updated\n";
push @fw_output, "firmware file is not valid\n";
$fw_install = 0;
+ unlink("$tmpdir/firmware");
+ system("/usr/local/bin/uploadctlservices","restore") and push @fw_output, "Failed to restart all services, please reboot this node.\n";
}
}
elsif($parms{dl_fw} =~ /^patch\S+\.tgz$/) # firmware patch
@@ -216,12 +223,16 @@ if($parms{button_dl_fw} and $parms{dl_fw} ne "default")
push @fw_output, "Firmware CANNOT be updated\n";
push @fw_output, "patch file is not valid\n";
$patch_install = 0;
+ unlink("$tmpdir/firmware");
+ system("/usr/local/bin/uploadctlservices","restore") and push @fw_output, "Failed to restart all services, please reboot this node.\n";
}
}
else
{
push @fw_output, "Firmware CANNOT be updated\n";
push @fw_output, "the downloaded file is not recognized\n";
+ unlink("$tmpdir/firmware");
+ system("/usr/local/bin/uploadctlservices","restore") and push @fw_output, "Failed to restart all services, please reboot this node.\n";
}
}
else
@@ -388,6 +399,10 @@ if($patch_install and -f "$tmpdir/firmware")
push(@fw_output, `cat $tmpdir/patch.out`) if $parms{dev};
push @fw_output, "Done.\n";
}
+
+ unlink("$tmpdir/firmware");
+ system("/usr/local/bin/uploadctlservices","restore") and push @fw_output, "Failed to restart all services, please reboot this node.\n";
+
}
@@ -411,6 +426,8 @@ if($parms{button_ul_pkg} and -f "/tmp/web/upload/file")
system "mv -f /tmp/web/upload/file /tmp/web/upload/newpkg.ipk";
push @pkg_output, `opkg -force-overwrite install /tmp/web/upload/newpkg.ipk 2>&1`;
system "rm -rf /tmp/opkg-*";
+ unlink("/tmp/web/upload/newpkg.ipk");
+ system("/usr/local/bin/uploadctlservices","restore") and push @pkg_output, "Failed to restart all services, please reboot this node.\n";
}
# download package
@@ -418,7 +435,9 @@ if($parms{button_dl_pkg} and $parms{dl_pkg} ne "default")
{
if(get_default_gw() ne "none")
{
+ system("/usr/local/bin/uploadctlservices","opkginstall");
push @pkg_output, `opkg -force-overwrite install $parms{dl_pkg} 2>&1`;
+ system("/usr/local/bin/uploadctlservices","restore") and push @pkg_output, "Failed to restart all services, please reboot this node.\n";
}
else
{
@@ -490,6 +509,8 @@ if($parms{button_ul_key} and -f "/tmp/web/upload/file")
{
push @key_output, "Key installed.\n";
}
+ unlink("/tmp/web/upload/file");
+ system("/usr/local/bin/uploadctlservices","restore") and push @key_output, "Failed to restart all services, please reboot this node.\n";
}
# remove key
diff --git a/files/www/cgi-bin/perlfunc.pm b/files/www/cgi-bin/perlfunc.pm
index 305c0552..33793bb4 100644
--- a/files/www/cgi-bin/perlfunc.pm
+++ b/files/www/cgi-bin/perlfunc.pm
@@ -212,8 +212,8 @@ sub read_postdata
$line = fgets(10);
push(@parse_errors, "not blank: '$line'") unless $line eq "\r\n";
$tmp = "";
- # drop the page cache to take pressure of tmps when uploading file
- `echo 3 > /proc/sys/vm/drop_caches`;
+ # Put us in upgrade mode (purge files, shutdown services)
+ system("/usr/local/bin/uploadctlservices","upgrade");
system "mkdir -p /tmp/web/upload";
open($handle, ">/tmp/web/upload/file");
while(1)
diff --git a/files/www/help.html b/files/www/help.html
index e1704982..cfe75cf0 100644
--- a/files/www/help.html
+++ b/files/www/help.html
@@ -681,6 +681,13 @@ for download, but don't do this frivolously. The package information database
gets stored locally and will use about 100KB of space in flash memory. The
average user will probably never have to use this function.
+
+
+NOTE: When uploading any file (Firmware, Patch, or Package) a node operating
+as a tunnel client or server will shutdown the tunnels before accepting the
+file for upload. If your connection path to the node being updated requires
+you to connect via a tunnel on the node the upload will not succeed.
+
The Remove Package list shows all packages on the
node. Selecting a package and clicking Remove will remove