diff --git a/patches/lede/0012-procd-update-to-git-HEAD-version.patch b/patches/lede/0012-procd-update-to-git-HEAD-version.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c9c08fd9dc22509c41573ba1ea344c3190ca6e34
--- /dev/null
+++ b/patches/lede/0012-procd-update-to-git-HEAD-version.patch
@@ -0,0 +1,26 @@
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Mon, 6 Mar 2017 17:25:44 +0100
+Subject: procd: update to git HEAD version
+
+8f218f5 procd: service gets deleted when its last instance is freed
+35209a0 procd: update modprobe path
+
+Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index fd1bca3f4b9665581f9e9ddd9b9294fa500a9d3d..43ea23aab00918a2b664e9a5da7767f90cd568db 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -12,9 +12,9 @@ PKG_RELEASE:=1
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git
+-PKG_SOURCE_DATE:=2017-02-15
+-PKG_SOURCE_VERSION:=5f9124103410c178d816bb5229fba7dd2286a49b
+-PKG_MIRROR_HASH:=ec887b349fc60ad3882fc9eaefb5cd299d64e7d43c062df9f7b7500591ba3e85
++PKG_SOURCE_DATE:=2017-03-05
++PKG_SOURCE_VERSION:=8f218f5626a3cb3900dbe9801ee8ace236b0e4a5
++PKG_MIRROR_HASH:=8ac8691888b64726453bd726fe0c98fc906540bbd2ae666dae6bea592b0b4e4d
+ CMAKE_INSTALL:=1
+ 
+ PKG_LICENSE:=GPL-2.0
diff --git a/patches/lede/0013-sunxi-clean-up-modules-definitions.patch b/patches/lede/0013-sunxi-clean-up-modules-definitions.patch
new file mode 100644
index 0000000000000000000000000000000000000000..175dda66136d9a29e3100eb49f75be0be50c361c
--- /dev/null
+++ b/patches/lede/0013-sunxi-clean-up-modules-definitions.patch
@@ -0,0 +1,128 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Thu, 4 May 2017 07:00:06 +0200
+Subject: sunxi: clean up modules definitions
+
+Module definitions for kmod-wdt-sunxi and kmod-eeprom-sunxi are removed
+(wdt-sunxi was builtin anyways; nvmem-sunxi, which is the new name of
+eeprom-sunxi is changed to builtin). As kmod-eeprom-sunxi was specified
+in DEFAULT_PACKAGES, but not available on kernel 4.4, it was breaking the
+image builder.
+
+Support for kmod-sunxi-ir is added for kernel 4.4 (it is unclear why it
+was disable before, it builds fine with with kernel 4.4).
+
+Condtionals only relevant for pre-4.4 kernels are removed from modules.mk,
+as sunxi does't support older kernels anymore.
+
+Fixes FS#755.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/sunxi/Makefile b/target/linux/sunxi/Makefile
+index b0bc1bab398af55b77909deccd8f059e17d96e67..3c2f14b8418e1d296a239027f6fdee9b5ba8f9b2 100644
+--- a/target/linux/sunxi/Makefile
++++ b/target/linux/sunxi/Makefile
+@@ -27,7 +27,7 @@ KERNELNAME:=zImage dtbs
+ 
+ include $(INCLUDE_DIR)/target.mk
+ 
+-DEFAULT_PACKAGES += uboot-envtools kmod-eeprom-sunxi kmod-wdt-sunxi
++DEFAULT_PACKAGES += uboot-envtools
+ DEFAULT_PACKAGES += mkf2fs e2fsprogs
+ 
+ $(eval $(call BuildTarget))
+diff --git a/target/linux/sunxi/config-4.4 b/target/linux/sunxi/config-4.4
+index 2253afa124ad6c3d6b9d6798dc29f68437455341..a978e9d15b8c358f69669d3afdbf4a14bba83d31 100644
+--- a/target/linux/sunxi/config-4.4
++++ b/target/linux/sunxi/config-4.4
+@@ -356,7 +356,7 @@ CONFIG_NO_HZ_COMMON=y
+ CONFIG_NO_HZ_IDLE=y
+ CONFIG_NR_CPUS=8
+ CONFIG_NVMEM=y
+-# CONFIG_NVMEM_SUNXI_SID is not set
++CONFIG_NVMEM_SUNXI_SID=y
+ CONFIG_OF=y
+ CONFIG_OF_ADDRESS=y
+ CONFIG_OF_EARLY_FLATTREE=y
+diff --git a/target/linux/sunxi/modules.mk b/target/linux/sunxi/modules.mk
+index 6f4991798decb4a65f615d3a7282270960a7555a..99b82a3b5f17348049458ced5823f7c90f784269 100644
+--- a/target/linux/sunxi/modules.mk
++++ b/target/linux/sunxi/modules.mk
+@@ -25,7 +25,7 @@ $(eval $(call KernelPackage,rtc-sunxi))
+ define KernelPackage/sunxi-ir
+     SUBMENU:=$(OTHER_MENU)
+     TITLE:=Sunxi SoC built-in IR support (A20)
+-    DEPENDS:=@TARGET_sunxi @!LINUX_4_4 +kmod-input-core 
++    DEPENDS:=@TARGET_sunxi +kmod-input-core
+     $(call AddDepends/rtc)
+     KCONFIG:= \
+ 	CONFIG_MEDIA_SUPPORT=y \
+@@ -42,22 +42,6 @@ endef
+ 
+ $(eval $(call KernelPackage,sunxi-ir))
+ 
+-define KernelPackage/eeprom-sunxi
+-    SUBMENU:=$(OTHER_MENU)
+-    TITLE:=AllWinner Security ID fuse support
+-    DEPENDS:=@TARGET_sunxi @!LINUX_4_4
+-    KCONFIG:= \
+-	CONFIG_EEPROM_SUNXI_SID
+-    FILES:=$(LINUX_DIR)/drivers/misc/eeprom/sunxi_sid.ko
+-    AUTOLOAD:=$(call AutoLoad,50,sunxi_sid)
+-endef
+-
+-define KernelPackage/eeprom-sunxi/description
+- Support for the AllWinner Security ID fuse support
+-endef
+-
+-$(eval $(call KernelPackage,eeprom-sunxi))
+-
+ define KernelPackage/ata-sunxi
+     TITLE:=AllWinner sunXi AHCI SATA support
+     SUBMENU:=$(BLOCK_MENU)
+@@ -76,7 +60,7 @@ $(eval $(call KernelPackage,ata-sunxi))
+ define KernelPackage/sun4i-emac
+   SUBMENU:=$(NETWORK_DEVICES_MENU)
+   TITLE:=AllWinner EMAC Ethernet support
+-  DEPENDS:=@TARGET_sunxi +LINUX_4_4:kmod-of-mdio +LINUX_4_4:kmod-libphy
++  DEPENDS:=@TARGET_sunxi +kmod-of-mdio +kmod-libphy
+   KCONFIG:=CONFIG_SUN4I_EMAC
+   FILES:=$(LINUX_DIR)/drivers/net/ethernet/allwinner/sun4i-emac.ko
+   AUTOLOAD:=$(call AutoProbe,sun4i-emac)
+@@ -85,35 +69,11 @@ endef
+ $(eval $(call KernelPackage,sun4i-emac))
+ 
+ 
+-define KernelPackage/wdt-sunxi
+-    SUBMENU:=$(OTHER_MENU)
+-    TITLE:=AllWinner sunXi Watchdog timer
+-    DEPENDS:=@TARGET_sunxi
+-    KCONFIG:=CONFIG_SUNXI_WATCHDOG
+-    FILES:=$(LINUX_DIR)/drivers/$(WATCHDOG_DIR)/sunxi_wdt.ko
+-    AUTOLOAD:=$(call AutoLoad,51,sunxi_wdt)
+-endef
+-
+-define KernelPackage/wdt-sunxi/description
+-    Kernel module for AllWinner sunXi watchdog timer.
+-endef
+-
+-$(eval $(call KernelPackage,wdt-sunxi))
+-
+-
+ define KernelPackage/sound-soc-sunxi
+   TITLE:=AllWinner built-in SoC sound support
+-  KCONFIG:= \
+-	CONFIG_SND_SUNXI_SOC_CODEC \
+-	CONFIG_SND_SUN4I_CODEC
+-ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),lt,4.4.0)),1)
+-  FILES+=$(LINUX_DIR)/sound/soc/sunxi/sunxi-codec.ko
+-  AUTOLOAD:=$(call AutoLoad,65,sunxi-codec)
+-endif
+-ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),ge,4.4.0)),1)
++  KCONFIG:=CONFIG_SND_SUN4I_CODEC
+   FILES:=$(LINUX_DIR)/sound/soc/sunxi/sun4i-codec.ko
+   AUTOLOAD:=$(call AutoLoad,65,sun4i-codec)
+-endif
+   DEPENDS:=@TARGET_sunxi +kmod-sound-soc-core
+   $(call AddDepends/sound)
+ endef
diff --git a/patches/lede/0014-procd-clean-up-trailing-whitespace-in-nand.sh.patch b/patches/lede/0014-procd-clean-up-trailing-whitespace-in-nand.sh.patch
new file mode 100644
index 0000000000000000000000000000000000000000..671b879d0a49a43ab38af90e347f595f1875f432
--- /dev/null
+++ b/patches/lede/0014-procd-clean-up-trailing-whitespace-in-nand.sh.patch
@@ -0,0 +1,28 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:27:40 +0200
+Subject: procd: clean up trailing whitespace in nand.sh
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/files/nand.sh b/package/system/procd/files/nand.sh
+index ebaaf2aa16009cc1431dbb79ba9f689c8b636069..8a164ee08537014936a8608f5a60fe0e27dcabd6 100644
+--- a/package/system/procd/files/nand.sh
++++ b/package/system/procd/files/nand.sh
+@@ -194,7 +194,7 @@ nand_upgrade_prepare_ubi() {
+ 
+ nand_do_upgrade_success() {
+ 	local conf_tar="/tmp/sysupgrade.tgz"
+-	
++
+ 	sync
+ 	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
+ 	echo "sysupgrade successful"
+@@ -231,7 +231,7 @@ nand_upgrade_ubifs() {
+ 	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
+ 
+ 	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
+-	
++
+ 	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+ 	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+ 	ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
diff --git a/patches/lede/0015-procd-prepare-NAND-sysupgrade-for-making-upgraded-dynamically-linked.patch b/patches/lede/0015-procd-prepare-NAND-sysupgrade-for-making-upgraded-dynamically-linked.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3d3c5b4eb8b9ac2cb147b907e9b99e4ac1fa38b0
--- /dev/null
+++ b/patches/lede/0015-procd-prepare-NAND-sysupgrade-for-making-upgraded-dynamically-linked.patch
@@ -0,0 +1,32 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:28:05 +0200
+Subject: procd: prepare NAND sysupgrade for making upgraded dynamically linked
+
+Use install_bin to copy upgraded with all dependencies. The old name
+/tmp/upgraded is temporarily retained as a symlink to avoid breaking
+things.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/files/nand.sh b/package/system/procd/files/nand.sh
+index 8a164ee08537014936a8608f5a60fe0e27dcabd6..6bd2005344c081df20e5a330a69e49e37225c39f 100644
+--- a/package/system/procd/files/nand.sh
++++ b/package/system/procd/files/nand.sh
+@@ -333,7 +333,7 @@ nand_upgrade_stage1() {
+ 		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+ 			rm $CONF_TAR
+ 
+-		ubus call system nandupgrade "{\"path\": \"$path\" }"
++		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
+ 		exit 0
+ 	}
+ }
+@@ -370,6 +370,7 @@ nand_do_platform_check() {
+ # $(1): file to be used for upgrade
+ nand_do_upgrade() {
+ 	echo -n $1 > /tmp/sysupgrade-nand-path
+-	cp /sbin/upgraded /tmp/
++	install_bin /sbin/upgraded
++	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
+ 	nand_upgrade_stage1
+ }
diff --git a/patches/lede/0016-procd-update-to-latest-git-HEAD.patch b/patches/lede/0016-procd-update-to-latest-git-HEAD.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6d6ed2fd8c72dda0356aa2fa7af5c725681290ef
--- /dev/null
+++ b/patches/lede/0016-procd-update-to-latest-git-HEAD.patch
@@ -0,0 +1,35 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Mon, 29 May 2017 23:15:22 +0200
+Subject: procd: update to latest git HEAD
+
+992b796 rcS: add missing fcntl.h include
+63789e5 init: add support for sysupgrades triggered from preinit
+5b1fb35 Remove code that has become unnecessary after sysupgrade changes
+5918b6d upgraded: add support for passing a "command" argument to stage2
+056d8dd upgraded: link dynamically, chroot during exec
+7c6cf55 system: always support staged sysupgrade
+d42b21e procd/rcS: Use /dev/null as stdin
+e0098d4 service/instance: add an auto start option
+1247db1 procd: Log initscript output prefixed with script name
+8d720b2 procd: Don't use syslog before its initialization
+2555474 procd: Add missing \n in debug message
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index 43ea23aab00918a2b664e9a5da7767f90cd568db..805583143fa865d9ffb38355f10ad300e222400e 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -12,9 +12,9 @@ PKG_RELEASE:=1
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git
+-PKG_SOURCE_DATE:=2017-03-05
+-PKG_SOURCE_VERSION:=8f218f5626a3cb3900dbe9801ee8ace236b0e4a5
+-PKG_MIRROR_HASH:=8ac8691888b64726453bd726fe0c98fc906540bbd2ae666dae6bea592b0b4e4d
++PKG_SOURCE_DATE:=2017-05-29
++PKG_SOURCE_VERSION:=992b796204caf5b0290ea4a1246b43b353b6c1d7
++PKG_MIRROR_HASH:=effecf66ef6a7396dd26d54a5d232b4a895d9fe7aaca83063aaffc7b39a051d5
+ CMAKE_INSTALL:=1
+ 
+ PKG_LICENSE:=GPL-2.0
diff --git a/patches/lede/0017-procd-remove-procd-nand-package.patch b/patches/lede/0017-procd-remove-procd-nand-package.patch
new file mode 100644
index 0000000000000000000000000000000000000000..89280b9da5a89587a1b0584884706b319f1d533a
--- /dev/null
+++ b/patches/lede/0017-procd-remove-procd-nand-package.patch
@@ -0,0 +1,934 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Fri, 21 Apr 2017 20:37:58 +0200
+Subject: procd: remove procd-nand package
+
+We always want to support staged upgrades now, so it's better to include
+upgraded into the main package. /lib/upgrade/nand.sh is moved to
+base-files.
+
+The procd-nand-firstboot package is removed for now, it may return later
+as a separate package.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/Makefile b/package/base-files/Makefile
+index 78c3dc9390cf58fde8483596563c2e6e5e500887..aeef3dbc12f0c5ffdef0e7034e5446bfe1a1c7c4 100644
+--- a/package/base-files/Makefile
++++ b/package/base-files/Makefile
+@@ -18,7 +18,9 @@ PKG_FILE_DEPENDS:=$(PLATFORM_DIR)/ $(GENERIC_PLATFORM_DIR)/base-files/
+ PKG_BUILD_DEPENDS:=usign/host
+ PKG_LICENSE:=GPL-2.0
+ 
+-PKG_CONFIG_DEPENDS := CONFIG_SIGNED_PACKAGES CONFIG_TARGET_INIT_PATH CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE
++PKG_CONFIG_DEPENDS := \
++	CONFIG_SIGNED_PACKAGES CONFIG_TARGET_INIT_PATH CONFIG_TARGET_PREINIT_DISABLE_FAILSAFE \
++	CONFIG_NAND_SUPPORT
+ 
+ include $(INCLUDE_DIR)/package.mk
+ 
+@@ -30,7 +32,7 @@ endif
+ define Package/base-files
+   SECTION:=base
+   CATEGORY:=Base system
+-  DEPENDS:=+netifd +libc +procd +jsonfilter +SIGNED_PACKAGES:usign +SIGNED_PACKAGES:lede-keyring +fstools +fwtool
++  DEPENDS:=+netifd +libc +procd +jsonfilter +SIGNED_PACKAGES:usign +SIGNED_PACKAGES:lede-keyring +NAND_SUPPORT:ubi-utils +fstools +fwtool
+   TITLE:=Base filesystem for Lede
+   URL:=http://openwrt.org/
+   VERSION:=$(PKG_RELEASE)-$(REVISION)
+@@ -105,9 +107,16 @@ ifdef CONFIG_SIGNED_PACKAGES
+   endef
+ endif
+ 
++ifeq ($(CONFIG_NAND_SUPPORT),)
++  define Package/base-files/nand-support
++	rm -f $(1)/lib/upgrade/nand.sh
++  endef
++endif
++
+ define Package/base-files/install
+ 	$(CP) ./files/* $(1)/
+ 	$(Package/base-files/install-key)
++	$(Package/base-files/nand-support)
+ 	if [ -d $(GENERIC_PLATFORM_DIR)/base-files/. ]; then \
+ 		$(CP) $(GENERIC_PLATFORM_DIR)/base-files/* $(1)/; \
+ 	fi
+diff --git a/package/base-files/files/lib/upgrade/nand.sh b/package/base-files/files/lib/upgrade/nand.sh
+new file mode 100644
+index 0000000000000000000000000000000000000000..6bd2005344c081df20e5a330a69e49e37225c39f
+--- /dev/null
++++ b/package/base-files/files/lib/upgrade/nand.sh
+@@ -0,0 +1,376 @@
++#!/bin/sh
++# Copyright (C) 2014 OpenWrt.org
++#
++
++. /lib/functions.sh
++
++# 'kernel' partition on NAND contains the kernel
++CI_KERNPART="kernel"
++
++# 'ubi' partition on NAND contains UBI
++CI_UBIPART="ubi"
++
++ubi_mknod() {
++	local dir="$1"
++	local dev="/dev/$(basename $dir)"
++
++	[ -e "$dev" ] && return 0
++
++	local devid="$(cat $dir/dev)"
++	local major="${devid%%:*}"
++	local minor="${devid##*:}"
++	mknod "$dev" c $major $minor
++}
++
++nand_find_volume() {
++	local ubidevdir ubivoldir
++	ubidevdir="/sys/devices/virtual/ubi/$1"
++	[ ! -d "$ubidevdir" ] && return 1
++	for ubivoldir in $ubidevdir/${1}_*; do
++		[ ! -d "$ubivoldir" ] && continue
++		if [ "$( cat $ubivoldir/name )" = "$2" ]; then
++			basename $ubivoldir
++			ubi_mknod "$ubivoldir"
++			return 0
++		fi
++	done
++}
++
++nand_find_ubi() {
++	local ubidevdir ubidev mtdnum
++	mtdnum="$( find_mtd_index $1 )"
++	[ ! "$mtdnum" ] && return 1
++	for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
++		[ ! -d "$ubidevdir" ] && continue
++		cmtdnum="$( cat $ubidevdir/mtd_num )"
++		[ ! "$mtdnum" ] && continue
++		if [ "$mtdnum" = "$cmtdnum" ]; then
++			ubidev=$( basename $ubidevdir )
++			ubi_mknod "$ubidevdir"
++			echo $ubidev
++			return 0
++		fi
++	done
++}
++
++nand_get_magic_long() {
++	dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
++}
++
++get_magic_long_tar() {
++	( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
++}
++
++identify_magic() {
++	local magic=$1
++	case "$magic" in
++		"55424923")
++			echo "ubi"
++			;;
++		"31181006")
++			echo "ubifs"
++			;;
++		"68737173")
++			echo "squashfs"
++			;;
++		"d00dfeed")
++			echo "fit"
++			;;
++		"4349"*)
++			echo "combined"
++			;;
++		*)
++			echo "unknown $magic"
++			;;
++	esac
++}
++
++
++identify() {
++	identify_magic $(nand_get_magic_long "$1" "${2:-0}")
++}
++
++identify_tar() {
++	identify_magic $(get_magic_long_tar "$1" "$2")
++}
++
++nand_restore_config() {
++	sync
++	local ubidev=$( nand_find_ubi $CI_UBIPART )
++	local ubivol="$( nand_find_volume $ubidev rootfs_data )"
++	[ ! "$ubivol" ] &&
++		ubivol="$( nand_find_volume $ubidev rootfs )"
++	mkdir /tmp/new_root
++	if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
++		echo "mounting ubifs $ubivol failed"
++		rmdir /tmp/new_root
++		return 1
++	fi
++	mv "$1" "/tmp/new_root/sysupgrade.tgz"
++	umount /tmp/new_root
++	sync
++	rmdir /tmp/new_root
++}
++
++nand_upgrade_prepare_ubi() {
++	local rootfs_length="$1"
++	local rootfs_type="$2"
++	local has_kernel="${3:-0}"
++	local has_env="${4:-0}"
++
++	local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
++	if [ ! "$mtdnum" ]; then
++		echo "cannot find ubi mtd partition $CI_UBIPART"
++		return 1
++	fi
++
++	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	if [ ! "$ubidev" ]; then
++		ubiattach -m "$mtdnum"
++		sync
++		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	fi
++
++	if [ ! "$ubidev" ]; then
++		ubiformat /dev/mtd$mtdnum -y
++		ubiattach -m "$mtdnum"
++		sync
++		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++		[ "$has_env" -gt 0 ] && {
++			ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
++			ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
++		}
++	fi
++
++	local kern_ubivol="$( nand_find_volume $ubidev kernel )"
++	local root_ubivol="$( nand_find_volume $ubidev rootfs )"
++	local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
++
++	# remove ubiblock device of rootfs
++	local root_ubiblk="ubiblock${root_ubivol:3}"
++	if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then
++		echo "removing $root_ubiblk"
++		if ! ubiblock -r /dev/$root_ubivol; then
++			echo "cannot remove $root_ubiblk"
++			return 1;
++		fi
++	fi
++
++	# kill volumes
++	[ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N kernel || true
++	[ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs || true
++	[ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
++
++	# update kernel
++	if [ "$has_kernel" = "1" ]; then
++		if ! ubimkvol /dev/$ubidev -N kernel -s $kernel_length; then
++			echo "cannot create kernel volume"
++			return 1;
++		fi
++	fi
++
++	# update rootfs
++	local root_size_param
++	if [ "$rootfs_type" = "ubifs" ]; then
++		root_size_param="-m"
++	else
++		root_size_param="-s $rootfs_length"
++	fi
++	if ! ubimkvol /dev/$ubidev -N rootfs $root_size_param; then
++		echo "cannot create rootfs volume"
++		return 1;
++	fi
++
++	# create rootfs_data for non-ubifs rootfs
++	if [ "$rootfs_type" != "ubifs" ]; then
++		if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
++			echo "cannot initialize rootfs_data volume"
++			return 1
++		fi
++	fi
++	sync
++	return 0
++}
++
++nand_do_upgrade_success() {
++	local conf_tar="/tmp/sysupgrade.tgz"
++
++	sync
++	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
++	echo "sysupgrade successful"
++	umount -a
++	reboot -f
++}
++
++# Flash the UBI image to MTD partition
++nand_upgrade_ubinized() {
++	local ubi_file="$1"
++	local mtdnum="$(find_mtd_index "$CI_UBIPART")"
++
++	[ ! "$mtdnum" ] && {
++		CI_UBIPART="rootfs"
++		mtdnum="$(find_mtd_index "$CI_UBIPART")"
++	}
++
++	if [ ! "$mtdnum" ]; then
++		echo "cannot find mtd device $CI_UBIPART"
++		umount -a
++		reboot -f
++	fi
++
++	local mtddev="/dev/mtd${mtdnum}"
++	ubidetach -p "${mtddev}" || true
++	sync
++	ubiformat "${mtddev}" -y -f "${ubi_file}"
++	ubiattach -p "${mtddev}"
++	nand_do_upgrade_success
++}
++
++# Write the UBIFS image to UBI volume
++nand_upgrade_ubifs() {
++	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
++
++	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
++
++	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
++	ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
++
++	nand_do_upgrade_success
++}
++
++nand_board_name() {
++	if type 'platform_nand_board_name' >/dev/null 2>/dev/null; then
++		platform_nand_board_name
++		return
++	fi
++
++	cat /tmp/sysinfo/board_name
++}
++
++nand_upgrade_tar() {
++	local tar_file="$1"
++	local board_name="$(nand_board_name)"
++	local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
++
++	local kernel_length=`(tar xf $tar_file sysupgrade-$board_name/kernel -O | wc -c) 2> /dev/null`
++	local rootfs_length=`(tar xf $tar_file sysupgrade-$board_name/root -O | wc -c) 2> /dev/null`
++
++	local rootfs_type="$(identify_tar "$tar_file" sysupgrade-$board_name/root)"
++
++	local has_kernel=1
++	local has_env=0
++
++	[ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
++		tar xf $tar_file sysupgrade-$board_name/kernel -O | mtd write - $CI_KERNPART
++	}
++	[ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
++
++	nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
++
++	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
++	[ "$has_kernel" = "1" ] && {
++		local kern_ubivol="$(nand_find_volume $ubidev kernel)"
++	 	tar xf $tar_file sysupgrade-$board_name/kernel -O | \
++			ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
++	}
++
++	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
++	tar xf $tar_file sysupgrade-$board_name/root -O | \
++		ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
++
++	nand_do_upgrade_success
++}
++
++# Recognize type of passed file and start the upgrade process
++nand_do_upgrade_stage2() {
++	local file_type=$(identify $1)
++
++	if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
++		platform_nand_pre_upgrade "$1"
++	fi
++
++	[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
++
++	case "$file_type" in
++		"ubi")		nand_upgrade_ubinized $1;;
++		"ubifs")	nand_upgrade_ubifs $1;;
++		*)		nand_upgrade_tar $1;;
++	esac
++}
++
++nand_upgrade_stage2() {
++	[ $1 = "nand" ] && {
++		[ -f "$2" ] && {
++			touch /tmp/sysupgrade
++
++			killall -9 telnetd
++			killall -9 dropbear
++			killall -9 ash
++
++			kill_remaining TERM
++			sleep 3
++			kill_remaining KILL
++
++			sleep 1
++
++			if [ -n "$(rootfs_type)" ]; then
++				v "Switching to ramdisk..."
++				run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
++			else
++				nand_do_upgrade_stage2 $2
++			fi
++			return 0
++		}
++		echo "Nand upgrade failed"
++		exit 1
++	}
++}
++
++nand_upgrade_stage1() {
++	[ -f /tmp/sysupgrade-nand-path ] && {
++		path="$(cat /tmp/sysupgrade-nand-path)"
++		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
++			rm $CONF_TAR
++
++		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
++		exit 0
++	}
++}
++
++# Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
++# 3 types of files:
++# 1) UBI - should contain an ubinized image, header is checked for the proper
++#    MAGIC
++# 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
++#    header is checked for the proper MAGIC
++# 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
++#    "CONTROL" file (at this point its content isn't verified)
++#
++# You usually want to call this function in platform_check_image.
++#
++# $(1): board name, used in case of passing TAR file
++# $(2): file to be checked
++nand_do_platform_check() {
++	local board_name="$1"
++	local tar_file="$2"
++	local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
++	local file_type="$(identify $2)"
++
++	[ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && {
++		echo "Invalid sysupgrade file."
++		return 1
++	}
++
++	return 0
++}
++
++# Start NAND upgrade process
++#
++# $(1): file to be used for upgrade
++nand_do_upgrade() {
++	echo -n $1 > /tmp/sysupgrade-nand-path
++	install_bin /sbin/upgraded
++	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
++	nand_upgrade_stage1
++}
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index 805583143fa865d9ffb38355f10ad300e222400e..775b9a64e172b250b3ba27e71fbf07aff46ede14 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -22,11 +22,9 @@ PKG_LICENSE_FILES:=
+ 
+ PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+ 
+-PKG_FLAGS:=nonshared
+-
+ PKG_CONFIG_DEPENDS:= \
+ 	CONFIG_TARGET_INIT_PATH CONFIG_KERNEL_SECCOMP \
+-	CONFIG_NAND_SUPPORT CONFIG_PROCD_SHOW_BOOT CONFIG_PROCD_ZRAM_TMPFS \
++	CONFIG_PROCD_SHOW_BOOT CONFIG_PROCD_ZRAM_TMPFS \
+ 	CONFIG_KERNEL_NAMESPACES CONFIG_PACKAGE_procd-ujail CONFIG_PACKAGE_procd-seccomp
+ 
+ include $(INCLUDE_DIR)/package.mk
+@@ -42,7 +40,7 @@ TARGET_LDFLAGS += $(if $(CONFIG_USE_GLIBC),-lrt)
+ define Package/procd
+   SECTION:=base
+   CATEGORY:=Base system
+-  DEPENDS:=+ubusd +ubus +libjson-script +ubox +USE_GLIBC:librt +libubox +libubus +NAND_SUPPORT:procd-nand
++  DEPENDS:=+ubusd +ubus +libjson-script +ubox +USE_GLIBC:librt +libubox +libubus
+   TITLE:=OpenWrt system process manager
+ endef
+ 
+@@ -60,20 +58,6 @@ define Package/procd-seccomp
+   TITLE:=OpenWrt process seccomp helper + utrace
+ endef
+ 
+-define Package/procd-nand
+-  SECTION:=utils
+-  CATEGORY:=Utilities
+-  DEPENDS:=@NAND_SUPPORT +ubi-utils
+-  TITLE:=OpenWrt sysupgrade nand helper
+-endef
+-
+-define Package/procd-nand-firstboot
+-  SECTION:=utils
+-  CATEGORY:=Utilities
+-  DEPENDS:=procd-nand
+-  TITLE:=OpenWrt firstboot nand helper
+-endef
+-
+ define Package/procd/config
+ menu "Configuration"
+ 	depends on PACKAGE_procd
+@@ -91,10 +75,6 @@ endmenu
+ endef
+ 
+ 
+-ifeq ($(CONFIG_NAND_SUPPORT),y)
+-  CMAKE_OPTIONS += -DBUILD_UPGRADED=1
+-endif
+-
+ ifeq ($(CONFIG_PROCD_SHOW_BOOT),y)
+   CMAKE_OPTIONS += -DSHOW_BOOT_ON_CONSOLE=1
+ endif
+@@ -114,7 +94,7 @@ endif
+ define Package/procd/install
+ 	$(INSTALL_DIR) $(1)/sbin $(1)/etc $(1)/lib/functions
+ 
+-	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{init,procd,askfirst,udevtrigger} $(1)/sbin/
++	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{init,procd,askfirst,udevtrigger,upgraded} $(1)/sbin/
+ 	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libsetlbf.so $(1)/lib
+ 	$(INSTALL_BIN) ./files/reload_config $(1)/sbin/
+ 	$(INSTALL_DATA) ./files/hotplug*.json $(1)/etc/
+@@ -133,21 +113,6 @@ define Package/procd-seccomp/install
+ 	$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libpreload-trace.so $(1)/lib
+ endef
+ 
+-define Package/procd-nand/install
+-	$(INSTALL_DIR) $(1)/sbin $(1)/lib/upgrade
+-
+-	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/upgraded $(1)/sbin/
+-	$(INSTALL_DATA) ./files/nand.sh $(1)/lib/upgrade/
+-endef
+-
+-define Package/procd-nand-firstboot/install
+-	$(INSTALL_DIR) $(1)/lib/preinit
+-
+-	$(INSTALL_DATA) ./files/nand-preinit.sh $(1)/lib/preinit/60-nand-firstboot.sh
+-endef
+-
+ $(eval $(call BuildPackage,procd))
+ $(eval $(call BuildPackage,procd-ujail))
+ $(eval $(call BuildPackage,procd-seccomp))
+-$(eval $(call BuildPackage,procd-nand))
+-$(eval $(call BuildPackage,procd-nand-firstboot))
+diff --git a/package/system/procd/files/nand-preinit.sh b/package/system/procd/files/nand-preinit.sh
+deleted file mode 100644
+index cf596246d1f2891cbeb7b5c7cac4bb6e002b13fb..0000000000000000000000000000000000000000
+--- a/package/system/procd/files/nand-preinit.sh
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#!/bin/sh
+-# Copyright (C) 2014 OpenWrt.org
+-
+-nand_takeover() {
+-	. /lib/upgrade/nand.sh
+-	mtd=$(find_mtd_index "$CI_UBIPART")
+-	esize=$(cat /proc/mtd | grep mtd$mtd |cut -d" " -f 3)
+-	[ -z "$esize" ] && return 1
+-	esize=$(printf "%d" 0x$esize)
+-	for a in `seq 0 64`; do
+-		mtd -o $((a * esize)) -l 400 dump /dev/mtd$mtd > /tmp/takeover.hdr
+-		MAGIC=$(dd if=/tmp/takeover.hdr bs=1 skip=261 count=5 2> /dev/null)
+-		SIZE=$(printf "%d" 0x$(dd if=/tmp/takeover.hdr bs=4 count=1 2> /dev/null | hexdump -v -n 4 -e '1/1 "%02x"'))
+-		[ "$MAGIC" = "ustar" ] && {
+-			mtd -o $((a * esize)) -l $((SIZE + 4)) dump /dev/mtd$mtd | dd bs=1 skip=4 of=/tmp/sysupgrade.tar
+-			nand_do_upgrade_stage2 /tmp/sysupgrade.tar
+-		}
+-	done
+-}
+-
+-boot_hook_add initramfs nand_takeover
+diff --git a/package/system/procd/files/nand.sh b/package/system/procd/files/nand.sh
+deleted file mode 100644
+index 6bd2005344c081df20e5a330a69e49e37225c39f..0000000000000000000000000000000000000000
+--- a/package/system/procd/files/nand.sh
++++ /dev/null
+@@ -1,376 +0,0 @@
+-#!/bin/sh
+-# Copyright (C) 2014 OpenWrt.org
+-#
+-
+-. /lib/functions.sh
+-
+-# 'kernel' partition on NAND contains the kernel
+-CI_KERNPART="kernel"
+-
+-# 'ubi' partition on NAND contains UBI
+-CI_UBIPART="ubi"
+-
+-ubi_mknod() {
+-	local dir="$1"
+-	local dev="/dev/$(basename $dir)"
+-
+-	[ -e "$dev" ] && return 0
+-
+-	local devid="$(cat $dir/dev)"
+-	local major="${devid%%:*}"
+-	local minor="${devid##*:}"
+-	mknod "$dev" c $major $minor
+-}
+-
+-nand_find_volume() {
+-	local ubidevdir ubivoldir
+-	ubidevdir="/sys/devices/virtual/ubi/$1"
+-	[ ! -d "$ubidevdir" ] && return 1
+-	for ubivoldir in $ubidevdir/${1}_*; do
+-		[ ! -d "$ubivoldir" ] && continue
+-		if [ "$( cat $ubivoldir/name )" = "$2" ]; then
+-			basename $ubivoldir
+-			ubi_mknod "$ubivoldir"
+-			return 0
+-		fi
+-	done
+-}
+-
+-nand_find_ubi() {
+-	local ubidevdir ubidev mtdnum
+-	mtdnum="$( find_mtd_index $1 )"
+-	[ ! "$mtdnum" ] && return 1
+-	for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
+-		[ ! -d "$ubidevdir" ] && continue
+-		cmtdnum="$( cat $ubidevdir/mtd_num )"
+-		[ ! "$mtdnum" ] && continue
+-		if [ "$mtdnum" = "$cmtdnum" ]; then
+-			ubidev=$( basename $ubidevdir )
+-			ubi_mknod "$ubidevdir"
+-			echo $ubidev
+-			return 0
+-		fi
+-	done
+-}
+-
+-nand_get_magic_long() {
+-	dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+-}
+-
+-get_magic_long_tar() {
+-	( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
+-}
+-
+-identify_magic() {
+-	local magic=$1
+-	case "$magic" in
+-		"55424923")
+-			echo "ubi"
+-			;;
+-		"31181006")
+-			echo "ubifs"
+-			;;
+-		"68737173")
+-			echo "squashfs"
+-			;;
+-		"d00dfeed")
+-			echo "fit"
+-			;;
+-		"4349"*)
+-			echo "combined"
+-			;;
+-		*)
+-			echo "unknown $magic"
+-			;;
+-	esac
+-}
+-
+-
+-identify() {
+-	identify_magic $(nand_get_magic_long "$1" "${2:-0}")
+-}
+-
+-identify_tar() {
+-	identify_magic $(get_magic_long_tar "$1" "$2")
+-}
+-
+-nand_restore_config() {
+-	sync
+-	local ubidev=$( nand_find_ubi $CI_UBIPART )
+-	local ubivol="$( nand_find_volume $ubidev rootfs_data )"
+-	[ ! "$ubivol" ] &&
+-		ubivol="$( nand_find_volume $ubidev rootfs )"
+-	mkdir /tmp/new_root
+-	if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
+-		echo "mounting ubifs $ubivol failed"
+-		rmdir /tmp/new_root
+-		return 1
+-	fi
+-	mv "$1" "/tmp/new_root/sysupgrade.tgz"
+-	umount /tmp/new_root
+-	sync
+-	rmdir /tmp/new_root
+-}
+-
+-nand_upgrade_prepare_ubi() {
+-	local rootfs_length="$1"
+-	local rootfs_type="$2"
+-	local has_kernel="${3:-0}"
+-	local has_env="${4:-0}"
+-
+-	local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
+-	if [ ! "$mtdnum" ]; then
+-		echo "cannot find ubi mtd partition $CI_UBIPART"
+-		return 1
+-	fi
+-
+-	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	if [ ! "$ubidev" ]; then
+-		ubiattach -m "$mtdnum"
+-		sync
+-		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	fi
+-
+-	if [ ! "$ubidev" ]; then
+-		ubiformat /dev/mtd$mtdnum -y
+-		ubiattach -m "$mtdnum"
+-		sync
+-		ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-		[ "$has_env" -gt 0 ] && {
+-			ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
+-			ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
+-		}
+-	fi
+-
+-	local kern_ubivol="$( nand_find_volume $ubidev kernel )"
+-	local root_ubivol="$( nand_find_volume $ubidev rootfs )"
+-	local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
+-
+-	# remove ubiblock device of rootfs
+-	local root_ubiblk="ubiblock${root_ubivol:3}"
+-	if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then
+-		echo "removing $root_ubiblk"
+-		if ! ubiblock -r /dev/$root_ubivol; then
+-			echo "cannot remove $root_ubiblk"
+-			return 1;
+-		fi
+-	fi
+-
+-	# kill volumes
+-	[ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N kernel || true
+-	[ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs || true
+-	[ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
+-
+-	# update kernel
+-	if [ "$has_kernel" = "1" ]; then
+-		if ! ubimkvol /dev/$ubidev -N kernel -s $kernel_length; then
+-			echo "cannot create kernel volume"
+-			return 1;
+-		fi
+-	fi
+-
+-	# update rootfs
+-	local root_size_param
+-	if [ "$rootfs_type" = "ubifs" ]; then
+-		root_size_param="-m"
+-	else
+-		root_size_param="-s $rootfs_length"
+-	fi
+-	if ! ubimkvol /dev/$ubidev -N rootfs $root_size_param; then
+-		echo "cannot create rootfs volume"
+-		return 1;
+-	fi
+-
+-	# create rootfs_data for non-ubifs rootfs
+-	if [ "$rootfs_type" != "ubifs" ]; then
+-		if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
+-			echo "cannot initialize rootfs_data volume"
+-			return 1
+-		fi
+-	fi
+-	sync
+-	return 0
+-}
+-
+-nand_do_upgrade_success() {
+-	local conf_tar="/tmp/sysupgrade.tgz"
+-
+-	sync
+-	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
+-	echo "sysupgrade successful"
+-	umount -a
+-	reboot -f
+-}
+-
+-# Flash the UBI image to MTD partition
+-nand_upgrade_ubinized() {
+-	local ubi_file="$1"
+-	local mtdnum="$(find_mtd_index "$CI_UBIPART")"
+-
+-	[ ! "$mtdnum" ] && {
+-		CI_UBIPART="rootfs"
+-		mtdnum="$(find_mtd_index "$CI_UBIPART")"
+-	}
+-
+-	if [ ! "$mtdnum" ]; then
+-		echo "cannot find mtd device $CI_UBIPART"
+-		umount -a
+-		reboot -f
+-	fi
+-
+-	local mtddev="/dev/mtd${mtdnum}"
+-	ubidetach -p "${mtddev}" || true
+-	sync
+-	ubiformat "${mtddev}" -y -f "${ubi_file}"
+-	ubiattach -p "${mtddev}"
+-	nand_do_upgrade_success
+-}
+-
+-# Write the UBIFS image to UBI volume
+-nand_upgrade_ubifs() {
+-	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
+-
+-	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
+-
+-	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+-	ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
+-
+-	nand_do_upgrade_success
+-}
+-
+-nand_board_name() {
+-	if type 'platform_nand_board_name' >/dev/null 2>/dev/null; then
+-		platform_nand_board_name
+-		return
+-	fi
+-
+-	cat /tmp/sysinfo/board_name
+-}
+-
+-nand_upgrade_tar() {
+-	local tar_file="$1"
+-	local board_name="$(nand_board_name)"
+-	local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
+-
+-	local kernel_length=`(tar xf $tar_file sysupgrade-$board_name/kernel -O | wc -c) 2> /dev/null`
+-	local rootfs_length=`(tar xf $tar_file sysupgrade-$board_name/root -O | wc -c) 2> /dev/null`
+-
+-	local rootfs_type="$(identify_tar "$tar_file" sysupgrade-$board_name/root)"
+-
+-	local has_kernel=1
+-	local has_env=0
+-
+-	[ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
+-		tar xf $tar_file sysupgrade-$board_name/kernel -O | mtd write - $CI_KERNPART
+-	}
+-	[ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
+-
+-	nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
+-
+-	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+-	[ "$has_kernel" = "1" ] && {
+-		local kern_ubivol="$(nand_find_volume $ubidev kernel)"
+-	 	tar xf $tar_file sysupgrade-$board_name/kernel -O | \
+-			ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
+-	}
+-
+-	local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+-	tar xf $tar_file sysupgrade-$board_name/root -O | \
+-		ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
+-
+-	nand_do_upgrade_success
+-}
+-
+-# Recognize type of passed file and start the upgrade process
+-nand_do_upgrade_stage2() {
+-	local file_type=$(identify $1)
+-
+-	if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
+-		platform_nand_pre_upgrade "$1"
+-	fi
+-
+-	[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
+-
+-	case "$file_type" in
+-		"ubi")		nand_upgrade_ubinized $1;;
+-		"ubifs")	nand_upgrade_ubifs $1;;
+-		*)		nand_upgrade_tar $1;;
+-	esac
+-}
+-
+-nand_upgrade_stage2() {
+-	[ $1 = "nand" ] && {
+-		[ -f "$2" ] && {
+-			touch /tmp/sysupgrade
+-
+-			killall -9 telnetd
+-			killall -9 dropbear
+-			killall -9 ash
+-
+-			kill_remaining TERM
+-			sleep 3
+-			kill_remaining KILL
+-
+-			sleep 1
+-
+-			if [ -n "$(rootfs_type)" ]; then
+-				v "Switching to ramdisk..."
+-				run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
+-			else
+-				nand_do_upgrade_stage2 $2
+-			fi
+-			return 0
+-		}
+-		echo "Nand upgrade failed"
+-		exit 1
+-	}
+-}
+-
+-nand_upgrade_stage1() {
+-	[ -f /tmp/sysupgrade-nand-path ] && {
+-		path="$(cat /tmp/sysupgrade-nand-path)"
+-		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+-			rm $CONF_TAR
+-
+-		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
+-		exit 0
+-	}
+-}
+-
+-# Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
+-# 3 types of files:
+-# 1) UBI - should contain an ubinized image, header is checked for the proper
+-#    MAGIC
+-# 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
+-#    header is checked for the proper MAGIC
+-# 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
+-#    "CONTROL" file (at this point its content isn't verified)
+-#
+-# You usually want to call this function in platform_check_image.
+-#
+-# $(1): board name, used in case of passing TAR file
+-# $(2): file to be checked
+-nand_do_platform_check() {
+-	local board_name="$1"
+-	local tar_file="$2"
+-	local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
+-	local file_type="$(identify $2)"
+-
+-	[ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && {
+-		echo "Invalid sysupgrade file."
+-		return 1
+-	}
+-
+-	return 0
+-}
+-
+-# Start NAND upgrade process
+-#
+-# $(1): file to be used for upgrade
+-nand_do_upgrade() {
+-	echo -n $1 > /tmp/sysupgrade-nand-path
+-	install_bin /sbin/upgraded
+-	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
+-	nand_upgrade_stage1
+-}
diff --git a/patches/lede/0018-base-files-always-use-staged-sysupgrade.patch b/patches/lede/0018-base-files-always-use-staged-sysupgrade.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7a67c8dd7b1e3fc590a1b5e05384ac7ec2f528d4
--- /dev/null
+++ b/patches/lede/0018-base-files-always-use-staged-sysupgrade.patch
@@ -0,0 +1,476 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 22 Apr 2017 00:54:50 +0200
+Subject: base-files: always use staged sysupgrade
+
+Support for the -d and -p options is dropped; it may be added again at some
+point by adding these flags to the ubus sysupgrade call.
+
+A downside of this is that we get a lot less information about the progress
+of the upgrade: as soon as the actual upgrade starts, all shell sessions
+are killed to allow unmounting the root filesystem.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
+index e3519ca2cb496ff0835a9ef87da7faf217a07964..17248c2b1decd6f92558fb89601238b55fd0f0d6 100644
+--- a/package/base-files/files/lib/upgrade/common.sh
++++ b/package/base-files/files/lib/upgrade/common.sh
+@@ -56,7 +56,6 @@ run_ramfs() { # <command> [...]
+ 		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
+ 		/bin/mknod
+ 
+-	install_bin /bin/uclient-fetch /bin/wget
+ 	install_bin /sbin/mtd
+ 	install_bin /sbin/mount_root
+ 	install_bin /sbin/snapshot
+@@ -96,51 +95,37 @@ run_ramfs() { # <command> [...]
+ 	exec /bin/busybox ash -c "$*"
+ }
+ 
+-kill_remaining() { # [ <signal> ]
++kill_remaining() { # [ <signal> [ <loop> ] ]
+ 	local sig="${1:-TERM}"
++	local loop="${2:-0}"
++	local run=true
++	local stat
++
+ 	echo -n "Sending $sig to remaining processes ... "
+ 
+-	local my_pid=$$
+-	local my_ppid=$(cut -d' ' -f4  /proc/$my_pid/stat)
+-	local my_ppisupgraded=
+-	grep -q upgraded /proc/$my_ppid/cmdline >/dev/null && {
+-		local my_ppisupgraded=1
+-	}
+-	
+-	local stat
+-	for stat in /proc/[0-9]*/stat; do
+-		[ -f "$stat" ] || continue
+-
+-		local pid name state ppid rest
+-		read pid name state ppid rest < $stat
+-		name="${name#(}"; name="${name%)}"
+-
+-		local cmdline
+-		read cmdline < /proc/$pid/cmdline
+-
+-		# Skip kernel threads
+-		[ -n "$cmdline" ] || continue
+-
+-		if [ $$ -eq 1 ] || [ $my_ppid -eq 1 ] && [ -n "$my_ppisupgraded" ]; then
+-			# Running as init process, kill everything except me
+-			if [ $pid -ne $$ ] && [ $pid -ne $my_ppid ]; then
+-				echo -n "$name "
+-				kill -$sig $pid 2>/dev/null
+-			fi
+-		else 
+-			case "$name" in
+-				# Skip essential services
+-				*procd*|*ash*|*init*|*watchdog*|*ssh*|*dropbear*|*telnet*|*login*|*hostapd*|*wpa_supplicant*|*nas*|*relayd*) : ;;
+-
+-				# Killable process
+-				*)
+-					if [ $pid -ne $$ ] && [ $ppid -ne $$ ]; then
+-						echo -n "$name "
+-						kill -$sig $pid 2>/dev/null
+-					fi
+-				;;
+-			esac
+-		fi
++	while $run; do
++		run=false
++		for stat in /proc/[0-9]*/stat; do
++			[ -f "$stat" ] || continue
++
++			local pid name state ppid rest
++			read pid name state ppid rest < $stat
++			name="${name#(}"; name="${name%)}"
++
++			# Skip PID1, ourself and our children
++			[ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
++
++			local cmdline
++			read cmdline < /proc/$pid/cmdline
++
++			# Skip kernel threads
++			[ -n "$cmdline" ] || continue
++
++			echo -n "$name "
++			kill -$sig $pid 2>/dev/null
++
++			[ $loop -eq 1 ] && run=true
++		done
+ 	done
+ 	echo ""
+ }
+@@ -175,28 +160,31 @@ v() {
+ 	[ "$VERBOSE" -ge 1 ] && echo "$@"
+ }
+ 
++json_string() {
++	local v="$1"
++	v="${v//\\/\\\\}"
++	v="${v//\"/\\\"}"
++	echo "\"$v\""
++}
++
+ rootfs_type() {
+ 	/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }'
+ }
+ 
+ get_image() { # <source> [ <command> ]
+ 	local from="$1"
+-	local conc="$2"
+-	local cmd
+-
+-	case "$from" in
+-		http://*|ftp://*) cmd="wget -O- -q";;
+-		*) cmd="cat";;
+-	esac
+-	if [ -z "$conc" ]; then
+-		local magic="$(eval $cmd \"$from\" 2>/dev/null | dd bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
++	local cat="$2"
++
++	if [ -z "$cat" ]; then
++		local magic="$(dd if="$from" bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
+ 		case "$magic" in
+-			1f8b) conc="zcat";;
+-			425a) conc="bzcat";;
++			1f8b) cat="zcat";;
++			425a) cat="bzcat";;
++			*) cat="cat";;
+ 		esac
+ 	fi
+ 
+-	eval "$cmd \"$from\" 2>/dev/null ${conc:+| $conc}"
++	$cat "$from" 2>/dev/null
+ }
+ 
+ get_magic_word() {
+@@ -320,12 +308,14 @@ default_do_upgrade() {
+ 	fi
+ }
+ 
+-do_upgrade() {
++do_upgrade_stage2() {
+ 	v "Performing system upgrade..."
+-	if type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
+-		platform_do_upgrade "$ARGV"
++	if [ -n "$do_upgrade" ]; then
++		$do_upgrade "$IMAGE"
++	elif type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
++		platform_do_upgrade "$IMAGE"
+ 	else
+-		default_do_upgrade "$ARGV"
++		default_do_upgrade "$IMAGE"
+ 	fi
+ 
+ 	if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
+@@ -333,12 +323,11 @@ do_upgrade() {
+ 	fi
+ 
+ 	v "Upgrade completed"
+-	[ -n "$DELAY" ] && sleep "$DELAY"
+-	ask_bool 1 "Reboot" && {
+-		v "Rebooting system..."
+-		umount -a
+-		reboot -f
+-		sleep 5
+-		echo b 2>/dev/null >/proc/sysrq-trigger
+-	}
++	sleep 1
++
++	v "Rebooting system..."
++	umount -a
++	reboot -f
++	sleep 5
++	echo b 2>/dev/null >/proc/sysrq-trigger
+ }
+diff --git a/package/base-files/files/lib/upgrade/nand.sh b/package/base-files/files/lib/upgrade/nand.sh
+index 6bd2005344c081df20e5a330a69e49e37225c39f..1e69c8f9657b39adf2a2c33bd9bac9303bcbc3d7 100644
+--- a/package/base-files/files/lib/upgrade/nand.sh
++++ b/package/base-files/files/lib/upgrade/nand.sh
+@@ -283,7 +283,16 @@ nand_upgrade_tar() {
+ }
+ 
+ # Recognize type of passed file and start the upgrade process
+-nand_do_upgrade_stage2() {
++nand_do_upgrade() {
++	if [ -n "$IS_PRE_UPGRADE" ]; then
++		# Previously, nand_do_upgrade was called from the platform_pre_upgrade
++		# hook; this piece of code handles scripts that haven't been
++		# updated. All scripts should gradually move to call nand_do_upgrade
++		# from platform_do_upgrade instead.
++		export do_upgrade=nand_do_upgrade
++		return
++	fi
++
+ 	local file_type=$(identify $1)
+ 
+ 	if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
+@@ -299,45 +308,6 @@ nand_do_upgrade_stage2() {
+ 	esac
+ }
+ 
+-nand_upgrade_stage2() {
+-	[ $1 = "nand" ] && {
+-		[ -f "$2" ] && {
+-			touch /tmp/sysupgrade
+-
+-			killall -9 telnetd
+-			killall -9 dropbear
+-			killall -9 ash
+-
+-			kill_remaining TERM
+-			sleep 3
+-			kill_remaining KILL
+-
+-			sleep 1
+-
+-			if [ -n "$(rootfs_type)" ]; then
+-				v "Switching to ramdisk..."
+-				run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
+-			else
+-				nand_do_upgrade_stage2 $2
+-			fi
+-			return 0
+-		}
+-		echo "Nand upgrade failed"
+-		exit 1
+-	}
+-}
+-
+-nand_upgrade_stage1() {
+-	[ -f /tmp/sysupgrade-nand-path ] && {
+-		path="$(cat /tmp/sysupgrade-nand-path)"
+-		[ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+-			rm $CONF_TAR
+-
+-		ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
+-		exit 0
+-	}
+-}
+-
+ # Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
+ # 3 types of files:
+ # 1) UBI - should contain an ubinized image, header is checked for the proper
+@@ -364,13 +334,3 @@ nand_do_platform_check() {
+ 
+ 	return 0
+ }
+-
+-# Start NAND upgrade process
+-#
+-# $(1): file to be used for upgrade
+-nand_do_upgrade() {
+-	echo -n $1 > /tmp/sysupgrade-nand-path
+-	install_bin /sbin/upgraded
+-	ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
+-	nand_upgrade_stage1
+-}
+diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2
+new file mode 100755
+index 0000000000000000000000000000000000000000..4e2aa3a23c3bab07a795762a30a4d4f701081934
+--- /dev/null
++++ b/package/base-files/files/lib/upgrade/stage2
+@@ -0,0 +1,50 @@
++#!/bin/sh
++
++. /lib/functions.sh
++. /lib/functions/system.sh
++
++export IMAGE="$1"
++COMMAND="$2"
++
++export ARGV="$IMAGE"
++export ARGC=1
++
++export SAVE_CONFIG=1
++export SAVE_PARTITIONS=1
++
++export INTERACTIVE=0
++export VERBOSE=1
++export CONFFILES=/tmp/sysupgrade.conffiles
++export CONF_TAR=/tmp/sysupgrade.tgz
++
++
++[ -f "$CONF_TAR" ] || export SAVE_CONFIG=0
++[ -f /tmp/sysupgrade.always.overwrite.bootdisk.partmap ] && export SAVE_PARTITIONS=0
++
++include /lib/upgrade
++
++
++killall -9 telnetd
++killall -9 dropbear
++killall -9 ash
++
++kill_remaining TERM
++sleep 3
++kill_remaining KILL 1
++
++sleep 1
++
++
++if [ -n "$IMAGE" ] && type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then
++	IS_PRE_UPGRADE=1 platform_pre_upgrade "$IMAGE"
++
++	# Needs to be unset again because of busybox weirdness ...
++	IS_PRE_UPGRADE=
++fi
++
++if [ -n "$(rootfs_type)" ]; then
++	echo "Switching to ramdisk..."
++	run_ramfs "$COMMAND"
++else
++	exec /bin/busybox ash -c "$COMMAND"
++fi
+diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
+index c095ca81c50c71021af2dc04a561ac22f6b7442b..2d67371ef74b4b970076a069e97f4fd6a1e0bc95 100755
+--- a/package/base-files/files/sbin/sysupgrade
++++ b/package/base-files/files/sbin/sysupgrade
+@@ -1,4 +1,7 @@
+ #!/bin/sh
++
++[ "$1" = "nand" ] && exec /lib/upgrade/stage2 "$2" "$3"
++
+ . /lib/functions.sh
+ . /lib/functions/system.sh
+ 
+@@ -11,7 +14,6 @@ export VERBOSE=1
+ export SAVE_CONFIG=1
+ export SAVE_OVERLAY=0
+ export SAVE_PARTITIONS=1
+-export DELAY=
+ export CONF_IMAGE=
+ export CONF_BACKUP_LIST=0
+ export CONF_BACKUP=
+@@ -25,7 +27,6 @@ export TEST=0
+ while [ -n "$1" ]; do
+ 	case "$1" in
+ 		-i) export INTERACTIVE=1;;
+-		-d) export DELAY="$2"; shift;;
+ 		-v) export VERBOSE="$(($VERBOSE + 1))";;
+ 		-q) export VERBOSE="$(($VERBOSE - 1))";;
+ 		-n) export SAVE_CONFIG=0;;
+@@ -50,10 +51,9 @@ done
+ export CONFFILES=/tmp/sysupgrade.conffiles
+ export CONF_TAR=/tmp/sysupgrade.tgz
+ 
+-export ARGV="$*"
+-export ARGC="$#"
++IMAGE="$1"
+ 
+-[ -z "$ARGV" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
++[ -z "$IMAGE" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
+ 	cat <<EOF
+ Usage: $0 [<upgrade-option>...] <image file or URL>
+        $0 [-q] [-i] <backup-command> <file>
+@@ -90,7 +90,7 @@ EOF
+ 	exit 1
+ }
+ 
+-[ -n "$ARGV" -a -n "$NEED_IMAGE" ] && {
++[ -n "$IMAGE" -a -n "$NEED_IMAGE" ] && {
+ 	cat <<-EOF
+ 		-b|--create-backup and -r|--restore-backup do not perform a firmware upgrade.
+ 		Do not specify both -b|-r and a firmware image.
+@@ -136,14 +136,13 @@ sysupgrade_pre_upgrade="fwtool_pre_upgrade"
+ 
+ include /lib/upgrade
+ 
+-[ "$1" = "nand" ] && nand_upgrade_stage2 $@
+-
+ do_save_conffiles() {
+ 	local conf_tar="${1:-$CONF_TAR}"
+ 
+ 	[ -z "$(rootfs_type)" ] && {
+ 		echo "Cannot save config while running from ramdisk."
+ 		ask_bool 0 "Abort" && exit
++		rm -f "$conf_tar"
+ 		return 0
+ 	}
+ 	run_hooks "$CONFFILES" $sysupgrade_init_conffiles
+@@ -184,8 +183,33 @@ type platform_check_image >/dev/null 2>/dev/null || {
+ 	exit 1
+ }
+ 
++case "$IMAGE" in
++	http://*)
++		wget -O/tmp/sysupgrade.img "$IMAGE"
++		IMAGE=/tmp/sysupgrade.img
++		;;
++esac
++
++IMAGE="$(readlink -f "$IMAGE")"
++
++case "$IMAGE" in
++	'')
++		echo "Image file not found."
++		exit 1
++		;;
++	/tmp/*)	;;
++	*)
++		v "Image not in /tmp, copying..."
++		cp -f "$IMAGE" /tmp/sysupgrade.img
++		IMAGE=/tmp/sysupgrade.img
++		;;
++esac
++
++export ARGV="$IMAGE"
++export ARGC=1
++
+ for check in $sysupgrade_image_check; do
+-	( eval "$check \"\$ARGV\"" ) || {
++	( $check "$IMAGE" ) || {
+ 		if [ $FORCE -eq 1 ]; then
+ 			echo "Image check '$check' failed but --force given - will update anyway!"
+ 			break
+@@ -211,6 +235,7 @@ elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
+ 	[ $TEST -eq 1 ] || do_save_conffiles
+ 	export SAVE_CONFIG=1
+ else
++	[ $TEST -eq 1 ] || rm -f "$CONF_TAR"
+ 	export SAVE_CONFIG=0
+ fi
+ 
+@@ -218,28 +243,18 @@ if [ $TEST -eq 1 ]; then
+ 	exit 0
+ fi
+ 
+-run_hooks "" $sysupgrade_pre_upgrade
+-
+-# Some platforms/devices may want different sysupgrade process, e.g. without
+-# killing processes yet or calling ubus system upgrade method.
+-# This is needed e.g. on NAND devices where we just want to trigger stage1 at
+-# this point.
+-if type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then
+-	platform_pre_upgrade "$ARGV"
++if [ $SAVE_PARTITIONS -eq 0 ]; then
++	touch /tmp/sysupgrade.always.overwrite.bootdisk.partmap
++else
++	rm -f /tmp/sysupgrade.always.overwrite.bootdisk.partmap
+ fi
+ 
+-ubus call system upgrade
+-touch /tmp/sysupgrade
+-
+-if [ ! -f /tmp/failsafe ] ; then
+-	kill_remaining TERM
+-	sleep 3
+-	kill_remaining KILL
+-fi
++run_hooks "" $sysupgrade_pre_upgrade
+ 
+-if [ -n "$(rootfs_type)" ]; then
+-	v "Switching to ramdisk..."
+-	run_ramfs '. /lib/functions.sh; include /lib/upgrade; do_upgrade'
+-else
+-	do_upgrade
+-fi
++install_bin /sbin/upgraded
++v "Commencing upgrade. All shell sessions will be closed now."
++ubus call system sysupgrade "{
++	\"prefix\": \"$RAM_ROOT\",
++	\"path\": $(json_string "$IMAGE"),
++	\"command\": \". /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2\"
++}"
diff --git a/patches/lede/0019-fstools-clean-up-trailing-whitespace-in-snapshot-script.patch b/patches/lede/0019-fstools-clean-up-trailing-whitespace-in-snapshot-script.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2df0942a213f6c24c3a824cf817ee68a5328d2cc
--- /dev/null
+++ b/patches/lede/0019-fstools-clean-up-trailing-whitespace-in-snapshot-script.patch
@@ -0,0 +1,19 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:29:24 +0200
+Subject: fstools: clean up trailing whitespace in snapshot script
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/fstools/files/snapshot b/package/system/fstools/files/snapshot
+index c1a5b733f3c70e2bb5f2e83d3589e2f10832760f..baf24f1e3e90fe7708e0f28c17ba270a35a2cd52 100644
+--- a/package/system/fstools/files/snapshot
++++ b/package/system/fstools/files/snapshot
+@@ -42,7 +42,7 @@ do_snapshot_upgrade() {
+ 
+ 	opkg list-upgradable
+ 	[ $? -eq 0 ] || exit 2
+-	
++
+ 	UPDATES=`opkg list-upgradable | cut -d" " -f1`
+ 	[ -z "${UPDATES}" ] && exit 0
+ 
diff --git a/patches/lede/0020-fstools-snapshot-handle-jffs2-conversion-using-upgraded.patch b/patches/lede/0020-fstools-snapshot-handle-jffs2-conversion-using-upgraded.patch
new file mode 100644
index 0000000000000000000000000000000000000000..906f6732b9a6382bc91460fbe89c4603a4cc4ae9
--- /dev/null
+++ b/patches/lede/0020-fstools-snapshot-handle-jffs2-conversion-using-upgraded.patch
@@ -0,0 +1,49 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:29:55 +0200
+Subject: fstools: snapshot: handle jffs2 conversion using upgraded
+
+We can reuse the kill_remaining and run_ramfs facilities of the stage2 run
+by upgraded.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile
+index 28f68b57d6f82dd066410a577e84e32a3a54dc37..2789424c5f5fb50cc1f004d2ab5223a7fecbf53a 100644
+--- a/package/system/fstools/Makefile
++++ b/package/system/fstools/Makefile
+@@ -8,7 +8,7 @@
+ include $(TOPDIR)/rules.mk
+ 
+ PKG_NAME:=fstools
+-PKG_RELEASE:=1
++PKG_RELEASE:=2
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/fstools.git
+diff --git a/package/system/fstools/files/snapshot b/package/system/fstools/files/snapshot
+index baf24f1e3e90fe7708e0f28c17ba270a35a2cd52..a495e3434523b7a4b1b2f1bc3f4c9298197fc745 100644
+--- a/package/system/fstools/files/snapshot
++++ b/package/system/fstools/files/snapshot
+@@ -64,14 +64,16 @@ do_convert_jffs2() {
+ do_convert() {
+ 	. /lib/functions.sh
+ 	. /lib/upgrade/common.sh
+-	ubus call system upgrade
+-	touch /tmp/sysupgrade
++
+ 	cd /overlay/upper
+ 	tar czf /tmp/snapshot.tar.gz *
+-	kill_remaining TERM
+-	sleep 3
+-	kill_remaining KILL
+-	run_ramfs '. /sbin/snapshot; do_convert_jffs2'
++
++	install_bin /sbin/upgraded
++	ubus call system sysupgrade "{
++		\"prefix\": \"$RAM_ROOT\",
++		\"path\": \"\",
++		\"command\": \". /sbin/snapshot; do_convert_jffs2\"
++	}"
+ }
+ 
+ [ -n "$(cat /proc/mounts|grep /overlay|grep jffs2)" ] && {
diff --git a/patches/lede/0021-base-files-sysupgrade-cleanup.patch b/patches/lede/0021-base-files-sysupgrade-cleanup.patch
new file mode 100644
index 0000000000000000000000000000000000000000..31afb9aeedba52ae41cc1bbabe20200acdca9a1f
--- /dev/null
+++ b/patches/lede/0021-base-files-sysupgrade-cleanup.patch
@@ -0,0 +1,258 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 23 Apr 2017 23:33:14 +0200
+Subject: base-files: sysupgrade cleanup
+
+Some functions only used by stage2 are moved there from common.sh.
+
+One piece that could still use more cleanup is platform_pre_upgrade: many
+targets reference files from there are aren't available in the ramfs, so
+we need to evaluate it before the switch; conversely, flash writes happen
+in that function on some targets. Targets that do the latter should be
+fixed eventually to use platform_do_upgrade for that purpose.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
+index 17248c2b1decd6f92558fb89601238b55fd0f0d6..fc59bf2323498d332159b00eb7ab443bfe6b147e 100644
+--- a/package/base-files/files/lib/upgrade/common.sh
++++ b/package/base-files/files/lib/upgrade/common.sh
+@@ -30,106 +30,6 @@ install_bin() { # <file> [ <symlink> ... ]
+ 	}; done
+ }
+ 
+-supivot() { # <new_root> <old_root>
+-	/bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1
+-	mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \
+-	/bin/mount -o noatime,move /proc $1/proc && \
+-	pivot_root $1 $1$2 || {
+-		/bin/umount -l $1 $1
+-		return 1
+-	}
+-
+-	/bin/mount -o noatime,move $2/sys /sys
+-	/bin/mount -o noatime,move $2/dev /dev
+-	/bin/mount -o noatime,move $2/tmp /tmp
+-	/bin/mount -o noatime,move $2/overlay /overlay 2>&-
+-	return 0
+-}
+-
+-run_ramfs() { # <command> [...]
+-	install_bin /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount	\
+-		/sbin/pivot_root /sbin/reboot /bin/sync /bin/dd	/bin/grep       \
+-		/bin/cp /bin/mv /bin/tar /usr/bin/md5sum "/usr/bin/[" /bin/dd	\
+-		/bin/vi /bin/ls /bin/cat /usr/bin/awk /usr/bin/hexdump		\
+-		/bin/sleep /bin/zcat /usr/bin/bzcat /usr/bin/printf /usr/bin/wc \
+-		/bin/cut /usr/bin/printf /bin/sync /bin/mkdir /bin/rmdir	\
+-		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
+-		/bin/mknod
+-
+-	install_bin /sbin/mtd
+-	install_bin /sbin/mount_root
+-	install_bin /sbin/snapshot
+-	install_bin /sbin/snapshot_tool
+-	install_bin /usr/sbin/ubiupdatevol
+-	install_bin /usr/sbin/ubiattach
+-	install_bin /usr/sbin/ubiblock
+-	install_bin /usr/sbin/ubiformat
+-	install_bin /usr/sbin/ubidetach
+-	install_bin /usr/sbin/ubirsvol
+-	install_bin /usr/sbin/ubirmvol
+-	install_bin /usr/sbin/ubimkvol
+-	install_bin /usr/sbin/partx
+-	install_bin /usr/sbin/losetup
+-	install_bin /usr/sbin/mkfs.ext4
+-	for file in $RAMFS_COPY_BIN; do
+-		install_bin ${file//:/ }
+-	done
+-	install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh $RAMFS_COPY_DATA
+-
+-	[ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64
+-
+-	supivot $RAM_ROOT /mnt || {
+-		echo "Failed to switch over to ramfs. Please reboot."
+-		exit 1
+-	}
+-
+-	/bin/mount -o remount,ro /mnt
+-	/bin/umount -l /mnt
+-
+-	grep /overlay /proc/mounts > /dev/null && {
+-		/bin/mount -o noatime,remount,ro /overlay
+-		/bin/umount -l /overlay
+-	}
+-
+-	# spawn a new shell from ramdisk to reduce the probability of cache issues
+-	exec /bin/busybox ash -c "$*"
+-}
+-
+-kill_remaining() { # [ <signal> [ <loop> ] ]
+-	local sig="${1:-TERM}"
+-	local loop="${2:-0}"
+-	local run=true
+-	local stat
+-
+-	echo -n "Sending $sig to remaining processes ... "
+-
+-	while $run; do
+-		run=false
+-		for stat in /proc/[0-9]*/stat; do
+-			[ -f "$stat" ] || continue
+-
+-			local pid name state ppid rest
+-			read pid name state ppid rest < $stat
+-			name="${name#(}"; name="${name%)}"
+-
+-			# Skip PID1, ourself and our children
+-			[ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
+-
+-			local cmdline
+-			read cmdline < /proc/$pid/cmdline
+-
+-			# Skip kernel threads
+-			[ -n "$cmdline" ] || continue
+-
+-			echo -n "$name "
+-			kill -$sig $pid 2>/dev/null
+-
+-			[ $loop -eq 1 ] && run=true
+-		done
+-	done
+-	echo ""
+-}
+-
+ run_hooks() {
+ 	local arg="$1"; shift
+ 	for func in "$@"; do
+diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2
+index 4e2aa3a23c3bab07a795762a30a4d4f701081934..cc8047d988e39ca9ba27d2588744aad469d1d978 100755
+--- a/package/base-files/files/lib/upgrade/stage2
++++ b/package/base-files/files/lib/upgrade/stage2
+@@ -24,6 +24,104 @@ export CONF_TAR=/tmp/sysupgrade.tgz
+ include /lib/upgrade
+ 
+ 
++supivot() { # <new_root> <old_root>
++	/bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1
++	mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \
++	/bin/mount -o noatime,move /proc $1/proc && \
++	pivot_root $1 $1$2 || {
++		/bin/umount -l $1 $1
++		return 1
++	}
++
++	/bin/mount -o noatime,move $2/sys /sys
++	/bin/mount -o noatime,move $2/dev /dev
++	/bin/mount -o noatime,move $2/tmp /tmp
++	/bin/mount -o noatime,move $2/overlay /overlay 2>&-
++	return 0
++}
++
++switch_to_ramfs() {
++	install_bin /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount	\
++		/sbin/pivot_root /sbin/reboot /bin/sync /bin/dd	/bin/grep       \
++		/bin/cp /bin/mv /bin/tar /usr/bin/md5sum "/usr/bin/[" /bin/dd	\
++		/bin/vi /bin/ls /bin/cat /usr/bin/awk /usr/bin/hexdump		\
++		/bin/sleep /bin/zcat /usr/bin/bzcat /usr/bin/printf /usr/bin/wc \
++		/bin/cut /usr/bin/printf /bin/sync /bin/mkdir /bin/rmdir	\
++		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
++		/bin/mknod
++
++	install_bin /sbin/mtd
++	install_bin /sbin/mount_root
++	install_bin /sbin/snapshot
++	install_bin /sbin/snapshot_tool
++	install_bin /usr/sbin/ubiupdatevol
++	install_bin /usr/sbin/ubiattach
++	install_bin /usr/sbin/ubiblock
++	install_bin /usr/sbin/ubiformat
++	install_bin /usr/sbin/ubidetach
++	install_bin /usr/sbin/ubirsvol
++	install_bin /usr/sbin/ubirmvol
++	install_bin /usr/sbin/ubimkvol
++	install_bin /usr/sbin/partx
++	install_bin /usr/sbin/losetup
++	install_bin /usr/sbin/mkfs.ext4
++	for file in $RAMFS_COPY_BIN; do
++		install_bin ${file//:/ }
++	done
++	install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh $RAMFS_COPY_DATA
++
++	[ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64
++
++	supivot $RAM_ROOT /mnt || {
++		echo "Failed to switch over to ramfs. Please reboot."
++		exit 1
++	}
++
++	/bin/mount -o remount,ro /mnt
++	/bin/umount -l /mnt
++
++	grep /overlay /proc/mounts > /dev/null && {
++		/bin/mount -o noatime,remount,ro /overlay
++		/bin/umount -l /overlay
++	}
++}
++
++kill_remaining() { # [ <signal> [ <loop> ] ]
++	local sig="${1:-TERM}"
++	local loop="${2:-0}"
++	local run=true
++	local stat
++
++	echo -n "Sending $sig to remaining processes ... "
++
++	while $run; do
++		run=false
++		for stat in /proc/[0-9]*/stat; do
++			[ -f "$stat" ] || continue
++
++			local pid name state ppid rest
++			read pid name state ppid rest < $stat
++			name="${name#(}"; name="${name%)}"
++
++			# Skip PID1, ourself and our children
++			[ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
++
++			local cmdline
++			read cmdline < /proc/$pid/cmdline
++
++			# Skip kernel threads
++			[ -n "$cmdline" ] || continue
++
++			echo -n "$name "
++			kill -$sig $pid 2>/dev/null
++
++			[ $loop -eq 1 ] && run=true
++		done
++	done
++	echo ""
++}
++
++
+ killall -9 telnetd
+ killall -9 dropbear
+ killall -9 ash
+@@ -44,7 +142,8 @@ fi
+ 
+ if [ -n "$(rootfs_type)" ]; then
+ 	echo "Switching to ramdisk..."
+-	run_ramfs "$COMMAND"
+-else
+-	exec /bin/busybox ash -c "$COMMAND"
++	switch_to_ramfs
+ fi
++
++# Exec new shell from ramfs
++exec /bin/busybox ash -c "$COMMAND"
+diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
+index 2d67371ef74b4b970076a069e97f4fd6a1e0bc95..200a0e520b5df8bcc208f4d8fd731756e94294fb 100755
+--- a/package/base-files/files/sbin/sysupgrade
++++ b/package/base-files/files/sbin/sysupgrade
+@@ -1,7 +1,5 @@
+ #!/bin/sh
+ 
+-[ "$1" = "nand" ] && exec /lib/upgrade/stage2 "$2" "$3"
+-
+ . /lib/functions.sh
+ . /lib/functions/system.sh
+ 
diff --git a/patches/lede/0022-base-files-add-support-for-staged-sysupgrades-from-failsafe-mode.patch b/patches/lede/0022-base-files-add-support-for-staged-sysupgrades-from-failsafe-mode.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5b5dceae7e9c06d571964a6c1b74dc34e95c489a
--- /dev/null
+++ b/patches/lede/0022-base-files-add-support-for-staged-sysupgrades-from-failsafe-mode.patch
@@ -0,0 +1,72 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Mon, 24 Apr 2017 01:31:04 +0200
+Subject: base-files: add support for staged sysupgrades from failsafe mode
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/base-files/files/lib/preinit/40_run_failsafe_hook b/package/base-files/files/lib/preinit/40_run_failsafe_hook
+index 7301f77349a1a1e42fcef9bcbc927ef55c83b991..533b0a9771e1aac603f00ecf7a4622ea9fee969d 100644
+--- a/package/base-files/files/lib/preinit/40_run_failsafe_hook
++++ b/package/base-files/files/lib/preinit/40_run_failsafe_hook
+@@ -5,8 +5,12 @@
+ run_failsafe_hook() {
+     [ "$pi_preinit_no_failsafe" = "y" ] && return
+     if [ "$FAILSAFE" = "true" ]; then
++	lock /tmp/.failsafe
+ 	boot_run_hook failsafe
+-	lock -w /tmp/.failsafe
++	while [ ! -e /tmp/sysupgrade ]; do
++	    lock -w /tmp/.failsafe
++	done
++	exit
+     fi
+ }
+ 
+diff --git a/package/base-files/files/lib/preinit/99_10_failsafe_login b/package/base-files/files/lib/preinit/99_10_failsafe_login
+index 3147cdc5a68a69cef6b1af6618a4e2367a143c2c..728c63b2e8aebf970cd7dff0d15518ccda83029c 100644
+--- a/package/base-files/files/lib/preinit/99_10_failsafe_login
++++ b/package/base-files/files/lib/preinit/99_10_failsafe_login
+@@ -8,10 +8,13 @@ failsafe_netlogin () {
+ }
+ 
+ failsafe_shell() {
+-	lock /tmp/.failsafe
+-	ash --login
+-	echo "Please reboot system when done with failsafe network logins"
+-	while true; do sleep 1; done
++	local console="$(sed -e 's/ /\n/g' /proc/cmdline | grep '^console=' | head -1 | sed -e 's/^console=//' -e 's/,.*//')"
++	[ -n "$console" ] || console=console
++	[ -c "/dev/$console" ] || return 0
++	while true; do
++		ash --login <"/dev/$console" >"/dev/$console" 2>"/dev/$console"
++		sleep 1
++	done &
+ }
+ 
+ boot_hook_add failsafe failsafe_netlogin
+diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
+index 200a0e520b5df8bcc208f4d8fd731756e94294fb..809e789f9f436aaeb47a906d46c94d5952583e5a 100755
+--- a/package/base-files/files/sbin/sysupgrade
++++ b/package/base-files/files/sbin/sysupgrade
+@@ -251,8 +251,16 @@ run_hooks "" $sysupgrade_pre_upgrade
+ 
+ install_bin /sbin/upgraded
+ v "Commencing upgrade. All shell sessions will be closed now."
+-ubus call system sysupgrade "{
+-	\"prefix\": \"$RAM_ROOT\",
+-	\"path\": $(json_string "$IMAGE"),
+-	\"command\": \". /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2\"
+-}"
++
++COMMAND='. /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2'
++
++if [ -n "$FAILSAFE" ]; then
++	printf '%s\x00%s\x00%s' "$RAM_ROOT" "$IMAGE" "$COMMAND" >/tmp/sysupgrade
++	lock -u /tmp/.failsafe
++else
++	ubus call system sysupgrade "{
++		\"prefix\": $(json_string "$RAM_ROOT"),
++		\"path\": $(json_string "$IMAGE"),
++		\"command\": $(json_string "$COMMAND")
++	}"
++fi
diff --git a/patches/lede/0023-ramips-sysupgrade-move-nand_do_upgrade-call-to-platform_do_upgrade.patch b/patches/lede/0023-ramips-sysupgrade-move-nand_do_upgrade-call-to-platform_do_upgrade.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4663dbc62e0871e51b55f15d95d5ebb0b79c80a2
--- /dev/null
+++ b/patches/lede/0023-ramips-sysupgrade-move-nand_do_upgrade-call-to-platform_do_upgrade.patch
@@ -0,0 +1,35 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 22 Apr 2017 21:27:04 +0200
+Subject: ramips: sysupgrade: move nand_do_upgrade call to platform_do_upgrade
+
+All targets with NAND support should gradually move their nand_do_upgrade
+calls from platform_pre_upgrade to platform_do_upgrade.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/ramips/base-files/lib/upgrade/platform.sh b/target/linux/ramips/base-files/lib/upgrade/platform.sh
+index 7f5b1dd070b1bfe0b86b093a55165b5a139eb37c..a5cca2080d3b96cef92286b1b15f4f8832d9f8c5 100755
+--- a/target/linux/ramips/base-files/lib/upgrade/platform.sh
++++ b/target/linux/ramips/base-files/lib/upgrade/platform.sh
+@@ -254,20 +254,13 @@ platform_nand_pre_upgrade() {
+ 	esac
+ }
+ 
+-platform_pre_upgrade() {
++platform_do_upgrade() {
+ 	local board=$(ramips_board_name)
+ 
+ 	case "$board" in
+     	ubnt-erx)
+ 		nand_do_upgrade "$ARGV"
+ 		;;
+-	esac
+-}
+-
+-platform_do_upgrade() {
+-	local board=$(ramips_board_name)
+-
+-	case "$board" in
+ 	*)
+ 		default_do_upgrade "$ARGV"
+ 		;;
diff --git a/patches/lede/0024-x86-sysupgrade-move-partition-table-change-check-to-platform_check_image.patch b/patches/lede/0024-x86-sysupgrade-move-partition-table-change-check-to-platform_check_image.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8da5a5d2c2d2e9c393a931ebad851ca582e82bc1
--- /dev/null
+++ b/patches/lede/0024-x86-sysupgrade-move-partition-table-change-check-to-platform_check_image.patch
@@ -0,0 +1,62 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 08:57:29 +0200
+Subject: x86: sysupgrade: move partition table change check to platform_check_image
+
+The staged sysupgrade will prevent us from using ask_bool in
+platform_do_upgrade; therefore, the check is moved to platform_check_image.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index d3e9f360aadedad0995da55205364940c9884ba4..81b349a81816033eef9df464b2a70fdb998e5a1d 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -1,13 +1,37 @@
+ platform_check_image() {
++	local diskdev partdev diff
+ 	[ "$#" -gt 1 ] && return 1
+ 
+ 	case "$(get_magic_word "$1")" in
+-		eb48|eb63) return 0;;
++		eb48|eb63) ;;
+ 		*)
+ 			echo "Invalid image type"
+ 			return 1
+ 		;;
+ 	esac
++
++	export_bootdevice && export_partdevice diskdev 0 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	get_partitions "/dev/$diskdev" bootdisk
++
++	#extract the boot sector from the image
++	get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null
++
++	get_partitions /tmp/image.bs image
++
++	#compare tables
++	diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++
++	rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image
++
++	if [ -n "$diff" ]; then
++		echo "Partition layout has changed. Full image will be written."
++		ask_bool 0 "Abort" && exit 1
++		return 0
++	fi
+ }
+ 
+ platform_copy_config() {
+@@ -36,9 +60,6 @@ platform_do_upgrade() {
+ 			#compare tables
+ 			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+ 			if [ -n "$diff" ]; then
+-				echo "Partition layout is changed.  Full image will be written."
+-				ask_bool 0 "Abort" && exit
+-
+ 				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+ 				return 0
+ 			fi
diff --git a/patches/lede/0025-x86-sysupgrade-refactor-platform_do_upgrade.patch b/patches/lede/0025-x86-sysupgrade-refactor-platform_do_upgrade.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a70f3ad481a9f44e65be8a72b9918949a5703281
--- /dev/null
+++ b/patches/lede/0025-x86-sysupgrade-refactor-platform_do_upgrade.patch
@@ -0,0 +1,90 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 09:05:25 +0200
+Subject: x86: sysupgrade: refactor platform_do_upgrade
+
+By returning early when no upgrade device can be found and handling the
+SAVE_PARTITIONS=0 case differently, we can get rid of two levels of if.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index 81b349a81816033eef9df464b2a70fdb998e5a1d..4fa71999be7be3972676a1019488972dccd57fa2 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -47,40 +47,43 @@ platform_copy_config() {
+ platform_do_upgrade() {
+ 	local diskdev partdev diff
+ 
+-	if export_bootdevice && export_partdevice diskdev 0; then
+-		sync
+-		if [ "$SAVE_PARTITIONS" = "1" ]; then
+-			get_partitions "/dev/$diskdev" bootdisk
+-
+-			#extract the boot sector from the image
+-			get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
+-
+-			get_partitions /tmp/image.bs image
+-
+-			#compare tables
+-			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+-			if [ -n "$diff" ]; then
+-				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+-				return 0
+-			fi
+-
+-			#iterate over each partition from the image and write it to the boot disk
+-			while read part start size; do
+-				if export_partdevice partdev $part; then
+-					echo "Writing image to /dev/$partdev..."
+-					get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
+-				else
+-					echo "Unable to find partition $part device, skipped."
+-				fi
+-			done < /tmp/partmap.image
+-
+-			#copy partition uuid
+-			echo "Writing new UUID to /dev/$diskdev..."
+-			get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
++	export_bootdevice && export_partdevice diskdev 0 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	sync
++
++	if [ "$SAVE_PARTITIONS" = "1" ]; then
++		get_partitions "/dev/$diskdev" bootdisk
++
++		#extract the boot sector from the image
++		get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
++
++		get_partitions /tmp/image.bs image
++
++		#compare tables
++		diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++	else
++		diff=1
++	fi
++
++	if [ -n "$diff" ]; then
++		get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++		return 0
++	fi
++
++	#iterate over each partition from the image and write it to the boot disk
++	while read part start size; do
++		if export_partdevice partdev $part; then
++			echo "Writing image to /dev/$partdev..."
++			get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
+ 		else
+-			get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++			echo "Unable to find partition $part device, skipped."
+ 		fi
++	done < /tmp/partmap.image
+ 
+-		sleep 1
+-	fi
++	#copy partition uuid
++	echo "Writing new UUID to /dev/$diskdev..."
++	get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
+ }
diff --git a/patches/lede/0026-x86-sysupgrade-explicitly-rescan-disk-after-writing-partition-table.patch b/patches/lede/0026-x86-sysupgrade-explicitly-rescan-disk-after-writing-partition-table.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4e46ce60e65bec91e9eb070f429129649b1abef5
--- /dev/null
+++ b/patches/lede/0026-x86-sysupgrade-explicitly-rescan-disk-after-writing-partition-table.patch
@@ -0,0 +1,26 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 3 May 2017 09:08:29 +0200
+Subject: x86: sysupgrade: explicitly rescan disk after writing partition table
+
+This should ensure that the kernel partition can be mounted in
+platform_copy_config when its size has changed.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index 4fa71999be7be3972676a1019488972dccd57fa2..439ba8f5125d97932248ff966340165a84e1b24a 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -70,6 +70,12 @@ platform_do_upgrade() {
+ 
+ 	if [ -n "$diff" ]; then
+ 		get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++
++		# Separate removal and addtion is necessary; otherwise, partition 1
++		# will be missing if it overlaps with the old partition 2
++		partx -d - "/dev/$diskdev"
++		partx -a - "/dev/$diskdev"
++
+ 		return 0
+ 	fi
+ 
diff --git a/patches/lede/0027-sunxi-sysupgrade-don-t-write-partitions-twice.patch b/patches/lede/0027-sunxi-sysupgrade-don-t-write-partitions-twice.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6aabf26b3d952331d2cc81da76d0842eb7ce40cd
--- /dev/null
+++ b/patches/lede/0027-sunxi-sysupgrade-don-t-write-partitions-twice.patch
@@ -0,0 +1,29 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Thu, 4 May 2017 07:29:58 +0200
+Subject: sunxi: sysupgrade: don't write partitions twice
+
+When existing partitions are retained, the dd call writing the uboot image
+in the space before the first partition was accidentally writing the whole
+image, making the code for individual partitions redundant. Limit the copy
+to 1016KiB (the first 8KiB are skipped, and the first partition starts at
+1024KiB).
+
+In addition, conv=notrunc is replaced with conv=fsync. It seems this was an
+oversight, as notrunc doesn't make sense for block devices and all other dd
+commands use conv=fsync.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/sunxi/base-files/lib/upgrade/platform.sh b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+index f2cd970d428a780d7497d8802765c656a47ff421..776bdf53bf89c5eafc24b7b59b943e12f3fab77e 100644
+--- a/target/linux/sunxi/base-files/lib/upgrade/platform.sh
++++ b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+@@ -43,7 +43,7 @@ platform_do_upgrade() {
+ 			fi
+ 
+ 			#write uboot image
+-			get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 conv=notrunc
++			get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 count=1016 conv=fsync
+ 			#iterate over each partition from the image and write it to the boot disk
+ 			while read part start size; do
+ 				part="$(($part - 2))"
diff --git a/patches/lede/0028-sunxi-sysupgrade-sync-with-x86.patch b/patches/lede/0028-sunxi-sysupgrade-sync-with-x86.patch
new file mode 100644
index 0000000000000000000000000000000000000000..293d07d7b1c83ec7e642f717f0ce641079124b8b
--- /dev/null
+++ b/patches/lede/0028-sunxi-sysupgrade-sync-with-x86.patch
@@ -0,0 +1,163 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Thu, 4 May 2017 07:39:20 +0200
+Subject: sunxi: sysupgrade: sync with x86
+
+sunxi sysupgrade was based on the x86 implementation; sync fixes and other
+changes from the current x86 version:
+
+x86: fix sysupgrades on disks with 4k block size
+x86: sysupgrade: move partition table change check to platform_check_image
+x86: sysupgrade: refactor platform_do_upgrade
+x86: sysupgrade: explicitly rescan disk after writing partition table
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/sunxi/Makefile b/target/linux/sunxi/Makefile
+index 3c2f14b8418e1d296a239027f6fdee9b5ba8f9b2..f8b8aa750a7145c9954df5a5a6a2e85f2610a72f 100644
+--- a/target/linux/sunxi/Makefile
++++ b/target/linux/sunxi/Makefile
+@@ -28,6 +28,6 @@ KERNELNAME:=zImage dtbs
+ include $(INCLUDE_DIR)/target.mk
+ 
+ DEFAULT_PACKAGES += uboot-envtools
+-DEFAULT_PACKAGES += mkf2fs e2fsprogs
++DEFAULT_PACKAGES += partx-utils mkf2fs e2fsprogs
+ 
+ $(eval $(call BuildTarget))
+diff --git a/target/linux/sunxi/base-files/lib/upgrade/platform.sh b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+index 776bdf53bf89c5eafc24b7b59b943e12f3fab77e..88ef4790e9c1452f8ce57fe1c265ce47810830ee 100644
+--- a/target/linux/sunxi/base-files/lib/upgrade/platform.sh
++++ b/target/linux/sunxi/base-files/lib/upgrade/platform.sh
+@@ -1,5 +1,28 @@
+ platform_check_image() {
+-	true
++	local diskdev partdev diff
++
++	export_bootdevice && export_partdevice diskdev -2 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	get_partitions "/dev/$diskdev" bootdisk
++
++	#extract the boot sector from the image
++	get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null
++
++	get_partitions /tmp/image.bs image
++
++	#compare tables
++	diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++
++	rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image
++
++	if [ -n "$diff" ]; then
++		echo "Partition layout has changed. Full image will be written."
++		ask_bool 0 "Abort" && exit 1
++		return 0
++	fi
+ }
+ 
+ platform_copy_config() {
+@@ -13,55 +36,54 @@ platform_copy_config() {
+ }
+ 
+ platform_do_upgrade() {
+-	local diskdev partdev ibs diff
+-
+-	if export_bootdevice && export_partdevice diskdev -2; then
+-		sync
+-		if [ "$SAVE_PARTITIONS" = "1" ]; then
+-			get_partitions "/dev/$diskdev" bootdisk
+-
+-			#get block size
+-			if [ -f "/sys/block/$diskdev/queue/physical_block_size" ]; then
+-				ibs="$(cat "/sys/block/$diskdev/queue/physical_block_size")"
+-			else
+-				ibs=512
+-			fi
+-
+-			#extract the boot sector from the image
+-			get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
+-
+-			get_partitions /tmp/image.bs image
+-
+-			#compare tables
+-			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+-			if [ -n "$diff" ]; then
+-				echo "Partition layout is changed.  Full image will be written."
+-				ask_bool 0 "Abort" && exit
+-
+-				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+-				return 0
+-			fi
+-
+-			#write uboot image
+-			get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 count=1016 conv=fsync
+-			#iterate over each partition from the image and write it to the boot disk
+-			while read part start size; do
+-				part="$(($part - 2))"
+-				if export_partdevice partdev $part; then
+-					echo "Writing image to /dev/$partdev..."
+-					get_image "$@" | dd of="/dev/$partdev" ibs="$ibs" obs=1M skip="$start" count="$size" conv=fsync
+-				else
+-					echo "Unable to find partition $part device, skipped."
+-				fi
+-			done < /tmp/partmap.image
+-
+-			#copy partition uuid
+-			echo "Writing new UUID to /dev/$diskdev..."
+-			get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
++	local diskdev partdev diff
++
++	export_bootdevice && export_partdevice diskdev -2 || {
++		echo "Unable to determine upgrade device"
++		return 1
++	}
++
++	sync
++
++	if [ "$SAVE_PARTITIONS" = "1" ]; then
++		get_partitions "/dev/$diskdev" bootdisk
++
++		#extract the boot sector from the image
++		get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
++
++		get_partitions /tmp/image.bs image
++
++		#compare tables
++		diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
++	else
++		diff=1
++	fi
++
++	if [ -n "$diff" ]; then
++		get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++
++		# Separate removal and addtion is necessary; otherwise, partition 1
++		# will be missing if it overlaps with the old partition 2
++		partx -d - "/dev/$diskdev"
++		partx -a - "/dev/$diskdev"
++
++		return 0
++	fi
++
++	#write uboot image
++	get_image "$@" | dd of="$diskdev" bs=1024 skip=8 seek=8 count=1016 conv=fsync
++	#iterate over each partition from the image and write it to the boot disk
++	while read part start size; do
++		part="$(($part - 2))"
++		if export_partdevice partdev $part; then
++			echo "Writing image to /dev/$partdev..."
++			get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
+ 		else
+-			get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
++			echo "Unable to find partition $part device, skipped."
+ 		fi
++	done < /tmp/partmap.image
+ 
+-		sleep 1
+-	fi
++	#copy partition uuid
++	echo "Writing new UUID to /dev/$diskdev..."
++	get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
+ }
diff --git a/patches/lede/0029-procd-update-to-latest-git-HEAD.patch b/patches/lede/0029-procd-update-to-latest-git-HEAD.patch
new file mode 100644
index 0000000000000000000000000000000000000000..e9f5eaa502d329ccfbf88a3be0c315d393d04c82
--- /dev/null
+++ b/patches/lede/0029-procd-update-to-latest-git-HEAD.patch
@@ -0,0 +1,25 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Tue, 30 May 2017 07:29:25 +0200
+Subject: procd: update to latest git HEAD
+
+e7bb2c8 upgraded: define __GNU_SOURCE
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile
+index 775b9a64e172b250b3ba27e71fbf07aff46ede14..f9d2f4d34f866a169eb1665ac2699c54422c3c4b 100644
+--- a/package/system/procd/Makefile
++++ b/package/system/procd/Makefile
+@@ -12,9 +12,9 @@ PKG_RELEASE:=1
+ 
+ PKG_SOURCE_PROTO:=git
+ PKG_SOURCE_URL=$(LEDE_GIT)/project/procd.git
+-PKG_SOURCE_DATE:=2017-05-29
+-PKG_SOURCE_VERSION:=992b796204caf5b0290ea4a1246b43b353b6c1d7
+-PKG_MIRROR_HASH:=effecf66ef6a7396dd26d54a5d232b4a895d9fe7aaca83063aaffc7b39a051d5
++PKG_SOURCE_DATE:=2017-05-30
++PKG_SOURCE_VERSION:=e7bb2c8d631862e1535cf6eead18387f02a69ad2
++PKG_MIRROR_HASH:=97bb96aba2db4730fd8b2edeb15f94e18caa6017d9e50a73777c14532154cade
+ CMAKE_INSTALL:=1
+ 
+ PKG_LICENSE:=GPL-2.0