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