Merge branch 'vuplus-1.6k' of /home/shcheong/work/stb/sw/oe_1.6/bm750/openembedded...
authorschon <schon@dev03-server>
Thu, 6 Sep 2012 19:19:29 +0000 (04:19 +0900)
committerschon <schon@dev03-server>
Thu, 6 Sep 2012 19:19:29 +0000 (04:19 +0900)
86 files changed:
conf/distro/vuplus.conf
conf/machine/vu7425.conf [new file with mode: 0644]
conf/machine/vuduo2.conf [new file with mode: 0644]
conf/machine/vusolo2.conf [new file with mode: 0644]
recipes/base-files/base-files/vu7425/fstab [new file with mode: 0755]
recipes/base-files/base-files/vu7425/fstab_3.1 [new file with mode: 0755]
recipes/base-files/base-files/vuduo2/fstab [new file with mode: 0755]
recipes/base-files/base-files/vuduo2/fstab_3.1 [new file with mode: 0755]
recipes/base-files/base-files/vusolo2/fstab [new file with mode: 0755]
recipes/base-files/base-files/vusolo2/fstab_3.1 [new file with mode: 0755]
recipes/directfb/directfb-1.4.2/directfb-vuplus-blit.patch [new file with mode: 0644]
recipes/directfb/directfb-1.4.2/directfbrc [new file with mode: 0644]
recipes/directfb/directfb.inc
recipes/directfb/directfb_1.4.2.bb
recipes/duo2lcd4linux/duo2lcd4linux_0.1.bb [new file with mode: 0644]
recipes/duo2lcd4linux/files/LCD4linux.tar.gz [new file with mode: 0644]
recipes/enigma2/enigma2.bb
recipes/enigma2/enigma2/vuplus/enigma2-hbbtv_20120604.patch [new file with mode: 0644]
recipes/images/vuplus-image.bb
recipes/initscripts/initscripts-1.0/vu7425/bootup [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vu7425/bootup_3.1 [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vu7425/halt [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vu7425/hotplug_br [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vu7425/make_mac_sector [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vuduo2/bootup [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vuduo2/bootup_3.1 [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vuduo2/halt [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vuduo2/hotplug_br [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vuduo2/make_mac_sector [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vusolo2/bootup [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vusolo2/bootup_3.1 [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vusolo2/halt [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vusolo2/hotplug_br [new file with mode: 0755]
recipes/initscripts/initscripts-1.0/vusolo2/make_mac_sector [new file with mode: 0755]
recipes/libdreamdvd/libdreamdvd.bb
recipes/linux/linux-vuduo2-3.1.1/brcm_disable_enet1.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/brcm_nand_timing.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/debug.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/dvb-core.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/fix_cpu_proc.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/pinmux.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/serial.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/stblinux-2.6.37-2.4.tar.bz2 [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/ubifs_backport.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/ubifs_packport.patch [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.0307 [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.0308 [new file with mode: 0644]
recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.org [new file with mode: 0644]
recipes/linux/linux-vuduo2_3.1.1.bb [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/bcmgenet_oobctrl.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/brcm_disable_enet1.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/brcm_nand_timing.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/debug.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/fix_cpu_proc.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/pinmux.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.4.tar.bz2 [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.8.tar.bz2 [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/ubifs_packport.patch [new file with mode: 0644]
recipes/linux/linux-vusolo2-2.6.37/vusolo2_defconfig [new file with mode: 0644]
recipes/linux/linux-vusolo2-3.1.1/vusolo2_defconfig [new file with mode: 0644]
recipes/linux/linux-vusolo2_2.6.37.bb [new file with mode: 0644]
recipes/opera-bb/files/opera-hbbtv.tar.gz [new file with mode: 0644]
recipes/opera-bb/opera-hbbtv_0.1.bb [new file with mode: 0755]
recipes/opkg/opkg-collateral/vu7425/dest [new file with mode: 0644]
recipes/opkg/opkg-collateral/vuduo2/dest [new file with mode: 0644]
recipes/opkg/opkg-collateral/vusolo2/dest [new file with mode: 0644]
recipes/png-util/files/png_util.cpp [new file with mode: 0755]
recipes/png-util/files/png_util.h [new file with mode: 0755]
recipes/png-util/files/png_util.i [new file with mode: 0755]
recipes/png-util/png-util_1.0.bb [new file with mode: 0755]
recipes/sysvinit/sysvinit/vu7425/inittab [new file with mode: 0755]
recipes/sysvinit/sysvinit/vuduo2/inittab [new file with mode: 0755]
recipes/sysvinit/sysvinit/vusolo2/inittab [new file with mode: 0755]
recipes/tasks/task-vuplus-enigma2.bb
recipes/tasks/task-vuplus-wlan.bb
recipes/tuxbox/libdvbsi++.bb
recipes/tuxbox/tuxbox-libtuxtxt.bb
recipes/udev/udev_124.bb
recipes/vuplus/vuplus-bootlogo.bb
recipes/vuplus/vuplus-bootlogo/vuduo2/initrd_cfe_auto.bin [new file with mode: 0644]
recipes/vuplus/vuplus-bootlogo/vuduo2/splash_cfe_auto.bin [new file with mode: 0755]
recipes/vuplus/vuplus-bootlogo/vusolo2/initrd_cfe_auto.bin [new file with mode: 0644]
recipes/vuplus/vuplus-bootlogo/vusolo2/splash_cfe_auto.bin [new file with mode: 0755]
recipes/vuplus/vuplus-dvb-modules.bb

index 1bda803..083f803 100644 (file)
@@ -48,7 +48,7 @@ IMAGE_FSTYPES ?= "tar.bz2 ubi"
 
 #2.8
 #FEED_URIS += "official##http://archive.vuplus.com/openembedded/1.1/vuplus/${MACHINE}/feeds/stable"
-DISTRO_FEED_URI = "http://archive.vuplus.com/openembedded/${DISTRO_VERSION}/vuplus/feeds/stable"
+DISTRO_FEED_URI = "http://archive.vuplus.com/openembedded/${DISTRO_VERSION}/beta/feeds/stable"
 
 # If we're using an .ipk based rootfs, we want to have opkg-nogpg installed so postinst script can run
 IPKG_VARIANT = "opkg-nogpg"
diff --git a/conf/machine/vu7425.conf b/conf/machine/vu7425.conf
new file mode 100644 (file)
index 0000000..83e00f9
--- /dev/null
@@ -0,0 +1,161 @@
+#@TYPE: Machine
+#@NAME: vuultimo
+#@DESCRIPTION: Machine configuration for the VuPlus
+
+TARGET_ARCH = "mipsel"
+
+PREFERRED_VERSION_linux-vuultimo = "3.1.1"
+PREFERRED_VERSION_linux-libc-headers = "2.6.31"
+
+PREFERRED_PROVIDER_virtual/kernel = "linux-${MACHINE}"
+
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.18 = "kernel vuplus-dvb-modules \
+        kernel-module-isofs \
+        kernel-module-sr-mod    kernel-module-usb-storage \
+        kernel-module-cdrom \
+        kernel-module-msdos kernel-module-vfat kernel-module-fat \
+        kernel-module-libata kernel-module-ntfs kernel-module-sata-svw \
+        kernel-module-nls-iso8859-15 kernel-module-nls-cp850 \
+        kernel-module-nls-utf8 \
+        kernel-module-i2c-core kernel-module-i2c-dev kernel-module-firmware-class kernel-module-input kernel-module-evdev \
+        kernel-module-snd-pcm kernel-module-snd \
+       kernel-module-tun \
+       kernel-module-fb \
+       v4l-dvb-module-dvb-core \
+       kernel-module-usbhid \
+       kernel-module-mousedev \
+        "
+
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.18 = "\
+        kernel-module-cifs \
+        kernel-module-exportfs \
+        kernel-module-ext2 \
+        kernel-module-reiserfs \
+        kernel-module-xfs \
+       "
+#MACHINE_ESSENTIAL_EXTRA_RDEPENDS_3.1.1 = "kernel vuplus-dvb-modules"
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS_3.1.1 = "kernel"
+
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_3.1.1 = "\
+       kernel-module-ext2 \
+       "
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS = ${@base_contains('PREFERRED_VERSION_linux-vuultimo', '2.6.18', '${MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.18}', '${MACHINE_ESSENTIAL_EXTRA_RDEPENDS_3.1.1}', d)}
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS = ${@base_contains('PREFERRED_VERSION_linux-vuultimo', '2.6.18', '${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.18}', '${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_3.1.1}', d)}
+
+require conf/machine/include/vuplus-modules.inc
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS += ${@base_contains('PREFERRED_VERSION_linux-vuultimo', '3.1.1', '${KERNEL_WIFI_MODULES}', '', d)}
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS += ${@base_contains('PREFERRED_VERSION_linux-vuultimo', '3.1.1', '${KERNEL_DVB_MODULES}', '', d)}
+
+PREFERRED_VERSION_wpa-supplicant = ${@base_contains('PREFERRED_VERSION_linux-vuultimo', '2.6.18', '0.5.10', '0.7.3', d)}
+
+IMAGE_FSTYPES = ${@base_contains('PREFERRED_VERSION_linux-vuultimo', '2.6.18', 'tar.bz2 jffs2', 'tar.bz2 ubi', d)}
+
+TARGET_FPU = "hard"
+
+MACHINE_FEATURES += "kernel26"
+
+TARGET_CC_ARCH = "-march=mips32"
+
+DISTRO_FEATURES += " mplt"
+
+PREFERRED_PROVIDER_task-vuplus-dvbapi = "task-vuplus-dvbapi3"
+PREFERRED_PROVIDER_task-vuplus-ui = "task-vuplus-enigma2"
+
+GLIBC_ADDONS ?= "ports,nptl,libidn"
+GLIBC_EXTRA_OECONF = "--disable-profile --with-tls --without-fp --with-__thread"
+
+PREFERRED_PROVIDER_xserver = "xserver-kdrive"
+
+EXTRA_IMAGEDEPENDS += "vuplus-makenfi-native"
+
+MACHINE_FEATURES += "alsa pci"
+MACHINE_FEATURES += "wifi"
+MACHINE_FEATURES += "vuwlan"
+MACHINE_FEATURES += "display-graphic-vfd"
+MACHINE_FEATURES += "right-half-vfd-skin"
+MACHINE_FEATURES += "enable-rc-kbd"
+
+
+
+EXTRA_IMAGECMD_jffs2 = " --eraseblock=0x20000 -n -l "
+IMAGE_CMD_jffs2 = " \
+       cp ${IMAGE_ROOTFS}/boot/vmlinux.gz ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz; \
+       rm -f ${IMAGE_ROOTFS}/boot/vmlinux.gz; \
+       mkfs.jffs2 --root=${IMAGE_ROOTFS}/boot --faketime \
+       --disable-compressor=lzo --compression-mode=size \
+       --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 \
+       ${EXTRA_IMAGECMD}; rm -rf ${IMAGE_ROOTFS}/boot/*; \
+       rm -rf ${IMAGE_ROOTFS}/tmp/*; \
+       mkfs.jffs2 --root=${IMAGE_ROOTFS} \
+       --disable-compressor=lzo --compression-mode=size \
+       --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 \
+       ${EXTRA_IMAGECMD}; \
+       vfi3 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz > ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.nfi; \
+       mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/ultimo; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 ${DEPLOY_DIR_IMAGE}/vuplus/ultimo/root_cfe_auto.jffs2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz ${DEPLOY_DIR_IMAGE}/vuplus/ultimo/kernel_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/vuplus/ultimo/boot_cfe_auto.jffs2; \
+       cd ${DEPLOY_DIR_IMAGE}; \
+       zip ${IMAGE_NAME}_usb.zip vuplus/ultimo/*; \
+       rm -rf vuplus; \       
+"
+
+
+
+UBI_VOLNAME = "rootfs"
+MKUBIFS_ARGS = "-m 2048 -e 126976 -c 3984 -F"
+UBINIZE_ARGS = "-m 2048 -p 128KiB"
+
+IMAGEDIR ?= "${MACHINE}"
+EXTRA_IMAGECMD_COMPAT = " --eraseblock=0x20000 -n -l "
+
+IMAGE_CMD_ubi_prepend = " \
+        cp ${IMAGE_ROOTFS}/boot/vmlinux.gz ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz; \
+        rm -f ${IMAGE_ROOTFS}/boot/vmlinux.gz; \
+        mkfs.jffs2 --root=${IMAGE_ROOTFS}/boot --faketime \
+        --disable-compressor=lzo --compression-mode=size \
+        --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 \
+        ${EXTRA_IMAGECMD_COMPAT}; rm -rf ${IMAGE_ROOTFS}/boot/*; \
+        "
+
+IMAGE_CMD_ubi_append = "; \
+       vfi3 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz > ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.nfi; \
+        mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/ultimo; \
+        cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${DEPLOY_DIR_IMAGE}/vuplus/ultimo/root_cfe_auto.jffs2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/vuplus/ultimo/boot_cfe_auto.jffs2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz ${DEPLOY_DIR_IMAGE}/vuplus/ultimo/kernel_cfe_auto.bin; \
+        cd ${DEPLOY_DIR_IMAGE}; \
+       zip ${IMAGE_NAME}_usb.zip vuplus/ultimo/*; \
+       rm -rf vuplus; \ 
+        "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/machine/vuduo2.conf b/conf/machine/vuduo2.conf
new file mode 100644 (file)
index 0000000..c44f372
--- /dev/null
@@ -0,0 +1,168 @@
+#@TYPE: Machine
+#@NAME: vuduo2
+#@DESCRIPTION: Machine configuration for the VuPlus
+
+TARGET_ARCH = "mipsel"
+
+PREFERRED_VERSION_linux-vuduo2 = "3.1.1"
+PREFERRED_VERSION_linux-libc-headers = "2.6.31"
+
+PREFERRED_PROVIDER_virtual/kernel = "linux-${MACHINE}"
+
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.18 = "kernel vuplus-dvb-modules \
+        kernel-module-isofs \
+        kernel-module-sr-mod    kernel-module-usb-storage \
+        kernel-module-cdrom \
+        kernel-module-msdos kernel-module-vfat kernel-module-fat \
+        kernel-module-libata kernel-module-ntfs kernel-module-sata-svw \
+        kernel-module-nls-iso8859-15 kernel-module-nls-cp850 \
+        kernel-module-nls-utf8 \
+        kernel-module-i2c-core kernel-module-i2c-dev kernel-module-firmware-class kernel-module-input kernel-module-evdev \
+        kernel-module-snd-pcm kernel-module-snd \
+       kernel-module-tun \
+       kernel-module-fb \
+       v4l-dvb-module-dvb-core \
+       kernel-module-usbhid \
+       kernel-module-mousedev \
+        "
+
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.18 = "\
+        kernel-module-cifs \
+        kernel-module-exportfs \
+        kernel-module-ext2 \
+        kernel-module-reiserfs \
+        kernel-module-xfs \
+       "
+#MACHINE_ESSENTIAL_EXTRA_RDEPENDS_3.1.1 = "kernel vuplus-dvb-modules"
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS_3.1.1 = "kernel vuplus-dvb-modules"
+
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_3.1.1 = "\
+       kernel-module-ext2 \
+       "
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS = ${@base_contains('PREFERRED_VERSION_linux-vuduo2', '2.6.18', '${MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.18}', '${MACHINE_ESSENTIAL_EXTRA_RDEPENDS_3.1.1}', d)}
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS = ${@base_contains('PREFERRED_VERSION_linux-vuduo2', '2.6.18', '${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.18}', '${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_3.1.1}', d)}
+
+require conf/machine/include/vuplus-modules.inc
+
+#MACHINE_ESSENTIAL_EXTRA_RDEPENDS += ${@base_contains('PREFERRED_VERSION_linux-vuduo2', '3.1.1', '${KERNEL_WIFI_MODULES}', '', d)}
+#MACHINE_ESSENTIAL_EXTRA_RDEPENDS += ${@base_contains('PREFERRED_VERSION_linux-vuduo2', '3.1.1', '${KERNEL_DVB_MODULES}', '', d)}
+
+PREFERRED_VERSION_wpa-supplicant = ${@base_contains('PREFERRED_VERSION_linux-vuduo2', '2.6.18', '0.5.10', '0.7.3', d)}
+
+IMAGE_FSTYPES = ${@base_contains('PREFERRED_VERSION_linux-vuduo2', '2.6.18', 'tar.bz2 jffs2', 'tar.bz2 ubi', d)}
+
+TARGET_FPU = "hard"
+
+MACHINE_FEATURES += "kernel26"
+
+TARGET_CC_ARCH = "-march=mips32"
+
+DISTRO_FEATURES += " mplt"
+
+PREFERRED_PROVIDER_task-vuplus-dvbapi = "task-vuplus-dvbapi3"
+PREFERRED_PROVIDER_task-vuplus-ui = "task-vuplus-enigma2"
+
+GLIBC_ADDONS ?= "ports,nptl,libidn"
+GLIBC_EXTRA_OECONF = "--disable-profile --with-tls --without-fp --with-__thread"
+
+PREFERRED_PROVIDER_xserver = "xserver-kdrive"
+
+EXTRA_IMAGEDEPENDS += "vuplus-makenfi-native"
+
+MACHINE_FEATURES += "alsa pci"
+MACHINE_FEATURES += "wifi"
+MACHINE_FEATURES += "vuwlan"
+MACHINE_FEATURES += "enable-rc-kbd"
+MACHINE_FEATURES += "display-text-vfd"
+
+
+
+EXTRA_IMAGECMD_jffs2 = " --eraseblock=0x20000 -n -l "
+IMAGE_CMD_jffs2 = " \
+       cp ${IMAGE_ROOTFS}/boot/vmlinux.gz ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz; \
+        cp ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin; \
+        cp ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin; \
+       rm -f ${IMAGE_ROOTFS}/boot/vmlinux.gz; \
+        rm -f ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin; \
+        rm -f ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin; \
+       mkfs.jffs2 --root=${IMAGE_ROOTFS}/boot --faketime \
+       --disable-compressor=lzo --compression-mode=size \
+       --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 \
+       ${EXTRA_IMAGECMD}; rm -rf ${IMAGE_ROOTFS}/boot/*; \
+       rm -rf ${IMAGE_ROOTFS}/tmp/*; \
+       mkfs.jffs2 --root=${IMAGE_ROOTFS} \
+       --disable-compressor=lzo --compression-mode=size \
+       --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 \
+       ${EXTRA_IMAGECMD}; \
+       vfi3 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz > ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.nfi; \
+       mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/duo2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 ${DEPLOY_DIR_IMAGE}/vuplus/duo2/root_cfe_auto.jffs2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz ${DEPLOY_DIR_IMAGE}/vuplus/duo2/kernel_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/vuplus/duo2/boot_cfe_auto.jffs2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/duo2/initrd_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/duo2/splash_cfe_auto.bin; \
+       cd ${DEPLOY_DIR_IMAGE}; \
+       zip ${IMAGE_NAME}_usb.zip vuplus/duo2/*; \
+       rm -rf vuplus; \       
+"
+
+
+
+UBI_VOLNAME = "rootfs"
+#MKUBIFS_ARGS = "-m 2048 -e 126976 -c 4096 -F"
+MKUBIFS_ARGS = "-m 2048 -e 126976 -c 4096"
+UBINIZE_ARGS = "-m 2048 -p 128KiB"
+
+IMAGEDIR ?= "${MACHINE}"
+EXTRA_IMAGECMD_COMPAT = " --eraseblock=0x20000 -n -l "
+
+IMAGE_CMD_ubi_prepend = " \
+        cp ${IMAGE_ROOTFS}/boot/vmlinux.gz ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz; \
+        cp ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin; \
+        cp ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin; \
+        rm -f ${IMAGE_ROOTFS}/boot/vmlinux.gz; \
+        rm -f ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin; \
+        rm -f ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin; \
+        "
+
+IMAGE_CMD_ubi_append = "; \
+       vfi3 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz > ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.nfi; \
+        mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/duo2; \
+        cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${DEPLOY_DIR_IMAGE}/vuplus/duo2/root_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz ${DEPLOY_DIR_IMAGE}/vuplus/duo2/kernel_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/duo2/initrd_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/duo2/splash_cfe_auto.bin; \
+        cd ${DEPLOY_DIR_IMAGE}; \
+       zip ${IMAGE_NAME}_usb.zip vuplus/duo2/*; \
+       rm -rf vuplus; \ 
+        "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/conf/machine/vusolo2.conf b/conf/machine/vusolo2.conf
new file mode 100644 (file)
index 0000000..5b60290
--- /dev/null
@@ -0,0 +1,165 @@
+#@TYPE: Machine
+#@NAME: vusolo2
+#@DESCRIPTION: Machine configuration for the VuPlus
+
+TARGET_ARCH = "mipsel"
+
+PREFERRED_VERSION_linux-vusolo2 = "2.6.37"
+PREFERRED_VERSION_linux-libc-headers = "2.6.31"
+
+PREFERRED_PROVIDER_virtual/kernel = "linux-vusolo2"
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.18 = "kernel vuplus-dvb-modules \
+        kernel-module-isofs \
+        kernel-module-sr-mod    kernel-module-usb-storage \
+        kernel-module-cdrom \
+        kernel-module-msdos kernel-module-vfat kernel-module-fat \
+        kernel-module-libata kernel-module-ntfs kernel-module-sata-svw \
+        kernel-module-nls-iso8859-15 kernel-module-nls-cp850 \
+        kernel-module-nls-utf8 \
+        kernel-module-i2c-core kernel-module-i2c-dev kernel-module-firmware-class kernel-module-input kernel-module-evdev \
+        kernel-module-snd-pcm kernel-module-snd \
+       kernel-module-tun \
+       kernel-module-fb \
+       v4l-dvb-module-dvb-core \
+       kernel-module-usbhid \
+       kernel-module-mousedev \
+        "
+
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.18 = "\
+        kernel-module-cifs \
+        kernel-module-exportfs \
+        kernel-module-ext2 \
+        kernel-module-reiserfs \
+        kernel-module-xfs \
+       "
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.37 = "kernel vuplus-dvb-modules"
+
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.37 = "\
+       kernel-module-ext2 \
+       "
+
+MACHINE_ESSENTIAL_EXTRA_RDEPENDS = ${@base_contains('PREFERRED_VERSION_linux-vusolo2', '2.6.18', '${MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.18}', '${MACHINE_ESSENTIAL_EXTRA_RDEPENDS_2.6.37}', d)}
+MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS = ${@base_contains('PREFERRED_VERSION_linux-vusolo2', '2.6.18', '${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.18}', '${MACHINE_ESSENTIAL_EXTRA_RRECOMMENDS_2.6.37}', d)}
+
+require conf/machine/include/vuplus-modules.inc
+
+#MACHINE_ESSENTIAL_EXTRA_RDEPENDS += ${@base_contains('PREFERRED_VERSION_linux-vusolo2', '2.6.37', '${KERNEL_WIFI_MODULES}', '', d)}
+#MACHINE_ESSENTIAL_EXTRA_RDEPENDS += ${@base_contains('PREFERRED_VERSION_linux-vusolo2', '2.6.37', '${KERNEL_DVB_MODULES}', '', d)}
+
+PREFERRED_VERSION_wpa-supplicant = ${@base_contains('PREFERRED_VERSION_linux-vusolo2', '2.6.18', '0.5.10', '0.7.3', d)}
+
+IMAGE_FSTYPES = ${@base_contains('PREFERRED_VERSION_linux-vusolo2', '2.6.18', 'tar.bz2 jffs2', 'tar.bz2 ubi', d)}
+
+TARGET_FPU = "hard"
+
+MACHINE_FEATURES += "kernel26"
+
+TARGET_CC_ARCH = "-march=mips32"
+
+DISTRO_FEATURES += " mplt"
+
+PREFERRED_PROVIDER_task-vuplus-dvbapi = "task-vuplus-dvbapi3"
+PREFERRED_PROVIDER_task-vuplus-ui = "task-vuplus-enigma2"
+
+GLIBC_ADDONS ?= "ports,nptl,libidn"
+GLIBC_EXTRA_OECONF = "--disable-profile --with-tls --without-fp --with-__thread"
+
+PREFERRED_PROVIDER_xserver = "xserver-kdrive"
+
+EXTRA_IMAGEDEPENDS += "vuplus-makenfi-native"
+
+MACHINE_FEATURES += "alsa pci"
+MACHINE_FEATURES += "wifi"
+MACHINE_FEATURES += "vuwlan"
+MACHINE_FEATURES += "enable-rc-kbd"
+MACHINE_FEATURES += "display-text-vfd"
+
+
+
+EXTRA_IMAGECMD_jffs2 = " --eraseblock=0x20000 -n -l "
+IMAGE_CMD_jffs2 = " \
+       cp ${IMAGE_ROOTFS}/boot/vmlinux.gz ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz; \
+        cp ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin; \
+        cp ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin; \
+       rm -f ${IMAGE_ROOTFS}/boot/vmlinux.gz; \
+        rm -f ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin; \
+        rm -f ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin; \
+       mkfs.jffs2 --root=${IMAGE_ROOTFS}/boot --faketime \
+       --disable-compressor=lzo --compression-mode=size \
+       --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 \
+       ${EXTRA_IMAGECMD}; rm -rf ${IMAGE_ROOTFS}/boot/*; \
+       rm -rf ${IMAGE_ROOTFS}/tmp/*; \
+       mkfs.jffs2 --root=${IMAGE_ROOTFS} \
+       --disable-compressor=lzo --compression-mode=size \
+       --output=${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 \
+       ${EXTRA_IMAGECMD}; \
+       vfi3 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz > ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.nfi; \
+       mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/solo2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.jffs2 ${DEPLOY_DIR_IMAGE}/vuplus/solo2/root_cfe_auto.jffs2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz ${DEPLOY_DIR_IMAGE}/vuplus/solo2/kernel_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/vuplus/solo2/boot_cfe_auto.jffs2; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/solo2/initrd_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/solo2/splash_cfe_auto.bin; \
+       cd ${DEPLOY_DIR_IMAGE}; \
+       zip ${IMAGE_NAME}_usb.zip vuplus/solo2/*; \
+       rm -rf vuplus; \       
+"
+
+
+
+UBI_VOLNAME = "rootfs"
+MKUBIFS_ARGS = "-m 2048 -e 126976 -c 3984"
+UBINIZE_ARGS = "-m 2048 -p 128KiB"
+
+IMAGEDIR ?= "${MACHINE}"
+EXTRA_IMAGECMD_COMPAT = " --eraseblock=0x20000 -n -l "
+
+IMAGE_CMD_ubi_prepend = " \
+        cp ${IMAGE_ROOTFS}/boot/vmlinux.gz ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz; \
+        cp ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin; \
+        cp ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin; \
+        rm -f ${IMAGE_ROOTFS}/boot/vmlinux.gz; \
+        rm -f ${IMAGE_ROOTFS}/boot/initrd_cfe_auto.bin; \
+        rm -f ${IMAGE_ROOTFS}/boot/splash_cfe_auto.bin; \
+        "
+
+IMAGE_CMD_ubi_append = "; \
+       vfi3 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.boot.jffs2 ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz > ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.nfi; \
+        mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/solo2; \
+        cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${DEPLOY_DIR_IMAGE}/vuplus/solo2/root_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vmlinux.gz ${DEPLOY_DIR_IMAGE}/vuplus/solo2/kernel_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.initrd_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/solo2/initrd_cfe_auto.bin; \
+       cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.splash_cfe_auto.bin ${DEPLOY_DIR_IMAGE}/vuplus/solo2/splash_cfe_auto.bin; \
+        cd ${DEPLOY_DIR_IMAGE}; \
+       zip ${IMAGE_NAME}_usb.zip vuplus/solo2/*; \
+       rm -rf vuplus; \ 
+        "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/recipes/base-files/base-files/vu7425/fstab b/recipes/base-files/base-files/vu7425/fstab
new file mode 100755 (executable)
index 0000000..5e15a51
--- /dev/null
@@ -0,0 +1,10 @@
+rootfs               /                    auto       defaults              1 1
+proc                 /proc                proc       defaults              0 0
+devpts               /dev/pts             devpts     mode=0620,gid=5       0 0
+usbdevfs             /proc/bus/usb        usbfs      defaults              0 0
+/dev/mtdblock2      /boot                jffs2      ro                    0 0
+tmpfs                /var                 tmpfs      defaults              0 0
+tmpfs                /tmp                 tmpfs      defaults              0 0
+tmpfs                /dev/shm             tmpfs      mode=0777             0  0
+/dev/sda1            /media/hdd           auto       defaults              0 0
+
diff --git a/recipes/base-files/base-files/vu7425/fstab_3.1 b/recipes/base-files/base-files/vu7425/fstab_3.1
new file mode 100755 (executable)
index 0000000..13869e9
--- /dev/null
@@ -0,0 +1,9 @@
+rootfs               /                    auto       defaults              1 1
+proc                 /proc                proc       defaults              0 0
+devpts               /dev/pts             devpts     mode=0620,gid=5       0 0
+usbdevfs             /proc/bus/usb        usbfs      defaults              0 0
+tmpfs                /var                 tmpfs      defaults              0 0
+tmpfs                /tmp                 tmpfs      defaults              0 0
+tmpfs                /dev/shm             tmpfs      mode=0777             0  0
+/dev/sda1            /media/hdd           auto       defaults              0 0
+
diff --git a/recipes/base-files/base-files/vuduo2/fstab b/recipes/base-files/base-files/vuduo2/fstab
new file mode 100755 (executable)
index 0000000..5e15a51
--- /dev/null
@@ -0,0 +1,10 @@
+rootfs               /                    auto       defaults              1 1
+proc                 /proc                proc       defaults              0 0
+devpts               /dev/pts             devpts     mode=0620,gid=5       0 0
+usbdevfs             /proc/bus/usb        usbfs      defaults              0 0
+/dev/mtdblock2      /boot                jffs2      ro                    0 0
+tmpfs                /var                 tmpfs      defaults              0 0
+tmpfs                /tmp                 tmpfs      defaults              0 0
+tmpfs                /dev/shm             tmpfs      mode=0777             0  0
+/dev/sda1            /media/hdd           auto       defaults              0 0
+
diff --git a/recipes/base-files/base-files/vuduo2/fstab_3.1 b/recipes/base-files/base-files/vuduo2/fstab_3.1
new file mode 100755 (executable)
index 0000000..13869e9
--- /dev/null
@@ -0,0 +1,9 @@
+rootfs               /                    auto       defaults              1 1
+proc                 /proc                proc       defaults              0 0
+devpts               /dev/pts             devpts     mode=0620,gid=5       0 0
+usbdevfs             /proc/bus/usb        usbfs      defaults              0 0
+tmpfs                /var                 tmpfs      defaults              0 0
+tmpfs                /tmp                 tmpfs      defaults              0 0
+tmpfs                /dev/shm             tmpfs      mode=0777             0  0
+/dev/sda1            /media/hdd           auto       defaults              0 0
+
diff --git a/recipes/base-files/base-files/vusolo2/fstab b/recipes/base-files/base-files/vusolo2/fstab
new file mode 100755 (executable)
index 0000000..5e15a51
--- /dev/null
@@ -0,0 +1,10 @@
+rootfs               /                    auto       defaults              1 1
+proc                 /proc                proc       defaults              0 0
+devpts               /dev/pts             devpts     mode=0620,gid=5       0 0
+usbdevfs             /proc/bus/usb        usbfs      defaults              0 0
+/dev/mtdblock2      /boot                jffs2      ro                    0 0
+tmpfs                /var                 tmpfs      defaults              0 0
+tmpfs                /tmp                 tmpfs      defaults              0 0
+tmpfs                /dev/shm             tmpfs      mode=0777             0  0
+/dev/sda1            /media/hdd           auto       defaults              0 0
+
diff --git a/recipes/base-files/base-files/vusolo2/fstab_3.1 b/recipes/base-files/base-files/vusolo2/fstab_3.1
new file mode 100755 (executable)
index 0000000..13869e9
--- /dev/null
@@ -0,0 +1,9 @@
+rootfs               /                    auto       defaults              1 1
+proc                 /proc                proc       defaults              0 0
+devpts               /dev/pts             devpts     mode=0620,gid=5       0 0
+usbdevfs             /proc/bus/usb        usbfs      defaults              0 0
+tmpfs                /var                 tmpfs      defaults              0 0
+tmpfs                /tmp                 tmpfs      defaults              0 0
+tmpfs                /dev/shm             tmpfs      mode=0777             0  0
+/dev/sda1            /media/hdd           auto       defaults              0 0
+
diff --git a/recipes/directfb/directfb-1.4.2/directfb-vuplus-blit.patch b/recipes/directfb/directfb-1.4.2/directfb-vuplus-blit.patch
new file mode 100644 (file)
index 0000000..adccbb1
--- /dev/null
@@ -0,0 +1,69 @@
+diff --git a/systems/fbdev/fbdev.c b/systems/fbdev/fbdev.c
+index cc73416..326b7d8 100644
+--- a/systems/fbdev/fbdev.c
++++ b/systems/fbdev/fbdev.c
+@@ -94,6 +94,12 @@
+ #include <core/core_system.h>
++typedef unsigned char __u8;
++#ifndef FBIO_BLIT
++#define FBIO_SET_MANUAL_BLIT _IOW('F', 0x21, __u8)
++#define FBIO_BLIT 0x22
++#endif
++
+ DFB_CORE_SYSTEM( fbdev )
+@@ -306,6 +312,11 @@ static DFBResult dfb_fbdev_open( void )
+           goto error;
+      }
++     {
++          unsigned char tmp = 1;
++          if(ioctl(dfb_fbdev->fd,FBIO_SET_MANUAL_BLIT, &tmp) < 0)
++               printf("FBIO_SET_MANUAL_BLIT Fail!!\n");
++     }
+      return DFB_OK;
+ error:
+      return error_result;
+@@ -777,6 +788,12 @@ system_leave( bool emergency )
+                return ret;
+      }
++     {
++          unsigned char tmp = 0;
++          if(ioctl(dfb_fbdev->fd,FBIO_SET_MANUAL_BLIT, &tmp) < 0)
++               printf("FBIO_SET_MANUAL_BLIT Fail!!\n");
++     }
++
+      close( dfb_fbdev->fd );
+      D_FREE( dfb_fbdev );
+diff --git a/systems/fbdev/fbdev_surface_pool.c b/systems/fbdev/fbdev_surface_pool.c
+index 7383681..569edf2 100644
+--- a/systems/fbdev/fbdev_surface_pool.c
++++ b/systems/fbdev/fbdev_surface_pool.c
+@@ -359,6 +359,12 @@ fbdevLock( CoreSurfacePool       *pool,
+      return DFB_OK;
+ }
++#include <sys/ioctl.h>
++typedef unsigned char __u8;
++#ifndef FBIO_BLIT
++#define FBIO_SET_MANUAL_BLIT _IOW('F', 0x21, __u8)
++#define FBIO_BLIT 0x22
++#endif
+ static DFBResult
+ fbdevUnlock( CoreSurfacePool       *pool,
+              void                  *pool_data,
+@@ -378,6 +384,9 @@ fbdevUnlock( CoreSurfacePool       *pool,
+      (void) alloc;
++     if (ioctl(dfb_fbdev->fd, FBIO_BLIT) < 0)
++          printf("FBIO_BLIT\n");
++
+      return DFB_OK;
+ }
diff --git a/recipes/directfb/directfb-1.4.2/directfbrc b/recipes/directfb/directfb-1.4.2/directfbrc
new file mode 100644 (file)
index 0000000..1633e41
--- /dev/null
@@ -0,0 +1,8 @@
+system=fbdev
+fbdev=/dev/fb0
+module-dir=/usr/lib/directfb-1.4-0
+mode=1280x720
+depth=32
+bg-none
+no-vt
+no-vt-switch
index 9066ff2..e05aba7 100644 (file)
@@ -38,6 +38,8 @@ do_stage() {
 
 do_install() {
         oe_runmake 'DESTDIR=${D}' install
+       install -d ${D}${sysconfdir}
+       install -m 755 ${WORKDIR}/directfbrc ${D}${sysconfdir}
 }
 
 
@@ -63,11 +65,13 @@ FILES_${PN}-dev += "\
   ${libdir}/directfb-${RV}/systems/*.la \
   ${libdir}/directfb-${RV}/inputdrivers/*.la \
   ${libdir}/directfb-${RV}/interfaces/*/*.la \
+  ${libdir}/directfb-${RV}/gfxdrivers/*.la \
   ${libdir}/directfb-${RV}/wm/*.la \
 "
 
 FILES_${PN} += "\
   ${libdir}/directfb-${RV}/systems/*.so \
+  ${libdir}/directfb-${RV}/gfxdrivers/*.so \
   ${libdir}/directfb-${RV}/inputdrivers/*.so \
   ${libdir}/directfb-${RV}/interfaces/*/*.so \
   ${libdir}/directfb-${RV}/wm/*.so \
index 1e15186..4c91d2d 100644 (file)
@@ -10,6 +10,8 @@ SRC_URI = " \
     file://mkdfiff.patch;patch=1 \
     file://dont-use-linux-config.patch;patch=1 \
     file://ts_lib_autotools.patch;patch=1 \
+    file://directfb-vuplus-blit.patch;patch=1 \
+    file://directfbrc \
 "
 
 EXTRA_OECONF = "\
diff --git a/recipes/duo2lcd4linux/duo2lcd4linux_0.1.bb b/recipes/duo2lcd4linux/duo2lcd4linux_0.1.bb
new file mode 100644 (file)
index 0000000..e95b4fc
--- /dev/null
@@ -0,0 +1,29 @@
+DESCRIPTION = "lcd4linux plugin for duo2"
+LICENSE = "GPLv2"
+
+SRC_URI = " \
+        file://LCD4linux.tar.gz \
+"
+
+RDEPENDS = python-codecs python-datetime python-textutils python-imaging
+
+S = "${WORKDIR}/LCD4linux"
+
+PR = "r0"
+
+do_install() {
+        install -d  ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux
+        install -m 0755 ${S}/*.py ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux/
+        install -m 0755 ${S}/*.png ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux
+        install -m 0755 ${S}/*.conf ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux
+        install -m 0755 ${S}/*.so ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux
+        install -m 0755 ${S}/*.pot ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux
+        install -d  ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux/locale/de/LC_MESSAGES
+        install -m 0644 ${S}/locale/de/LC_MESSAGES/LCD4linux.mo ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux/locale/de/LC_MESSAGES
+        install -d  ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux/wetter
+        install -m 0755 ${S}/wetter/*.gif ${D}/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux/wetter
+}
+
+FILES_${PN} = "/usr/lib/enigma2/python/Plugins/Extensions/LCD4linux"
+
+PACKAGE_ARCH = "${MACHINE_ARCH}"
diff --git a/recipes/duo2lcd4linux/files/LCD4linux.tar.gz b/recipes/duo2lcd4linux/files/LCD4linux.tar.gz
new file mode 100644 (file)
index 0000000..8da13fa
Binary files /dev/null and b/recipes/duo2lcd4linux/files/LCD4linux.tar.gz differ
index 61d87c1..132d49f 100644 (file)
@@ -31,6 +31,9 @@ RDEPENDS_append_bm750 = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-av
 RDEPENDS_append_vusolo = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-avi"
 RDEPENDS_append_vuuno = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-avi"
 RDEPENDS_append_vuultimo = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-avi"
+RDEPENDS_append_vu7425 = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-avi"
+RDEPENDS_append_vuduo2 = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-avi"
+RDEPENDS_append_vusolo2 = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-avi"
 RDEPENDS_append_dm7020hd = " ${GST_BASE_RDEPENDS} ${GST_DVD_RDEPENDS} gst-plugin-avi"
 
 # 'forward depends' - no two providers can have the same PACKAGES_DYNAMIC, however both
@@ -144,6 +147,11 @@ SRC_URI_append_vuultimo = " \
            file://skin_user.xml \
            file://vfd_icons \
 "
+SRC_URI_append_vu7425 = " \
+           file://analog.ttf \
+           file://skin_user.xml \
+           file://vfd_icons \
+"
 
 def change_po():
         import os
diff --git a/recipes/enigma2/enigma2/vuplus/enigma2-hbbtv_20120604.patch b/recipes/enigma2/enigma2/vuplus/enigma2-hbbtv_20120604.patch
new file mode 100644 (file)
index 0000000..1aa3bda
--- /dev/null
@@ -0,0 +1,1392 @@
+diff --git a/configure.ac b/configure.ac
+index 18a5986..138cb10 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -225,6 +225,8 @@ lib/python/Plugins/Extensions/DLNAServer/Makefile
+ lib/python/Plugins/Extensions/DLNAServer/meta/Makefile
+ lib/python/Plugins/Extensions/DLNABrowser/Makefile
+ lib/python/Plugins/Extensions/DLNABrowser/meta/Makefile
++lib/python/Plugins/Extensions/HbbTV/Makefile
++lib/python/Plugins/Extensions/HbbTV/meta/Makefile
+ lib/python/Plugins/SystemPlugins/CleanupWizard/Makefile
+ lib/python/Plugins/SystemPlugins/CleanupWizard/meta/Makefile
+ lib/python/Plugins/SystemPlugins/CommonInterfaceAssignment/Makefile
+diff --git a/data/keymap.xml b/data/keymap.xml
+index 10a36de..cdc583e 100755
+--- a/data/keymap.xml
++++ b/data/keymap.xml
+@@ -225,6 +225,12 @@
+               <key id="KEY_GREEN" mapto="subserviceSelection" flags="b" />
+       </map>
++      <map context="InfobarRedButtonActions">
++              <device name="dreambox advanced remote control (native)">
++                      <key id="KEY_RED" mapto="activateRedButton" flags="b" />
++              </device>
++      </map>
++
+       <map context="InfobarSubserviceQuickzapActions">
+               <key id="KEY_PREVIOUS" mapto="prevSubservice" flags="m" />
+               <key id="KEY_NEXT" mapto="nextSubservice" flags="m" />
+diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp
+index 227928b..9773a56 100644
+--- a/lib/dvb/pmt.cpp
++++ b/lib/dvb/pmt.cpp
+@@ -20,6 +20,11 @@
+ #include <dvbsi++/registration_descriptor.h>
+ #include <dvbsi++/ac3_descriptor.h>
++#include <dvbsi++/simple_application_location_descriptor.h>
++#include <dvbsi++/simple_application_boundary_descriptor.h>
++#include <dvbsi++/transport_protocol_descriptor.h>
++
++
+ eDVBServicePMTHandler::eDVBServicePMTHandler()
+       :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF), m_no_pat_entry_delay(eTimer::create())
+ {
+@@ -29,6 +34,9 @@ eDVBServicePMTHandler::eDVBServicePMTHandler()
+       CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready);
+       CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready);
+       CONNECT(m_no_pat_entry_delay->timeout, eDVBServicePMTHandler::sendEventNoPatEntry);
++
++      CONNECT(m_AIT.tableReady, eDVBServicePMTHandler::AITready);
++      CONNECT(m_OC.tableReady, eDVBServicePMTHandler::OCready);
+ }
+ eDVBServicePMTHandler::~eDVBServicePMTHandler()
+@@ -188,6 +196,93 @@ void eDVBServicePMTHandler::PATready(int)
+               serviceEvent(eventNoPAT);
+ }
++void eDVBServicePMTHandler::AITready(int error)
++{
++      eDebug("AITready");
++      ePtr<eTable<ApplicationInformationSection> > ptr;
++      if (!m_AIT.getCurrent(ptr))
++      {
++              m_HBBTVUrl = "";
++              for (std::vector<ApplicationInformationSection*>::const_iterator it = ptr->getSections().begin(); it != ptr->getSections().end(); ++it)
++              {
++                      for (std::list<ApplicationInformation *>::const_iterator i = (*it)->getApplicationInformation()->begin(); i != (*it)->getApplicationInformation()->end(); ++i)
++                      {
++                              if ((*i)->getApplicationControlCode() == 0x01) /* AUTOSTART */
++                              {
++                                      for (DescriptorConstIterator desc = (*i)->getDescriptors()->begin();
++                                              desc != (*i)->getDescriptors()->end(); ++desc)
++                                      {
++                                              switch ((*desc)->getTag())
++                                              {
++                                              case APPLICATION_DESCRIPTOR:
++                                                      break;
++                                              case APPLICATION_NAME_DESCRIPTOR:
++                                                      break;
++                                              case TRANSPORT_PROTOCOL_DESCRIPTOR:
++                                              {
++                                                      TransportProtocolDescriptor *transport = (TransportProtocolDescriptor*)(*desc);
++                                                      switch (transport->getProtocolId())
++                                                      {
++                                                      case 1: /* object carousel */
++                                                              if (m_dsmcc_pid >= 0)
++                                                              {
++                                                                      m_OC.begin(eApp, eDVBDSMCCDLDataSpec(m_dsmcc_pid), m_demux);
++                                                              }
++                                                              break;
++                                                      case 2: /* ip */
++                                                              break;
++                                                      case 3: /* interaction */
++                                                              for (InterActionTransportConstIterator interactionit = transport->getInteractionTransports()->begin(); interactionit != transport->getInteractionTransports()->end(); ++interactionit)
++                                                              {
++                                                                      m_HBBTVUrl = (*interactionit)->getUrlBase()->getUrl();
++                                                                      break;
++                                                              }
++                                                              break;
++                                                      }
++                                                      break;
++                                              }
++                                              case GRAPHICS_CONSTRAINTS_DESCRIPTOR:
++                                                      break;
++                                              case SIMPLE_APPLICATION_LOCATION_DESCRIPTOR:
++                                              {
++                                                      SimpleApplicationLocationDescriptor *applicationlocation = (SimpleApplicationLocationDescriptor*)(*desc);
++                                                      m_HBBTVUrl += applicationlocation->getInitialPath();
++                                                      break;
++                                              }
++                                              case APPLICATION_USAGE_DESCRIPTOR:
++                                                      break;
++                                              case SIMPLE_APPLICATION_BOUNDARY_DESCRIPTOR:
++                                                      break;
++                                              }
++                                      }
++                              }
++                      }
++              }
++              if (!m_HBBTVUrl.empty())
++              {
++                      eDebug(">> parsed hbbtv url : [%s]", m_HBBTVUrl.c_str());
++                      serviceEvent(eventHBBTVInfo);
++              }
++      }
++      /* for now, do not keep listening for table updates */
++      m_AIT.stop();
++}
++
++void eDVBServicePMTHandler::OCready(int error)
++{
++      eDebug("OCready");
++      ePtr<eTable<OCSection> > ptr;
++      if (!m_OC.getCurrent(ptr))
++      {
++              std::string data;
++              for (std::vector<OCSection*>::const_iterator it = ptr->getSections().begin(); it != ptr->getSections().end(); ++it)
++              {
++              }
++      }
++      /* for now, do not keep listening for table updates */
++      m_OC.stop();
++}
++
+ PyObject *eDVBServicePMTHandler::getCaIds(bool pair)
+ {
+       ePyObject ret;
+@@ -582,6 +677,22 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
+                                               }
+                                               prev_audio = 0;
+                                       }
++                                      case 0x05: /* ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private sections */
++                                      {
++                                              for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
++                                                      desc != (*es)->getDescriptors()->end(); ++desc)
++                                              {
++                                                      switch ((*desc)->getTag())
++                                                      {
++                                                      case APPLICATION_SIGNALLING_DESCRIPTOR:
++                                                              program.aitPid = (*es)->getPid();
++                                                              m_AIT.begin(eApp, eDVBAITSpec(program.aitPid), m_demux);
++                                                              break;
++                                                      }
++                                              }
++                                              break;
++                                      }
++
+                                       default:
+                                               break;
+                                       }
+@@ -911,6 +1022,9 @@ void eDVBServicePMTHandler::free()
+               m_pvr_channel->setCueSheet(0);
+       }
++      m_OC.stop();
++      m_AIT.stop();
++
+       m_PMT.stop();
+       m_PAT.stop();
+       m_service = 0;
+diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h
+index 4be8000..5942498 100644
+--- a/lib/dvb/pmt.h
++++ b/lib/dvb/pmt.h
+@@ -21,6 +21,26 @@
+ class eDVBCAService;
+ class eDVBScan;
++#include <dvbsi++/application_information_section.h>
++class OCSection : public LongCrcSection
++{
++      protected:
++              void *data;
++
++      public:
++              OCSection(const uint8_t * const buffer)
++              : LongCrcSection(buffer)
++              {
++                      data = malloc(getSectionLength());
++                      memcpy(data, buffer, getSectionLength());
++              }
++              ~OCSection()
++              {
++                      free(data);
++              }
++              void *getData() { return data; }
++};
++
+ struct channel_data: public Object
+ {
+       ePtr<eDVBChannel> m_channel;
+@@ -95,11 +115,19 @@ class eDVBServicePMTHandler: public Object
+       void SDTScanEvent(int);
+       ePtr<eConnection> m_scan_event_connection;
++      eAUTable<eTable<ApplicationInformationSection> > m_AIT;
++      eAUTable<eTable<OCSection> > m_OC;
++
+       void PMTready(int error);
+       void PATready(int error);
+       
+       int m_pmt_pid;
+       
++      void AITready(int error);
++      void OCready(int error);
++      int m_dsmcc_pid;
++      std::string m_HBBTVUrl;
++      
+       int m_use_decode_demux;
+       uint8_t m_decode_demux_num;
+       ePtr<eTimer> m_no_pat_entry_delay;
+@@ -128,6 +156,8 @@ public:
+               eventSOF,          // seek pre start
+               eventEOF,          // a file playback did end
+               
++              eventHBBTVInfo, /* HBBTV information was detected in the AIT */
++              
+               eventMisconfiguration, // a channel was not found in any list, or no frontend was found which could provide this channel
+       };
+ #ifndef SWIG
+@@ -196,6 +226,7 @@ public:
+               int pcrPid;
+               int pmtPid;
+               int textPid;
++              int aitPid;
+               bool isCrypted() { return !caids.empty(); }
+               PyObject *createPythonObject();
+       };
+@@ -213,6 +244,8 @@ public:
+       void resetCachedProgram() { m_have_cached_program = false; }
+       void sendEventNoPatEntry();
++      void getHBBTVUrl(std::string &ret) { ret = m_HBBTVUrl; }
++
+       /* deprecated interface */
+       int tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *sg=0, bool simulate=false, eDVBService *service = 0);
+diff --git a/lib/dvb/specs.h b/lib/dvb/specs.h
+index 6be938c..d6ddde4 100644
+--- a/lib/dvb/specs.h
++++ b/lib/dvb/specs.h
+@@ -165,4 +165,44 @@ public:
+       }
+ };
++#include <dvbsi++/application_information_section.h>
++
++struct eDVBAITSpec
++{
++      eDVBTableSpec m_spec;
++public:
++      eDVBAITSpec(int pid)
++      {
++              m_spec.pid     = pid;
++              m_spec.tid     = ApplicationInformationSection::TID;
++              m_spec.timeout = ApplicationInformationSection::TIMEOUT;
++              m_spec.flags   = eDVBTableSpec::tfAnyVersion |
++                      eDVBTableSpec::tfHaveTID | eDVBTableSpec::tfCheckCRC |
++                      eDVBTableSpec::tfHaveTimeout;
++      }
++      operator eDVBTableSpec &()
++      {
++              return m_spec;
++      }
++};
++
++struct eDVBDSMCCDLDataSpec
++{
++      eDVBTableSpec m_spec;
++public:
++      eDVBDSMCCDLDataSpec(int pid)
++      {
++              m_spec.pid     = pid;
++              m_spec.tid     = TID_DSMCC_DL_DATA;
++              m_spec.timeout = 20000;
++              m_spec.flags   = eDVBTableSpec::tfAnyVersion |
++                      eDVBTableSpec::tfHaveTID | eDVBTableSpec::tfCheckCRC |
++                      eDVBTableSpec::tfHaveTimeout;
++      }
++      operator eDVBTableSpec &()
++      {
++              return m_spec;
++      }
++};
++
+ #endif
+diff --git a/lib/python/Components/Converter/ServiceInfo.py b/lib/python/Components/Converter/ServiceInfo.py
+index e2fa12c..b39aaa1 100644
+--- a/lib/python/Components/Converter/ServiceInfo.py
++++ b/lib/python/Components/Converter/ServiceInfo.py
+@@ -20,7 +20,7 @@ class ServiceInfo(Converter, object):
+       SID = 14
+       FRAMERATE = 15
+       TRANSFERBPS = 16
+-      
++      HAS_HBBTV = 17  
+       def __init__(self, type):
+               Converter.__init__(self, type)
+@@ -42,6 +42,7 @@ class ServiceInfo(Converter, object):
+                               "Sid": (self.SID, (iPlayableService.evUpdatedInfo,)),
+                               "Framerate": (self.FRAMERATE, (iPlayableService.evVideoSizeChanged,iPlayableService.evUpdatedInfo,)),
+                               "TransferBPS": (self.TRANSFERBPS, (iPlayableService.evUpdatedInfo,)),
++                              "HasHBBTV": (self.HAS_HBBTV, (iPlayableService.evUpdatedInfo,iPlayableService.evHBBTVInfo,)),
+                       }[type]
+       def getServiceInfoString(self, info, what, convert = lambda x: "%d" % x):
+@@ -82,6 +83,9 @@ class ServiceInfo(Converter, object):
+               elif self.type == self.SUBSERVICES_AVAILABLE:
+                       subservices = service.subServices()
+                       return subservices and subservices.getNumberOfSubservices() > 0
++              elif self.type == self.HAS_HBBTV:
++                      return info.getInfoString(iServiceInformation.sHBBTVUrl) != ""
++
+       boolean = property(getBoolean)
+       
+diff --git a/lib/python/Components/Sources/CurrentService.py b/lib/python/Components/Sources/CurrentService.py
+index 2501c17..133f863 100644
+--- a/lib/python/Components/Sources/CurrentService.py
++++ b/lib/python/Components/Sources/CurrentService.py
+@@ -15,7 +15,8 @@ class CurrentService(PerServiceBase, Source):
+                               iPlayableService.evUpdatedInfo: self.serviceEvent,
+                               iPlayableService.evUpdatedEventInfo: self.serviceEvent,
+                               iPlayableService.evCuesheetChanged: self.serviceEvent,
+-                              iPlayableService.evVideoSizeChanged: self.serviceEvent
++                              iPlayableService.evVideoSizeChanged: self.serviceEvent,
++                              iPlayableService.evHBBTVInfo: self.serviceEvent
+                       }, with_event=True)
+               self.navcore = navcore
+diff --git a/lib/python/Plugins/Extensions/HbbTV/Makefile.am b/lib/python/Plugins/Extensions/HbbTV/Makefile.am
+new file mode 100644
+index 0000000..18e39a1
+--- /dev/null
++++ b/lib/python/Plugins/Extensions/HbbTV/Makefile.am
+@@ -0,0 +1,9 @@
++installdir = $(pkglibdir)/python/Plugins/Extensions/HbbTV
++
++SUBDIRS = meta 
++
++install_PYTHON = \
++      __init__.py \
++      plugin.py 
++
++
+diff --git a/lib/python/Plugins/Extensions/HbbTV/__init__.py b/lib/python/Plugins/Extensions/HbbTV/__init__.py
+new file mode 100644
+index 0000000..a103e92
+--- /dev/null
++++ b/lib/python/Plugins/Extensions/HbbTV/__init__.py
+@@ -0,0 +1 @@
++#dumy
+diff --git a/lib/python/Plugins/Extensions/HbbTV/meta/Makefile.am b/lib/python/Plugins/Extensions/HbbTV/meta/Makefile.am
+new file mode 100644
+index 0000000..4b556b3
+--- /dev/null
++++ b/lib/python/Plugins/Extensions/HbbTV/meta/Makefile.am
+@@ -0,0 +1,3 @@
++installdir = $(datadir)/meta
++
++dist_install_DATA = plugin_hbbtv.xml
+diff --git a/lib/python/Plugins/Extensions/HbbTV/meta/plugin_hbbtv.xml b/lib/python/Plugins/Extensions/HbbTV/meta/plugin_hbbtv.xml
+new file mode 100644
+index 0000000..830b46e
+--- /dev/null
++++ b/lib/python/Plugins/Extensions/HbbTV/meta/plugin_hbbtv.xml
+@@ -0,0 +1,21 @@
++<default>
++        <prerequisites>
++                    <tag type="Network" />
++        </prerequisites>
++          <info>
++                    <author>kos</author>
++                    <name>HbbTV</name>
++                    <packagename>enigma2-plugin-extensions-hbbtv</packagename>
++                    <shortdescription>this is hbbtv plugin</shortdescription>
++                    <description>this is hbbtv plugin</description>
++          </info>
++        <files type="package"> <!-- without version, without .ipk -->
++              <file type="package" name="enigma2-plugin-extensions-hbbtv" />
++                <file type="package" name="libgmp3" />
++                <file type="package" name="libmpfr1" />
++                <file type="package" name="tslib-conf" />
++                <file type="package" name="libts-1.0-0" />
++                <file type="package" name="libsysfs2" />
++                <file type="package" name="directfb" />
++        </files>
++</default>
+diff --git a/lib/python/Plugins/Extensions/HbbTV/plugin.py b/lib/python/Plugins/Extensions/HbbTV/plugin.py
+new file mode 100644
+index 0000000..4ae2590
+--- /dev/null
++++ b/lib/python/Plugins/Extensions/HbbTV/plugin.py
+@@ -0,0 +1,861 @@
++from Plugins.Plugin import PluginDescriptor
++
++from Screens.Screen import Screen
++from Screens.InfoBar import InfoBar
++from Screens.ChoiceBox import ChoiceBox
++from Screens.MessageBox import MessageBox
++from Screens.InfoBarGenerics import InfoBarNotifications
++from Screens.VirtualKeyBoard import VirtualKeyBoard
++
++from Components.Button import Button
++from Components.Label import Label
++from Components.Sources.StaticText import StaticText
++from Components.ActionMap import NumberActionMap, ActionMap
++from Components.ServiceEventTracker import ServiceEventTracker
++from Components.MenuList import MenuList
++from Components.Label import Label, MultiColorLabel
++from Components.ConfigList import ConfigListScreen
++from Components.config import config, ConfigSubsection, ConfigPosition, getConfigListEntry, ConfigBoolean, ConfigInteger, ConfigText, ConfigSelection, configfile, getCharValue
++
++from enigma import eTimer, eConsoleAppContainer, getDesktop, eServiceReference, iPlayableService, iServiceInformation, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, getPrevAsciiCode
++
++
++import os, struct, threading, stat, select, time
++
++strIsEmpty = lambda x: x is None or len(x) == 0
++
++CORSAIR_PATH = "/usr/local/hbb-browser"
++
++_magic   = 0xBBADBEE
++_header  = '!IiII'
++_headlen = struct.calcsize(_header)
++_command_server = None
++_g_command_util = None
++def _unpack(packed_data):
++      global _magic
++      global _header
++      global _headlen
++      if strIsEmpty(packed_data):
++              return None
++      (m, o, l, s) = struct.unpack(_header, packed_data[:_headlen])
++      #print (m, o, l)
++      if m != _magic:
++              return None
++      d = packed_data[_headlen:_headlen+l]
++      return (o,d,s)
++
++def _pack(opcode, params=None, special=0):
++      global _magic
++      global _header
++      global _headlen
++      if strIsEmpty(params):
++              params = ''
++      packed_data = struct.pack(_header, _magic, opcode, len(params), special)
++      #print len(packed_data)
++      return packed_data + params
++
++class HbbTVPlayer(Screen, InfoBarNotifications):
++      skin =  """
++              <screen name="HbbTVPlayer" flags="wfNoBorder" position="0,0" size="0,0" title="HbbTV Player" backgroundColor="transparent">
++              </screen>
++              """
++      PLAYER_IDLE     = 0
++      PLAYER_PLAYING  = 1
++      PLAYER_PAUSED   = 2
++
++      def __init__(self, session, service):
++              Screen.__init__(self, session)
++              InfoBarNotifications.__init__(self)
++
++              self.session = session
++              self.service = service
++
++              global _g_command_util
++              self._command_util = _g_command_util
++
++              self["actions"] = ActionMap(["MinuteInputActions", "ColorActions", "InputActions", "InfobarChannelSelection", "EPGSelectActions"], {
++                      "ok"    : self._on_keyok,
++                      "cancel": self._on_keycancel,
++                      "up"    : self._on_keyup,
++                      "down"  : self._on_keydown,
++                      "left"  : self._on_keyleft,
++                      "right" : self._on_keyright,
++                      "red"   : self._on_keyred,
++                      "green" : self._on_keygreen,
++                      "yellow": self._on_keyyellow,
++                      "blue"  : self._on_keyblue,
++              }, -2)
++
++              self.__event_tracker = ServiceEventTracker(screen = self, eventmap = {
++                      iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
++                      iPlayableService.evStart: self.__serviceStarted,
++              })
++
++              self.state = self.PLAYER_PLAYING
++              self.lastseekstate = self.PLAYER_PLAYING
++              self.__seekableStatusChanged()
++
++              self.onClose.append(self.__onClose)
++              self.doPlay()
++
++      def _send_command(self, command, key=''):
++              params = None
++              if command == 'control_key':
++                      params = str(self._command_util.getKeyData(key))
++                      if params is None:
++                              return
++              self._command_util.doSend(command, params)
++
++      def __onClose(self):
++              self.session.nav.stopService()
++
++      def __seekableStatusChanged(self):
++              service = self.session.nav.getCurrentService()
++              if service is not None:
++                      seek = service.seek()
++                      if seek is None or not seek.isCurrentlySeekable():
++                              self.setSeekState(self.PLAYER_PLAYING)
++
++      def __serviceStarted(self):
++              self.state = self.PLAYER_PLAYING
++              self.__seekableStatusChanged()
++
++
++      def setSeekState(self, wantstate):
++              service = self.session.nav.getCurrentService()
++              if service is None:
++                      print "No Service found"
++                      return
++
++              pauseable = service.pause()
++              if pauseable is not None:
++                      if wantstate == self.PLAYER_PAUSED:
++                              pauseable.pause()
++                              self.state = self.PLAYER_PAUSED
++                              if not self.shown:
++                                      self.show()
++                      elif wantstate == self.PLAYER_PLAYING:
++                              pauseable.unpause()
++                              self.state = self.PLAYER_PLAYING
++              else:
++                      self.state = self.PLAYER_PLAYING
++
++      def _on_keyok(self):
++              self._send_command('control_key', 'key_ok')
++      def _on_keycancel(self):
++              self._send_command('control_back')
++              self.close()
++      def _on_keyup(self):
++              self._send_command('control_key', 'key_up')
++      def _on_keydown(self):
++              self._send_command('control_key', 'key_down')
++      def _on_keyleft(self):
++              self._send_command('control_key', 'key_left')
++      def _on_keyright(self):
++              self._send_command('control_key', 'key_right')
++      def _on_keyred(self):
++              self._send_command('control_key', 'key_red')
++      def _on_keygreen(self):
++              self._send_command('control_key', 'key_green')
++      def _on_keyyellow(self):
++              self._send_command('control_key', 'key_yellow')
++      def _on_keyblue(self):
++              self._send_command('control_key', 'key_blue')
++
++      def doPlay(self):
++              self.state = self.PLAYER_PLAYING
++              self.session.nav.playService(self.service)
++
++      def playpauseService(self):
++              if self.state == self.PLAYER_PLAYING:
++                      self.setSeekState(self.PLAYER_PAUSED)
++              elif self.state == self.PLAYER_PAUSED:
++                      self.setSeekState(self.PLAYER_PLAYING)
++
++class BrowserCommandServer:
++      global _magic
++      global _header
++      global _headlen
++      _fd = None
++      _server_thread = None
++      _terminated = True
++      _buff_size = 4096
++
++      def __init__(self):
++              self._opcode_map = {
++                      0x01 : self._url_stream
++              }
++              self.session = None
++              self._before_service = None
++
++      def open(self, session, filename):
++              self._session = session
++              try:
++                      os.unlink(filename)
++              except: pass
++              #if(os.stat(filename) < 0):
++              os.mknod(filename, stat.S_IFIFO|0666, 0);
++              self._fd = os.open(filename, os.O_RDONLY|os.O_NDELAY);
++              if self._fd < 0:
++                      print "Could not open pipe to controller plugin, UI will probably not work correctly"
++                      self._fd = None
++                      return False;
++              return True
++
++      def close(self):
++              if self._fd is not None:
++                      os.close(self._fd)
++
++      def start(self):
++              if self._fd is None:
++                      print "fd is none!!"
++                      return
++              self._terminated = False
++              self._server_thread = threading.Thread(target=self._run)
++              self._server_thread.start()
++              print "command server started!!"
++
++      def stop(self):
++              self._terminated = True
++
++      def _run(self):
++              while not self._terminated:
++                      try:
++                              packed_data = os.read(self._fd, self._buff_size)
++                              if packed_data is not None and len(packed_data) > 0:
++                                      self._handler(packed_data)
++                                      continue
++                              time.sleep(1)
++                      except Exception, ErrMsg:
++                              print ErrMsg
++                              pass
++
++      def _handler(self, data):
++              unpacked_data  = _unpack(data)
++              if unpacked_data is None:
++                      return
++              (opcode, params, special) = unpacked_data
++              print ">> recv : [%d] - [%s]" %(opcode, params)
++              try:
++                      self._opcode_map[opcode](params)
++              except: pass
++
++      def _url_stream(self, url):
++              #print "Stream URL Data :", url
++              #if strIsEmpty(rul):
++              #       print "Stream URL is empty!!"
++              #       return
++              self._before_service = self._session.nav.getCurrentlyPlayingServiceReference()
++              self._session.openWithCallback(self._cb_finished_stream, HbbTVPlayer, eServiceReference(4097, 0, url))
++
++      def _cb_finished_stream(self, data=None):
++              if self._before_service is not None:
++                      self._session.nav.playService(self._before_service)
++                      self._before_service = None
++
++
++class BrowserCommandUtil:
++      global _magic
++      global _header
++      global _headlen
++      _fd = None
++      _opcode_map = {
++               "control_back"   : 0x01
++              ,"control_forward": 0x02
++              ,"control_stop"   : 0x03
++              ,"control_reload" : 0x04
++              ,"control_openurl": 0x05
++              ,"control_exit"   : 0x06
++              ,"control_key"    : 0x07
++              ,"control_ascii"  : 0x08
++      }
++      _keycode_map = {
++               "key_f12"      : 61538
++              ,"key_red"      : 61506
++              ,"key_green"    : 61507
++              ,"key_yellow"   : 61508
++              ,"key_blue"     : 61509
++              ,"key_left"     : 57387
++              ,"key_right"    : 57388
++              ,"key_down"     : 57386
++              ,"key_up"       : 57385
++              ,"key_0"        : 63003
++              ,"key_1"        : 63004
++              ,"key_2"        : 63005
++              ,"key_3"        : 63006
++              ,"key_4"        : 63007
++              ,"key_5"        : 63008
++              ,"key_6"        : 63009
++              ,"key_7"        : 63010
++              ,"key_8"        : 63011
++              ,"key_9"        : 63012
++              ,"key_ok"       : 61451
++              ,"key_sh_left"  : 61531
++              ,"key_sh_right" : 61532
++              ,"key_backspace": 70000
++      }
++
++      def isConnected(self):
++              if self._fd is None:
++                      return False
++              return True
++
++      def doConnect(self, filename):
++              if not os.path.exists(filename):
++                      print "file not exists :", filename
++                      return False
++              try:
++                      self._fd = os.open(filename, os.O_WRONLY|os.O_NONBLOCK)
++                      if self._fd is None:
++                              print "fail to open file :", filename
++                              return False
++              except Exception, ErrMsg:
++                      print ErrMsg
++                      self._fd = None
++                      return False
++              print "connected!! to ", filename
++              return True
++
++      def doDisconnect(self):
++              if self._fd is None:
++                      return
++              os.close(self._fd)
++              self._fd = None
++
++      def doSend(self, command, params=None, special=0):
++              if self._fd is None:
++                      print "connected pipe was not exists!!"
++                      return False
++              data = ''
++              try:
++                      data = _pack(self._opcode_map[command], params, special)
++                      if data is None:
++                              return False
++                      os.write(self._fd, data)
++              except: return False
++              return True
++
++      def getKeyData(self, hash):
++              try:
++                      return self._keycode_map[hash]
++              except: pass
++              return None
++
++class BlankWindow(Screen):
++      skin =  """
++              <screen name="BlankWindow" position="0,0" size="1280,720" backgroundColor="transparent" flags="wfNoBorder" title="BlankWindow">
++              </screen>
++              """
++      def __init__(self, session):
++              Screen.__init__(self, session)
++              self._timer_close = eTimer()
++              self._timer_close.callback.append(self._cb_close)
++              self._timer_close.start(2000)
++
++      def _cb_close(self):
++              self.close()
++
++class OperaBrowserController(Screen):
++      skin =  """
++              <screen name="OperaBrowserController" position="0,0" size="1280,720" backgroundColor="transparent" flags="wfNoBorder" title="OperaBrowser">
++              </screen>
++              """
++      def __init__(self, session, url):
++              self._url     = url
++              self._session = session
++
++              Screen.__init__(self, session)
++              self["actions"] = ActionMap(["MinuteInputActions", "ColorActions", "InputActions", "InfobarChannelSelection", "EPGSelectActions"], {
++                      "ok"    : self._on_keyok,
++                      "cancel": self._on_keycancel,
++                      "up"    : self._on_keyup,
++                      "down"  : self._on_keydown,
++                      "left"  : self._on_keyleft,
++                      "right" : self._on_keyright,
++                      "red"   : self._on_keyred,
++                      "green" : self._on_keygreen,
++                      "yellow": self._on_keyyellow,
++                      "blue"  : self._on_keyblue,
++                      "info"  : self._on_keyinfo,
++                      "historyBack" : self._on_keyback,
++                      "historyNext" : self._on_keynext,
++              }, -2)
++              self["NumberActions"] = NumberActionMap( ["NumberActions"], {
++                      "0"     : self._on_keynumber,
++                      "1"     : self._on_keynumber,
++                      "2"     : self._on_keynumber,
++                      "3"     : self._on_keynumber,
++                      "4"     : self._on_keynumber,
++                      "5"     : self._on_keynumber,
++                      "6"     : self._on_keynumber,
++                      "7"     : self._on_keynumber,
++                      "8"     : self._on_keynumber,
++                      "9"     : self._on_keynumber,
++              })
++
++              self._opera_container = eConsoleAppContainer()
++              self._opera_container.dataAvail.append(self._cb_opera_container_dataAvail)
++              self._opera_container.appClosed.append(self._cb_opera_container_appClosed)
++
++              try:
++                      os.unlink('/tmp/.sock.hbbtv.cmd')
++              except: pass
++
++              global CORSAIR_PATH
++              command = 'cd %s; ./run-browser --url:%s &' %(CORSAIR_PATH, self._url)
++              print "COMMAND >>", command
++              self._opera_container.execute(command)
++
++              global _g_command_util
++              #_g_command_util = BrowserCommandUtil()
++              self._command_util = _g_command_util
++
++              '''
++              if not self._command_util.doConnect('/tmp/.sock.hbbtv.cmd'):
++                      print "fail to connect command server!!"
++              print "------------->> OK!!"
++              '''
++
++      def _cb_opera_container_dataAvail(self, data):
++              print data
++
++      def _cb_opera_container_appClosed(self, ret):
++              print ret
++              self._on_keycancel()
++
++      def _on_keynext(self):
++              self.sendCommand('control_forward')
++      def _on_keyback(self):
++              self.sendCommand('control_back')
++      def _on_keyup(self):
++              self.sendKeyCommand('key_up')
++      def _on_keydown(self):
++              self.sendKeyCommand('key_down')
++      def _on_keyleft(self):
++              self.sendKeyCommand('key_left')
++      def _on_keyright(self):
++              self.sendKeyCommand('key_right')
++      def _on_keyok(self):
++              self.sendKeyCommand('key_ok')
++      def _on_keyred(self):
++              self.sendKeyCommand('key_red')
++      def _on_keygreen(self):
++              self.sendKeyCommand('key_green')
++      def _on_keyyellow(self):
++              self.sendKeyCommand('key_yellow')
++      def _on_keyblue(self):
++              self.sendKeyCommand('key_blue')
++      def _on_keynumber(self, number):
++              self.sendKeyCommand('key_%d'%(number))
++      def _on_keyinfo(self):
++              if strIsEmpty(self._url):
++                      return
++              self.sendCommand('control_openurl', self._url)
++
++      def _on_keycancel(self):
++              self.sendCommand('control_openurl', '/usr/local/hbb-browser/index.html')
++              time.sleep(1)
++              self.sendCommand('control_exit')
++              #self._opera_container.kill()
++              self._command_util.doDisconnect()
++              self.session.openWithCallback(self._cb_close, BlankWindow)
++
++      def _cb_close(self):
++              self.close()
++              #print "---------------->> closed!!"
++
++      def sendKeyCommand(self, command):
++              params = str(self._command_util.getKeyData(command))
++              if params is None:
++                      return False
++              return self.sendCommand('control_key', params)
++
++      def sendCommand(self, command, params=None):
++              if not self._command_util.isConnected():
++                      self._command_util.doConnect('/tmp/.sock.hbbtv.cmd')
++                      #return False
++              self._command_util.doSend(command, params)
++              return True
++
++class HbbTVHelper(Screen):
++      skin =  """<screen position="0,0" size="0,0"></screen>"""
++      def __init__(self, session):
++              Screen.__init__(self, session)
++              self._session = session
++              self._timer_infobar = eTimer()
++              self._timer_infobar.callback.append(self._cb_registrate_infobar)
++              self._timer_infobar.start(1000)
++
++              self._excuted_browser = False
++
++              global _g_command_util
++              _g_command_util = BrowserCommandUtil()
++
++              global _command_server
++              self._cmd_server = _command_server
++              self._cmd_server.open(session, '/tmp/.sock.hbbtv.url')
++              
++      def _cb_registrate_infobar(self):
++              if InfoBar.instance:
++                      self._timer_infobar.stop()
++                      if self._cb_hbbtv_activated not in InfoBar.instance.onHBBTVActivation:
++                              InfoBar.instance.onHBBTVActivation.append(self._cb_hbbtv_activated)
++
++      def _cb_hbbtv_activated(self):
++              url = self.getHbbTVUrl()
++              if strIsEmpty(url):
++                      print "can't get url of hbbtv!!"
++                      return
++              print "success to get url of hbbtv!! >>", url
++              if self._excuted_browser:
++                      print "already excuted opera browser!!"
++                      return
++              self._cmd_server.start()
++              self.session.openWithCallback(self._cb_closed_browser, OperaBrowserController, url)
++              self._excuted_browser = True
++
++      def _cb_closed_browser(self):
++              self._excuted_browser = False
++              self._cmd_server.stop()
++
++      def getHbbTVUrl(self):
++              try:
++                      service = self._session.nav.getCurrentService()
++                      info    = service and service.info()
++                      return info.getInfoString(iServiceInformation.sHBBTVUrl)
++              except Exception, ErrMsg:
++                      print ErrMsg
++                      pass
++              return None
++
++class OperaBrowserMain(Screen):
++      MENUBAR_ITEM_WIDTH  = 150
++      MENUBAR_ITEM_HEIGHT = 30
++      SUBMENULIST_WIDTH   = 200
++      SUBMENULIST_HEIGHT  = 25
++      SUBMENULIST_NEXT    = 2
++
++      skin =  """
++              <screen name="BrowserMain" position="44,25" size="1210,680" backgroundColor="transparent" flags="wfNoBorder" title="BrowserMain">
++                      <widget name="topArea" zPosition="-1" position="0,0" size="1280,30" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" />
++                      <widget name="menuitemFile" position="0,0" size="150,30" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" foregroundColors="#9f1313,#a08500" />
++                      <widget name="menuitemHelp" position="150,0" size="150,30" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" foregroundColors="#9f1313,#a08500" />
++                      <widget name="menulist" position="0,%d" size="%d,150" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />
++                      <widget name="submenulist" position="%d,%d" size="%d,150" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />
++                      <widget name="bottomArea" position="0,600" size="1280,80" font="Regular;20" valign="center" halign="center" backgroundColor="#000000" />
++              </screen>
++              """ % (MENUBAR_ITEM_HEIGHT, SUBMENULIST_WIDTH, SUBMENULIST_WIDTH+SUBMENULIST_NEXT, MENUBAR_ITEM_HEIGHT, SUBMENULIST_WIDTH)
++
++      MENUITEMS_LIST =[[('Open Location', None), ('Exit', None)],
++                       [('About', None)]]
++      def __init__(self, session):
++              Screen.__init__(self, session)
++              self["actions"] = ActionMap(["MinuteInputActions", "ColorActions", "InputActions", "InfobarChannelSelection", "EPGSelectActions", "InputAsciiActions", "KeyboardInputActions"], {
++                       "cancel"      : self.keyCancel
++                      ,"ok"          : self.keyOK
++                      ,"left"        : self.keyLeft
++                      ,"right"       : self.keyRight
++                      ,"up"          : self.keyUp
++                      ,"down"        : self.keyDown
++                      ,"menu"        : self.keyCancel
++                      ,"gotAsciiCode": self.gotAsciiCode
++                      ,"historyBack" : self.keyLeft
++                      ,"historyNext" : self._on_keynext
++                      ,"deleteBackward":self._on_keyback
++              }, -2)
++              self["NumberActions"] = NumberActionMap( ["NumberActions"], {
++                      "0"     : self._on_keynumber,
++                      "1"     : self._on_keynumber,
++                      "2"     : self._on_keynumber,
++                      "3"     : self._on_keynumber,
++                      "4"     : self._on_keynumber,
++                      "5"     : self._on_keynumber,
++                      "6"     : self._on_keynumber,
++                      "7"     : self._on_keynumber,
++                      "8"     : self._on_keynumber,
++                      "9"     : self._on_keynumber,
++              })
++
++              self.menubarCurrentIndex = 0
++              self.lvMenuItems = []
++              self.lvSubMenuItems = []
++
++              self["topArea"]    = Label()
++              self["bottomArea"] = Label()
++
++              self["menuitemFile"] = MultiColorLabel()
++              self["menuitemHelp"] = MultiColorLabel()
++
++              self["menulist"] = MenuList(self.setListOnView())
++              self["submenulist"] = MenuList(self.setSubListOnView())
++
++              self.toggleMainScreenFlag = True
++              self.toggleListViewFlag = False
++              self.toggleSubListViewFlag = False
++              self.currentListView = self["menulist"]
++
++              self.onLayoutFinish.append(self.layoutFinished)
++
++              self._opera_command_mode = False
++
++              global _g_command_util
++              self._command_util = _g_command_util
++
++      def layoutFinished(self):
++              self["menuitemFile"].setText("File")
++              self["menuitemHelp"].setText("Help")
++
++              self["menulist"].hide()
++              self["submenulist"].hide()
++
++              self["bottomArea"].setText("Here is bottom area!!!!!!!!")
++              self.setTitle("BrowserMain")
++              self.selectMenuitem()
++
++      def gotAsciiCode(self):
++              if not self._opera_command_mode:
++                      return
++              asciicode = getPrevAsciiCode()
++              if asciicode == 28:
++                      self.keyOK()
++                      return
++              charvalue = getCharValue(asciicode)
++              if charvalue is None:
++                      return
++              try:
++                      temp = str(charvalue)
++                      self.sendCommand('control_ascii', temp, 0)
++              except Exception, ErrMsg: 
++                      pass
++
++      def selectMenuitem(self):
++              tmp = [self["menuitemFile"], self["menuitemHelp"]]
++              self["menuitemFile"].setForegroundColorNum(0)
++              self["menuitemHelp"].setForegroundColorNum(0)
++              tmp[self.menubarCurrentIndex].setForegroundColorNum(1)
++
++      def popupCloseAll(self):
++              self.keyLeft()
++              self.keyLeft()
++              self.keyUp()
++              self.keyCancel()
++
++      def setListOnView(self):
++              self.lvMenuItems = self.MENUITEMS_LIST[self.menubarCurrentIndex]        
++              return self.lvMenuItems
++
++      def setSubListOnView(self):
++              self.lvSubMenuItems = []
++              xl = self["menulist"].getCurrent()[1]
++              if xl is None: return []
++              for x in xl:
++                      self.lvSubMenuItems.append((x,None))
++              return self.lvSubMenuItems
++
++      def toggleMainScreen(self):
++              if not self.toggleMainScreenFlag:
++                      self.show()
++              else:   self.hide()
++              self.toggleMainScreenFlag = not self.toggleMainScreenFlag
++
++      def toggleListView(self):
++              if not self.toggleListViewFlag:
++                      self["menulist"].show()
++              else:   self["menulist"].hide()
++              self.toggleListViewFlag = not self.toggleListViewFlag
++
++      def toggleSubListView(self):
++              #print "------------------>> LEFT", self.toggleListViewFlag
++              if not self.toggleSubListViewFlag:
++                      self["submenulist"].show()
++              else:   self["submenulist"].hide()
++              self.toggleSubListViewFlag = not self.toggleSubListViewFlag
++
++      def setCurrentListView(self, listViewIdx):
++              if listViewIdx == 0:
++                      self.currentListView = None
++              elif listViewIdx == 1:
++                      self.currentListView = self["menulist"]
++              elif listViewIdx == 2:
++                      self.currentListView = self["submenulist"]
++
++      def _cmd_on_OpenLocation(self):
++              #self.session.open(MessageBox, 'Clicked!! Open Location', type = MessageBox.TYPE_INFO)
++              self.session.openWithCallback(self.cbKeyText, VirtualKeyBoard, title=("Please enter URL here"), text='http://google.com')
++      def _cmd_on_About(self):
++              self.session.open(MessageBox, 'Opera Web-Browser Launcher Plugin v0.1(beta)', type = MessageBox.TYPE_INFO)
++      def _cmd_on_Exit(self):
++              self.close()
++
++      def cbKeyText(self, data=None):
++              if strIsEmpty(data):
++                      return
++              self.popupCloseAll()
++              #print "---------------------------->> URL :", data
++              self._opera_container = eConsoleAppContainer()
++              self._opera_container.dataAvail.append(self._cb_opera_container_dataAvail)
++              self._opera_container.appClosed.append(self._cb_opera_container_appClosed)
++
++              try:
++                      os.unlink('/tmp/.sock.hbbtv.cmd')
++              except: pass
++
++              global CORSAIR_PATH
++              command = 'cd %s; ./run-browser --url:%s &' %(CORSAIR_PATH, data)
++              print "COMMAND >>", command
++              self._opera_command_mode = True
++              self._opera_container.execute(command)
++
++      def _cb_opera_container_dataAvail(self, data):
++              print data
++
++      def _cb_opera_container_appClosed(self, ret):
++              print ret
++              self.keyCancel()
++
++      def doCommand(self, command):
++              cmd_map = {
++                       'Exit'          :self._cmd_on_Exit
++                      ,'About'         :self._cmd_on_About
++                      ,'Open Location' :self._cmd_on_OpenLocation
++              }
++              try:
++                      cmd_map[command]()
++              except: pass
++      def _on_keynext(self):
++              self.sendCommand('control_forward')
++      def _on_keyback(self):
++              self.sendCommand('control_back')
++      def keyOK(self):
++              if self._opera_command_mode:
++                      self.sendKeyCommand('key_ok')
++                      return
++              if not self.toggleListViewFlag:
++                      self.keyDown()
++                      return
++              if self.currentListView.getCurrent()[1] is None:
++                      self.doCommand(self.currentListView.getCurrent()[0])
++                      #self.session.open(MessageBox, _(self.currentListView.getCurrent()[0]), type = MessageBox.TYPE_INFO)
++                      return
++              self.keyRight()
++
++      def updateSelectedMenuitem(self, status):
++              if self.menubarCurrentIndex == 0 and status < 0:
++                      self.menubarCurrentIndex = 1
++              elif self.menubarCurrentIndex == 1 and status > 0:
++                      self.menubarCurrentIndex = 0
++              else:   self.menubarCurrentIndex += status
++              self.selectMenuitem()
++
++      def keyLeft(self):
++              #print "------------------>> LEFT", self.toggleSubListViewFlag
++              if self._opera_command_mode:
++                      self.sendKeyCommand('key_left')
++                      return
++
++              if not self.toggleMainScreenFlag:
++                      return
++              if not self.toggleListViewFlag:
++                      self.updateSelectedMenuitem(-1)
++                      return
++              if self.toggleSubListViewFlag:
++                      self.setCurrentListView(1)
++                      self.toggleSubListView()
++                      return
++              if self.currentListView.getSelectedIndex():
++                      self.currentListView.pageUp()
++
++      def keyBackSpace(self):
++              if self._opera_command_mode:
++                      self.sendKeyCommand('key_backspace')
++
++      def keyRight(self):
++              #print "------------------>> RIGHT"
++              if self._opera_command_mode:
++                      self.sendKeyCommand('key_right')
++                      return
++              if not self.toggleMainScreenFlag:
++                      return
++              if not self.toggleListViewFlag:
++                      self.updateSelectedMenuitem(1)
++                      return
++              if self.currentListView is None:
++                      return
++              if self.currentListView.getCurrent()[1] is not None:
++                      parentSelectedIndex = self.currentListView.getSelectedIndex()
++                      self.setCurrentListView(2)
++                      self.currentListView.setList(self.setSubListOnView())
++                      self.currentListView.resize(self.SUBMENULIST_WIDTH, self.SUBMENULIST_HEIGHT*len(self.lvSubMenuItems)+5)
++                      self.currentListView.move(self.MENUBAR_ITEM_WIDTH*self.menubarCurrentIndex + self.SUBMENULIST_WIDTH+self.SUBMENULIST_NEXT,self.MENUBAR_ITEM_HEIGHT+(parentSelectedIndex*self.SUBMENULIST_HEIGHT))
++                      self.toggleSubListView()
++
++      def keyDown(self):
++              if self._opera_command_mode:
++                      self.sendKeyCommand('key_down')
++                      return
++              if not self.toggleMainScreenFlag:
++                      return
++              if self.currentListView is None:
++                      return
++              if not self.toggleListViewFlag:
++                      self.currentListView.setList(self.setListOnView())
++                      self.currentListView.resize(self.SUBMENULIST_WIDTH, self.SUBMENULIST_HEIGHT*len(self.lvMenuItems)+5)
++                      self.currentListView.move(self.MENUBAR_ITEM_WIDTH*self.menubarCurrentIndex+1,self.MENUBAR_ITEM_HEIGHT)
++                      self.toggleListView()
++                      return
++              self.currentListView.down()
++              print "----->> DOWN"
++
++      def keyUp(self):
++              if self._opera_command_mode:
++                      self.sendKeyCommand('key_up')
++                      return
++              if not self.toggleMainScreenFlag:
++                      return
++              if self.currentListView is None:
++                      return
++              if self.currentListView == self["menulist"]:
++                      if self.currentListView.getSelectedIndex() == 0:
++                              self.toggleListView()
++                              return
++              self.currentListView.up()
++
++      def keyCancel(self):
++              if self._opera_command_mode:
++                      self.sendCommand('control_openurl', '/home/root/index.html')
++                      time.sleep(2)
++                      self.sendCommand('control_exit')
++                      self._command_util.doDisconnect()
++                      self._opera_command_mode = False
++                      return
++              self.toggleMainScreen()
++
++      def _on_keynumber(self, number):
++              self.sendKeyCommand('key_%d'%(number))
++
++      def sendKeyCommand(self, command, special=0):
++              params = str(self._command_util.getKeyData(command))
++              if params is None:
++                      return False
++              return self.sendCommand('control_key', params, special)
++
++      def sendCommand(self, command, params=None, special=0):
++              if not self._command_util.isConnected():
++                      self._command_util.doConnect('/tmp/.sock.hbbtv.cmd')
++                      #return False
++              self._command_util.doSend(command, params, special)
++              return True
++
++def session_start_main(session, **kwargs):
++      global _command_server
++      _command_server = BrowserCommandServer()
++      session.open(HbbTVHelper)
++
++def plugin_start_main(session, **kwargs):
++      session.open(OperaBrowserMain)
++
++def Plugins(**kwargs):
++      return [PluginDescriptor(name="HbbTV", description="hbbtv", where=PluginDescriptor.WHERE_SESSIONSTART, needsRestart=True, fnc=session_start_main),
++              PluginDescriptor(name="Opera Launcher", description="This is opera launcher(beta)!!", where=PluginDescriptor.WHERE_PLUGINMENU, needsRestart=True, fnc=plugin_start_main)]
++
++
+diff --git a/lib/python/Plugins/Extensions/Makefile.am b/lib/python/Plugins/Extensions/Makefile.am
+index c5806a3..0daed1f 100755
+--- a/lib/python/Plugins/Extensions/Makefile.am
++++ b/lib/python/Plugins/Extensions/Makefile.am
+@@ -1,7 +1,7 @@
+ installdir = $(pkglibdir)/python/Plugins/Extensions
+ SUBDIRS = TuxboxPlugins CutListEditor PicturePlayer MediaScanner MediaPlayer GraphMultiEPG SocketMMI DVDBurn Modem WebBrowser \
+-      VuplusEvent StreamTV DLNABrowser DLNAServer 
++      VuplusEvent StreamTV DLNABrowser DLNAServer HbbTV
+ if HAVE_LIBDDVD
+ SUBDIRS += DVDPlayer
+diff --git a/lib/python/Screens/InfoBar.py b/lib/python/Screens/InfoBar.py
+index 860022a..ed8acf6 100755
+--- a/lib/python/Screens/InfoBar.py
++++ b/lib/python/Screens/InfoBar.py
+@@ -11,7 +11,7 @@ from enigma import iPlayableService
+ profile("LOAD:InfoBarGenerics")
+ from Screens.InfoBarGenerics import InfoBarShowHide, \
+       InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarRdsDecoder, \
+-      InfoBarEPG, InfoBarSeek, InfoBarInstantRecord, \
++      InfoBarEPG, InfoBarSeek, InfoBarInstantRecord, InfoBarRedButton, \
+       InfoBarAudioSelection, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarUnhandledKey, \
+       InfoBarSubserviceSelection, InfoBarShowMovies, InfoBarTimeshift,  \
+       InfoBarServiceNotifications, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarSimpleEventView, \
+@@ -28,7 +28,7 @@ from Screens.HelpMenu import HelpableScreen
+ class InfoBar(InfoBarBase, InfoBarShowHide,
+       InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder,
+-      InfoBarInstantRecord, InfoBarAudioSelection, 
++      InfoBarInstantRecord, InfoBarAudioSelection, InfoBarRedButton,
+       HelpableScreen, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarUnhandledKey,
+       InfoBarSubserviceSelection, InfoBarTimeshift, InfoBarSeek,
+       InfoBarSummarySupport, InfoBarTimeshiftState, InfoBarTeletextPlugin, InfoBarExtensions,
+@@ -54,7 +54,7 @@ class InfoBar(InfoBarBase, InfoBarShowHide,
+               for x in HelpableScreen, \
+                               InfoBarBase, InfoBarShowHide, \
+                               InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder, \
+-                              InfoBarInstantRecord, InfoBarAudioSelection, InfoBarUnhandledKey, \
++                              InfoBarInstantRecord, InfoBarAudioSelection, InfoBarRedButton, InfoBarUnhandledKey, \
+                               InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarSubserviceSelection, \
+                               InfoBarTimeshift, InfoBarSeek, InfoBarSummarySupport, InfoBarTimeshiftState, \
+                               InfoBarTeletextPlugin, InfoBarExtensions, InfoBarPiP, InfoBarSubtitleSupport, InfoBarJobman, \
+diff --git a/lib/python/Screens/InfoBarGenerics.py b/lib/python/Screens/InfoBarGenerics.py
+index 6ca65e3..a924ad6 100755
+--- a/lib/python/Screens/InfoBarGenerics.py
++++ b/lib/python/Screens/InfoBarGenerics.py
+@@ -1844,6 +1844,25 @@ class InfoBarSubserviceSelection:
+               else:
+                       del self.selectedSubservice
++class InfoBarRedButton:
++      def __init__(self):
++              self["RedButtonActions"] = HelpableActionMap(self, "InfobarRedButtonActions",
++                      {
++                              "activateRedButton": (self.activateRedButton, _("Red button...")),
++                      })
++              self.onHBBTVActivation = [ ]
++              self.onRedButtonActivation = [ ]
++
++      def activateRedButton(self):
++              service = self.session.nav.getCurrentService()
++              info = service and service.info()
++              if info and info.getInfoString(iServiceInformation.sHBBTVUrl) != "":
++                      for x in self.onHBBTVActivation:
++                              x()
++              elif False: # TODO: other red button services
++                      for x in self.onRedButtonActivation:
++                              x()
++
+ class InfoBarAdditionalInfo:
+       def __init__(self):
+diff --git a/lib/service/iservice.h b/lib/service/iservice.h
+index 7f58249..dffea52 100644
+--- a/lib/service/iservice.h
++++ b/lib/service/iservice.h
+@@ -359,6 +359,8 @@ public:
+               sTransferBPS,
++              sHBBTVUrl,
++
+               sUser = 0x100
+       };
+       enum {
+@@ -836,6 +838,7 @@ public:
+               evBuffering,
+               evStopped,
++              evHBBTVInfo,
+               evUser = 0x100
+       };
+diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp
+index 383b38e..71f885e 100644
+--- a/lib/service/servicedvb.cpp
++++ b/lib/service/servicedvb.cpp
+@@ -1720,6 +1720,13 @@ std::string eDVBServicePlay::getInfoString(int w)
+               return m_dvb_service->m_provider_name;
+       case sServiceref:
+               return m_reference.toString();
++      case sHBBTVUrl:
++      {
++              std::string url;
++              eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
++              h.getHBBTVUrl(url);
++              return url;
++      }
+       default:
+               break;
+       }
index ae4977d..af63928 100755 (executable)
@@ -75,3 +75,12 @@ do_rootfs_append_vuuno() {
 do_rootfs_append_vuultimo() {
     generate_nfo
 }
+do_rootfs_append_vu7425() {
+    generate_nfo
+}
+do_rootfs_append_vuduo2() {
+    generate_nfo
+}
+do_rootfs_append_vusolo2() {
+    generate_nfo
+}
diff --git a/recipes/initscripts/initscripts-1.0/vu7425/bootup b/recipes/initscripts/initscripts-1.0/vu7425/bootup
new file mode 100755 (executable)
index 0000000..509a8d3
--- /dev/null
@@ -0,0 +1,79 @@
+for mod in sata_svw libata nls_base nls_cp437 nls_iso8859-1; do
+       modprobe $mod
+done
+
+for mod in input evdev i2c-core i2c-dev firmware_class; do
+       modprobe $mod
+done
+
+for mod in snd snd-pcm; do
+        modprobe $mod
+done
+
+for mod in procmk dvb-bcm7413 brcmfb fpga_directc; do
+        modprobe $mod
+done
+
+
+
+
+depmod -Ae
+echo 12 > /proc/progress
+
+for mod in isofs cifs usb-storage sr_mod vfat cdrom ntfs; do
+       modprobe $mod
+done
+
+
+echo 13 > /proc/progress
+
+
+mount -at nonfs,nosmbfs,noncpfs,nocifs
+echo 14 > /proc/progress
+
+swapon -a
+echo 15 > /proc/progress
+
+tar xzf /etc/var.tar.gz -C /
+echo 16 > /proc/progress
+
+# sleep after 10min
+hdparm -S 120 /dev/sda
+
+echo 17 > /proc/progress
+
+# accustic management
+hdparm -M128 /dev/sda
+
+echo 19 > /proc/progress
+
+cat /etc/videomode > /proc/stb/video/videomode
+
+echo 20 > /proc/progress
+
+
+echo 21 > /proc/progress
+
+[ -e /etc/dropbear/dropbear_rsa_host_key ] && /usr/bin/showiframe /boot/bootlogo.mvi || /usr/bin/showiframe /boot/bootlogo_wait.mvi
+
+hostname -F /etc/hostname
+
+echo 22 > /proc/progress
+
+echo 23 > /proc/progress
+
+[ -e "/etc/sysctl.conf" ] && /sbin/sysctl -p "/etc/sysctl.conf"
+
+echo 24 > /proc/progress
+
+ldconfig
+
+echo 25 > /proc/progress
+
+ipkg-cl configure
+
+if [ -f /usr/local/bin/vucamd ];
+then /usr/local/bin/vucamd &
+fi
+
+/usr/bin/hotplug_br &
diff --git a/recipes/initscripts/initscripts-1.0/vu7425/bootup_3.1 b/recipes/initscripts/initscripts-1.0/vu7425/bootup_3.1
new file mode 100755 (executable)
index 0000000..0fd99f7
--- /dev/null
@@ -0,0 +1,63 @@
+
+#Double check driver existence
+if lsmod | grep -q 'brcmfb'; then      
+        echo driver is installed  
+else                           
+       for mod in procmk dvb-bcm7413 brcmfb fpga_directc; do
+               modprobe $mod
+       done
+fi
+
+
+depmod -Ae
+echo 12 > /proc/progress
+
+
+mount -at nonfs,nosmbfs,noncpfs,nocifs
+echo 14 > /proc/progress
+
+swapon -a
+echo 15 > /proc/progress
+
+tar xzf /etc/var.tar.gz -C /
+echo 16 > /proc/progress
+
+# sleep after 10min
+hdparm -S 120 /dev/sda
+
+echo 17 > /proc/progress
+
+# accustic management
+hdparm -M128 /dev/sda
+
+echo 19 > /proc/progress
+
+cat /etc/videomode > /proc/stb/video/videomode
+
+echo 20 > /proc/progress
+
+
+echo 21 > /proc/progress
+
+[ -e /etc/dropbear/dropbear_rsa_host_key ] && /usr/bin/showiframe /boot/bootlogo.mvi || /usr/bin/showiframe /boot/bootlogo_wait.mvi
+
+hostname -F /etc/hostname
+
+echo 22 > /proc/progress
+
+echo 23 > /proc/progress
+
+[ -e "/etc/sysctl.conf" ] && /sbin/sysctl -p "/etc/sysctl.conf"
+
+echo 24 > /proc/progress
+
+ldconfig
+
+echo 25 > /proc/progress
+
+ipkg-cl configure
+
+if [ -f /usr/local/bin/vucamd ];
+then /usr/local/bin/vucamd &
+fi
+
diff --git a/recipes/initscripts/initscripts-1.0/vu7425/halt b/recipes/initscripts/initscripts-1.0/vu7425/halt
new file mode 100755 (executable)
index 0000000..e31ef66
--- /dev/null
@@ -0,0 +1,29 @@
+#! /bin/sh
+#
+# halt         Execute the halt command.
+#
+# Version:      @(#)halt  2.84-2  07-Jan-2002  miquels@cistron.nl
+#
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+# See if we need to cut the power.
+if test -x /etc/init.d/ups-monitor
+then
+       /etc/init.d/ups-monitor poweroff
+fi
+
+# Don't shut down drives if we're using RAID.
+hddown="-h"
+if grep -qs '^md.*active' /proc/mdstat
+then
+       hddown=""
+fi
+
+showiframe /usr/share/switchoff.mvi
+
+/usr/bin/turnoff_power
+
+halt -d -f -i -p $hddown
+
+: exit 0
diff --git a/recipes/initscripts/initscripts-1.0/vu7425/hotplug_br b/recipes/initscripts/initscripts-1.0/vu7425/hotplug_br
new file mode 100755 (executable)
index 0000000..442d25f
Binary files /dev/null and b/recipes/initscripts/initscripts-1.0/vu7425/hotplug_br differ
diff --git a/recipes/initscripts/initscripts-1.0/vu7425/make_mac_sector b/recipes/initscripts/initscripts-1.0/vu7425/make_mac_sector
new file mode 100755 (executable)
index 0000000..34affcc
Binary files /dev/null and b/recipes/initscripts/initscripts-1.0/vu7425/make_mac_sector differ
diff --git a/recipes/initscripts/initscripts-1.0/vuduo2/bootup b/recipes/initscripts/initscripts-1.0/vuduo2/bootup
new file mode 100755 (executable)
index 0000000..509a8d3
--- /dev/null
@@ -0,0 +1,79 @@
+for mod in sata_svw libata nls_base nls_cp437 nls_iso8859-1; do
+       modprobe $mod
+done
+
+for mod in input evdev i2c-core i2c-dev firmware_class; do
+       modprobe $mod
+done
+
+for mod in snd snd-pcm; do
+        modprobe $mod
+done
+
+for mod in procmk dvb-bcm7413 brcmfb fpga_directc; do
+        modprobe $mod
+done
+
+
+
+
+depmod -Ae
+echo 12 > /proc/progress
+
+for mod in isofs cifs usb-storage sr_mod vfat cdrom ntfs; do
+       modprobe $mod
+done
+
+
+echo 13 > /proc/progress
+
+
+mount -at nonfs,nosmbfs,noncpfs,nocifs
+echo 14 > /proc/progress
+
+swapon -a
+echo 15 > /proc/progress
+
+tar xzf /etc/var.tar.gz -C /
+echo 16 > /proc/progress
+
+# sleep after 10min
+hdparm -S 120 /dev/sda
+
+echo 17 > /proc/progress
+
+# accustic management
+hdparm -M128 /dev/sda
+
+echo 19 > /proc/progress
+
+cat /etc/videomode > /proc/stb/video/videomode
+
+echo 20 > /proc/progress
+
+
+echo 21 > /proc/progress
+
+[ -e /etc/dropbear/dropbear_rsa_host_key ] && /usr/bin/showiframe /boot/bootlogo.mvi || /usr/bin/showiframe /boot/bootlogo_wait.mvi
+
+hostname -F /etc/hostname
+
+echo 22 > /proc/progress
+
+echo 23 > /proc/progress
+
+[ -e "/etc/sysctl.conf" ] && /sbin/sysctl -p "/etc/sysctl.conf"
+
+echo 24 > /proc/progress
+
+ldconfig
+
+echo 25 > /proc/progress
+
+ipkg-cl configure
+
+if [ -f /usr/local/bin/vucamd ];
+then /usr/local/bin/vucamd &
+fi
+
+/usr/bin/hotplug_br &
diff --git a/recipes/initscripts/initscripts-1.0/vuduo2/bootup_3.1 b/recipes/initscripts/initscripts-1.0/vuduo2/bootup_3.1
new file mode 100755 (executable)
index 0000000..0fd99f7
--- /dev/null
@@ -0,0 +1,63 @@
+
+#Double check driver existence
+if lsmod | grep -q 'brcmfb'; then      
+        echo driver is installed  
+else                           
+       for mod in procmk dvb-bcm7413 brcmfb fpga_directc; do
+               modprobe $mod
+       done
+fi
+
+
+depmod -Ae
+echo 12 > /proc/progress
+
+
+mount -at nonfs,nosmbfs,noncpfs,nocifs
+echo 14 > /proc/progress
+
+swapon -a
+echo 15 > /proc/progress
+
+tar xzf /etc/var.tar.gz -C /
+echo 16 > /proc/progress
+
+# sleep after 10min
+hdparm -S 120 /dev/sda
+
+echo 17 > /proc/progress
+
+# accustic management
+hdparm -M128 /dev/sda
+
+echo 19 > /proc/progress
+
+cat /etc/videomode > /proc/stb/video/videomode
+
+echo 20 > /proc/progress
+
+
+echo 21 > /proc/progress
+
+[ -e /etc/dropbear/dropbear_rsa_host_key ] && /usr/bin/showiframe /boot/bootlogo.mvi || /usr/bin/showiframe /boot/bootlogo_wait.mvi
+
+hostname -F /etc/hostname
+
+echo 22 > /proc/progress
+
+echo 23 > /proc/progress
+
+[ -e "/etc/sysctl.conf" ] && /sbin/sysctl -p "/etc/sysctl.conf"
+
+echo 24 > /proc/progress
+
+ldconfig
+
+echo 25 > /proc/progress
+
+ipkg-cl configure
+
+if [ -f /usr/local/bin/vucamd ];
+then /usr/local/bin/vucamd &
+fi
+
diff --git a/recipes/initscripts/initscripts-1.0/vuduo2/halt b/recipes/initscripts/initscripts-1.0/vuduo2/halt
new file mode 100755 (executable)
index 0000000..e31ef66
--- /dev/null
@@ -0,0 +1,29 @@
+#! /bin/sh
+#
+# halt         Execute the halt command.
+#
+# Version:      @(#)halt  2.84-2  07-Jan-2002  miquels@cistron.nl
+#
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+# See if we need to cut the power.
+if test -x /etc/init.d/ups-monitor
+then
+       /etc/init.d/ups-monitor poweroff
+fi
+
+# Don't shut down drives if we're using RAID.
+hddown="-h"
+if grep -qs '^md.*active' /proc/mdstat
+then
+       hddown=""
+fi
+
+showiframe /usr/share/switchoff.mvi
+
+/usr/bin/turnoff_power
+
+halt -d -f -i -p $hddown
+
+: exit 0
diff --git a/recipes/initscripts/initscripts-1.0/vuduo2/hotplug_br b/recipes/initscripts/initscripts-1.0/vuduo2/hotplug_br
new file mode 100755 (executable)
index 0000000..442d25f
Binary files /dev/null and b/recipes/initscripts/initscripts-1.0/vuduo2/hotplug_br differ
diff --git a/recipes/initscripts/initscripts-1.0/vuduo2/make_mac_sector b/recipes/initscripts/initscripts-1.0/vuduo2/make_mac_sector
new file mode 100755 (executable)
index 0000000..34affcc
Binary files /dev/null and b/recipes/initscripts/initscripts-1.0/vuduo2/make_mac_sector differ
diff --git a/recipes/initscripts/initscripts-1.0/vusolo2/bootup b/recipes/initscripts/initscripts-1.0/vusolo2/bootup
new file mode 100755 (executable)
index 0000000..6fb52ac
--- /dev/null
@@ -0,0 +1,79 @@
+for mod in sata_svw libata nls_base nls_cp437 nls_iso8859-1; do
+       modprobe $mod
+done
+
+for mod in input evdev i2c-core i2c-dev firmware_class; do
+       modprobe $mod
+done
+
+for mod in snd snd-pcm; do
+        modprobe $mod
+done
+
+for mod in procmk dvb-bcm7356 brcmfb fpga_directc; do
+        modprobe $mod
+done
+
+
+
+
+depmod -Ae
+echo 12 > /proc/progress
+
+for mod in isofs cifs usb-storage sr_mod vfat cdrom ntfs; do
+       modprobe $mod
+done
+
+
+echo 13 > /proc/progress
+
+
+mount -at nonfs,nosmbfs,noncpfs,nocifs
+echo 14 > /proc/progress
+
+swapon -a
+echo 15 > /proc/progress
+
+tar xzf /etc/var.tar.gz -C /
+echo 16 > /proc/progress
+
+# sleep after 10min
+hdparm -S 120 /dev/sda
+
+echo 17 > /proc/progress
+
+# accustic management
+hdparm -M128 /dev/sda
+
+echo 19 > /proc/progress
+
+cat /etc/videomode > /proc/stb/video/videomode
+
+echo 20 > /proc/progress
+
+
+echo 21 > /proc/progress
+
+[ -e /etc/dropbear/dropbear_rsa_host_key ] && /usr/bin/showiframe /boot/bootlogo.mvi || /usr/bin/showiframe /boot/bootlogo_wait.mvi
+
+hostname -F /etc/hostname
+
+echo 22 > /proc/progress
+
+echo 23 > /proc/progress
+
+[ -e "/etc/sysctl.conf" ] && /sbin/sysctl -p "/etc/sysctl.conf"
+
+echo 24 > /proc/progress
+
+ldconfig
+
+echo 25 > /proc/progress
+
+ipkg-cl configure
+
+if [ -f /usr/local/bin/vucamd ];
+then /usr/local/bin/vucamd &
+fi
+
+/usr/bin/hotplug_br &
diff --git a/recipes/initscripts/initscripts-1.0/vusolo2/bootup_3.1 b/recipes/initscripts/initscripts-1.0/vusolo2/bootup_3.1
new file mode 100755 (executable)
index 0000000..0fd99f7
--- /dev/null
@@ -0,0 +1,63 @@
+
+#Double check driver existence
+if lsmod | grep -q 'brcmfb'; then      
+        echo driver is installed  
+else                           
+       for mod in procmk dvb-bcm7413 brcmfb fpga_directc; do
+               modprobe $mod
+       done
+fi
+
+
+depmod -Ae
+echo 12 > /proc/progress
+
+
+mount -at nonfs,nosmbfs,noncpfs,nocifs
+echo 14 > /proc/progress
+
+swapon -a
+echo 15 > /proc/progress
+
+tar xzf /etc/var.tar.gz -C /
+echo 16 > /proc/progress
+
+# sleep after 10min
+hdparm -S 120 /dev/sda
+
+echo 17 > /proc/progress
+
+# accustic management
+hdparm -M128 /dev/sda
+
+echo 19 > /proc/progress
+
+cat /etc/videomode > /proc/stb/video/videomode
+
+echo 20 > /proc/progress
+
+
+echo 21 > /proc/progress
+
+[ -e /etc/dropbear/dropbear_rsa_host_key ] && /usr/bin/showiframe /boot/bootlogo.mvi || /usr/bin/showiframe /boot/bootlogo_wait.mvi
+
+hostname -F /etc/hostname
+
+echo 22 > /proc/progress
+
+echo 23 > /proc/progress
+
+[ -e "/etc/sysctl.conf" ] && /sbin/sysctl -p "/etc/sysctl.conf"
+
+echo 24 > /proc/progress
+
+ldconfig
+
+echo 25 > /proc/progress
+
+ipkg-cl configure
+
+if [ -f /usr/local/bin/vucamd ];
+then /usr/local/bin/vucamd &
+fi
+
diff --git a/recipes/initscripts/initscripts-1.0/vusolo2/halt b/recipes/initscripts/initscripts-1.0/vusolo2/halt
new file mode 100755 (executable)
index 0000000..e31ef66
--- /dev/null
@@ -0,0 +1,29 @@
+#! /bin/sh
+#
+# halt         Execute the halt command.
+#
+# Version:      @(#)halt  2.84-2  07-Jan-2002  miquels@cistron.nl
+#
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+# See if we need to cut the power.
+if test -x /etc/init.d/ups-monitor
+then
+       /etc/init.d/ups-monitor poweroff
+fi
+
+# Don't shut down drives if we're using RAID.
+hddown="-h"
+if grep -qs '^md.*active' /proc/mdstat
+then
+       hddown=""
+fi
+
+showiframe /usr/share/switchoff.mvi
+
+/usr/bin/turnoff_power
+
+halt -d -f -i -p $hddown
+
+: exit 0
diff --git a/recipes/initscripts/initscripts-1.0/vusolo2/hotplug_br b/recipes/initscripts/initscripts-1.0/vusolo2/hotplug_br
new file mode 100755 (executable)
index 0000000..442d25f
Binary files /dev/null and b/recipes/initscripts/initscripts-1.0/vusolo2/hotplug_br differ
diff --git a/recipes/initscripts/initscripts-1.0/vusolo2/make_mac_sector b/recipes/initscripts/initscripts-1.0/vusolo2/make_mac_sector
new file mode 100755 (executable)
index 0000000..34affcc
Binary files /dev/null and b/recipes/initscripts/initscripts-1.0/vusolo2/make_mac_sector differ
index 5437724..2f56355 100755 (executable)
@@ -22,6 +22,8 @@ CFLAGS_bm750_append = " -DHARDWARE_SUPPORT_LPCM"
 CFLAGS_vusolo_append = " -DHARDWARE_SUPPORT_LPCM"
 CFLAGS_vuuno_append = " -DHARDWARE_SUPPORT_LPCM"
 CFLAGS_vuultimo_append = " -DHARDWARE_SUPPORT_LPCM"
+CFLAGS_vuduo2_append = " -DHARDWARE_SUPPORT_LPCM"
+CFLAGS_vusolo2_append = " -DHARDWARE_SUPPORT_LPCM"
 
 S = "${WORKDIR}/git"
 
diff --git a/recipes/linux/linux-vuduo2-3.1.1/brcm_disable_enet1.patch b/recipes/linux/linux-vuduo2-3.1.1/brcm_disable_enet1.patch
new file mode 100644 (file)
index 0000000..6b9f24f
--- /dev/null
@@ -0,0 +1,28 @@
+diff --git a/arch/mips/brcmstb/Kconfig b/arch/mips/brcmstb/Kconfig
+index 6cdb475..dfe9d63 100644
+--- a/arch/mips/brcmstb/Kconfig
++++ b/arch/mips/brcmstb/Kconfig
+@@ -272,7 +272,6 @@ config BCM7425B0
+       select BRCM_UARTC_IS_16550
+       select BRCM_HAS_PCIE
+       select BRCM_HAS_GENET_0
+-      select BRCM_HAS_MOCA_20
+       select BRCM_MOCA_ON_GENET_1
+       select BRCM_GENET_V3
+       select BRCM_HAS_NOR
+@@ -987,15 +986,6 @@ config BRCM_HAS_GENET_0
+       bool
+       select BRCM_HAS_GENET
+-# select for standalone GENET_1
+-config BRCM_HAS_GENET_1
+-      bool
+-      select BRCM_HAS_GENET
+-
+-# MoCA controller
+-config BRCM_HAS_MOCA
+-      bool
+-
+ # Original MoCA 1.1
+ config BRCM_HAS_MOCA_11
+       bool
diff --git a/recipes/linux/linux-vuduo2-3.1.1/brcm_nand_timing.patch b/recipes/linux/linux-vuduo2-3.1.1/brcm_nand_timing.patch
new file mode 100644 (file)
index 0000000..aa06633
--- /dev/null
@@ -0,0 +1,16 @@
+diff --git a/drivers/mtd/nand/brcmstb_nand.c b/drivers/mtd/nand/brcmstb_nand.c
+index 97bd867..c28e090 100644
+--- a/drivers/mtd/nand/brcmstb_nand.c
++++ b/drivers/mtd/nand/brcmstb_nand.c
+@@ -1268,6 +1268,11 @@ static int __devinit brcmstb_nand_probe(struct platform_device *pdev)
+               goto out;
+       }
++      //Timing Adjust
++        BDEV_WR_RB(REG_TIMING_1(host->cs), 0x4232222D);
++        BDEV_WR_RB(REG_TIMING_2(host->cs), 0x1a84);
++
++
+ #ifdef CONFIG_MTD_PARTITIONS
+       nr_parts = parse_mtd_partitions(mtd, part_probe_types, &parts, 0);
+       if (nr_parts <= 0) {
diff --git a/recipes/linux/linux-vuduo2-3.1.1/debug.patch b/recipes/linux/linux-vuduo2-3.1.1/debug.patch
new file mode 100644 (file)
index 0000000..5576999
--- /dev/null
@@ -0,0 +1,44 @@
+diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
+index da606e6..d75f8c7 100644
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -1319,6 +1319,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
+       if (up->port.flags & UPF_FOURPORT)
+               outb_p(save_ICP, ICP);
++      printk("irq %d\n", irq);
+       up->port.irq = (irq > 0) ? irq : 0;
+ }
+@@ -2774,6 +2775,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+       }
+       serial8250_isa_init_ports();
++      printk("serial8250_register_ports %d\n", nr_uarts);
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+@@ -2783,6 +2785,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+               if (up->port.flags & UPF_FIXED_TYPE)
+                       serial8250_init_fixed_type_port(up, up->port.type);
++              printk("serial8250_register_ports --> uart_add_one_port %d\n", up->port.irq);
+               uart_add_one_port(drv, &up->port);
+       }
+ }
+@@ -3045,6 +3048,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
+               port.pm                 = p->pm;
+               port.dev                = &dev->dev;
+               port.irqflags           |= irqflag;
++              printk("serial8250_probe %d\n", port.irq);
+               ret = serial8250_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+@@ -3216,6 +3220,7 @@ int serial8250_register_port(struct uart_port *port)
+                       serial8250_isa_config(0, &uart->port,
+                                       &uart->capabilities);
++              printk("serial8250_register_port %d --> uart_add_one_port\n", uart->port.irq);
+               ret = uart_add_one_port(&serial8250_reg, &uart->port);
+               if (ret == 0)
+                       ret = uart->port.line;
diff --git a/recipes/linux/linux-vuduo2-3.1.1/dvb-core.patch b/recipes/linux/linux-vuduo2-3.1.1/dvb-core.patch
new file mode 100644 (file)
index 0000000..87b1738
--- /dev/null
@@ -0,0 +1,1330 @@
+diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
+index 0b51828..8f22bcd 100644
+--- a/drivers/media/dvb/dvb-core/Makefile
++++ b/drivers/media/dvb/dvb-core/Makefile
+@@ -2,8 +2,10 @@
+ # Makefile for the kernel DVB device drivers.
+ #
++dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
++
+ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o   \
+                dvb_ca_en50221.o dvb_frontend.o                \
+-               dvb_net.o dvb_ringbuffer.o dvb_math.o
++               $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
+ obj-$(CONFIG_DVB_CORE) += dvb-core.o
+diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
+index ad1f61d..cb59681 100644
+--- a/drivers/media/dvb/dvb-core/dmxdev.c
++++ b/drivers/media/dvb/dvb-core/dmxdev.c
+@@ -83,7 +83,11 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+               ret = wait_event_interruptible(src->queue,
+                                              !dvb_ringbuffer_empty(src) ||
+-                                             (src->error != 0));
++                                             (src->error != 0) ||
++                                             (src->do_wait != 1));
++              if (src->do_wait != 1)
++                      ret = -EINTR;
++
+               if (ret < 0)
+                       break;
+@@ -572,13 +576,13 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+       dmx_output_t otype;
+       int ret;
+       int ts_type;
+-      enum dmx_ts_pes ts_pes;
++      dmx_pes_type_t ts_pes;
+       struct dmx_ts_feed *tsfeed;
+       feed->ts = NULL;
+       otype = para->output;
+-      ts_pes = (enum dmx_ts_pes)para->pes_type;
++      ts_pes = para->pes_type;
+       if (ts_pes < DMX_PES_OTHER)
+               ts_type = TS_DECODER;
+@@ -963,6 +967,22 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count,
+       return ret;
+ }
++static int dvb_demux_lock_filter(struct dmxdev_filter *dmxdevfilter)
++{
++      int ret;
++
++      dmxdevfilter->buffer.do_wait = 0;
++
++      if (waitqueue_active(&dmxdevfilter->buffer.queue))
++              wake_up(&dmxdevfilter->buffer.queue);
++
++      ret = mutex_lock_interruptible(&dmxdevfilter->mutex);
++
++      dmxdevfilter->buffer.do_wait = 1;
++
++      return ret;
++}
++
+ static int dvb_demux_do_ioctl(struct file *file,
+                             unsigned int cmd, void *parg)
+ {
+@@ -976,7 +996,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+       switch (cmd) {
+       case DMX_START:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -988,7 +1008,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_STOP:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -997,7 +1017,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_SET_FILTER:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -1006,7 +1026,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_SET_PES_FILTER:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -1015,7 +1035,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_SET_BUFFER_SIZE:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -1059,7 +1079,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_ADD_PID:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+@@ -1068,7 +1088,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_REMOVE_PID:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
+index 4a88a3e..faa3671 100644
+--- a/drivers/media/dvb/dvb-core/dvb_demux.c
++++ b/drivers/media/dvb/dvb-core/dvb_demux.c
+@@ -478,97 +478,94 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
+ EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
+-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
++static inline int find_next_packet(const u8 *buf, int pos, size_t count,
++                                 const int pktsize)
+ {
+-      int p = 0, i, j;
++      int start = pos, lost;
+-      spin_lock(&demux->lock);
+-
+-      if (demux->tsbufp) {
+-              i = demux->tsbufp;
+-              j = 188 - i;
+-              if (count < j) {
+-                      memcpy(&demux->tsbuf[i], buf, count);
+-                      demux->tsbufp += count;
+-                      goto bailout;
+-              }
+-              memcpy(&demux->tsbuf[i], buf, j);
+-              if (demux->tsbuf[0] == 0x47)
+-                      dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+-              demux->tsbufp = 0;
+-              p += j;
++      while (pos < count) {
++              if (buf[pos] == 0x47 ||
++                  (pktsize == 204 && buf[pos] == 0xB8))
++                      break;
++              pos++;
+       }
+-      while (p < count) {
+-              if (buf[p] == 0x47) {
+-                      if (count - p >= 188) {
+-                              dvb_dmx_swfilter_packet(demux, &buf[p]);
+-                              p += 188;
+-                      } else {
+-                              i = count - p;
+-                              memcpy(demux->tsbuf, &buf[p], i);
+-                              demux->tsbufp = i;
+-                              goto bailout;
+-                      }
+-              } else
+-                      p++;
++      lost = pos - start;
++      if (lost) {
++              /* This garbage is part of a valid packet? */
++              int backtrack = pos - pktsize;
++              if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
++                  (pktsize == 204 && buf[backtrack] == 0xB8)))
++                      return backtrack;
+       }
+-bailout:
+-      spin_unlock(&demux->lock);
++      return pos;
+ }
+-EXPORT_SYMBOL(dvb_dmx_swfilter);
+-
+-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
++/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
++static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
++              size_t count, const int pktsize)
+ {
+       int p = 0, i, j;
+-      u8 tmppack[188];
++      const u8 *q;
+       spin_lock(&demux->lock);
+-      if (demux->tsbufp) {
++      if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
+               i = demux->tsbufp;
+-              j = 204 - i;
++              j = pktsize - i;
+               if (count < j) {
+                       memcpy(&demux->tsbuf[i], buf, count);
+                       demux->tsbufp += count;
+                       goto bailout;
+               }
+               memcpy(&demux->tsbuf[i], buf, j);
+-              if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
+-                      memcpy(tmppack, demux->tsbuf, 188);
+-                      if (tmppack[0] == 0xB8)
+-                              tmppack[0] = 0x47;
+-                      dvb_dmx_swfilter_packet(demux, tmppack);
+-              }
++              if (demux->tsbuf[0] == 0x47) /* double check */
++                      dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+               demux->tsbufp = 0;
+               p += j;
+       }
+-      while (p < count) {
+-              if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
+-                      if (count - p >= 204) {
+-                              memcpy(tmppack, &buf[p], 188);
+-                              if (tmppack[0] == 0xB8)
+-                                      tmppack[0] = 0x47;
+-                              dvb_dmx_swfilter_packet(demux, tmppack);
+-                              p += 204;
+-                      } else {
+-                              i = count - p;
+-                              memcpy(demux->tsbuf, &buf[p], i);
+-                              demux->tsbufp = i;
+-                              goto bailout;
+-                      }
+-              } else {
+-                      p++;
++      while (1) {
++              p = find_next_packet(buf, p, count, pktsize);
++              if (p >= count)
++                      break;
++              if (count - p < pktsize)
++                      break;
++
++              q = &buf[p];
++
++              if (pktsize == 204 && (*q == 0xB8)) {
++                      memcpy(demux->tsbuf, q, 188);
++                      demux->tsbuf[0] = 0x47;
++                      q = demux->tsbuf;
+               }
++              dvb_dmx_swfilter_packet(demux, q);
++              p += pktsize;
++      }
++
++      i = count - p;
++      if (i) {
++              memcpy(demux->tsbuf, &buf[p], i);
++              demux->tsbufp = i;
++              if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
++                      demux->tsbuf[0] = 0x47;
+       }
+ bailout:
+       spin_unlock(&demux->lock);
+ }
++void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
++{
++      _dvb_dmx_swfilter(demux, buf, count, 188);
++}
++EXPORT_SYMBOL(dvb_dmx_swfilter);
++
++void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
++{
++      _dvb_dmx_swfilter(demux, buf, count, 204);
++}
+ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+ static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
+index cad6634..efe9c30 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
+@@ -105,7 +105,8 @@ struct dvb_frontend_private {
+       /* thread/frontend values */
+       struct dvb_device *dvbdev;
+-      struct dvb_frontend_parameters parameters;
++      struct dvb_frontend_parameters parameters_in;
++      struct dvb_frontend_parameters parameters_out;
+       struct dvb_fe_events events;
+       struct semaphore sem;
+       struct list_head list_head;
+@@ -160,12 +161,11 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
+       e = &events->events[events->eventw];
+-      memcpy (&e->parameters, &fepriv->parameters,
+-              sizeof (struct dvb_frontend_parameters));
+-
+       if (status & FE_HAS_LOCK)
+               if (fe->ops.get_frontend)
+-                      fe->ops.get_frontend(fe, &e->parameters);
++                      fe->ops.get_frontend(fe, &fepriv->parameters_out);
++
++      e->parameters = fepriv->parameters_out;
+       events->eventw = wp;
+@@ -277,12 +277,12 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
+       int ready = 0;
+       int fe_set_err = 0;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+-      int original_inversion = fepriv->parameters.inversion;
+-      u32 original_frequency = fepriv->parameters.frequency;
++      int original_inversion = fepriv->parameters_in.inversion;
++      u32 original_frequency = fepriv->parameters_in.frequency;
+       /* are we using autoinversion? */
+       autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+-                       (fepriv->parameters.inversion == INVERSION_AUTO));
++                       (fepriv->parameters_in.inversion == INVERSION_AUTO));
+       /* setup parameters correctly */
+       while(!ready) {
+@@ -348,18 +348,19 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
+               fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
+       /* set the frontend itself */
+-      fepriv->parameters.frequency += fepriv->lnb_drift;
++      fepriv->parameters_in.frequency += fepriv->lnb_drift;
+       if (autoinversion)
+-              fepriv->parameters.inversion = fepriv->inversion;
++              fepriv->parameters_in.inversion = fepriv->inversion;
+       if (fe->ops.set_frontend)
+-              fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
++              fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
++      fepriv->parameters_out = fepriv->parameters_in;
+       if (fe_set_err < 0) {
+               fepriv->state = FESTATE_ERROR;
+               return fe_set_err;
+       }
+-      fepriv->parameters.frequency = original_frequency;
+-      fepriv->parameters.inversion = original_inversion;
++      fepriv->parameters_in.frequency = original_frequency;
++      fepriv->parameters_in.inversion = original_inversion;
+       fepriv->auto_sub_step++;
+       return 0;
+@@ -383,7 +384,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+               if (fepriv->state & FESTATE_RETUNE) {
+                       if (fe->ops.set_frontend)
+                               retval = fe->ops.set_frontend(fe,
+-                                                      &fepriv->parameters);
++                                                      &fepriv->parameters_in);
++                      fepriv->parameters_out = fepriv->parameters_in;
+                       if (retval < 0)
+                               fepriv->state = FESTATE_ERROR;
+                       else
+@@ -413,8 +415,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+               /* if we're tuned, then we have determined the correct inversion */
+               if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+-                  (fepriv->parameters.inversion == INVERSION_AUTO)) {
+-                      fepriv->parameters.inversion = fepriv->inversion;
++                  (fepriv->parameters_in.inversion == INVERSION_AUTO)) {
++                      fepriv->parameters_in.inversion = fepriv->inversion;
+               }
+               return;
+       }
+@@ -594,12 +596,14 @@ restart:
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
+-                                      params = &fepriv->parameters;
++                                      params = &fepriv->parameters_in;
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               if (fe->ops.tune)
+                                       fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
++                              if (params)
++                                      fepriv->parameters_out = *params;
+                               if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+                                       dprintk("%s: state changed, adding current state\n", __func__);
+@@ -612,11 +616,9 @@ restart:
+                               dvb_frontend_swzigzag(fe);
+                               break;
+                       case DVBFE_ALGO_CUSTOM:
+-                              params = NULL; /* have we been asked to RETUNE ?        */
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+-                                      params = &fepriv->parameters;
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               /* Case where we are going to search for a carrier
+@@ -625,7 +627,7 @@ restart:
+                                */
+                               if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+                                       if (fe->ops.search) {
+-                                              fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
++                                              fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
+                                               /* We did do a search as was requested, the flags are
+                                                * now unset as well and has the flags wrt to search.
+                                                */
+@@ -636,11 +638,12 @@ restart:
+                               /* Track the carrier if the search was successful */
+                               if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
+                                       if (fe->ops.track)
+-                                              fe->ops.track(fe, &fepriv->parameters);
++                                              fe->ops.track(fe, &fepriv->parameters_in);
+                               } else {
+                                       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       fepriv->delay = HZ / 2;
+                               }
++                              fepriv->parameters_out = fepriv->parameters_in;
+                               fe->ops.read_status(fe, &s);
+                               if (s != fepriv->status) {
+                                       dvb_frontend_add_event(fe, s); /* update event list */
+@@ -860,34 +863,34 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+ {
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int i;
+-      memset(&(fe->dtv_property_cache), 0,
+-                      sizeof(struct dtv_frontend_properties));
+-
+-      fe->dtv_property_cache.state = DTV_CLEAR;
+-      fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
+-      fe->dtv_property_cache.inversion = INVERSION_AUTO;
+-      fe->dtv_property_cache.fec_inner = FEC_AUTO;
+-      fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+-      fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO;
+-      fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+-      fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
+-      fe->dtv_property_cache.symbol_rate = QAM_AUTO;
+-      fe->dtv_property_cache.code_rate_HP = FEC_AUTO;
+-      fe->dtv_property_cache.code_rate_LP = FEC_AUTO;
+-
+-      fe->dtv_property_cache.isdbt_partial_reception = -1;
+-      fe->dtv_property_cache.isdbt_sb_mode = -1;
+-      fe->dtv_property_cache.isdbt_sb_subchannel = -1;
+-      fe->dtv_property_cache.isdbt_sb_segment_idx = -1;
+-      fe->dtv_property_cache.isdbt_sb_segment_count = -1;
+-      fe->dtv_property_cache.isdbt_layer_enabled = 0x7;
++      memset(c, 0, sizeof(struct dtv_frontend_properties));
++
++      c->state = DTV_CLEAR;
++      c->delivery_system = SYS_UNDEFINED;
++      c->inversion = INVERSION_AUTO;
++      c->fec_inner = FEC_AUTO;
++      c->transmission_mode = TRANSMISSION_MODE_AUTO;
++      c->bandwidth_hz = BANDWIDTH_AUTO;
++      c->guard_interval = GUARD_INTERVAL_AUTO;
++      c->hierarchy = HIERARCHY_AUTO;
++      c->symbol_rate = QAM_AUTO;
++      c->code_rate_HP = FEC_AUTO;
++      c->code_rate_LP = FEC_AUTO;
++
++      c->isdbt_partial_reception = -1;
++      c->isdbt_sb_mode = -1;
++      c->isdbt_sb_subchannel = -1;
++      c->isdbt_sb_segment_idx = -1;
++      c->isdbt_sb_segment_count = -1;
++      c->isdbt_layer_enabled = 0x7;
+       for (i = 0; i < 3; i++) {
+-              fe->dtv_property_cache.layer[i].fec = FEC_AUTO;
+-              fe->dtv_property_cache.layer[i].modulation = QAM_AUTO;
+-              fe->dtv_property_cache.layer[i].interleaving = -1;
+-              fe->dtv_property_cache.layer[i].segment_count = -1;
++              c->layer[i].fec = FEC_AUTO;
++              c->layer[i].modulation = QAM_AUTO;
++              c->layer[i].interleaving = -1;
++              c->layer[i].segment_count = -1;
+       }
+       return 0;
+@@ -901,7 +904,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+       .buffer = b \
+ }
+-static struct dtv_cmds_h dtv_cmds[] = {
++static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
+       _DTV_CMD(DTV_TUNE, 1, 0),
+       _DTV_CMD(DTV_CLEAR, 1, 0),
+@@ -963,6 +966,7 @@ static struct dtv_cmds_h dtv_cmds[] = {
+       _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
+       _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
++      _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
+       /* Get */
+       _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
+@@ -1020,10 +1024,9 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
+  * it's being used for the legacy or new API, reducing code and complexity.
+  */
+ static void dtv_property_cache_sync(struct dvb_frontend *fe,
+-                                  struct dvb_frontend_parameters *p)
++                                  struct dtv_frontend_properties *c,
++                                  const struct dvb_frontend_parameters *p)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+-
+       c->frequency = p->frequency;
+       c->inversion = p->inversion;
+@@ -1074,9 +1077,9 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
+  */
+ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+-      struct dvb_frontend_parameters *p = &fepriv->parameters;
++      struct dvb_frontend_parameters *p = &fepriv->parameters_in;
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+@@ -1086,14 +1089,12 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+               dprintk("%s() Preparing QPSK req\n", __func__);
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+-              c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               dprintk("%s() Preparing QAM req\n", __func__);
+               p->u.qam.symbol_rate = c->symbol_rate;
+               p->u.qam.fec_inner = c->fec_inner;
+               p->u.qam.modulation = c->modulation;
+-              c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               dprintk("%s() Preparing OFDM req\n", __func__);
+@@ -1111,15 +1112,10 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+               p->u.ofdm.transmission_mode = c->transmission_mode;
+               p->u.ofdm.guard_interval = c->guard_interval;
+               p->u.ofdm.hierarchy_information = c->hierarchy;
+-              c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               dprintk("%s() Preparing VSB req\n", __func__);
+               p->u.vsb.modulation = c->modulation;
+-              if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+-                      c->delivery_system = SYS_ATSC;
+-              else
+-                      c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+ }
+@@ -1129,9 +1125,9 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+  */
+ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+-      struct dvb_frontend_parameters *p = &fepriv->parameters;
++      struct dvb_frontend_parameters *p = &fepriv->parameters_in;
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+@@ -1148,10 +1144,9 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+               break;
+       }
+-      if(c->delivery_system == SYS_ISDBT) {
+-              /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+-              p->frequency = c->frequency;
+-              p->inversion = c->inversion;
++      /* Fake out a generic DVB-T request so we pass validation in the ioctl */
++      if ((c->delivery_system == SYS_ISDBT) ||
++          (c->delivery_system == SYS_DVBT2)) {
+               p->u.ofdm.constellation = QAM_AUTO;
+               p->u.ofdm.code_rate_HP = FEC_AUTO;
+               p->u.ofdm.code_rate_LP = FEC_AUTO;
+@@ -1171,7 +1166,7 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+ static void dtv_property_cache_submit(struct dvb_frontend *fe)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       /* For legacy delivery systems we don't need the delivery_system to
+        * be specified, but we populate the older structures from the cache
+@@ -1204,133 +1199,149 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
+                                   struct dtv_property *tvp,
+                                   struct file *file)
+ {
+-      int r = 0;
+-
+-      /* Allow the frontend to validate incoming properties */
+-      if (fe->ops.get_property)
+-              r = fe->ops.get_property(fe, tvp);
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      struct dvb_frontend_private *fepriv = fe->frontend_priv;
++      struct dtv_frontend_properties cdetected;
++      int r;
+-      if (r < 0)
+-              return r;
++      /*
++       * If the driver implements a get_frontend function, then convert
++       * detected parameters to S2API properties.
++       */
++      if (fe->ops.get_frontend) {
++              cdetected = *c;
++              dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
++              c = &cdetected;
++      }
+       switch(tvp->cmd) {
+       case DTV_FREQUENCY:
+-              tvp->u.data = fe->dtv_property_cache.frequency;
++              tvp->u.data = c->frequency;
+               break;
+       case DTV_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.modulation;
++              tvp->u.data = c->modulation;
+               break;
+       case DTV_BANDWIDTH_HZ:
+-              tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
++              tvp->u.data = c->bandwidth_hz;
+               break;
+       case DTV_INVERSION:
+-              tvp->u.data = fe->dtv_property_cache.inversion;
++              tvp->u.data = c->inversion;
+               break;
+       case DTV_SYMBOL_RATE:
+-              tvp->u.data = fe->dtv_property_cache.symbol_rate;
++              tvp->u.data = c->symbol_rate;
+               break;
+       case DTV_INNER_FEC:
+-              tvp->u.data = fe->dtv_property_cache.fec_inner;
++              tvp->u.data = c->fec_inner;
+               break;
+       case DTV_PILOT:
+-              tvp->u.data = fe->dtv_property_cache.pilot;
++              tvp->u.data = c->pilot;
+               break;
+       case DTV_ROLLOFF:
+-              tvp->u.data = fe->dtv_property_cache.rolloff;
++              tvp->u.data = c->rolloff;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+-              tvp->u.data = fe->dtv_property_cache.delivery_system;
++              tvp->u.data = c->delivery_system;
+               break;
+       case DTV_VOLTAGE:
+-              tvp->u.data = fe->dtv_property_cache.voltage;
++              tvp->u.data = c->voltage;
+               break;
+       case DTV_TONE:
+-              tvp->u.data = fe->dtv_property_cache.sectone;
++              tvp->u.data = c->sectone;
+               break;
+       case DTV_API_VERSION:
+               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+               break;
+       case DTV_CODE_RATE_HP:
+-              tvp->u.data = fe->dtv_property_cache.code_rate_HP;
++              tvp->u.data = c->code_rate_HP;
+               break;
+       case DTV_CODE_RATE_LP:
+-              tvp->u.data = fe->dtv_property_cache.code_rate_LP;
++              tvp->u.data = c->code_rate_LP;
+               break;
+       case DTV_GUARD_INTERVAL:
+-              tvp->u.data = fe->dtv_property_cache.guard_interval;
++              tvp->u.data = c->guard_interval;
+               break;
+       case DTV_TRANSMISSION_MODE:
+-              tvp->u.data = fe->dtv_property_cache.transmission_mode;
++              tvp->u.data = c->transmission_mode;
+               break;
+       case DTV_HIERARCHY:
+-              tvp->u.data = fe->dtv_property_cache.hierarchy;
++              tvp->u.data = c->hierarchy;
+               break;
+       /* ISDB-T Support here */
+       case DTV_ISDBT_PARTIAL_RECEPTION:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception;
++              tvp->u.data = c->isdbt_partial_reception;
+               break;
+       case DTV_ISDBT_SOUND_BROADCASTING:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode;
++              tvp->u.data = c->isdbt_sb_mode;
+               break;
+       case DTV_ISDBT_SB_SUBCHANNEL_ID:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel;
++              tvp->u.data = c->isdbt_sb_subchannel;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_IDX:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx;
++              tvp->u.data = c->isdbt_sb_segment_idx;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count;
++              tvp->u.data = c->isdbt_sb_segment_count;
+               break;
+       case DTV_ISDBT_LAYER_ENABLED:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled;
++              tvp->u.data = c->isdbt_layer_enabled;
+               break;
+       case DTV_ISDBT_LAYERA_FEC:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].fec;
++              tvp->u.data = c->layer[0].fec;
+               break;
+       case DTV_ISDBT_LAYERA_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].modulation;
++              tvp->u.data = c->layer[0].modulation;
+               break;
+       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].segment_count;
++              tvp->u.data = c->layer[0].segment_count;
+               break;
+       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].interleaving;
++              tvp->u.data = c->layer[0].interleaving;
+               break;
+       case DTV_ISDBT_LAYERB_FEC:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].fec;
++              tvp->u.data = c->layer[1].fec;
+               break;
+       case DTV_ISDBT_LAYERB_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].modulation;
++              tvp->u.data = c->layer[1].modulation;
+               break;
+       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].segment_count;
++              tvp->u.data = c->layer[1].segment_count;
+               break;
+       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].interleaving;
++              tvp->u.data = c->layer[1].interleaving;
+               break;
+       case DTV_ISDBT_LAYERC_FEC:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].fec;
++              tvp->u.data = c->layer[2].fec;
+               break;
+       case DTV_ISDBT_LAYERC_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].modulation;
++              tvp->u.data = c->layer[2].modulation;
+               break;
+       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].segment_count;
++              tvp->u.data = c->layer[2].segment_count;
+               break;
+       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
++              tvp->u.data = c->layer[2].interleaving;
+               break;
+       case DTV_ISDBS_TS_ID:
+-              tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
++              tvp->u.data = c->isdbs_ts_id;
++              break;
++      case DTV_DVBT2_PLP_ID:
++              tvp->u.data = c->dvbt2_plp_id;
+               break;
+       default:
+-              r = -1;
++              return -EINVAL;
++      }
++
++      /* Allow the frontend to override outgoing properties */
++      if (fe->ops.get_property) {
++              r = fe->ops.get_property(fe, tvp);
++              if (r < 0)
++                      return r;
+       }
+       dtv_property_dump(tvp);
+-      return r;
++      return 0;
+ }
+ static int dtv_property_process_set(struct dvb_frontend *fe,
+@@ -1338,15 +1349,16 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
+                                   struct file *file)
+ {
+       int r = 0;
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       dtv_property_dump(tvp);
+       /* Allow the frontend to validate incoming properties */
+-      if (fe->ops.set_property)
++      if (fe->ops.set_property) {
+               r = fe->ops.set_property(fe, tvp);
+-
+-      if (r < 0)
+-              return r;
++              if (r < 0)
++                      return r;
++      }
+       switch(tvp->cmd) {
+       case DTV_CLEAR:
+@@ -1361,126 +1373,129 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
+                * tunerequest so we can pass validation in the FE_SET_FRONTEND
+                * ioctl.
+                */
+-              fe->dtv_property_cache.state = tvp->cmd;
++              c->state = tvp->cmd;
+               dprintk("%s() Finalised property cache\n", __func__);
+               dtv_property_cache_submit(fe);
+-              r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
+-                      &fepriv->parameters);
++              r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
++                      &fepriv->parameters_in);
+               break;
+       case DTV_FREQUENCY:
+-              fe->dtv_property_cache.frequency = tvp->u.data;
++              c->frequency = tvp->u.data;
+               break;
+       case DTV_MODULATION:
+-              fe->dtv_property_cache.modulation = tvp->u.data;
++              c->modulation = tvp->u.data;
+               break;
+       case DTV_BANDWIDTH_HZ:
+-              fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
++              c->bandwidth_hz = tvp->u.data;
+               break;
+       case DTV_INVERSION:
+-              fe->dtv_property_cache.inversion = tvp->u.data;
++              c->inversion = tvp->u.data;
+               break;
+       case DTV_SYMBOL_RATE:
+-              fe->dtv_property_cache.symbol_rate = tvp->u.data;
++              c->symbol_rate = tvp->u.data;
+               break;
+       case DTV_INNER_FEC:
+-              fe->dtv_property_cache.fec_inner = tvp->u.data;
++              c->fec_inner = tvp->u.data;
+               break;
+       case DTV_PILOT:
+-              fe->dtv_property_cache.pilot = tvp->u.data;
++              c->pilot = tvp->u.data;
+               break;
+       case DTV_ROLLOFF:
+-              fe->dtv_property_cache.rolloff = tvp->u.data;
++              c->rolloff = tvp->u.data;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+-              fe->dtv_property_cache.delivery_system = tvp->u.data;
++              c->delivery_system = tvp->u.data;
+               break;
+       case DTV_VOLTAGE:
+-              fe->dtv_property_cache.voltage = tvp->u.data;
++              c->voltage = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
+-                      (void *)fe->dtv_property_cache.voltage);
++                      (void *)c->voltage);
+               break;
+       case DTV_TONE:
+-              fe->dtv_property_cache.sectone = tvp->u.data;
++              c->sectone = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
+-                      (void *)fe->dtv_property_cache.sectone);
++                      (void *)c->sectone);
+               break;
+       case DTV_CODE_RATE_HP:
+-              fe->dtv_property_cache.code_rate_HP = tvp->u.data;
++              c->code_rate_HP = tvp->u.data;
+               break;
+       case DTV_CODE_RATE_LP:
+-              fe->dtv_property_cache.code_rate_LP = tvp->u.data;
++              c->code_rate_LP = tvp->u.data;
+               break;
+       case DTV_GUARD_INTERVAL:
+-              fe->dtv_property_cache.guard_interval = tvp->u.data;
++              c->guard_interval = tvp->u.data;
+               break;
+       case DTV_TRANSMISSION_MODE:
+-              fe->dtv_property_cache.transmission_mode = tvp->u.data;
++              c->transmission_mode = tvp->u.data;
+               break;
+       case DTV_HIERARCHY:
+-              fe->dtv_property_cache.hierarchy = tvp->u.data;
++              c->hierarchy = tvp->u.data;
+               break;
+       /* ISDB-T Support here */
+       case DTV_ISDBT_PARTIAL_RECEPTION:
+-              fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data;
++              c->isdbt_partial_reception = tvp->u.data;
+               break;
+       case DTV_ISDBT_SOUND_BROADCASTING:
+-              fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data;
++              c->isdbt_sb_mode = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SUBCHANNEL_ID:
+-              fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data;
++              c->isdbt_sb_subchannel = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_IDX:
+-              fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data;
++              c->isdbt_sb_segment_idx = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_COUNT:
+-              fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data;
++              c->isdbt_sb_segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYER_ENABLED:
+-              fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data;
++              c->isdbt_layer_enabled = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_FEC:
+-              fe->dtv_property_cache.layer[0].fec = tvp->u.data;
++              c->layer[0].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_MODULATION:
+-              fe->dtv_property_cache.layer[0].modulation = tvp->u.data;
++              c->layer[0].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+-              fe->dtv_property_cache.layer[0].segment_count = tvp->u.data;
++              c->layer[0].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+-              fe->dtv_property_cache.layer[0].interleaving = tvp->u.data;
++              c->layer[0].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_FEC:
+-              fe->dtv_property_cache.layer[1].fec = tvp->u.data;
++              c->layer[1].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_MODULATION:
+-              fe->dtv_property_cache.layer[1].modulation = tvp->u.data;
++              c->layer[1].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+-              fe->dtv_property_cache.layer[1].segment_count = tvp->u.data;
++              c->layer[1].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+-              fe->dtv_property_cache.layer[1].interleaving = tvp->u.data;
++              c->layer[1].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_FEC:
+-              fe->dtv_property_cache.layer[2].fec = tvp->u.data;
++              c->layer[2].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_MODULATION:
+-              fe->dtv_property_cache.layer[2].modulation = tvp->u.data;
++              c->layer[2].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+-              fe->dtv_property_cache.layer[2].segment_count = tvp->u.data;
++              c->layer[2].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+-              fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
++              c->layer[2].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBS_TS_ID:
+-              fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
++              c->isdbs_ts_id = tvp->u.data;
++              break;
++      case DTV_DVBT2_PLP_ID:
++              c->dvbt2_plp_id = tvp->u.data;
+               break;
+       default:
+-              r = -1;
++              return -EINVAL;
+       }
+       return r;
+@@ -1491,6 +1506,7 @@ static int dvb_frontend_ioctl(struct file *file,
+ {
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int err = -EOPNOTSUPP;
+@@ -1510,7 +1526,7 @@ static int dvb_frontend_ioctl(struct file *file,
+       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+               err = dvb_frontend_ioctl_properties(file, cmd, parg);
+       else {
+-              fe->dtv_property_cache.state = DTV_UNDEFINED;
++              c->state = DTV_UNDEFINED;
+               err = dvb_frontend_ioctl_legacy(file, cmd, parg);
+       }
+@@ -1523,6 +1539,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+ {
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int err = 0;
+       struct dtv_properties *tvps = NULL;
+@@ -1554,11 +1571,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+               }
+               for (i = 0; i < tvps->num; i++) {
+-                      (tvp + i)->result = dtv_property_process_set(fe, tvp + i, file);
+-                      err |= (tvp + i)->result;
++                      err = dtv_property_process_set(fe, tvp + i, file);
++                      if (err < 0)
++                              goto out;
++                      (tvp + i)->result = err;
+               }
+-              if(fe->dtv_property_cache.state == DTV_TUNE)
++              if (c->state == DTV_TUNE)
+                       dprintk("%s() Property cache is full, tuning\n", __func__);
+       } else
+@@ -1586,8 +1605,10 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+               }
+               for (i = 0; i < tvps->num; i++) {
+-                      (tvp + i)->result = dtv_property_process_get(fe, tvp + i, file);
+-                      err |= (tvp + i)->result;
++                      err = dtv_property_process_get(fe, tvp + i, file);
++                      if (err < 0)
++                              goto out;
++                      (tvp + i)->result = err;
+               }
+               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+@@ -1638,7 +1659,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+       case FE_READ_STATUS: {
+               fe_status_t* status = parg;
+-              /* if retune was requested but hasn't occured yet, prevent
++              /* if retune was requested but hasn't occurred yet, prevent
+                * that user get signal state from previous tuning */
+               if (fepriv->state == FESTATE_RETUNE ||
+                   fepriv->state == FESTATE_ERROR) {
+@@ -1729,7 +1750,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+                        * Dish network legacy switches (as used by Dish500)
+                        * are controlled by sending 9-bit command words
+                        * spaced 8msec apart.
+-                       * the actual command word is switch/port dependant
++                       * the actual command word is switch/port dependent
+                        * so it is up to the userspace application to send
+                        * the right command.
+                        * The command must always start with a '0' after
+@@ -1787,10 +1808,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+               break;
+       case FE_SET_FRONTEND: {
++              struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+               struct dvb_frontend_tune_settings fetunesettings;
+-              if(fe->dtv_property_cache.state == DTV_TUNE) {
+-                      if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
++              if (c->state == DTV_TUNE) {
++                      if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
+                               err = -EINVAL;
+                               break;
+                       }
+@@ -1800,9 +1822,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+                               break;
+                       }
+-                      memcpy (&fepriv->parameters, parg,
++                      memcpy (&fepriv->parameters_in, parg,
+                               sizeof (struct dvb_frontend_parameters));
+-                      dtv_property_cache_sync(fe, &fepriv->parameters);
++                      dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
+               }
+               memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
+@@ -1811,15 +1833,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+               /* force auto frequency inversion if requested */
+               if (dvb_force_auto_inversion) {
+-                      fepriv->parameters.inversion = INVERSION_AUTO;
++                      fepriv->parameters_in.inversion = INVERSION_AUTO;
+                       fetunesettings.parameters.inversion = INVERSION_AUTO;
+               }
+               if (fe->ops.info.type == FE_OFDM) {
+                       /* without hierarchical coding code_rate_LP is irrelevant,
+                        * so we tolerate the otherwise invalid FEC_NONE setting */
+-                      if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+-                          fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
+-                              fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
++                      if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
++                          fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
++                              fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
+               }
+               /* get frontend-specific tuning settings */
+@@ -1832,8 +1854,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+                       switch(fe->ops.info.type) {
+                       case FE_QPSK:
+                               fepriv->min_delay = HZ/20;
+-                              fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
+-                              fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
++                              fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
++                              fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
+                               break;
+                       case FE_QAM:
+@@ -1875,8 +1897,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+       case FE_GET_FRONTEND:
+               if (fe->ops.get_frontend) {
+-                      memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
+-                      err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
++                      err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
++                      memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
+               }
+               break;
+@@ -1967,6 +1989,14 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
+       if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+               if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
+                       goto err0;
++
++              /* If we took control of the bus, we need to force
++                 reinitialization.  This is because many ts_bus_ctrl()
++                 functions strobe the RESET pin on the demod, and if the
++                 frontend thread already exists then the dvb_init() routine
++                 won't get called (which is what usually does initial
++                 register configuration). */
++              fepriv->reinitialise = 1;
+       }
+       if ((ret = dvb_generic_open (inode, file)) < 0)
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
+index f9f19be..5590eb6 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
+@@ -239,7 +239,6 @@ struct analog_demod_ops {
+       void (*set_params)(struct dvb_frontend *fe,
+                          struct analog_parameters *params);
+       int  (*has_signal)(struct dvb_frontend *fe);
+-      int  (*is_stereo)(struct dvb_frontend *fe);
+       int  (*get_afc)(struct dvb_frontend *fe);
+       void (*tuner_status)(struct dvb_frontend *fe);
+       void (*standby)(struct dvb_frontend *fe);
+@@ -359,6 +358,9 @@ struct dtv_frontend_properties {
+       /* ISDB-T specifics */
+       u32                     isdbs_ts_id;
++
++      /* DVB-T2 specifics */
++      u32                     dvbt2_plp_id;
+ };
+ struct dvb_frontend {
+diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
+index 4df42aa..51752a9 100644
+--- a/drivers/media/dvb/dvb-core/dvb_net.c
++++ b/drivers/media/dvb/dvb-core/dvb_net.c
+@@ -1329,7 +1329,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
+               return -EBUSY;
+       dvb_net_stop(net);
+-      flush_scheduled_work();
++      flush_work_sync(&priv->set_multicast_list_wq);
++      flush_work_sync(&priv->restart_net_feed_wq);
+       printk("dvb_net: removed network interface %s\n", net->name);
+       unregister_netdev(net);
+       dvbnet->state[num]=0;
+diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
+index 3a3126c..1e53acd 100644
+--- a/drivers/media/dvb/dvb-core/dvb_net.h
++++ b/drivers/media/dvb/dvb-core/dvb_net.h
+@@ -32,6 +32,8 @@
+ #define DVB_NET_DEVICES_MAX 10
++#ifdef CONFIG_DVB_NET
++
+ struct dvb_net {
+       struct dvb_device *dvbdev;
+       struct net_device *device[DVB_NET_DEVICES_MAX];
+@@ -40,8 +42,25 @@ struct dvb_net {
+       struct dmx_demux *demux;
+ };
+-
+ void dvb_net_release(struct dvb_net *);
+ int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
++#else
++
++struct dvb_net {
++      struct dvb_device *dvbdev;
++};
++
++static inline void dvb_net_release(struct dvb_net *dvbnet)
++{
++}
++
++static inline int dvb_net_init(struct dvb_adapter *adap,
++                             struct dvb_net *dvbnet, struct dmx_demux *dmx)
++{
++      return 0;
++}
++
++#endif /* ifdef CONFIG_DVB_NET */
++
+ #endif
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+index a5712cd..d5333f3 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+@@ -45,6 +45,7 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
+       rbuf->data=data;
+       rbuf->size=len;
+       rbuf->error=0;
++      rbuf->do_wait=1;
+       init_waitqueue_head(&rbuf->queue);
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+index 41f04da..6951dd3 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+@@ -39,6 +39,7 @@ struct dvb_ringbuffer {
+       wait_queue_head_t queue;
+       spinlock_t        lock;
++      int               do_wait;
+ };
+ #define DVB_RINGBUFFER_PKTHDRSIZE 3
+diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h
+index fec66bd..d47bccd 100644
+--- a/include/linux/dvb/audio.h
++++ b/include/linux/dvb/audio.h
+@@ -67,7 +67,7 @@ typedef struct audio_status {
+ typedef
+-struct audio_karaoke{  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
++struct audio_karaoke {  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
+       int vocal1;    /* into left and right t at 70% each */
+       int vocal2;    /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
+       int melody;    /* mixed into the left channel and */
+diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
+index 493a2bf..36a3ed6 100644
+--- a/include/linux/dvb/frontend.h
++++ b/include/linux/dvb/frontend.h
+@@ -175,14 +175,20 @@ typedef enum fe_transmit_mode {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_AUTO,
+-      TRANSMISSION_MODE_4K
++      TRANSMISSION_MODE_4K,
++      TRANSMISSION_MODE_1K,
++      TRANSMISSION_MODE_16K,
++      TRANSMISSION_MODE_32K,
+ } fe_transmit_mode_t;
+ typedef enum fe_bandwidth {
+       BANDWIDTH_8_MHZ,
+       BANDWIDTH_7_MHZ,
+       BANDWIDTH_6_MHZ,
+-      BANDWIDTH_AUTO
++      BANDWIDTH_AUTO,
++      BANDWIDTH_5_MHZ,
++      BANDWIDTH_10_MHZ,
++      BANDWIDTH_1_712_MHZ,
+ } fe_bandwidth_t;
+@@ -191,7 +197,10 @@ typedef enum fe_guard_interval {
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+-      GUARD_INTERVAL_AUTO
++      GUARD_INTERVAL_AUTO,
++      GUARD_INTERVAL_1_128,
++      GUARD_INTERVAL_19_128,
++      GUARD_INTERVAL_19_256,
+ } fe_guard_interval_t;
+@@ -305,7 +314,9 @@ struct dvb_frontend_event {
+ #define DTV_ISDBS_TS_ID               42
+-#define DTV_MAX_COMMAND                               DTV_ISDBS_TS_ID
++#define DTV_DVBT2_PLP_ID      43
++
++#define DTV_MAX_COMMAND                               DTV_DVBT2_PLP_ID
+ typedef enum fe_pilot {
+       PILOT_ON,
+@@ -337,6 +348,7 @@ typedef enum fe_delivery_system {
+       SYS_DMBTH,
+       SYS_CMMB,
+       SYS_DAB,
++      SYS_DVBT2,
+ } fe_delivery_system_t;
+ struct dtv_cmds_h {
+diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
+index 5a7546c..1421cc8 100644
+--- a/include/linux/dvb/version.h
++++ b/include/linux/dvb/version.h
+@@ -24,6 +24,6 @@
+ #define _DVBVERSION_H_
+ #define DVB_API_VERSION 5
+-#define DVB_API_VERSION_MINOR 2
++#define DVB_API_VERSION_MINOR 3
+ #endif /*_DVBVERSION_H_*/
diff --git a/recipes/linux/linux-vuduo2-3.1.1/fix_cpu_proc.patch b/recipes/linux/linux-vuduo2-3.1.1/fix_cpu_proc.patch
new file mode 100644 (file)
index 0000000..2074d6a
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
+index e56931e..b740915 100644
+--- a/arch/mips/kernel/cpu-probe.c
++++ b/arch/mips/kernel/cpu-probe.c
+@@ -936,7 +936,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
+       case PRID_IMP_BMIPS5000:
+       case PRID_IMP_BMIPS5200:
+               c->cputype = CPU_BMIPS5000;
+-              __cpu_name[cpu] = "Broadcom BMIPS5000";
++              __cpu_name[cpu] = "Brcm4380";
+               set_elf_platform(cpu, "bmips5000");
+               c->options |= MIPS_CPU_ULRI;
+               break;
diff --git a/recipes/linux/linux-vuduo2-3.1.1/pinmux.patch b/recipes/linux/linux-vuduo2-3.1.1/pinmux.patch
new file mode 100644 (file)
index 0000000..ac9cfbb
--- /dev/null
@@ -0,0 +1,15 @@
+diff --git a/arch/mips/brcmstb/board.c b/arch/mips/brcmstb/board.c
+index 706c3c4..4cc0a4c 100644
+--- a/arch/mips/brcmstb/board.c
++++ b/arch/mips/brcmstb/board.c
+@@ -604,6 +604,10 @@ void board_pinmux_setup(void)
+       PINMUX(18, sgpio_00, 1);        /* MoCA I2C */
+       PINMUX(19, sgpio_01, 1);
++
++      PINMUX(6, gpio_006, 2);
++      PINMUX(6, gpio_007, 2);
++
+ #if defined(CONFIG_BCM7425B0)
+       brcm_moca_i2c_base = BPHYSADDR(BCHP_BSCC_REG_START);
+ #else
diff --git a/recipes/linux/linux-vuduo2-3.1.1/serial.patch b/recipes/linux/linux-vuduo2-3.1.1/serial.patch
new file mode 100644 (file)
index 0000000..9a96395
--- /dev/null
@@ -0,0 +1,12 @@
+diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
+index d75f8c7..49e0930 100644
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -1696,6 +1696,7 @@ static int serial_link_irq_chain(struct uart_8250_port *up)
+               i->head = &up->list;
+               spin_unlock_irq(&i->lock);
+               irq_flags |= up->port.irqflags;
++              printk("request_irq %d %d %p\n", irq_flags, up->port.irq, i);
+               ret = request_irq(up->port.irq, serial8250_interrupt,
+                                 irq_flags, "serial", i);
+               if (ret < 0)
diff --git a/recipes/linux/linux-vuduo2-3.1.1/stblinux-2.6.37-2.4.tar.bz2 b/recipes/linux/linux-vuduo2-3.1.1/stblinux-2.6.37-2.4.tar.bz2
new file mode 100644 (file)
index 0000000..dbb8ab2
Binary files /dev/null and b/recipes/linux/linux-vuduo2-3.1.1/stblinux-2.6.37-2.4.tar.bz2 differ
diff --git a/recipes/linux/linux-vuduo2-3.1.1/ubifs_backport.patch b/recipes/linux/linux-vuduo2-3.1.1/ubifs_backport.patch
new file mode 100644 (file)
index 0000000..b3a7c94
--- /dev/null
@@ -0,0 +1,11520 @@
+diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
+index 3cf193f..4dcc752 100644
+--- a/drivers/mtd/ubi/Kconfig
++++ b/drivers/mtd/ubi/Kconfig
+@@ -52,6 +52,12 @@ config MTD_UBI_GLUEBI
+          work on top of UBI. Do not enable this unless you use legacy
+          software.
+-source "drivers/mtd/ubi/Kconfig.debug"
++config MTD_UBI_DEBUG
++      bool "UBI debugging"
++      depends on SYSFS
++      select DEBUG_FS
++      select KALLSYMS
++      help
++        This option enables UBI debugging.
+ endif # MTD_UBI
+diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
+index fba2b66..ba73c00 100644
+--- a/drivers/mtd/ubi/build.c
++++ b/drivers/mtd/ubi/build.c
+@@ -690,11 +690,25 @@ static int io_init(struct ubi_device *ubi)
+       ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size);
+       ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0);
++      ubi->max_write_size = ubi->mtd->writebufsize;
++      /*
++       * Maximum write size has to be greater or equivalent to min. I/O
++       * size, and be multiple of min. I/O size.
++       */
++      if (ubi->max_write_size < ubi->min_io_size ||
++          ubi->max_write_size % ubi->min_io_size ||
++          !is_power_of_2(ubi->max_write_size)) {
++              ubi_err("bad write buffer size %d for %d min. I/O unit",
++                      ubi->max_write_size, ubi->min_io_size);
++              return -EINVAL;
++      }
++
+       /* Calculate default aligned sizes of EC and VID headers */
+       ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size);
+       ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size);
+       dbg_msg("min_io_size      %d", ubi->min_io_size);
++      dbg_msg("max_write_size   %d", ubi->max_write_size);
+       dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size);
+       dbg_msg("ec_hdr_alsize    %d", ubi->ec_hdr_alsize);
+       dbg_msg("vid_hdr_alsize   %d", ubi->vid_hdr_alsize);
+@@ -711,7 +725,7 @@ static int io_init(struct ubi_device *ubi)
+       }
+       /* Similar for the data offset */
+-      ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE;
++      ubi->leb_start = ubi->vid_hdr_offset + UBI_VID_HDR_SIZE;
+       ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
+       dbg_msg("vid_hdr_offset   %d", ubi->vid_hdr_offset);
+@@ -923,31 +937,26 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+       spin_lock_init(&ubi->volumes_lock);
+       ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
++      dbg_msg("sizeof(struct ubi_scan_leb) %zu", sizeof(struct ubi_scan_leb));
++      dbg_msg("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
+       err = io_init(ubi);
+       if (err)
+               goto out_free;
+       err = -ENOMEM;
+-      ubi->peb_buf1 = vmalloc(ubi->peb_size);
+-      if (!ubi->peb_buf1)
++      ubi->peb_buf = vmalloc(ubi->peb_size);
++      if (!ubi->peb_buf)
+               goto out_free;
+-      ubi->peb_buf2 = vmalloc(ubi->peb_size);
+-      if (!ubi->peb_buf2)
+-              goto out_free;
+-
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+-      mutex_init(&ubi->dbg_buf_mutex);
+-      ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
+-      if (!ubi->dbg_peb_buf)
++      err = ubi_debugging_init_dev(ubi);
++      if (err)
+               goto out_free;
+-#endif
+       err = attach_by_scanning(ubi);
+       if (err) {
+               dbg_err("failed to attach by scanning, error %d", err);
+-              goto out_free;
++              goto out_debugging;
+       }
+       if (ubi->autoresize_vol_id != -1) {
+@@ -960,12 +969,16 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+       if (err)
+               goto out_detach;
++      err = ubi_debugfs_init_dev(ubi);
++      if (err)
++              goto out_uif;
++
+       ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+       if (IS_ERR(ubi->bgt_thread)) {
+               err = PTR_ERR(ubi->bgt_thread);
+               ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
+                       err);
+-              goto out_uif;
++              goto out_debugfs;
+       }
+       ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
+@@ -991,8 +1004,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+        * checks @ubi->thread_enabled. Otherwise we may fail to wake it up.
+        */
+       spin_lock(&ubi->wl_lock);
+-      if (!DBG_DISABLE_BGT)
+-              ubi->thread_enabled = 1;
++      ubi->thread_enabled = 1;
+       wake_up_process(ubi->bgt_thread);
+       spin_unlock(&ubi->wl_lock);
+@@ -1000,18 +1012,20 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
+       ubi_notify_all(ubi, UBI_VOLUME_ADDED, NULL);
+       return ubi_num;
++out_debugfs:
++      ubi_debugfs_exit_dev(ubi);
+ out_uif:
++      get_device(&ubi->dev);
++      ubi_assert(ref);
+       uif_close(ubi);
+ out_detach:
+       ubi_wl_close(ubi);
+       free_internal_volumes(ubi);
+       vfree(ubi->vtbl);
++out_debugging:
++      ubi_debugging_exit_dev(ubi);
+ out_free:
+-      vfree(ubi->peb_buf1);
+-      vfree(ubi->peb_buf2);
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+-      vfree(ubi->dbg_peb_buf);
+-#endif
++      vfree(ubi->peb_buf);
+       if (ref)
+               put_device(&ubi->dev);
+       else
+@@ -1075,16 +1089,14 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
+        */
+       get_device(&ubi->dev);
++      ubi_debugfs_exit_dev(ubi);
+       uif_close(ubi);
+       ubi_wl_close(ubi);
+       free_internal_volumes(ubi);
+       vfree(ubi->vtbl);
+       put_mtd_device(ubi->mtd);
+-      vfree(ubi->peb_buf1);
+-      vfree(ubi->peb_buf2);
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+-      vfree(ubi->dbg_peb_buf);
+-#endif
++      ubi_debugging_exit_dev(ubi);
++      vfree(ubi->peb_buf);
+       ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
+       put_device(&ubi->dev);
+       return 0;
+@@ -1197,6 +1209,11 @@ static int __init ubi_init(void)
+       if (!ubi_wl_entry_slab)
+               goto out_dev_unreg;
++      err = ubi_debugfs_init();
++      if (err)
++              goto out_slab;
++
++
+       /* Attach MTD devices */
+       for (i = 0; i < mtd_devs; i++) {
+               struct mtd_dev_param *p = &mtd_dev_param[i];
+@@ -1245,6 +1262,8 @@ out_detach:
+                       ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
++      ubi_debugfs_exit();
++out_slab:
+       kmem_cache_destroy(ubi_wl_entry_slab);
+ out_dev_unreg:
+       misc_deregister(&ubi_ctrl_cdev);
+@@ -1256,11 +1275,7 @@ out:
+       ubi_err("UBI error: cannot initialize UBI, error %d", err);
+       return err;
+ }
+-#if defined(CONFIG_BRCMSTB) && !defined(MODULE)
+-late_initcall(ubi_init);      /* need to wait for the MTD driver */
+-#else
+ module_init(ubi_init);
+-#endif
+ static void __exit ubi_exit(void)
+ {
+@@ -1272,6 +1287,7 @@ static void __exit ubi_exit(void)
+                       ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
++      ubi_debugfs_exit();
+       kmem_cache_destroy(ubi_wl_entry_slab);
+       misc_deregister(&ubi_ctrl_cdev);
+       class_remove_file(ubi_class, &ubi_version);
+diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
+index af9fb0f..cdea669 100644
+--- a/drivers/mtd/ubi/cdev.c
++++ b/drivers/mtd/ubi/cdev.c
+@@ -115,7 +115,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
+               mode = UBI_READONLY;
+       dbg_gen("open device %d, volume %d, mode %d",
+-              ubi_num, vol_id, mode);
++              ubi_num, vol_id, mode);
+       desc = ubi_open_volume(ubi_num, vol_id, mode);
+       if (IS_ERR(desc))
+@@ -158,7 +158,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
+       loff_t new_offset;
+       if (vol->updating) {
+-               /* Update is in progress, seeking is prohibited */
++              /* Update is in progress, seeking is prohibited */
+               dbg_err("updating");
+               return -EBUSY;
+       }
+@@ -561,18 +561,18 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
+       }
+       /* Set volume property command */
+-      case UBI_IOCSETPROP:
++      case UBI_IOCSETVOLPROP:
+       {
+-              struct ubi_set_prop_req req;
++              struct ubi_set_vol_prop_req req;
+               err = copy_from_user(&req, argp,
+-                              sizeof(struct ubi_set_prop_req));
++                                   sizeof(struct ubi_set_vol_prop_req));
+               if (err) {
+                       err = -EFAULT;
+                       break;
+               }
+               switch (req.property) {
+-              case UBI_PROP_DIRECT_WRITE:
++              case UBI_VOL_PROP_DIRECT_WRITE:
+                       mutex_lock(&ubi->device_mutex);
+                       desc->vol->direct_writes = !!req.value;
+                       mutex_unlock(&ubi->device_mutex);
+@@ -628,6 +628,9 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
+       if (req->alignment != 1 && n)
+               goto bad;
++      if (!req->name[0] || !req->name_len)
++              goto bad;
++
+       if (req->name_len > UBI_VOL_NAME_MAX) {
+               err = -ENAMETOOLONG;
+               goto bad;
+@@ -1100,5 +1103,5 @@ const struct file_operations ubi_ctrl_cdev_operations = {
+       .owner          = THIS_MODULE,
+       .unlocked_ioctl = ctrl_cdev_ioctl,
+       .compat_ioctl   = ctrl_cdev_compat_ioctl,
+-      .llseek         = noop_llseek,
++      .llseek         = no_llseek,
+ };
+diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
+index 4876977..ab80c0d 100644
+--- a/drivers/mtd/ubi/debug.c
++++ b/drivers/mtd/ubi/debug.c
+@@ -27,6 +27,9 @@
+ #ifdef CONFIG_MTD_UBI_DEBUG
+ #include "ubi.h"
++#include <linux/debugfs.h>
++#include <linux/uaccess.h>
++#include <linux/module.h>
+ /**
+  * ubi_dbg_dump_ec_hdr - dump an erase counter header.
+@@ -61,15 +64,15 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
+ {
+       printk(KERN_DEBUG "Volume identifier header dump:\n");
+       printk(KERN_DEBUG "\tmagic     %08x\n", be32_to_cpu(vid_hdr->magic));
+-      printk(KERN_DEBUG "\tversion   %d\n",   (int)vid_hdr->version);
+-      printk(KERN_DEBUG "\tvol_type  %d\n",   (int)vid_hdr->vol_type);
+-      printk(KERN_DEBUG "\tcopy_flag %d\n",   (int)vid_hdr->copy_flag);
+-      printk(KERN_DEBUG "\tcompat    %d\n",   (int)vid_hdr->compat);
+-      printk(KERN_DEBUG "\tvol_id    %d\n",   be32_to_cpu(vid_hdr->vol_id));
+-      printk(KERN_DEBUG "\tlnum      %d\n",   be32_to_cpu(vid_hdr->lnum));
+-      printk(KERN_DEBUG "\tdata_size %d\n",   be32_to_cpu(vid_hdr->data_size));
+-      printk(KERN_DEBUG "\tused_ebs  %d\n",   be32_to_cpu(vid_hdr->used_ebs));
+-      printk(KERN_DEBUG "\tdata_pad  %d\n",   be32_to_cpu(vid_hdr->data_pad));
++      printk(KERN_DEBUG "\tversion   %d\n",  (int)vid_hdr->version);
++      printk(KERN_DEBUG "\tvol_type  %d\n",  (int)vid_hdr->vol_type);
++      printk(KERN_DEBUG "\tcopy_flag %d\n",  (int)vid_hdr->copy_flag);
++      printk(KERN_DEBUG "\tcompat    %d\n",  (int)vid_hdr->compat);
++      printk(KERN_DEBUG "\tvol_id    %d\n",  be32_to_cpu(vid_hdr->vol_id));
++      printk(KERN_DEBUG "\tlnum      %d\n",  be32_to_cpu(vid_hdr->lnum));
++      printk(KERN_DEBUG "\tdata_size %d\n",  be32_to_cpu(vid_hdr->data_size));
++      printk(KERN_DEBUG "\tused_ebs  %d\n",  be32_to_cpu(vid_hdr->used_ebs));
++      printk(KERN_DEBUG "\tdata_pad  %d\n",  be32_to_cpu(vid_hdr->data_pad));
+       printk(KERN_DEBUG "\tsqnum     %llu\n",
+               (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+       printk(KERN_DEBUG "\thdr_crc   %08x\n", be32_to_cpu(vid_hdr->hdr_crc));
+@@ -228,4 +231,261 @@ out:
+       return;
+ }
++/**
++ * ubi_debugging_init_dev - initialize debugging for an UBI device.
++ * @ubi: UBI device description object
++ *
++ * This function initializes debugging-related data for UBI device @ubi.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubi_debugging_init_dev(struct ubi_device *ubi)
++{
++      ubi->dbg = kzalloc(sizeof(struct ubi_debug_info), GFP_KERNEL);
++      if (!ubi->dbg)
++              return -ENOMEM;
++
++      return 0;
++}
++
++/**
++ * ubi_debugging_exit_dev - free debugging data for an UBI device.
++ * @ubi: UBI device description object
++ */
++void ubi_debugging_exit_dev(struct ubi_device *ubi)
++{
++      kfree(ubi->dbg);
++}
++
++/*
++ * Root directory for UBI stuff in debugfs. Contains sub-directories which
++ * contain the stuff specific to particular UBI devices.
++ */
++static struct dentry *dfs_rootdir;
++
++/**
++ * ubi_debugfs_init - create UBI debugfs directory.
++ *
++ * Create UBI debugfs directory. Returns zero in case of success and a negative
++ * error code in case of failure.
++ */
++int ubi_debugfs_init(void)
++{
++      dfs_rootdir = debugfs_create_dir("ubi", NULL);
++      if (IS_ERR_OR_NULL(dfs_rootdir)) {
++              int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);
++
++              ubi_err("cannot create \"ubi\" debugfs directory, error %d\n",
++                      err);
++              return err;
++      }
++
++      return 0;
++}
++
++/**
++ * ubi_debugfs_exit - remove UBI debugfs directory.
++ */
++void ubi_debugfs_exit(void)
++{
++      debugfs_remove(dfs_rootdir);
++}
++
++/* Read an UBI debugfs file */
++static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
++                           size_t count, loff_t *ppos)
++{
++      unsigned long ubi_num = (unsigned long)file->private_data;
++      struct dentry *dent = file->f_path.dentry;
++      struct ubi_device *ubi;
++      struct ubi_debug_info *d;
++      char buf[3];
++      int val;
++
++      ubi = ubi_get_device(ubi_num);
++      if (!ubi)
++              return -ENODEV;
++      d = ubi->dbg;
++
++      if (dent == d->dfs_chk_gen)
++              val = d->chk_gen;
++      else if (dent == d->dfs_chk_io)
++              val = d->chk_io;
++      else if (dent == d->dfs_disable_bgt)
++              val = d->disable_bgt;
++      else if (dent == d->dfs_emulate_bitflips)
++              val = d->emulate_bitflips;
++      else if (dent == d->dfs_emulate_io_failures)
++              val = d->emulate_io_failures;
++      else {
++              count = -EINVAL;
++              goto out;
++      }
++
++      if (val)
++              buf[0] = '1';
++      else
++              buf[0] = '0';
++      buf[1] = '\n';
++      buf[2] = 0x00;
++
++      count = simple_read_from_buffer(user_buf, count, ppos, buf, 2);
++
++out:
++      ubi_put_device(ubi);
++      return count;
++}
++
++/* Write an UBI debugfs file */
++static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
++                            size_t count, loff_t *ppos)
++{
++      unsigned long ubi_num = (unsigned long)file->private_data;
++      struct dentry *dent = file->f_path.dentry;
++      struct ubi_device *ubi;
++      struct ubi_debug_info *d;
++      size_t buf_size;
++      char buf[8];
++      int val;
++
++      ubi = ubi_get_device(ubi_num);
++      if (!ubi)
++              return -ENODEV;
++      d = ubi->dbg;
++
++      buf_size = min_t(size_t, count, (sizeof(buf) - 1));
++      if (copy_from_user(buf, user_buf, buf_size)) {
++              count = -EFAULT;
++              goto out;
++      }
++
++      if (buf[0] == '1')
++              val = 1;
++      else if (buf[0] == '0')
++              val = 0;
++      else {
++              count = -EINVAL;
++              goto out;
++      }
++
++      if (dent == d->dfs_chk_gen)
++              d->chk_gen = val;
++      else if (dent == d->dfs_chk_io)
++              d->chk_io = val;
++      else if (dent == d->dfs_disable_bgt)
++              d->disable_bgt = val;
++      else if (dent == d->dfs_emulate_bitflips)
++              d->emulate_bitflips = val;
++      else if (dent == d->dfs_emulate_io_failures)
++              d->emulate_io_failures = val;
++      else
++              count = -EINVAL;
++
++out:
++      ubi_put_device(ubi);
++      return count;
++}
++
++static int default_open(struct inode *inode, struct file *file)
++{
++      if (inode->i_private)
++              file->private_data = inode->i_private;
++
++      return 0;
++}
++
++/* File operations for all UBI debugfs files */
++static const struct file_operations dfs_fops = {
++      .read   = dfs_file_read,
++      .write  = dfs_file_write,
++      .open   = default_open,
++      .llseek = no_llseek,
++      .owner  = THIS_MODULE,
++};
++
++/**
++ * ubi_debugfs_init_dev - initialize debugfs for an UBI device.
++ * @ubi: UBI device description object
++ *
++ * This function creates all debugfs files for UBI device @ubi. Returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++int ubi_debugfs_init_dev(struct ubi_device *ubi)
++{
++      int err, n;
++      unsigned long ubi_num = ubi->ubi_num;
++      const char *fname;
++      struct dentry *dent;
++      struct ubi_debug_info *d = ubi->dbg;
++
++      n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME,
++                   ubi->ubi_num);
++      if (n == UBI_DFS_DIR_LEN) {
++              /* The array size is too small */
++              fname = UBI_DFS_DIR_NAME;
++              dent = ERR_PTR(-EINVAL);
++              goto out;
++      }
++
++      fname = d->dfs_dir_name;
++      dent = debugfs_create_dir(fname, dfs_rootdir);
++      if (IS_ERR_OR_NULL(dent))
++              goto out;
++      d->dfs_dir = dent;
++
++      fname = "chk_gen";
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_gen = dent;
++
++      fname = "chk_io";
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_io = dent;
++
++      fname = "tst_disable_bgt";
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_disable_bgt = dent;
++
++      fname = "tst_emulate_bitflips";
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_emulate_bitflips = dent;
++
++      fname = "tst_emulate_io_failures";
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_emulate_io_failures = dent;
++
++      return 0;
++
++out_remove:
++      debugfs_remove_recursive(d->dfs_dir);
++out:
++      err = dent ? PTR_ERR(dent) : -ENODEV;
++      ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n",
++              fname, err);
++      return err;
++}
++
++/**
++ * dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi
++ * @ubi: UBI device description object
++ */
++void ubi_debugfs_exit_dev(struct ubi_device *ubi)
++{
++      debugfs_remove_recursive(ubi->dbg->dfs_dir);
++}
++
+ #endif /* CONFIG_MTD_UBI_DEBUG */
+diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
+index 9eca950..8c513ee 100644
+--- a/drivers/mtd/ubi/debug.h
++++ b/drivers/mtd/ubi/debug.h
+@@ -24,8 +24,6 @@
+ #ifdef CONFIG_MTD_UBI_DEBUG
+ #include <linux/random.h>
+-#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
+-
+ #define ubi_assert(expr)  do {                                               \
+       if (unlikely(!(expr))) {                                             \
+               printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
+@@ -34,19 +32,31 @@
+       }                                                                    \
+ } while (0)
++#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
++
++#define ubi_dbg_dump_stack() dump_stack()
++
++#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  \
++              print_hex_dump(l, ps, pt, r, g, b, len, a)
++
++#define ubi_dbg_msg(type, fmt, ...) \
++      pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__)
++
++/* Just a debugging messages not related to any specific UBI subsystem */
+ #define dbg_msg(fmt, ...)                                    \
+       printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
+              current->pid, __func__, ##__VA_ARGS__)
+-#define ubi_dbg_dump_stack() dump_stack()
+-
+-struct ubi_ec_hdr;
+-struct ubi_vid_hdr;
+-struct ubi_volume;
+-struct ubi_vtbl_record;
+-struct ubi_scan_volume;
+-struct ubi_scan_leb;
+-struct ubi_mkvol_req;
++/* General debugging messages */
++#define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__)
++/* Messages from the eraseblock association sub-system */
++#define dbg_eba(fmt, ...) ubi_dbg_msg("eba", fmt, ##__VA_ARGS__)
++/* Messages from the wear-leveling sub-system */
++#define dbg_wl(fmt, ...)  ubi_dbg_msg("wl", fmt, ##__VA_ARGS__)
++/* Messages from the input/output sub-system */
++#define dbg_io(fmt, ...)  ubi_dbg_msg("io", fmt, ##__VA_ARGS__)
++/* Initialization and build messages */
++#define dbg_bld(fmt, ...) ubi_dbg_msg("bld", fmt, ##__VA_ARGS__)
+ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
+ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
+@@ -56,134 +66,174 @@ void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
+ void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
+ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
+ void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
+-
+-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  \
+-              print_hex_dump(l, ps, pt, r, g, b, len, a)
+-
+-#ifdef CONFIG_MTD_UBI_DEBUG_MSG
+-/* General debugging messages */
+-#define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-#else
+-#define dbg_gen(fmt, ...) ({})
+-#endif
+-
+-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
+-/* Messages from the eraseblock association sub-system */
+-#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-#else
+-#define dbg_eba(fmt, ...) ({})
+-#endif
+-
+-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
+-/* Messages from the wear-leveling sub-system */
+-#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-#else
+-#define dbg_wl(fmt, ...) ({})
+-#endif
+-
+-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
+-/* Messages from the input/output sub-system */
+-#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-#else
+-#define dbg_io(fmt, ...) ({})
+-#endif
+-
+-#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
+-/* Initialization and build messages */
+-#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-#define UBI_IO_DEBUG 1
+-#else
+-#define dbg_bld(fmt, ...) ({})
+-#define UBI_IO_DEBUG 0
+-#endif
+-
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
+ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+                       int offset, int len);
+-#else
+-#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
+-#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
+-#endif
++int ubi_debugging_init_dev(struct ubi_device *ubi);
++void ubi_debugging_exit_dev(struct ubi_device *ubi);
++int ubi_debugfs_init(void);
++void ubi_debugfs_exit(void);
++int ubi_debugfs_init_dev(struct ubi_device *ubi);
++void ubi_debugfs_exit_dev(struct ubi_device *ubi);
+-#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT
+-#define DBG_DISABLE_BGT 1
+-#else
+-#define DBG_DISABLE_BGT 0
+-#endif
++/*
++ * The UBI debugfs directory name pattern and maximum name length (3 for "ubi"
++ * + 2 for the number plus 1 for the trailing zero byte.
++ */
++#define UBI_DFS_DIR_NAME "ubi%d"
++#define UBI_DFS_DIR_LEN  (3 + 2 + 1)
++
++/**
++ * struct ubi_debug_info - debugging information for an UBI device.
++ *
++ * @chk_gen: if UBI general extra checks are enabled
++ * @chk_io: if UBI I/O extra checks are enabled
++ * @disable_bgt: disable the background task for testing purposes
++ * @emulate_bitflips: emulate bit-flips for testing purposes
++ * @emulate_io_failures: emulate write/erase failures for testing purposes
++ * @dfs_dir_name: name of debugfs directory containing files of this UBI device
++ * @dfs_dir: direntry object of the UBI device debugfs directory
++ * @dfs_chk_gen: debugfs knob to enable UBI general extra checks
++ * @dfs_chk_io: debugfs knob to enable UBI I/O extra checks
++ * @dfs_disable_bgt: debugfs knob to disable the background task
++ * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips
++ * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures
++ */
++struct ubi_debug_info {
++      unsigned int chk_gen:1;
++      unsigned int chk_io:1;
++      unsigned int disable_bgt:1;
++      unsigned int emulate_bitflips:1;
++      unsigned int emulate_io_failures:1;
++      char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
++      struct dentry *dfs_dir;
++      struct dentry *dfs_chk_gen;
++      struct dentry *dfs_chk_io;
++      struct dentry *dfs_disable_bgt;
++      struct dentry *dfs_emulate_bitflips;
++      struct dentry *dfs_emulate_io_failures;
++};
++
++/**
++ * ubi_dbg_is_bgt_disabled - if the background thread is disabled.
++ * @ubi: UBI device description object
++ *
++ * Returns non-zero if the UBI background thread is disabled for testing
++ * purposes.
++ */
++static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
++{
++      return ubi->dbg->disable_bgt;
++}
+-#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS
+ /**
+  * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
++ * @ubi: UBI device description object
+  *
+  * Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
+  */
+-static inline int ubi_dbg_is_bitflip(void)
++static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
+ {
+-      return !(random32() % 200);
++      if (ubi->dbg->emulate_bitflips)
++              return !(random32() % 200);
++      return 0;
+ }
+-#else
+-#define ubi_dbg_is_bitflip() 0
+-#endif
+-#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES
+ /**
+  * ubi_dbg_is_write_failure - if it is time to emulate a write failure.
++ * @ubi: UBI device description object
+  *
+  * Returns non-zero if a write failure should be emulated, otherwise returns
+  * zero.
+  */
+-static inline int ubi_dbg_is_write_failure(void)
++static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
+ {
+-      return !(random32() % 500);
++      if (ubi->dbg->emulate_io_failures)
++              return !(random32() % 500);
++      return 0;
+ }
+-#else
+-#define ubi_dbg_is_write_failure() 0
+-#endif
+-#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES
+ /**
+  * ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
++ * @ubi: UBI device description object
+  *
+  * Returns non-zero if an erase failure should be emulated, otherwise returns
+  * zero.
+  */
+-static inline int ubi_dbg_is_erase_failure(void)
++static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
+ {
++      if (ubi->dbg->emulate_io_failures)
+               return !(random32() % 400);
++      return 0;
+ }
+-#else
+-#define ubi_dbg_is_erase_failure() 0
+-#endif
+ #else
+-#define ubi_assert(expr)                 ({})
+-#define dbg_err(fmt, ...)                ({})
+-#define dbg_msg(fmt, ...)                ({})
+-#define dbg_gen(fmt, ...)                ({})
+-#define dbg_eba(fmt, ...)                ({})
+-#define dbg_wl(fmt, ...)                 ({})
+-#define dbg_io(fmt, ...)                 ({})
+-#define dbg_bld(fmt, ...)                ({})
+-#define ubi_dbg_dump_stack()             ({})
+-#define ubi_dbg_dump_ec_hdr(ec_hdr)      ({})
+-#define ubi_dbg_dump_vid_hdr(vid_hdr)    ({})
+-#define ubi_dbg_dump_vol_info(vol)       ({})
+-#define ubi_dbg_dump_vtbl_record(r, idx) ({})
+-#define ubi_dbg_dump_sv(sv)              ({})
+-#define ubi_dbg_dump_seb(seb, type)      ({})
+-#define ubi_dbg_dump_mkvol_req(req)      ({})
+-#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
+-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  ({})
+-
+-#define UBI_IO_DEBUG               0
+-#define DBG_DISABLE_BGT            0
+-#define ubi_dbg_is_bitflip()       0
+-#define ubi_dbg_is_write_failure() 0
+-#define ubi_dbg_is_erase_failure() 0
+-#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
+-#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
++/* Use "if (0)" to make compiler check arguments even if debugging is off */
++#define ubi_assert(expr)  do {                                               \
++      if (0) {                                                             \
++              printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
++                     __func__, __LINE__, current->pid);                    \
++      }                                                                    \
++} while (0)
++
++#define dbg_err(fmt, ...) do {                                               \
++      if (0)                                                               \
++              ubi_err(fmt, ##__VA_ARGS__);                                 \
++} while (0)
++
++#define ubi_dbg_msg(fmt, ...) do {                                           \
++      if (0)                                                               \
++              pr_debug(fmt "\n", ##__VA_ARGS__);                           \
++} while (0)
++
++#define dbg_msg(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_gen(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_eba(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_wl(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_io(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_bld(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
++
++static inline void ubi_dbg_dump_stack(void)                          { return; }
++static inline void
++ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)                 { return; }
++static inline void
++ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)              { return; }
++static inline void
++ubi_dbg_dump_vol_info(const struct ubi_volume *vol)                  { return; }
++static inline void
++ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)   { return; }
++static inline void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) { return; }
++static inline void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb,
++                                  int type)                        { return; }
++static inline void
++ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)              { return; }
++static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
++                                    int pnum, int offset, int len) { return; }
++static inline void
++ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
++                     int g, const void *b, size_t len, bool a)     { return; }
++static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
++                                     int pnum, int offset,
++                                     int len)                    { return 0; }
++static inline int ubi_dbg_check_write(struct ubi_device *ubi,
++                                    const void *buf, int pnum,
++                                    int offset, int len)         { return 0; }
++
++static inline int ubi_debugging_init_dev(struct ubi_device *ubi)   { return 0; }
++static inline void ubi_debugging_exit_dev(struct ubi_device *ubi)  { return; }
++static inline int ubi_debugfs_init(void)                           { return 0; }
++static inline void ubi_debugfs_exit(void)                          { return; }
++static inline int ubi_debugfs_init_dev(struct ubi_device *ubi)     { return 0; }
++static inline void ubi_debugfs_exit_dev(struct ubi_device *ubi)    { return; }
++
++static inline int
++ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)              { return 0; }
++static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) { return 0; }
++static inline int
++ubi_dbg_is_write_failure(const struct ubi_device *ubi)             { return 0; }
++static inline int
++ubi_dbg_is_erase_failure(const struct ubi_device *ubi)             { return 0; }
+ #endif /* !CONFIG_MTD_UBI_DEBUG */
+ #endif /* !__UBI_DEBUG_H__ */
+diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
+index fb7f19b..9b7f87e 100644
+--- a/drivers/mtd/ubi/eba.c
++++ b/drivers/mtd/ubi/eba.c
+@@ -443,7 +443,7 @@ retry:
+               if (err == UBI_IO_BITFLIPS) {
+                       scrub = 1;
+                       err = 0;
+-              } else if (mtd_is_eccerr(err)) {
++              } else if (err == -EBADMSG) {
+                       if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+                               goto out_unlock;
+                       scrub = 1;
+@@ -529,18 +529,18 @@ retry:
+       data_size = offset + len;
+       mutex_lock(&ubi->buf_mutex);
+-      memset(ubi->peb_buf1 + offset, 0xFF, len);
++      memset(ubi->peb_buf + offset, 0xFF, len);
+       /* Read everything before the area where the write failure happened */
+       if (offset > 0) {
+-              err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
++              err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
+               if (err && err != UBI_IO_BITFLIPS)
+                       goto out_unlock;
+       }
+-      memcpy(ubi->peb_buf1 + offset, buf, len);
++      memcpy(ubi->peb_buf + offset, buf, len);
+-      err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
++      err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
+       if (err) {
+               mutex_unlock(&ubi->buf_mutex);
+               goto write_error;
+@@ -979,7 +979,7 @@ static int is_error_sane(int err)
+  * physical eraseblock @to. The @vid_hdr buffer may be changed by this
+  * function. Returns:
+  *   o %0 in case of success;
+- *   o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_CANCEL_BITFLIPS, etc;
++ *   o %MOVE_CANCEL_RACE, %MOVE_TARGET_WR_ERR, %MOVE_TARGET_BITFLIPS, etc;
+  *   o a negative error code in case of failure.
+  */
+ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+@@ -1028,12 +1028,14 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+        * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
+        * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
+        * LEB is already locked, we just do not move it and return
+-       * %MOVE_CANCEL_RACE, which means that UBI will re-try, but later.
++       * %MOVE_RETRY. Note, we do not return %MOVE_CANCEL_RACE here because
++       * we do not know the reasons of the contention - it may be just a
++       * normal I/O on this LEB, so we want to re-try.
+        */
+       err = leb_write_trylock(ubi, vol_id, lnum);
+       if (err) {
+               dbg_wl("contention on LEB %d:%d, cancel", vol_id, lnum);
+-              return MOVE_CANCEL_RACE;
++              return MOVE_RETRY;
+       }
+       /*
+@@ -1051,13 +1053,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+       /*
+        * OK, now the LEB is locked and we can safely start moving it. Since
+-       * this function utilizes the @ubi->peb_buf1 buffer which is shared
++       * this function utilizes the @ubi->peb_buf buffer which is shared
+        * with some other functions - we lock the buffer by taking the
+        * @ubi->buf_mutex.
+        */
+       mutex_lock(&ubi->buf_mutex);
+       dbg_wl("read %d bytes of data", aldata_size);
+-      err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
++      err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size);
+       if (err && err != UBI_IO_BITFLIPS) {
+               ubi_warn("error %d while reading data from PEB %d",
+                        err, from);
+@@ -1077,10 +1079,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+        */
+       if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
+               aldata_size = data_size =
+-                      ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
++                      ubi_calc_data_len(ubi, ubi->peb_buf, data_size);
+       cond_resched();
+-      crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
++      crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size);
+       cond_resched();
+       /*
+@@ -1114,12 +1116,12 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+                       if (is_error_sane(err))
+                               err = MOVE_TARGET_RD_ERR;
+               } else
+-                      err = MOVE_CANCEL_BITFLIPS;
++                      err = MOVE_TARGET_BITFLIPS;
+               goto out_unlock_buf;
+       }
+       if (data_size > 0) {
+-              err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
++              err = ubi_io_write_data(ubi, ubi->peb_buf, to, 0, aldata_size);
+               if (err) {
+                       if (err == -EIO)
+                               err = MOVE_TARGET_WR_ERR;
+@@ -1132,8 +1134,8 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+                * We've written the data and are going to read it back to make
+                * sure it was written correctly.
+                */
+-
+-              err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
++              memset(ubi->peb_buf, 0xFF, aldata_size);
++              err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size);
+               if (err) {
+                       if (err != UBI_IO_BITFLIPS) {
+                               ubi_warn("error %d while reading data back "
+@@ -1141,13 +1143,13 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
+                               if (is_error_sane(err))
+                                       err = MOVE_TARGET_RD_ERR;
+                       } else
+-                              err = MOVE_CANCEL_BITFLIPS;
++                              err = MOVE_TARGET_BITFLIPS;
+                       goto out_unlock_buf;
+               }
+               cond_resched();
+-              if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
++              if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) {
+                       ubi_warn("read data back from PEB %d and it is "
+                                "different", to);
+                       err = -EINVAL;
+diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
+index 8ca890c..2614dcc 100644
+--- a/drivers/mtd/ubi/io.c
++++ b/drivers/mtd/ubi/io.c
+@@ -91,7 +91,7 @@
+ #include <linux/slab.h>
+ #include "ubi.h"
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
+ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
+ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+@@ -146,13 +146,35 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
+       if (err)
+               return err;
++      /*
++       * Deliberately corrupt the buffer to improve robustness. Indeed, if we
++       * do not do this, the following may happen:
++       * 1. The buffer contains data from previous operation, e.g., read from
++       *    another PEB previously. The data looks like expected, e.g., if we
++       *    just do not read anything and return - the caller would not
++       *    notice this. E.g., if we are reading a VID header, the buffer may
++       *    contain a valid VID header from another PEB.
++       * 2. The driver is buggy and returns us success or -EBADMSG or
++       *    -EUCLEAN, but it does not actually put any data to the buffer.
++       *
++       * This may confuse UBI or upper layers - they may think the buffer
++       * contains valid data while in fact it is just old data. This is
++       * especially possible because UBI (and UBIFS) relies on CRC, and
++       * treats data as correct even in case of ECC errors if the CRC is
++       * correct.
++       *
++       * Try to prevent this situation by changing the first byte of the
++       * buffer.
++       */
++      *((uint8_t *)buf) ^= 0xFF;
++
+       addr = (loff_t)pnum * ubi->peb_size + offset;
+ retry:
+       err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+       if (err) {
+-              const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : "";
++              const char *errstr = (err == -EBADMSG) ? " (ECC error)" : "";
+-              if (mtd_is_bitflip(err)) {
++              if (err == -EUCLEAN) {
+                       /*
+                        * -EUCLEAN is reported if there was a bit-flip which
+                        * was corrected, so this is harmless.
+@@ -166,9 +188,9 @@ retry:
+                       return UBI_IO_BITFLIPS;
+               }
+-              if (read != len && retries++ < UBI_IO_RETRIES) {
+-                      dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
+-                             " read only %zd bytes, retry",
++              if (retries++ < UBI_IO_RETRIES) {
++                      dbg_io("error %d%s while reading %d bytes from PEB "
++                             "%d:%d, read only %zd bytes, retry",
+                              err, errstr, len, pnum, offset, read);
+                       yield();
+                       goto retry;
+@@ -183,14 +205,14 @@ retry:
+                * all the requested data. But some buggy drivers might do
+                * this, so we change it to -EIO.
+                */
+-              if (read != len && mtd_is_eccerr(err)) {
++              if (read != len && err == -EBADMSG) {
+                       ubi_assert(0);
+                       err = -EIO;
+               }
+       } else {
+               ubi_assert(len == read);
+-              if (ubi_dbg_is_bitflip()) {
++              if (ubi_dbg_is_bitflip(ubi)) {
+                       dbg_gen("bit-flip (emulated)");
+                       err = UBI_IO_BITFLIPS;
+               }
+@@ -259,7 +281,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+                       return err;
+       }
+-      if (ubi_dbg_is_write_failure()) {
++      if (ubi_dbg_is_write_failure(ubi)) {
+               dbg_err("cannot write %d bytes to PEB %d:%d "
+                       "(emulated)", len, pnum, offset);
+               ubi_dbg_dump_stack();
+@@ -322,6 +344,12 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum)
+       wait_queue_head_t wq;
+       dbg_io("erase PEB %d", pnum);
++      ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
++
++      if (ubi->ro_mode) {
++              ubi_err("read-only mode");
++              return -EROFS;
++      }
+ retry:
+       init_waitqueue_head(&wq);
+@@ -368,7 +396,7 @@ retry:
+       if (err)
+               return err;
+-      if (ubi_dbg_is_erase_failure() && !err) {
++      if (ubi_dbg_is_erase_failure(ubi)) {
+               dbg_err("cannot erase PEB %d (emulated)", pnum);
+               return -EIO;
+       }
+@@ -403,11 +431,11 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
+                       goto out;
+               /* Make sure the PEB contains only 0xFF bytes */
+-              err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
++              err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
+               if (err)
+                       goto out;
+-              err = ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
++              err = ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->peb_size);
+               if (err == 0) {
+                       ubi_err("erased PEB %d, but a non-0xFF byte found",
+                               pnum);
+@@ -416,17 +444,17 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
+               }
+               /* Write a pattern and check it */
+-              memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
+-              err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
++              memset(ubi->peb_buf, patterns[i], ubi->peb_size);
++              err = ubi_io_write(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
+               if (err)
+                       goto out;
+-              memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
+-              err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
++              memset(ubi->peb_buf, ~patterns[i], ubi->peb_size);
++              err = ubi_io_read(ubi, ubi->peb_buf, pnum, 0, ubi->peb_size);
+               if (err)
+                       goto out;
+-              err = ubi_check_pattern(ubi->peb_buf1, patterns[i],
++              err = ubi_check_pattern(ubi->peb_buf, patterns[i],
+                                       ubi->peb_size);
+               if (err == 0) {
+                       ubi_err("pattern %x checking failed for PEB %d",
+@@ -437,11 +465,11 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
+       }
+       err = patt_count;
+-      ubi_msg("PEB %d passed torture test, do not mark it a bad", pnum);
++      ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum);
+ out:
+       mutex_unlock(&ubi->buf_mutex);
+-      if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
++      if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+               /*
+                * If a bit-flip or data integrity error was detected, the test
+                * has not passed because it happened on a freshly erased
+@@ -480,6 +508,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
+       size_t written;
+       loff_t addr;
+       uint32_t data = 0;
++      /*
++       * Note, we cannot generally define VID header buffers on stack,
++       * because of the way we deal with these buffers (see the header
++       * comment in this file). But we know this is a NOR-specific piece of
++       * code, so we can do this. But yes, this is error-prone and we should
++       * (pre-)allocate VID header buffer instead.
++       */
+       struct ubi_vid_hdr vid_hdr;
+       /*
+@@ -507,11 +542,13 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
+        * PEB.
+        */
+       err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
+-      if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) {
++      if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
++          err1 == UBI_IO_FF) {
+               struct ubi_ec_hdr ec_hdr;
+               err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
+-              if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR)
++              if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
++                  err1 == UBI_IO_FF)
+                       /*
+                        * Both VID and EC headers are corrupted, so we can
+                        * safely erase this PEB and not afraid that it will be
+@@ -723,7 +760,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
+       read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
+       if (read_err) {
+-              if (read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
++              if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG)
+                       return read_err;
+               /*
+@@ -739,7 +776,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
+       magic = be32_to_cpu(ec_hdr->magic);
+       if (magic != UBI_EC_HDR_MAGIC) {
+-              if (mtd_is_eccerr(read_err))
++              if (read_err == -EBADMSG)
+                       return UBI_IO_BAD_HDR_EBADMSG;
+               /*
+@@ -752,9 +789,8 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
+                       if (verbose)
+                               ubi_warn("no EC header found at PEB %d, "
+                                        "only 0xFF bytes", pnum);
+-                      else if (UBI_IO_DEBUG)
+-                              dbg_msg("no EC header found at PEB %d, "
+-                                      "only 0xFF bytes", pnum);
++                      dbg_bld("no EC header found at PEB %d, "
++                              "only 0xFF bytes", pnum);
+                       if (!read_err)
+                               return UBI_IO_FF;
+                       else
+@@ -769,9 +805,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
+                       ubi_warn("bad magic number at PEB %d: %08x instead of "
+                                "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
+                       ubi_dbg_dump_ec_hdr(ec_hdr);
+-              } else if (UBI_IO_DEBUG)
+-                      dbg_msg("bad magic number at PEB %d: %08x instead of "
+-                              "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
++              }
++              dbg_bld("bad magic number at PEB %d: %08x instead of "
++                      "%08x", pnum, magic, UBI_EC_HDR_MAGIC);
+               return UBI_IO_BAD_HDR;
+       }
+@@ -783,9 +819,9 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
+                       ubi_warn("bad EC header CRC at PEB %d, calculated "
+                                "%#08x, read %#08x", pnum, crc, hdr_crc);
+                       ubi_dbg_dump_ec_hdr(ec_hdr);
+-              } else if (UBI_IO_DEBUG)
+-                      dbg_msg("bad EC header CRC at PEB %d, calculated "
+-                              "%#08x, read %#08x", pnum, crc, hdr_crc);
++              }
++              dbg_bld("bad EC header CRC at PEB %d, calculated "
++                      "%#08x, read %#08x", pnum, crc, hdr_crc);
+               if (!read_err)
+                       return UBI_IO_BAD_HDR;
+@@ -996,21 +1032,20 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
+       p = (char *)vid_hdr - ubi->vid_hdr_shift;
+       read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+                         ubi->vid_hdr_alsize);
+-      if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err))
++      if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG)
+               return read_err;
+       magic = be32_to_cpu(vid_hdr->magic);
+       if (magic != UBI_VID_HDR_MAGIC) {
+-              if (mtd_is_eccerr(read_err))
++              if (read_err == -EBADMSG)
+                       return UBI_IO_BAD_HDR_EBADMSG;
+               if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+                       if (verbose)
+                               ubi_warn("no VID header found at PEB %d, "
+                                        "only 0xFF bytes", pnum);
+-                      else if (UBI_IO_DEBUG)
+-                              dbg_msg("no VID header found at PEB %d, "
+-                                      "only 0xFF bytes", pnum);
++                      dbg_bld("no VID header found at PEB %d, "
++                              "only 0xFF bytes", pnum);
+                       if (!read_err)
+                               return UBI_IO_FF;
+                       else
+@@ -1021,9 +1056,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
+                       ubi_warn("bad magic number at PEB %d: %08x instead of "
+                                "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
+                       ubi_dbg_dump_vid_hdr(vid_hdr);
+-              } else if (UBI_IO_DEBUG)
+-                      dbg_msg("bad magic number at PEB %d: %08x instead of "
+-                              "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
++              }
++              dbg_bld("bad magic number at PEB %d: %08x instead of "
++                      "%08x", pnum, magic, UBI_VID_HDR_MAGIC);
+               return UBI_IO_BAD_HDR;
+       }
+@@ -1035,9 +1070,9 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
+                       ubi_warn("bad CRC at PEB %d, calculated %#08x, "
+                                "read %#08x", pnum, crc, hdr_crc);
+                       ubi_dbg_dump_vid_hdr(vid_hdr);
+-              } else if (UBI_IO_DEBUG)
+-                      dbg_msg("bad CRC at PEB %d, calculated %#08x, "
+-                              "read %#08x", pnum, crc, hdr_crc);
++              }
++              dbg_bld("bad CRC at PEB %d, calculated %#08x, "
++                      "read %#08x", pnum, crc, hdr_crc);
+               if (!read_err)
+                       return UBI_IO_BAD_HDR;
+               else
+@@ -1097,7 +1132,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
+       return err;
+ }
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ /**
+  * paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
+@@ -1111,6 +1146,9 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
+ {
+       int err;
++      if (!ubi->dbg->chk_io)
++              return 0;
++
+       err = ubi_io_is_bad(ubi, pnum);
+       if (!err)
+               return err;
+@@ -1135,6 +1173,9 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+       int err;
+       uint32_t magic;
++      if (!ubi->dbg->chk_io)
++              return 0;
++
+       magic = be32_to_cpu(ec_hdr->magic);
+       if (magic != UBI_EC_HDR_MAGIC) {
+               ubi_err("bad magic %#08x, must be %#08x",
+@@ -1170,12 +1211,15 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
+       uint32_t crc, hdr_crc;
+       struct ubi_ec_hdr *ec_hdr;
++      if (!ubi->dbg->chk_io)
++              return 0;
++
+       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
+       if (!ec_hdr)
+               return -ENOMEM;
+       err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE);
+-      if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
++      if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+               goto exit;
+       crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
+@@ -1211,6 +1255,9 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+       int err;
+       uint32_t magic;
++      if (!ubi->dbg->chk_io)
++              return 0;
++
+       magic = be32_to_cpu(vid_hdr->magic);
+       if (magic != UBI_VID_HDR_MAGIC) {
+               ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
+@@ -1249,6 +1296,9 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
+       struct ubi_vid_hdr *vid_hdr;
+       void *p;
++      if (!ubi->dbg->chk_io)
++              return 0;
++
+       vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
+       if (!vid_hdr)
+               return -ENOMEM;
+@@ -1256,7 +1306,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
+       p = (char *)vid_hdr - ubi->vid_hdr_shift;
+       err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset,
+                         ubi->vid_hdr_alsize);
+-      if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
++      if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+               goto exit;
+       crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+@@ -1294,15 +1344,26 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+                       int offset, int len)
+ {
+       int err, i;
++      size_t read;
++      void *buf1;
++      loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+-      mutex_lock(&ubi->dbg_buf_mutex);
+-      err = ubi_io_read(ubi, ubi->dbg_peb_buf, pnum, offset, len);
+-      if (err)
+-              goto out_unlock;
++      if (!ubi->dbg->chk_io)
++              return 0;
++
++      buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
++      if (!buf1) {
++              ubi_err("cannot allocate memory to check writes");
++              return 0;
++      }
++
++      err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1);
++      if (err && err != -EUCLEAN)
++              goto out_free;
+       for (i = 0; i < len; i++) {
+               uint8_t c = ((uint8_t *)buf)[i];
+-              uint8_t c1 = ((uint8_t *)ubi->dbg_peb_buf)[i];
++              uint8_t c1 = ((uint8_t *)buf1)[i];
+               int dump_len;
+               if (c == c1)
+@@ -1319,17 +1380,17 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+               ubi_msg("hex dump of the read buffer from %d to %d",
+                       i, i + dump_len);
+               print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+-                             ubi->dbg_peb_buf + i, dump_len, 1);
++                             buf1 + i, dump_len, 1);
+               ubi_dbg_dump_stack();
+               err = -EINVAL;
+-              goto out_unlock;
++              goto out_free;
+       }
+-      mutex_unlock(&ubi->dbg_buf_mutex);
++      vfree(buf1);
+       return 0;
+-out_unlock:
+-      mutex_unlock(&ubi->dbg_buf_mutex);
++out_free:
++      vfree(buf1);
+       return err;
+ }
+@@ -1348,36 +1409,44 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
+ {
+       size_t read;
+       int err;
++      void *buf;
+       loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+-      mutex_lock(&ubi->dbg_buf_mutex);
+-      err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
+-      if (err && !mtd_is_bitflip(err)) {
++      if (!ubi->dbg->chk_io)
++              return 0;
++
++      buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubi_err("cannot allocate memory to check for 0xFFs");
++              return 0;
++      }
++
++      err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
++      if (err && err != -EUCLEAN) {
+               ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+                       "read %zd bytes", err, len, pnum, offset, read);
+               goto error;
+       }
+-      err = ubi_check_pattern(ubi->dbg_peb_buf, 0xFF, len);
++      err = ubi_check_pattern(buf, 0xFF, len);
+       if (err == 0) {
+               ubi_err("flash region at PEB %d:%d, length %d does not "
+                       "contain all 0xFF bytes", pnum, offset, len);
+               goto fail;
+       }
+-      mutex_unlock(&ubi->dbg_buf_mutex);
++      vfree(buf);
+       return 0;
+ fail:
+       ubi_err("paranoid check failed for PEB %d", pnum);
+       ubi_msg("hex dump of the %d-%d region", offset, offset + len);
+-      print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+-                     ubi->dbg_peb_buf, len, 1);
++      print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
+       err = -EINVAL;
+ error:
+       ubi_dbg_dump_stack();
+-      mutex_unlock(&ubi->dbg_buf_mutex);
++      vfree(buf);
+       return err;
+ }
+-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
++#endif /* CONFIG_MTD_UBI_DEBUG */
+diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
+index 1c95758..d39716e 100644
+--- a/drivers/mtd/ubi/kapi.c
++++ b/drivers/mtd/ubi/kapi.c
+@@ -40,7 +40,9 @@ void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di)
+ {
+       di->ubi_num = ubi->ubi_num;
+       di->leb_size = ubi->leb_size;
++      di->leb_start = ubi->leb_start;
+       di->min_io_size = ubi->min_io_size;
++      di->max_write_size = ubi->max_write_size;
+       di->ro_mode = ubi->ro_mode;
+       di->cdev = ubi->cdev.dev;
+ }
+@@ -408,7 +410,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+               return 0;
+       err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check);
+-      if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
++      if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) {
+               ubi_warn("mark volume %d as corrupted", vol_id);
+               vol->corrupted = 1;
+       }
+diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
+index f6a7d7a..ff2a65c 100644
+--- a/drivers/mtd/ubi/misc.c
++++ b/drivers/mtd/ubi/misc.c
+@@ -81,7 +81,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
+               err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1);
+               if (err) {
+-                      if (mtd_is_eccerr(err))
++                      if (err == -EBADMSG)
+                               err = 1;
+                       break;
+               }
+diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
+index 438ec20..22f03d6 100644
+--- a/drivers/mtd/ubi/scan.c
++++ b/drivers/mtd/ubi/scan.c
+@@ -39,32 +39,46 @@
+  * eraseblocks are put to the @free list and the physical eraseblock to be
+  * erased are put to the @erase list.
+  *
++ * About corruptions
++ * ~~~~~~~~~~~~~~~~~
++ *
++ * UBI protects EC and VID headers with CRC-32 checksums, so it can detect
++ * whether the headers are corrupted or not. Sometimes UBI also protects the
++ * data with CRC-32, e.g., when it executes the atomic LEB change operation, or
++ * when it moves the contents of a PEB for wear-leveling purposes.
++ *
+  * UBI tries to distinguish between 2 types of corruptions.
+- * 1. Corruptions caused by power cuts. These are harmless and expected
+- *    corruptions and UBI tries to handle them gracefully, without printing too
+- *    many warnings and error messages. The idea is that we do not lose
+- *    important data in these case - we may lose only the data which was being
+- *    written to the media just before the power cut happened, and the upper
+- *    layers (e.g., UBIFS) are supposed to handle these situations. UBI puts
+- *    these PEBs to the head of the @erase list and they are scheduled for
+- *    erasure.
++ *
++ * 1. Corruptions caused by power cuts. These are expected corruptions and UBI
++ * tries to handle them gracefully, without printing too many warnings and
++ * error messages. The idea is that we do not lose important data in these case
++ * - we may lose only the data which was being written to the media just before
++ * the power cut happened, and the upper layers (e.g., UBIFS) are supposed to
++ * handle such data losses (e.g., by using the FS journal).
++ *
++ * When UBI detects a corruption (CRC-32 mismatch) in a PEB, and it looks like
++ * the reason is a power cut, UBI puts this PEB to the @erase list, and all
++ * PEBs in the @erase list are scheduled for erasure later.
+  *
+  * 2. Unexpected corruptions which are not caused by power cuts. During
+- *    scanning, such PEBs are put to the @corr list and UBI preserves them.
+- *    Obviously, this lessens the amount of available PEBs, and if at some
+- *    point UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly
+- *    informs about such PEBs every time the MTD device is attached.
++ * scanning, such PEBs are put to the @corr list and UBI preserves them.
++ * Obviously, this lessens the amount of available PEBs, and if at some  point
++ * UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
++ * about such PEBs every time the MTD device is attached.
+  *
+  * However, it is difficult to reliably distinguish between these types of
+- * corruptions and UBI's strategy is as follows. UBI assumes (2.) if the VID
+- * header is corrupted and the data area does not contain all 0xFFs, and there
+- * were not bit-flips or integrity errors while reading the data area. Otherwise
+- * UBI assumes (1.). The assumptions are:
+- *   o if the data area contains only 0xFFs, there is no data, and it is safe
+- *     to just erase this PEB.
+- *   o if the data area has bit-flips and data integrity errors (ECC errors on
++ * corruptions and UBI's strategy is as follows. UBI assumes corruption type 2
++ * if the VID header is corrupted and the data area does not contain all 0xFFs,
++ * and there were no bit-flips or integrity errors while reading the data area.
++ * Otherwise UBI assumes corruption type 1. So the decision criteria are as
++ * follows.
++ *   o If the data area contains only 0xFFs, there is no data, and it is safe
++ *     to just erase this PEB - this is corruption type 1.
++ *   o If the data area has bit-flips or data integrity errors (ECC errors on
+  *     NAND), it is probably a PEB which was being erased when power cut
+- *     happened.
++ *     happened, so this is corruption type 1. However, this is just a guess,
++ *     which might be wrong.
++ *   o Otherwise this it corruption type 2.
+  */
+ #include <linux/err.h>
+@@ -74,7 +88,7 @@
+ #include <linux/random.h>
+ #include "ubi.h"
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
+ #else
+ #define paranoid_check_si(ubi, si) 0
+@@ -115,7 +129,7 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head,
+       } else
+               BUG();
+-      seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
++      seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
+       if (!seb)
+               return -ENOMEM;
+@@ -144,7 +158,7 @@ static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
+       dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
+-      seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
++      seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
+       if (!seb)
+               return -ENOMEM;
+@@ -381,7 +395,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
+       }
+       err = ubi_io_read_data(ubi, buf, pnum, 0, len);
+-      if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
++      if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)
+               goto out_free_buf;
+       data_crc = be32_to_cpu(vid_hdr->data_crc);
+@@ -553,7 +567,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
+       if (err)
+               return err;
+-      seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
++      seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
+       if (!seb)
+               return -ENOMEM;
+@@ -775,11 +789,11 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
+       int err;
+       mutex_lock(&ubi->buf_mutex);
+-      memset(ubi->peb_buf1, 0x00, ubi->leb_size);
++      memset(ubi->peb_buf, 0x00, ubi->leb_size);
+-      err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start,
++      err = ubi_io_read(ubi, ubi->peb_buf, pnum, ubi->leb_start,
+                         ubi->leb_size);
+-      if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) {
++      if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
+               /*
+                * Bit-flips or integrity errors while reading the data area.
+                * It is difficult to say for sure what type of corruption is
+@@ -794,7 +808,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
+       if (err)
+               goto out_unlock;
+-      if (ubi_check_pattern(ubi->peb_buf1, 0xFF, ubi->leb_size))
++      if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
+               goto out_unlock;
+       ubi_err("PEB %d contains corrupted VID header, and the data does not "
+@@ -804,7 +818,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
+       dbg_msg("hexdump of PEB %d offset %d, length %d",
+               pnum, ubi->leb_start, ubi->leb_size);
+       ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+-                             ubi->peb_buf1, ubi->leb_size, 1);
++                             ubi->peb_buf, ubi->leb_size, 1);
+       err = 1;
+ out_unlock:
+@@ -1089,7 +1103,7 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
+                * otherwise, only print a warning.
+                */
+               if (si->corr_peb_count >= max_corr) {
+-                      ubi_err("too many corrupted PEBs, refusing this device");
++                      ubi_err("too many corrupted PEBs, refusing");
+                       return -EINVAL;
+               }
+       }
+@@ -1152,6 +1166,12 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
+       si->volumes = RB_ROOT;
+       err = -ENOMEM;
++      si->scan_leb_slab = kmem_cache_create("ubi_scan_leb_slab",
++                                            sizeof(struct ubi_scan_leb),
++                                            0, 0, NULL);
++      if (!si->scan_leb_slab)
++              goto out_si;
++
+       ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+       if (!ech)
+               goto out_si;
+@@ -1223,11 +1243,12 @@ out_si:
+ /**
+  * destroy_sv - free the scanning volume information
+  * @sv: scanning volume information
++ * @si: scanning information
+  *
+  * This function destroys the volume RB-tree (@sv->root) and the scanning
+  * volume information.
+  */
+-static void destroy_sv(struct ubi_scan_volume *sv)
++static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
+ {
+       struct ubi_scan_leb *seb;
+       struct rb_node *this = sv->root.rb_node;
+@@ -1247,7 +1268,7 @@ static void destroy_sv(struct ubi_scan_volume *sv)
+                                       this->rb_right = NULL;
+                       }
+-                      kfree(seb);
++                      kmem_cache_free(si->scan_leb_slab, seb);
+               }
+       }
+       kfree(sv);
+@@ -1265,19 +1286,19 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
+       list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
+               list_del(&seb->u.list);
+-              kfree(seb);
++              kmem_cache_free(si->scan_leb_slab, seb);
+       }
+       list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
+               list_del(&seb->u.list);
+-              kfree(seb);
++              kmem_cache_free(si->scan_leb_slab, seb);
+       }
+       list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
+               list_del(&seb->u.list);
+-              kfree(seb);
++              kmem_cache_free(si->scan_leb_slab, seb);
+       }
+       list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
+               list_del(&seb->u.list);
+-              kfree(seb);
++              kmem_cache_free(si->scan_leb_slab, seb);
+       }
+       /* Destroy the volume RB-tree */
+@@ -1298,14 +1319,17 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
+                                       rb->rb_right = NULL;
+                       }
+-                      destroy_sv(sv);
++                      destroy_sv(si, sv);
+               }
+       }
++      if (si->scan_leb_slab)
++              kmem_cache_destroy(si->scan_leb_slab);
++
+       kfree(si);
+ }
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ /**
+  * paranoid_check_si - check the scanning information.
+@@ -1323,6 +1347,9 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
+       struct ubi_scan_leb *seb, *last_seb;
+       uint8_t *buf;
++      if (!ubi->dbg->chk_gen)
++              return 0;
++
+       /*
+        * At first, check that scanning information is OK.
+        */
+@@ -1575,4 +1602,4 @@ out:
+       return -EINVAL;
+ }
+-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
++#endif /* CONFIG_MTD_UBI_DEBUG */
+diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
+index a3264f0..d48aef1 100644
+--- a/drivers/mtd/ubi/scan.h
++++ b/drivers/mtd/ubi/scan.h
+@@ -109,6 +109,7 @@ struct ubi_scan_volume {
+  * @mean_ec: mean erase counter value
+  * @ec_sum: a temporary variable used when calculating @mean_ec
+  * @ec_count: a temporary variable used when calculating @mean_ec
++ * @scan_leb_slab: slab cache for &struct ubi_scan_leb objects
+  *
+  * This data structure contains the result of scanning and may be used by other
+  * UBI sub-systems to build final UBI data structures, further error-recovery
+@@ -134,6 +135,7 @@ struct ubi_scan_info {
+       int mean_ec;
+       uint64_t ec_sum;
+       int ec_count;
++      struct kmem_cache *scan_leb_slab;
+ };
+ struct ubi_device;
+diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
+index 503ea9b..6fb8ec2 100644
+--- a/drivers/mtd/ubi/ubi-media.h
++++ b/drivers/mtd/ubi/ubi-media.h
+@@ -164,7 +164,7 @@ struct ubi_ec_hdr {
+       __be32  image_seq;
+       __u8    padding2[32];
+       __be32  hdr_crc;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubi_vid_hdr - on-flash UBI volume identifier header.
+@@ -292,7 +292,7 @@ struct ubi_vid_hdr {
+       __be64  sqnum;
+       __u8    padding3[12];
+       __be32  hdr_crc;
+-} __attribute__ ((packed));
++} __packed;
+ /* Internal UBI volumes count */
+ #define UBI_INT_VOL_COUNT 1
+@@ -373,6 +373,6 @@ struct ubi_vtbl_record {
+       __u8    flags;
+       __u8    padding[23];
+       __be32  crc;
+-} __attribute__ ((packed));
++} __packed;
+ #endif /* !__UBI_MEDIA_H__ */
+diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
+index 0b0149c..b162790 100644
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -40,10 +40,10 @@
+ #include <linux/notifier.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/ubi.h>
++#include <asm/pgtable.h>
+ #include "ubi-media.h"
+ #include "scan.h"
+-#include "debug.h"
+ /* Maximum number of supported UBI devices */
+ #define UBI_MAX_DEVICES 32
+@@ -118,15 +118,17 @@ enum {
+  *                     PEB
+  * MOVE_TARGET_WR_ERR: canceled because there was a write error to the target
+  *                     PEB
+- * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the
++ * MOVE_TARGET_BITFLIPS: canceled because a bit-flip was detected in the
+  *                       target PEB
++ * MOVE_RETRY: retry scrubbing the PEB
+  */
+ enum {
+       MOVE_CANCEL_RACE = 1,
+       MOVE_SOURCE_RD_ERR,
+       MOVE_TARGET_RD_ERR,
+       MOVE_TARGET_WR_ERR,
+-      MOVE_CANCEL_BITFLIPS,
++      MOVE_TARGET_BITFLIPS,
++      MOVE_RETRY,
+ };
+ /**
+@@ -340,8 +342,8 @@ struct ubi_wl_entry;
+  *      protected from the wear-leveling worker)
+  * @pq_head: protection queue head
+  * @wl_lock: protects the @used, @free, @pq, @pq_head, @lookuptbl, @move_from,
+- *         @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
+- *         @erroneous, and @erroneous_peb_count fields
++ *         @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
++ *         @erroneous, and @erroneous_peb_count fields
+  * @move_mutex: serializes eraseblock moves
+  * @work_sem: synchronizes the WL worker with use tasks
+  * @wl_scheduled: non-zero if the wear-leveling was scheduled
+@@ -381,14 +383,15 @@ struct ubi_wl_entry;
+  * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
+  *               not
+  * @nor_flash: non-zero if working on top of NOR flash
++ * @max_write_size: maximum amount of bytes the underlying flash can write at a
++ *                  time (MTD write buffer size)
+  * @mtd: MTD device descriptor
+  *
+- * @peb_buf1: a buffer of PEB size used for different purposes
+- * @peb_buf2: another buffer of PEB size used for different purposes
+- * @buf_mutex: protects @peb_buf1 and @peb_buf2
++ * @peb_buf: a buffer of PEB size used for different purposes
++ * @buf_mutex: protects @peb_buf
+  * @ckvol_mutex: serializes static volume checking when opening
+- * @dbg_peb_buf: buffer of PEB size used for debugging
+- * @dbg_buf_mutex: protects @dbg_peb_buf
++ *
++ * @dbg: debugging information for this UBI device
+  */
+ struct ubi_device {
+       struct cdev cdev;
+@@ -464,18 +467,18 @@ struct ubi_device {
+       int vid_hdr_shift;
+       unsigned int bad_allowed:1;
+       unsigned int nor_flash:1;
++      int max_write_size;
+       struct mtd_info *mtd;
+-      void *peb_buf1;
+-      void *peb_buf2;
++      void *peb_buf;
+       struct mutex buf_mutex;
+       struct mutex ckvol_mutex;
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
+-      void *dbg_peb_buf;
+-      struct mutex dbg_buf_mutex;
+-#endif
++
++      struct ubi_debug_info *dbg;
+ };
++#include "debug.h"
++
+ extern struct kmem_cache *ubi_wl_entry_slab;
+ extern const struct file_operations ubi_ctrl_cdev_operations;
+ extern const struct file_operations ubi_cdev_operations;
+@@ -664,6 +667,7 @@ static inline void ubi_ro_mode(struct ubi_device *ubi)
+       if (!ubi->ro_mode) {
+               ubi->ro_mode = 1;
+               ubi_warn("switch to read-only mode");
++              ubi_dbg_dump_stack();
+       }
+ }
+diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
+index c47620d..97e093d 100644
+--- a/drivers/mtd/ubi/vmt.c
++++ b/drivers/mtd/ubi/vmt.c
+@@ -28,7 +28,7 @@
+ #include <linux/slab.h>
+ #include "ubi.h"
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ static int paranoid_check_volumes(struct ubi_device *ubi);
+ #else
+ #define paranoid_check_volumes(ubi) 0
+@@ -711,7 +711,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
+       volume_sysfs_close(vol);
+ }
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ /**
+  * paranoid_check_volume - check volume information.
+@@ -790,11 +790,6 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
+               goto fail;
+       }
+-      if (!vol->name) {
+-              ubi_err("NULL volume name");
+-              goto fail;
+-      }
+-
+       n = strnlen(vol->name, vol->name_len + 1);
+       if (n != vol->name_len) {
+               ubi_err("bad name_len %lld", n);
+@@ -876,6 +871,9 @@ static int paranoid_check_volumes(struct ubi_device *ubi)
+ {
+       int i, err = 0;
++      if (!ubi->dbg->chk_gen)
++              return 0;
++
+       for (i = 0; i < ubi->vtbl_slots; i++) {
+               err = paranoid_check_volume(ubi, i);
+               if (err)
+diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
+index 157d88b..a547990 100644
+--- a/drivers/mtd/ubi/vtbl.c
++++ b/drivers/mtd/ubi/vtbl.c
+@@ -62,7 +62,7 @@
+ #include <asm/div64.h>
+ #include "ubi.h"
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ static void paranoid_vtbl_check(const struct ubi_device *ubi);
+ #else
+ #define paranoid_vtbl_check(ubi)
+@@ -306,9 +306,8 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
+                      int copy, void *vtbl)
+ {
+       int err, tries = 0;
+-      static struct ubi_vid_hdr *vid_hdr;
+-      struct ubi_scan_volume *sv;
+-      struct ubi_scan_leb *new_seb, *old_seb = NULL;
++      struct ubi_vid_hdr *vid_hdr;
++      struct ubi_scan_leb *new_seb;
+       ubi_msg("create volume table (copy #%d)", copy + 1);
+@@ -316,15 +315,6 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
+       if (!vid_hdr)
+               return -ENOMEM;
+-      /*
+-       * Check if there is a logical eraseblock which would have to contain
+-       * this volume table copy was found during scanning. It has to be wiped
+-       * out.
+-       */
+-      sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
+-      if (sv)
+-              old_seb = ubi_scan_find_seb(sv, copy);
+-
+ retry:
+       new_seb = ubi_scan_get_free_peb(ubi, si);
+       if (IS_ERR(new_seb)) {
+@@ -332,7 +322,7 @@ retry:
+               goto out_free;
+       }
+-      vid_hdr->vol_type = UBI_VID_DYNAMIC;
++      vid_hdr->vol_type = UBI_LAYOUT_VOLUME_TYPE;
+       vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID);
+       vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
+       vid_hdr->data_size = vid_hdr->used_ebs =
+@@ -351,8 +341,8 @@ retry:
+               goto write_error;
+       /*
+-       * And add it to the scanning information. Don't delete the old
+-       * @old_seb as it will be deleted and freed in 'ubi_scan_add_used()'.
++       * And add it to the scanning information. Don't delete the old version
++       * of this LEB as it will be deleted and freed in 'ubi_scan_add_used()'.
+        */
+       err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
+                               vid_hdr, 0);
+@@ -434,7 +424,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
+               err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
+                                      ubi->vtbl_size);
+-              if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))
++              if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+                       /*
+                        * Scrub the PEB later. Note, -EBADMSG indicates an
+                        * uncorrectable ECC error, but we have our own CRC and
+@@ -644,7 +634,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
+               return -ENOMEM;
+       vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS;
+-      vol->alignment = 1;
++      vol->alignment = UBI_LAYOUT_VOLUME_ALIGN;
+       vol->vol_type = UBI_DYNAMIC_VOLUME;
+       vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1;
+       memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1);
+@@ -870,7 +860,7 @@ out_free:
+       return err;
+ }
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ /**
+  * paranoid_vtbl_check - check volume table.
+@@ -878,10 +868,13 @@ out_free:
+  */
+ static void paranoid_vtbl_check(const struct ubi_device *ubi)
+ {
++      if (!ubi->dbg->chk_gen)
++              return;
++
+       if (vtbl_check(ubi, ubi->vtbl)) {
+               ubi_err("paranoid check failed");
+               BUG();
+       }
+ }
+-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
++#endif /* CONFIG_MTD_UBI_DEBUG */
+diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
+index 655bbbe..7c1a9bf 100644
+--- a/drivers/mtd/ubi/wl.c
++++ b/drivers/mtd/ubi/wl.c
+@@ -1,4 +1,5 @@
+ /*
++ * @ubi: UBI device description object
+  * Copyright (c) International Business Machines Corp., 2006
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -161,14 +162,16 @@ struct ubi_work {
+       int torture;
+ };
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
+-static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
++static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
++                                   struct ubi_wl_entry *e,
+                                    struct rb_root *root);
+-static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e);
++static int paranoid_check_in_pq(const struct ubi_device *ubi,
++                              struct ubi_wl_entry *e);
+ #else
+ #define paranoid_check_ec(ubi, pnum, ec) 0
+-#define paranoid_check_in_wl_tree(e, root)
++#define paranoid_check_in_wl_tree(ubi, e, root)
+ #define paranoid_check_in_pq(ubi, e) 0
+ #endif
+@@ -347,18 +350,19 @@ static void prot_queue_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
+ /**
+  * find_wl_entry - find wear-leveling entry closest to certain erase counter.
+  * @root: the RB-tree where to look for
+- * @max: highest possible erase counter
++ * @diff: maximum possible difference from the smallest erase counter
+  *
+  * This function looks for a wear leveling entry with erase counter closest to
+- * @max and less than @max.
++ * min + @diff, where min is the smallest erase counter.
+  */
+-static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
++static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int diff)
+ {
+       struct rb_node *p;
+       struct ubi_wl_entry *e;
++      int max;
+       e = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb);
+-      max += e->ec;
++      max = e->ec + diff;
+       p = root->rb_node;
+       while (p) {
+@@ -386,7 +390,7 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max)
+  */
+ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
+ {
+-      int err, medium_ec;
++      int err;
+       struct ubi_wl_entry *e, *first, *last;
+       ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
+@@ -424,7 +428,7 @@ retry:
+                * For unknown data we pick a physical eraseblock with medium
+                * erase counter. But we by no means can pick a physical
+                * eraseblock with erase counter greater or equivalent than the
+-               * lowest erase counter plus %WL_FREE_MAX_DIFF.
++               * lowest erase counter plus %WL_FREE_MAX_DIFF/2.
+                */
+               first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
+                                       u.rb);
+@@ -433,10 +437,8 @@ retry:
+               if (last->ec - first->ec < WL_FREE_MAX_DIFF)
+                       e = rb_entry(ubi->free.rb_node,
+                                       struct ubi_wl_entry, u.rb);
+-              else {
+-                      medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
+-                      e = find_wl_entry(&ubi->free, medium_ec);
+-              }
++              else
++                      e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
+               break;
+       case UBI_SHORTTERM:
+               /*
+@@ -449,7 +451,7 @@ retry:
+               BUG();
+       }
+-      paranoid_check_in_wl_tree(e, &ubi->free);
++      paranoid_check_in_wl_tree(ubi, e, &ubi->free);
+       /*
+        * Move the physical eraseblock to the protection queue where it will
+@@ -613,7 +615,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
+       list_add_tail(&wrk->list, &ubi->works);
+       ubi_assert(ubi->works_count >= 0);
+       ubi->works_count += 1;
+-      if (ubi->thread_enabled)
++      if (ubi->thread_enabled && !ubi_dbg_is_bgt_disabled(ubi))
+               wake_up_process(ubi->bgt_thread);
+       spin_unlock(&ubi->wl_lock);
+ }
+@@ -712,7 +714,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
+                              e1->ec, e2->ec);
+                       goto out_cancel;
+               }
+-              paranoid_check_in_wl_tree(e1, &ubi->used);
++              paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
+               rb_erase(&e1->u.rb, &ubi->used);
+               dbg_wl("move PEB %d EC %d to PEB %d EC %d",
+                      e1->pnum, e1->ec, e2->pnum, e2->ec);
+@@ -721,12 +723,12 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
+               scrubbing = 1;
+               e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, u.rb);
+               e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
+-              paranoid_check_in_wl_tree(e1, &ubi->scrub);
++              paranoid_check_in_wl_tree(ubi, e1, &ubi->scrub);
+               rb_erase(&e1->u.rb, &ubi->scrub);
+               dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
+       }
+-      paranoid_check_in_wl_tree(e2, &ubi->free);
++      paranoid_check_in_wl_tree(ubi, e2, &ubi->free);
+       rb_erase(&e2->u.rb, &ubi->free);
+       ubi->move_from = e1;
+       ubi->move_to = e2;
+@@ -792,8 +794,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
+                       protect = 1;
+                       goto out_not_moved;
+               }
+-
+-              if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
++              if (err == MOVE_RETRY) {
++                      scrubbing = 1;
++                      goto out_not_moved;
++              }
++              if (err == MOVE_TARGET_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
+                   err == MOVE_TARGET_RD_ERR) {
+                       /*
+                        * Target PEB had bit-flips or write error - torture it.
+@@ -1046,7 +1051,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+       ubi_err("failed to erase PEB %d, error %d", pnum, err);
+       kfree(wl_wrk);
+-      kmem_cache_free(ubi_wl_entry_slab, e);
+       if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+           err == -EBUSY) {
+@@ -1059,14 +1063,16 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+                       goto out_ro;
+               }
+               return err;
+-      } else if (err != -EIO) {
++      }
++
++      kmem_cache_free(ubi_wl_entry_slab, e);
++      if (err != -EIO)
+               /*
+                * If this is not %-EIO, we have no idea what to do. Scheduling
+                * this physical eraseblock for erasure again would cause
+                * errors again and again. Well, lets switch to R/O mode.
+                */
+               goto out_ro;
+-      }
+       /* It is %-EIO, the PEB went bad */
+@@ -1169,13 +1175,13 @@ retry:
+               return 0;
+       } else {
+               if (in_wl_tree(e, &ubi->used)) {
+-                      paranoid_check_in_wl_tree(e, &ubi->used);
++                      paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+                       rb_erase(&e->u.rb, &ubi->used);
+               } else if (in_wl_tree(e, &ubi->scrub)) {
+-                      paranoid_check_in_wl_tree(e, &ubi->scrub);
++                      paranoid_check_in_wl_tree(ubi, e, &ubi->scrub);
+                       rb_erase(&e->u.rb, &ubi->scrub);
+               } else if (in_wl_tree(e, &ubi->erroneous)) {
+-                      paranoid_check_in_wl_tree(e, &ubi->erroneous);
++                      paranoid_check_in_wl_tree(ubi, e, &ubi->erroneous);
+                       rb_erase(&e->u.rb, &ubi->erroneous);
+                       ubi->erroneous_peb_count -= 1;
+                       ubi_assert(ubi->erroneous_peb_count >= 0);
+@@ -1242,7 +1248,7 @@ retry:
+       }
+       if (in_wl_tree(e, &ubi->used)) {
+-              paranoid_check_in_wl_tree(e, &ubi->used);
++              paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+               rb_erase(&e->u.rb, &ubi->used);
+       } else {
+               int err;
+@@ -1364,7 +1370,7 @@ int ubi_thread(void *u)
+               spin_lock(&ubi->wl_lock);
+               if (list_empty(&ubi->works) || ubi->ro_mode ||
+-                             !ubi->thread_enabled) {
++                  !ubi->thread_enabled || ubi_dbg_is_bgt_disabled(ubi)) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       spin_unlock(&ubi->wl_lock);
+                       schedule();
+@@ -1561,7 +1567,7 @@ void ubi_wl_close(struct ubi_device *ubi)
+       kfree(ubi->lookuptbl);
+ }
+-#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
++#ifdef CONFIG_MTD_UBI_DEBUG
+ /**
+  * paranoid_check_ec - make sure that the erase counter of a PEB is correct.
+@@ -1570,7 +1576,8 @@ void ubi_wl_close(struct ubi_device *ubi)
+  * @ec: the erase counter to check
+  *
+  * This function returns zero if the erase counter of physical eraseblock @pnum
+- * is equivalent to @ec, and a negative error code if not or if an error occurred.
++ * is equivalent to @ec, and a negative error code if not or if an error
++ * occurred.
+  */
+ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
+ {
+@@ -1578,6 +1585,9 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
+       long long read_ec;
+       struct ubi_ec_hdr *ec_hdr;
++      if (!ubi->dbg->chk_gen)
++              return 0;
++
+       ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
+       if (!ec_hdr)
+               return -ENOMEM;
+@@ -1605,15 +1615,20 @@ out_free:
+ /**
+  * paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
++ * @ubi: UBI device description object
+  * @e: the wear-leveling entry to check
+  * @root: the root of the tree
+  *
+  * This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
+  * is not.
+  */
+-static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
++static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
++                                   struct ubi_wl_entry *e,
+                                    struct rb_root *root)
+ {
++      if (!ubi->dbg->chk_gen)
++              return 0;
++
+       if (in_wl_tree(e, root))
+               return 0;
+@@ -1631,11 +1646,15 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
+  *
+  * This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
+  */
+-static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
++static int paranoid_check_in_pq(const struct ubi_device *ubi,
++                              struct ubi_wl_entry *e)
+ {
+       struct ubi_wl_entry *p;
+       int i;
++      if (!ubi->dbg->chk_gen)
++              return 0;
++
+       for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i)
+               list_for_each_entry(p, &ubi->pq[i], u.list)
+                       if (p == e)
+@@ -1646,4 +1665,5 @@ static int paranoid_check_in_pq(struct ubi_device *ubi, struct ubi_wl_entry *e)
+       ubi_dbg_dump_stack();
+       return -EINVAL;
+ }
+-#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */
++
++#endif /* CONFIG_MTD_UBI_DEBUG */
+diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
+index 830e3f7..f8b0160 100644
+--- a/fs/ubifs/Kconfig
++++ b/fs/ubifs/Kconfig
+@@ -44,29 +44,17 @@ config UBIFS_FS_ZLIB
+ # Debugging-related stuff
+ config UBIFS_FS_DEBUG
+-      bool "Enable debugging"
++      bool "Enable debugging support"
+       depends on UBIFS_FS
+       select DEBUG_FS
+-      select KALLSYMS_ALL
+-      help
+-        This option enables UBIFS debugging.
+-
+-config UBIFS_FS_DEBUG_MSG_LVL
+-      int "Default message level (0 = no extra messages, 3 = lots)"
+-      depends on UBIFS_FS_DEBUG
+-      default "0"
+-      help
+-        This controls the amount of debugging messages produced by UBIFS.
+-        If reporting bugs, please try to have available a full dump of the
+-        messages at level 1 while the misbehaviour was occurring. Level 2
+-        may become necessary if level 1 messages were not enough to find the
+-        bug. Generally Level 3 should be avoided.
+-
+-config UBIFS_FS_DEBUG_CHKS
+-      bool "Enable extra checks"
+-      depends on UBIFS_FS_DEBUG
+-      help
+-        If extra checks are enabled UBIFS will check the consistency of its
+-        internal data structures during operation. However, UBIFS performance
+-        is dramatically slower when this option is selected especially if the
+-        file system is large.
++      select KALLSYMS
++      help
++        This option enables UBIFS debugging support. It makes sure various
++        assertions, self-checks, debugging messages and test modes are compiled
++        in (this all is compiled out otherwise). Assertions are light-weight
++        and this option also enables them. Self-checks, debugging messages and
++        test modes are switched off by default. Thus, it is safe and actually
++        recommended to have debugging support enabled, and it should not slow
++        down UBIFS. You can then further enable / disable individual  debugging
++        features using UBIFS module parameters and the corresponding sysfs
++        interfaces.
+diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
+index c8ff0d1..02c73e7 100644
+--- a/fs/ubifs/budget.c
++++ b/fs/ubifs/budget.c
+@@ -106,7 +106,7 @@ static long long get_liability(struct ubifs_info *c)
+       long long liab;
+       spin_lock(&c->space_lock);
+-      liab = c->budg_idx_growth + c->budg_data_growth + c->budg_dd_growth;
++      liab = c->bi.idx_growth + c->bi.data_growth + c->bi.dd_growth;
+       spin_unlock(&c->space_lock);
+       return liab;
+ }
+@@ -180,7 +180,7 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
+       int idx_lebs;
+       long long idx_size;
+-      idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
++      idx_size = c->bi.old_idx_sz + c->bi.idx_growth + c->bi.uncommitted_idx;
+       /* And make sure we have thrice the index size of space reserved */
+       idx_size += idx_size << 1;
+       /*
+@@ -292,13 +292,13 @@ static int can_use_rp(struct ubifs_info *c)
+  * budgeted index space to the size of the current index, multiplies this by 3,
+  * and makes sure this does not exceed the amount of free LEBs.
+  *
+- * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables:
++ * Notes about @c->bi.min_idx_lebs and @c->lst.idx_lebs variables:
+  * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might
+  *    be large, because UBIFS does not do any index consolidation as long as
+  *    there is free space. IOW, the index may take a lot of LEBs, but the LEBs
+  *    will contain a lot of dirt.
+- * o @c->min_idx_lebs is the number of LEBS the index presumably takes. IOW,
+- *    the index may be consolidated to take up to @c->min_idx_lebs LEBs.
++ * o @c->bi.min_idx_lebs is the number of LEBS the index presumably takes. IOW,
++ *    the index may be consolidated to take up to @c->bi.min_idx_lebs LEBs.
+  *
+  * This function returns zero in case of success, and %-ENOSPC in case of
+  * failure.
+@@ -343,13 +343,13 @@ static int do_budget_space(struct ubifs_info *c)
+              c->lst.taken_empty_lebs;
+       if (unlikely(rsvd_idx_lebs > lebs)) {
+               dbg_budg("out of indexing space: min_idx_lebs %d (old %d), "
+-                       "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs,
++                       "rsvd_idx_lebs %d", min_idx_lebs, c->bi.min_idx_lebs,
+                        rsvd_idx_lebs);
+               return -ENOSPC;
+       }
+       available = ubifs_calc_available(c, min_idx_lebs);
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
+       if (unlikely(available < outstanding)) {
+               dbg_budg("out of data space: available %lld, outstanding %lld",
+@@ -360,7 +360,7 @@ static int do_budget_space(struct ubifs_info *c)
+       if (available - outstanding <= c->rp_size && !can_use_rp(c))
+               return -ENOSPC;
+-      c->min_idx_lebs = min_idx_lebs;
++      c->bi.min_idx_lebs = min_idx_lebs;
+       return 0;
+ }
+@@ -393,11 +393,11 @@ static int calc_data_growth(const struct ubifs_info *c,
+ {
+       int data_growth;
+-      data_growth = req->new_ino  ? c->inode_budget : 0;
++      data_growth = req->new_ino  ? c->bi.inode_budget : 0;
+       if (req->new_page)
+-              data_growth += c->page_budget;
++              data_growth += c->bi.page_budget;
+       if (req->new_dent)
+-              data_growth += c->dent_budget;
++              data_growth += c->bi.dent_budget;
+       data_growth += req->new_ino_d;
+       return data_growth;
+ }
+@@ -413,12 +413,12 @@ static int calc_dd_growth(const struct ubifs_info *c,
+ {
+       int dd_growth;
+-      dd_growth = req->dirtied_page ? c->page_budget : 0;
++      dd_growth = req->dirtied_page ? c->bi.page_budget : 0;
+       if (req->dirtied_ino)
+-              dd_growth += c->inode_budget << (req->dirtied_ino - 1);
++              dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1);
+       if (req->mod_dent)
+-              dd_growth += c->dent_budget;
++              dd_growth += c->bi.dent_budget;
+       dd_growth += req->dirtied_ino_d;
+       return dd_growth;
+ }
+@@ -460,19 +460,19 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
+ again:
+       spin_lock(&c->space_lock);
+-      ubifs_assert(c->budg_idx_growth >= 0);
+-      ubifs_assert(c->budg_data_growth >= 0);
+-      ubifs_assert(c->budg_dd_growth >= 0);
++      ubifs_assert(c->bi.idx_growth >= 0);
++      ubifs_assert(c->bi.data_growth >= 0);
++      ubifs_assert(c->bi.dd_growth >= 0);
+-      if (unlikely(c->nospace) && (c->nospace_rp || !can_use_rp(c))) {
++      if (unlikely(c->bi.nospace) && (c->bi.nospace_rp || !can_use_rp(c))) {
+               dbg_budg("no space");
+               spin_unlock(&c->space_lock);
+               return -ENOSPC;
+       }
+-      c->budg_idx_growth += idx_growth;
+-      c->budg_data_growth += data_growth;
+-      c->budg_dd_growth += dd_growth;
++      c->bi.idx_growth += idx_growth;
++      c->bi.data_growth += data_growth;
++      c->bi.dd_growth += dd_growth;
+       err = do_budget_space(c);
+       if (likely(!err)) {
+@@ -484,9 +484,9 @@ again:
+       }
+       /* Restore the old values */
+-      c->budg_idx_growth -= idx_growth;
+-      c->budg_data_growth -= data_growth;
+-      c->budg_dd_growth -= dd_growth;
++      c->bi.idx_growth -= idx_growth;
++      c->bi.data_growth -= data_growth;
++      c->bi.dd_growth -= dd_growth;
+       spin_unlock(&c->space_lock);
+       if (req->fast) {
+@@ -506,9 +506,9 @@ again:
+                       goto again;
+               }
+               dbg_budg("FS is full, -ENOSPC");
+-              c->nospace = 1;
++              c->bi.nospace = 1;
+               if (can_use_rp(c) || c->rp_size == 0)
+-                      c->nospace_rp = 1;
++                      c->bi.nospace_rp = 1;
+               smp_wmb();
+       } else
+               ubifs_err("cannot budget space, error %d", err);
+@@ -523,8 +523,8 @@ again:
+  * This function releases the space budgeted by 'ubifs_budget_space()'. Note,
+  * since the index changes (which were budgeted for in @req->idx_growth) will
+  * only be written to the media on commit, this function moves the index budget
+- * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be
+- * zeroed by the commit operation.
++ * from @c->bi.idx_growth to @c->bi.uncommitted_idx. The latter will be zeroed
++ * by the commit operation.
+  */
+ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
+ {
+@@ -553,23 +553,23 @@ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
+       if (!req->data_growth && !req->dd_growth)
+               return;
+-      c->nospace = c->nospace_rp = 0;
++      c->bi.nospace = c->bi.nospace_rp = 0;
+       smp_wmb();
+       spin_lock(&c->space_lock);
+-      c->budg_idx_growth -= req->idx_growth;
+-      c->budg_uncommitted_idx += req->idx_growth;
+-      c->budg_data_growth -= req->data_growth;
+-      c->budg_dd_growth -= req->dd_growth;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+-
+-      ubifs_assert(c->budg_idx_growth >= 0);
+-      ubifs_assert(c->budg_data_growth >= 0);
+-      ubifs_assert(c->budg_dd_growth >= 0);
+-      ubifs_assert(c->min_idx_lebs < c->main_lebs);
+-      ubifs_assert(!(c->budg_idx_growth & 7));
+-      ubifs_assert(!(c->budg_data_growth & 7));
+-      ubifs_assert(!(c->budg_dd_growth & 7));
++      c->bi.idx_growth -= req->idx_growth;
++      c->bi.uncommitted_idx += req->idx_growth;
++      c->bi.data_growth -= req->data_growth;
++      c->bi.dd_growth -= req->dd_growth;
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++
++      ubifs_assert(c->bi.idx_growth >= 0);
++      ubifs_assert(c->bi.data_growth >= 0);
++      ubifs_assert(c->bi.dd_growth >= 0);
++      ubifs_assert(c->bi.min_idx_lebs < c->main_lebs);
++      ubifs_assert(!(c->bi.idx_growth & 7));
++      ubifs_assert(!(c->bi.data_growth & 7));
++      ubifs_assert(!(c->bi.dd_growth & 7));
+       spin_unlock(&c->space_lock);
+ }
+@@ -586,13 +586,13 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
+ {
+       spin_lock(&c->space_lock);
+       /* Release the index growth reservation */
+-      c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
++      c->bi.idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       /* Release the data growth reservation */
+-      c->budg_data_growth -= c->page_budget;
++      c->bi.data_growth -= c->bi.page_budget;
+       /* Increase the dirty data growth reservation instead */
+-      c->budg_dd_growth += c->page_budget;
++      c->bi.dd_growth += c->bi.page_budget;
+       /* And re-calculate the indexing space reservation */
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       spin_unlock(&c->space_lock);
+ }
+@@ -612,7 +612,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
+       memset(&req, 0, sizeof(struct ubifs_budget_req));
+       /* The "no space" flags will be cleared because dd_growth is > 0 */
+-      req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
++      req.dd_growth = c->bi.inode_budget + ALIGN(ui->data_len, 8);
+       ubifs_release_budget(c, &req);
+ }
+@@ -682,9 +682,9 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
+       int rsvd_idx_lebs, lebs;
+       long long available, outstanding, free;
+-      ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
+-      available = ubifs_calc_available(c, c->min_idx_lebs);
++      ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
++      available = ubifs_calc_available(c, c->bi.min_idx_lebs);
+       /*
+        * When reporting free space to user-space, UBIFS guarantees that it is
+@@ -697,8 +697,8 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
+        * Note, the calculations below are similar to what we have in
+        * 'do_budget_space()', so refer there for comments.
+        */
+-      if (c->min_idx_lebs > c->lst.idx_lebs)
+-              rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs;
++      if (c->bi.min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
+       else
+               rsvd_idx_lebs = 0;
+       lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
+index 02429d8..fb3b5c8 100644
+--- a/fs/ubifs/commit.c
++++ b/fs/ubifs/commit.c
+@@ -48,6 +48,56 @@
+ #include <linux/slab.h>
+ #include "ubifs.h"
++/*
++ * nothing_to_commit - check if there is nothing to commit.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function which checks if there is anything to commit. It is
++ * used as an optimization to avoid starting the commit if it is not really
++ * necessary. Indeed, the commit operation always assumes flash I/O (e.g.,
++ * writing the commit start node to the log), and it is better to avoid doing
++ * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is
++ * nothing to commit, it is more optimal to avoid any flash I/O.
++ *
++ * This function has to be called with @c->commit_sem locked for writing -
++ * this function does not take LPT/TNC locks because the @c->commit_sem
++ * guarantees that we have exclusive access to the TNC and LPT data structures.
++ *
++ * This function returns %1 if there is nothing to commit and %0 otherwise.
++ */
++static int nothing_to_commit(struct ubifs_info *c)
++{
++      /*
++       * During mounting or remounting from R/O mode to R/W mode we may
++       * commit for various recovery-related reasons.
++       */
++      if (c->mounting || c->remounting_rw)
++              return 0;
++
++      /*
++       * If the root TNC node is dirty, we definitely have something to
++       * commit.
++       */
++      if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
++              return 0;
++
++      /*
++       * Even though the TNC is clean, the LPT tree may have dirty nodes. For
++       * example, this may happen if the budgeting subsystem invoked GC to
++       * make some free space, and the GC found an LEB with only dirty and
++       * free space. In this case GC would just change the lprops of this
++       * LEB (by turning all space into free space) and unmap it.
++       */
++      if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags))
++              return 0;
++
++      ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0);
++      ubifs_assert(c->dirty_pn_cnt == 0);
++      ubifs_assert(c->dirty_nn_cnt == 0);
++
++      return 1;
++}
++
+ /**
+  * do_commit - commit the journal.
+  * @c: UBIFS file-system description object
+@@ -70,6 +120,12 @@ static int do_commit(struct ubifs_info *c)
+               goto out_up;
+       }
++      if (nothing_to_commit(c)) {
++              up_write(&c->commit_sem);
++              err = 0;
++              goto out_cancel;
++      }
++
+       /* Sync all write buffers (necessary for recovery) */
+       for (i = 0; i < c->jhead_cnt; i++) {
+               err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+@@ -126,7 +182,7 @@ static int do_commit(struct ubifs_info *c)
+       c->mst_node->root_len    = cpu_to_le32(zroot.len);
+       c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
+       c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
+-      c->mst_node->index_size  = cpu_to_le64(c->old_idx_sz);
++      c->mst_node->index_size  = cpu_to_le64(c->bi.old_idx_sz);
+       c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
+       c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
+       c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
+@@ -162,12 +218,12 @@ static int do_commit(struct ubifs_info *c)
+       if (err)
+               goto out;
++out_cancel:
+       spin_lock(&c->cs_lock);
+       c->cmt_state = COMMIT_RESTING;
+       wake_up(&c->cmt_wq);
+       dbg_cmt("commit end");
+       spin_unlock(&c->cs_lock);
+-
+       return 0;
+ out_up:
+@@ -362,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
+       spin_lock(&c->cs_lock);
+       if (c->cmt_state == COMMIT_BROKEN) {
+-              err = -EINVAL;
++              err = -EROFS;
+               goto out;
+       }
+@@ -388,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
+        * re-check it.
+        */
+       if (c->cmt_state == COMMIT_BROKEN) {
+-              err = -EINVAL;
++              err = -EROFS;
+               goto out_cmt_unlock;
+       }
+@@ -520,8 +576,8 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+       struct idx_node *i;
+       size_t sz;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX))
+-              goto out;
++      if (!dbg_is_chk_index(c))
++              return 0;
+       INIT_LIST_HEAD(&list);
+diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
+index 0bee4db..1934084 100644
+--- a/fs/ubifs/debug.c
++++ b/fs/ubifs/debug.c
+@@ -27,33 +27,16 @@
+  * various local functions of those subsystems.
+  */
+-#define UBIFS_DBG_PRESERVE_UBI
+-
+-#include "ubifs.h"
+ #include <linux/module.h>
+-#include <linux/moduleparam.h>
+ #include <linux/debugfs.h>
+ #include <linux/math64.h>
+-#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/random.h>
++#include "ubifs.h"
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+-DEFINE_SPINLOCK(dbg_lock);
+-
+-static char dbg_key_buf0[128];
+-static char dbg_key_buf1[128];
+-
+-unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT;
+-unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT;
+-unsigned int ubifs_tst_flags;
+-
+-module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
+-module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
+-module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
+-
+-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
+-MODULE_PARM_DESC(debug_chks, "Debug check flags");
+-MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
++static DEFINE_SPINLOCK(dbg_lock);
+ static const char *get_key_fmt(int fmt)
+ {
+@@ -95,8 +78,30 @@ static const char *get_key_type(int type)
+       }
+ }
+-static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+-                      char *buffer)
++static const char *get_dent_type(int type)
++{
++      switch (type) {
++      case UBIFS_ITYPE_REG:
++              return "file";
++      case UBIFS_ITYPE_DIR:
++              return "dir";
++      case UBIFS_ITYPE_LNK:
++              return "symlink";
++      case UBIFS_ITYPE_BLK:
++              return "blkdev";
++      case UBIFS_ITYPE_CHR:
++              return "char dev";
++      case UBIFS_ITYPE_FIFO:
++              return "fifo";
++      case UBIFS_ITYPE_SOCK:
++              return "socket";
++      default:
++              return "unknown/invalid type";
++      }
++}
++
++const char *dbg_snprintf_key(const struct ubifs_info *c,
++                           const union ubifs_key *key, char *buffer, int len)
+ {
+       char *p = buffer;
+       int type = key_type(c, key);
+@@ -104,45 +109,34 @@ static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+       if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
+               switch (type) {
+               case UBIFS_INO_KEY:
+-                      sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
+-                             get_key_type(type));
++                      len -= snprintf(p, len, "(%lu, %s)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type));
+                       break;
+               case UBIFS_DENT_KEY:
+               case UBIFS_XENT_KEY:
+-                      sprintf(p, "(%lu, %s, %#08x)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type), key_hash(c, key));
++                      len -= snprintf(p, len, "(%lu, %s, %#08x)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type), key_hash(c, key));
+                       break;
+               case UBIFS_DATA_KEY:
+-                      sprintf(p, "(%lu, %s, %u)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type), key_block(c, key));
++                      len -= snprintf(p, len, "(%lu, %s, %u)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type), key_block(c, key));
+                       break;
+               case UBIFS_TRUN_KEY:
+-                      sprintf(p, "(%lu, %s)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type));
++                      len -= snprintf(p, len, "(%lu, %s)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type));
+                       break;
+               default:
+-                      sprintf(p, "(bad key type: %#08x, %#08x)",
+-                              key->u32[0], key->u32[1]);
++                      len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
++                                      key->u32[0], key->u32[1]);
+               }
+       } else
+-              sprintf(p, "bad key format %d", c->key_fmt);
+-}
+-
+-const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
+-{
+-      /* dbg_lock must be held */
+-      sprintf_key(c, key, dbg_key_buf0);
+-      return dbg_key_buf0;
+-}
+-
+-const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
+-{
+-      /* dbg_lock must be held */
+-      sprintf_key(c, key, dbg_key_buf1);
+-      return dbg_key_buf1;
++              len -= snprintf(p, len, "bad key format %d", c->key_fmt);
++      ubifs_assert(len > 0);
++      return p;
+ }
+ const char *dbg_ntype(int type)
+@@ -227,53 +221,83 @@ const char *dbg_jhead(int jhead)
+ static void dump_ch(const struct ubifs_ch *ch)
+ {
+-      printk(KERN_DEBUG "\tmagic          %#x\n", le32_to_cpu(ch->magic));
+-      printk(KERN_DEBUG "\tcrc            %#x\n", le32_to_cpu(ch->crc));
+-      printk(KERN_DEBUG "\tnode_type      %d (%s)\n", ch->node_type,
++      printk(KERN_ERR "\tmagic          %#x\n", le32_to_cpu(ch->magic));
++      printk(KERN_ERR "\tcrc            %#x\n", le32_to_cpu(ch->crc));
++      printk(KERN_ERR "\tnode_type      %d (%s)\n", ch->node_type,
+              dbg_ntype(ch->node_type));
+-      printk(KERN_DEBUG "\tgroup_type     %d (%s)\n", ch->group_type,
++      printk(KERN_ERR "\tgroup_type     %d (%s)\n", ch->group_type,
+              dbg_gtype(ch->group_type));
+-      printk(KERN_DEBUG "\tsqnum          %llu\n",
++      printk(KERN_ERR "\tsqnum          %llu\n",
+              (unsigned long long)le64_to_cpu(ch->sqnum));
+-      printk(KERN_DEBUG "\tlen            %u\n", le32_to_cpu(ch->len));
++      printk(KERN_ERR "\tlen            %u\n", le32_to_cpu(ch->len));
+ }
+-void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode)
++void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
+ {
+       const struct ubifs_inode *ui = ubifs_inode(inode);
++      struct qstr nm = { .name = NULL };
++      union ubifs_key key;
++      struct ubifs_dent_node *dent, *pdent = NULL;
++      int count = 2;
+-      printk(KERN_DEBUG "Dump in-memory inode:");
+-      printk(KERN_DEBUG "\tinode          %lu\n", inode->i_ino);
+-      printk(KERN_DEBUG "\tsize           %llu\n",
++      printk(KERN_ERR "Dump in-memory inode:");
++      printk(KERN_ERR "\tinode          %lu\n", inode->i_ino);
++      printk(KERN_ERR "\tsize           %llu\n",
+              (unsigned long long)i_size_read(inode));
+-      printk(KERN_DEBUG "\tnlink          %u\n", inode->i_nlink);
+-      printk(KERN_DEBUG "\tuid            %u\n", (unsigned int)inode->i_uid);
+-      printk(KERN_DEBUG "\tgid            %u\n", (unsigned int)inode->i_gid);
+-      printk(KERN_DEBUG "\tatime          %u.%u\n",
++      printk(KERN_ERR "\tnlink          %u\n", inode->i_nlink);
++      printk(KERN_ERR "\tuid            %u\n", (unsigned int)inode->i_uid);
++      printk(KERN_ERR "\tgid            %u\n", (unsigned int)inode->i_gid);
++      printk(KERN_ERR "\tatime          %u.%u\n",
+              (unsigned int)inode->i_atime.tv_sec,
+              (unsigned int)inode->i_atime.tv_nsec);
+-      printk(KERN_DEBUG "\tmtime          %u.%u\n",
++      printk(KERN_ERR "\tmtime          %u.%u\n",
+              (unsigned int)inode->i_mtime.tv_sec,
+              (unsigned int)inode->i_mtime.tv_nsec);
+-      printk(KERN_DEBUG "\tctime          %u.%u\n",
++      printk(KERN_ERR "\tctime          %u.%u\n",
+              (unsigned int)inode->i_ctime.tv_sec,
+              (unsigned int)inode->i_ctime.tv_nsec);
+-      printk(KERN_DEBUG "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
+-      printk(KERN_DEBUG "\txattr_size     %u\n", ui->xattr_size);
+-      printk(KERN_DEBUG "\txattr_cnt      %u\n", ui->xattr_cnt);
+-      printk(KERN_DEBUG "\txattr_names    %u\n", ui->xattr_names);
+-      printk(KERN_DEBUG "\tdirty          %u\n", ui->dirty);
+-      printk(KERN_DEBUG "\txattr          %u\n", ui->xattr);
+-      printk(KERN_DEBUG "\tbulk_read      %u\n", ui->xattr);
+-      printk(KERN_DEBUG "\tsynced_i_size  %llu\n",
++      printk(KERN_ERR "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
++      printk(KERN_ERR "\txattr_size     %u\n", ui->xattr_size);
++      printk(KERN_ERR "\txattr_cnt      %u\n", ui->xattr_cnt);
++      printk(KERN_ERR "\txattr_names    %u\n", ui->xattr_names);
++      printk(KERN_ERR "\tdirty          %u\n", ui->dirty);
++      printk(KERN_ERR "\txattr          %u\n", ui->xattr);
++      printk(KERN_ERR "\tbulk_read      %u\n", ui->xattr);
++      printk(KERN_ERR "\tsynced_i_size  %llu\n",
+              (unsigned long long)ui->synced_i_size);
+-      printk(KERN_DEBUG "\tui_size        %llu\n",
++      printk(KERN_ERR "\tui_size        %llu\n",
+              (unsigned long long)ui->ui_size);
+-      printk(KERN_DEBUG "\tflags          %d\n", ui->flags);
+-      printk(KERN_DEBUG "\tcompr_type     %d\n", ui->compr_type);
+-      printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read);
+-      printk(KERN_DEBUG "\tread_in_a_row  %lu\n", ui->read_in_a_row);
+-      printk(KERN_DEBUG "\tdata_len       %d\n", ui->data_len);
++      printk(KERN_ERR "\tflags          %d\n", ui->flags);
++      printk(KERN_ERR "\tcompr_type     %d\n", ui->compr_type);
++      printk(KERN_ERR "\tlast_page_read %lu\n", ui->last_page_read);
++      printk(KERN_ERR "\tread_in_a_row  %lu\n", ui->read_in_a_row);
++      printk(KERN_ERR "\tdata_len       %d\n", ui->data_len);
++
++      if (!S_ISDIR(inode->i_mode))
++              return;
++
++      printk(KERN_ERR "List of directory entries:\n");
++      ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
++
++      lowest_dent_key(c, &key, inode->i_ino);
++      while (1) {
++              dent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (IS_ERR(dent)) {
++                      if (PTR_ERR(dent) != -ENOENT)
++                              printk(KERN_ERR "error %ld\n", PTR_ERR(dent));
++                      break;
++              }
++
++              printk(KERN_ERR "\t%d: %s (%s)\n",
++                     count++, dent->name, get_dent_type(dent->type));
++
++              nm.name = dent->name;
++              nm.len = le16_to_cpu(dent->nlen);
++              kfree(pdent);
++              pdent = dent;
++              key_read(c, &dent->key, &key);
++      }
++      kfree(pdent);
+ }
+ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+@@ -281,14 +305,15 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       int i, n;
+       union ubifs_key key;
+       const struct ubifs_ch *ch = node;
++      char key_buf[DBG_KEY_BUF_LEN];
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+       /* If the magic is incorrect, just hexdump the first bytes */
+       if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) {
+-              printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ);
+-              print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
++              printk(KERN_ERR "Not a node, first %zu bytes:", UBIFS_CH_SZ);
++              print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1,
+                              (void *)node, UBIFS_CH_SZ, 1);
+               return;
+       }
+@@ -301,7 +326,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_pad_node *pad = node;
+-              printk(KERN_DEBUG "\tpad_len        %u\n",
++              printk(KERN_ERR "\tpad_len        %u\n",
+                      le32_to_cpu(pad->pad_len));
+               break;
+       }
+@@ -310,48 +335,50 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_sb_node *sup = node;
+               unsigned int sup_flags = le32_to_cpu(sup->flags);
+-              printk(KERN_DEBUG "\tkey_hash       %d (%s)\n",
++              printk(KERN_ERR "\tkey_hash       %d (%s)\n",
+                      (int)sup->key_hash, get_key_hash(sup->key_hash));
+-              printk(KERN_DEBUG "\tkey_fmt        %d (%s)\n",
++              printk(KERN_ERR "\tkey_fmt        %d (%s)\n",
+                      (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
+-              printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
+-              printk(KERN_DEBUG "\t  big_lpt      %u\n",
++              printk(KERN_ERR "\tflags          %#x\n", sup_flags);
++              printk(KERN_ERR "\t  big_lpt      %u\n",
+                      !!(sup_flags & UBIFS_FLG_BIGLPT));
+-              printk(KERN_DEBUG "\tmin_io_size    %u\n",
++              printk(KERN_ERR "\t  space_fixup  %u\n",
++                     !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
++              printk(KERN_ERR "\tmin_io_size    %u\n",
+                      le32_to_cpu(sup->min_io_size));
+-              printk(KERN_DEBUG "\tleb_size       %u\n",
++              printk(KERN_ERR "\tleb_size       %u\n",
+                      le32_to_cpu(sup->leb_size));
+-              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++              printk(KERN_ERR "\tleb_cnt        %u\n",
+                      le32_to_cpu(sup->leb_cnt));
+-              printk(KERN_DEBUG "\tmax_leb_cnt    %u\n",
++              printk(KERN_ERR "\tmax_leb_cnt    %u\n",
+                      le32_to_cpu(sup->max_leb_cnt));
+-              printk(KERN_DEBUG "\tmax_bud_bytes  %llu\n",
++              printk(KERN_ERR "\tmax_bud_bytes  %llu\n",
+                      (unsigned long long)le64_to_cpu(sup->max_bud_bytes));
+-              printk(KERN_DEBUG "\tlog_lebs       %u\n",
++              printk(KERN_ERR "\tlog_lebs       %u\n",
+                      le32_to_cpu(sup->log_lebs));
+-              printk(KERN_DEBUG "\tlpt_lebs       %u\n",
++              printk(KERN_ERR "\tlpt_lebs       %u\n",
+                      le32_to_cpu(sup->lpt_lebs));
+-              printk(KERN_DEBUG "\torph_lebs      %u\n",
++              printk(KERN_ERR "\torph_lebs      %u\n",
+                      le32_to_cpu(sup->orph_lebs));
+-              printk(KERN_DEBUG "\tjhead_cnt      %u\n",
++              printk(KERN_ERR "\tjhead_cnt      %u\n",
+                      le32_to_cpu(sup->jhead_cnt));
+-              printk(KERN_DEBUG "\tfanout         %u\n",
++              printk(KERN_ERR "\tfanout         %u\n",
+                      le32_to_cpu(sup->fanout));
+-              printk(KERN_DEBUG "\tlsave_cnt      %u\n",
++              printk(KERN_ERR "\tlsave_cnt      %u\n",
+                      le32_to_cpu(sup->lsave_cnt));
+-              printk(KERN_DEBUG "\tdefault_compr  %u\n",
++              printk(KERN_ERR "\tdefault_compr  %u\n",
+                      (int)le16_to_cpu(sup->default_compr));
+-              printk(KERN_DEBUG "\trp_size        %llu\n",
++              printk(KERN_ERR "\trp_size        %llu\n",
+                      (unsigned long long)le64_to_cpu(sup->rp_size));
+-              printk(KERN_DEBUG "\trp_uid         %u\n",
++              printk(KERN_ERR "\trp_uid         %u\n",
+                      le32_to_cpu(sup->rp_uid));
+-              printk(KERN_DEBUG "\trp_gid         %u\n",
++              printk(KERN_ERR "\trp_gid         %u\n",
+                      le32_to_cpu(sup->rp_gid));
+-              printk(KERN_DEBUG "\tfmt_version    %u\n",
++              printk(KERN_ERR "\tfmt_version    %u\n",
+                      le32_to_cpu(sup->fmt_version));
+-              printk(KERN_DEBUG "\ttime_gran      %u\n",
++              printk(KERN_ERR "\ttime_gran      %u\n",
+                      le32_to_cpu(sup->time_gran));
+-              printk(KERN_DEBUG "\tUUID           %pUB\n",
++              printk(KERN_ERR "\tUUID           %pUB\n",
+                      sup->uuid);
+               break;
+       }
+@@ -359,61 +386,61 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_mst_node *mst = node;
+-              printk(KERN_DEBUG "\thighest_inum   %llu\n",
++              printk(KERN_ERR "\thighest_inum   %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->highest_inum));
+-              printk(KERN_DEBUG "\tcommit number  %llu\n",
++              printk(KERN_ERR "\tcommit number  %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->cmt_no));
+-              printk(KERN_DEBUG "\tflags          %#x\n",
++              printk(KERN_ERR "\tflags          %#x\n",
+                      le32_to_cpu(mst->flags));
+-              printk(KERN_DEBUG "\tlog_lnum       %u\n",
++              printk(KERN_ERR "\tlog_lnum       %u\n",
+                      le32_to_cpu(mst->log_lnum));
+-              printk(KERN_DEBUG "\troot_lnum      %u\n",
++              printk(KERN_ERR "\troot_lnum      %u\n",
+                      le32_to_cpu(mst->root_lnum));
+-              printk(KERN_DEBUG "\troot_offs      %u\n",
++              printk(KERN_ERR "\troot_offs      %u\n",
+                      le32_to_cpu(mst->root_offs));
+-              printk(KERN_DEBUG "\troot_len       %u\n",
++              printk(KERN_ERR "\troot_len       %u\n",
+                      le32_to_cpu(mst->root_len));
+-              printk(KERN_DEBUG "\tgc_lnum        %u\n",
++              printk(KERN_ERR "\tgc_lnum        %u\n",
+                      le32_to_cpu(mst->gc_lnum));
+-              printk(KERN_DEBUG "\tihead_lnum     %u\n",
++              printk(KERN_ERR "\tihead_lnum     %u\n",
+                      le32_to_cpu(mst->ihead_lnum));
+-              printk(KERN_DEBUG "\tihead_offs     %u\n",
++              printk(KERN_ERR "\tihead_offs     %u\n",
+                      le32_to_cpu(mst->ihead_offs));
+-              printk(KERN_DEBUG "\tindex_size     %llu\n",
++              printk(KERN_ERR "\tindex_size     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->index_size));
+-              printk(KERN_DEBUG "\tlpt_lnum       %u\n",
++              printk(KERN_ERR "\tlpt_lnum       %u\n",
+                      le32_to_cpu(mst->lpt_lnum));
+-              printk(KERN_DEBUG "\tlpt_offs       %u\n",
++              printk(KERN_ERR "\tlpt_offs       %u\n",
+                      le32_to_cpu(mst->lpt_offs));
+-              printk(KERN_DEBUG "\tnhead_lnum     %u\n",
++              printk(KERN_ERR "\tnhead_lnum     %u\n",
+                      le32_to_cpu(mst->nhead_lnum));
+-              printk(KERN_DEBUG "\tnhead_offs     %u\n",
++              printk(KERN_ERR "\tnhead_offs     %u\n",
+                      le32_to_cpu(mst->nhead_offs));
+-              printk(KERN_DEBUG "\tltab_lnum      %u\n",
++              printk(KERN_ERR "\tltab_lnum      %u\n",
+                      le32_to_cpu(mst->ltab_lnum));
+-              printk(KERN_DEBUG "\tltab_offs      %u\n",
++              printk(KERN_ERR "\tltab_offs      %u\n",
+                      le32_to_cpu(mst->ltab_offs));
+-              printk(KERN_DEBUG "\tlsave_lnum     %u\n",
++              printk(KERN_ERR "\tlsave_lnum     %u\n",
+                      le32_to_cpu(mst->lsave_lnum));
+-              printk(KERN_DEBUG "\tlsave_offs     %u\n",
++              printk(KERN_ERR "\tlsave_offs     %u\n",
+                      le32_to_cpu(mst->lsave_offs));
+-              printk(KERN_DEBUG "\tlscan_lnum     %u\n",
++              printk(KERN_ERR "\tlscan_lnum     %u\n",
+                      le32_to_cpu(mst->lscan_lnum));
+-              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++              printk(KERN_ERR "\tleb_cnt        %u\n",
+                      le32_to_cpu(mst->leb_cnt));
+-              printk(KERN_DEBUG "\tempty_lebs     %u\n",
++              printk(KERN_ERR "\tempty_lebs     %u\n",
+                      le32_to_cpu(mst->empty_lebs));
+-              printk(KERN_DEBUG "\tidx_lebs       %u\n",
++              printk(KERN_ERR "\tidx_lebs       %u\n",
+                      le32_to_cpu(mst->idx_lebs));
+-              printk(KERN_DEBUG "\ttotal_free     %llu\n",
++              printk(KERN_ERR "\ttotal_free     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_free));
+-              printk(KERN_DEBUG "\ttotal_dirty    %llu\n",
++              printk(KERN_ERR "\ttotal_dirty    %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dirty));
+-              printk(KERN_DEBUG "\ttotal_used     %llu\n",
++              printk(KERN_ERR "\ttotal_used     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_used));
+-              printk(KERN_DEBUG "\ttotal_dead     %llu\n",
++              printk(KERN_ERR "\ttotal_dead     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dead));
+-              printk(KERN_DEBUG "\ttotal_dark     %llu\n",
++              printk(KERN_ERR "\ttotal_dark     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dark));
+               break;
+       }
+@@ -421,11 +448,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_ref_node *ref = node;
+-              printk(KERN_DEBUG "\tlnum           %u\n",
++              printk(KERN_ERR "\tlnum           %u\n",
+                      le32_to_cpu(ref->lnum));
+-              printk(KERN_DEBUG "\toffs           %u\n",
++              printk(KERN_ERR "\toffs           %u\n",
+                      le32_to_cpu(ref->offs));
+-              printk(KERN_DEBUG "\tjhead          %u\n",
++              printk(KERN_ERR "\tjhead          %u\n",
+                      le32_to_cpu(ref->jhead));
+               break;
+       }
+@@ -434,39 +461,40 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_ino_node *ino = node;
+               key_read(c, &ino->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tcreat_sqnum    %llu\n",
+                      (unsigned long long)le64_to_cpu(ino->creat_sqnum));
+-              printk(KERN_DEBUG "\tsize           %llu\n",
++              printk(KERN_ERR "\tsize           %llu\n",
+                      (unsigned long long)le64_to_cpu(ino->size));
+-              printk(KERN_DEBUG "\tnlink          %u\n",
++              printk(KERN_ERR "\tnlink          %u\n",
+                      le32_to_cpu(ino->nlink));
+-              printk(KERN_DEBUG "\tatime          %lld.%u\n",
++              printk(KERN_ERR "\tatime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->atime_sec),
+                      le32_to_cpu(ino->atime_nsec));
+-              printk(KERN_DEBUG "\tmtime          %lld.%u\n",
++              printk(KERN_ERR "\tmtime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->mtime_sec),
+                      le32_to_cpu(ino->mtime_nsec));
+-              printk(KERN_DEBUG "\tctime          %lld.%u\n",
++              printk(KERN_ERR "\tctime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->ctime_sec),
+                      le32_to_cpu(ino->ctime_nsec));
+-              printk(KERN_DEBUG "\tuid            %u\n",
++              printk(KERN_ERR "\tuid            %u\n",
+                      le32_to_cpu(ino->uid));
+-              printk(KERN_DEBUG "\tgid            %u\n",
++              printk(KERN_ERR "\tgid            %u\n",
+                      le32_to_cpu(ino->gid));
+-              printk(KERN_DEBUG "\tmode           %u\n",
++              printk(KERN_ERR "\tmode           %u\n",
+                      le32_to_cpu(ino->mode));
+-              printk(KERN_DEBUG "\tflags          %#x\n",
++              printk(KERN_ERR "\tflags          %#x\n",
+                      le32_to_cpu(ino->flags));
+-              printk(KERN_DEBUG "\txattr_cnt      %u\n",
++              printk(KERN_ERR "\txattr_cnt      %u\n",
+                      le32_to_cpu(ino->xattr_cnt));
+-              printk(KERN_DEBUG "\txattr_size     %u\n",
++              printk(KERN_ERR "\txattr_size     %u\n",
+                      le32_to_cpu(ino->xattr_size));
+-              printk(KERN_DEBUG "\txattr_names    %u\n",
++              printk(KERN_ERR "\txattr_names    %u\n",
+                      le32_to_cpu(ino->xattr_names));
+-              printk(KERN_DEBUG "\tcompr_type     %#x\n",
++              printk(KERN_ERR "\tcompr_type     %#x\n",
+                      (int)le16_to_cpu(ino->compr_type));
+-              printk(KERN_DEBUG "\tdata len       %u\n",
++              printk(KERN_ERR "\tdata len       %u\n",
+                      le32_to_cpu(ino->data_len));
+               break;
+       }
+@@ -477,15 +505,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               int nlen = le16_to_cpu(dent->nlen);
+               key_read(c, &dent->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tinum           %llu\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tinum           %llu\n",
+                      (unsigned long long)le64_to_cpu(dent->inum));
+-              printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
+-              printk(KERN_DEBUG "\tnlen           %d\n", nlen);
+-              printk(KERN_DEBUG "\tname           ");
++              printk(KERN_ERR "\ttype           %d\n", (int)dent->type);
++              printk(KERN_ERR "\tnlen           %d\n", nlen);
++              printk(KERN_ERR "\tname           ");
+               if (nlen > UBIFS_MAX_NLEN)
+-                      printk(KERN_DEBUG "(bad name length, not printing, "
++                      printk(KERN_ERR "(bad name length, not printing, "
+                                         "bad or corrupted node)");
+               else {
+                       for (i = 0; i < nlen && dent->name[i]; i++)
+@@ -501,15 +530,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
+               key_read(c, &dn->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tsize           %u\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tsize           %u\n",
+                      le32_to_cpu(dn->size));
+-              printk(KERN_DEBUG "\tcompr_typ      %d\n",
++              printk(KERN_ERR "\tcompr_typ      %d\n",
+                      (int)le16_to_cpu(dn->compr_type));
+-              printk(KERN_DEBUG "\tdata size      %d\n",
++              printk(KERN_ERR "\tdata size      %d\n",
+                      dlen);
+-              printk(KERN_DEBUG "\tdata:\n");
+-              print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1,
++              printk(KERN_ERR "\tdata:\n");
++              print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
+                              (void *)&dn->data, dlen, 0);
+               break;
+       }
+@@ -517,11 +547,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_trun_node *trun = node;
+-              printk(KERN_DEBUG "\tinum           %u\n",
++              printk(KERN_ERR "\tinum           %u\n",
+                      le32_to_cpu(trun->inum));
+-              printk(KERN_DEBUG "\told_size       %llu\n",
++              printk(KERN_ERR "\told_size       %llu\n",
+                      (unsigned long long)le64_to_cpu(trun->old_size));
+-              printk(KERN_DEBUG "\tnew_size       %llu\n",
++              printk(KERN_ERR "\tnew_size       %llu\n",
+                      (unsigned long long)le64_to_cpu(trun->new_size));
+               break;
+       }
+@@ -530,19 +560,21 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_idx_node *idx = node;
+               n = le16_to_cpu(idx->child_cnt);
+-              printk(KERN_DEBUG "\tchild_cnt      %d\n", n);
+-              printk(KERN_DEBUG "\tlevel          %d\n",
++              printk(KERN_ERR "\tchild_cnt      %d\n", n);
++              printk(KERN_ERR "\tlevel          %d\n",
+                      (int)le16_to_cpu(idx->level));
+-              printk(KERN_DEBUG "\tBranches:\n");
++              printk(KERN_ERR "\tBranches:\n");
+               for (i = 0; i < n && i < c->fanout - 1; i++) {
+                       const struct ubifs_branch *br;
+                       br = ubifs_idx_branch(c, idx, i);
+                       key_read(c, &br->key, &key);
+-                      printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
++                      printk(KERN_ERR "\t%d: LEB %d:%d len %d key %s\n",
+                              i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
+-                             le32_to_cpu(br->len), DBGKEY(&key));
++                             le32_to_cpu(br->len),
++                             dbg_snprintf_key(c, &key, key_buf,
++                                              DBG_KEY_BUF_LEN));
+               }
+               break;
+       }
+@@ -552,20 +584,20 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_orph_node *orph = node;
+-              printk(KERN_DEBUG "\tcommit number  %llu\n",
++              printk(KERN_ERR "\tcommit number  %llu\n",
+                      (unsigned long long)
+                               le64_to_cpu(orph->cmt_no) & LLONG_MAX);
+-              printk(KERN_DEBUG "\tlast node flag %llu\n",
++              printk(KERN_ERR "\tlast node flag %llu\n",
+                      (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
+               n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
+-              printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n);
++              printk(KERN_ERR "\t%d orphan inode numbers:\n", n);
+               for (i = 0; i < n; i++)
+-                      printk(KERN_DEBUG "\t  ino %llu\n",
++                      printk(KERN_ERR "\t  ino %llu\n",
+                              (unsigned long long)le64_to_cpu(orph->inos[i]));
+               break;
+       }
+       default:
+-              printk(KERN_DEBUG "node type %d was not recognized\n",
++              printk(KERN_ERR "node type %d was not recognized\n",
+                      (int)ch->node_type);
+       }
+       spin_unlock(&dbg_lock);
+@@ -574,16 +606,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+ {
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n",
++      printk(KERN_ERR "Budgeting request: new_ino %d, dirtied_ino %d\n",
+              req->new_ino, req->dirtied_ino);
+-      printk(KERN_DEBUG "\tnew_ino_d   %d, dirtied_ino_d %d\n",
++      printk(KERN_ERR "\tnew_ino_d   %d, dirtied_ino_d %d\n",
+              req->new_ino_d, req->dirtied_ino_d);
+-      printk(KERN_DEBUG "\tnew_page    %d, dirtied_page %d\n",
++      printk(KERN_ERR "\tnew_page    %d, dirtied_page %d\n",
+              req->new_page, req->dirtied_page);
+-      printk(KERN_DEBUG "\tnew_dent    %d, mod_dent     %d\n",
++      printk(KERN_ERR "\tnew_dent    %d, mod_dent     %d\n",
+              req->new_dent, req->mod_dent);
+-      printk(KERN_DEBUG "\tidx_growth  %d\n", req->idx_growth);
+-      printk(KERN_DEBUG "\tdata_growth %d dd_growth     %d\n",
++      printk(KERN_ERR "\tidx_growth  %d\n", req->idx_growth);
++      printk(KERN_ERR "\tdata_growth %d dd_growth     %d\n",
+              req->data_growth, req->dd_growth);
+       spin_unlock(&dbg_lock);
+ }
+@@ -591,18 +623,18 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+ void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
+ {
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, "
++      printk(KERN_ERR "(pid %d) Lprops statistics: empty_lebs %d, "
+              "idx_lebs  %d\n", current->pid, lst->empty_lebs, lst->idx_lebs);
+-      printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
++      printk(KERN_ERR "\ttaken_empty_lebs %d, total_free %lld, "
+              "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
+              lst->total_dirty);
+-      printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, "
++      printk(KERN_ERR "\ttotal_used %lld, total_dark %lld, "
+              "total_dead %lld\n", lst->total_used, lst->total_dark,
+              lst->total_dead);
+       spin_unlock(&dbg_lock);
+ }
+-void dbg_dump_budg(struct ubifs_info *c)
++void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
+ {
+       int i;
+       struct rb_node *rb;
+@@ -610,51 +642,69 @@ void dbg_dump_budg(struct ubifs_info *c)
+       struct ubifs_gced_idx_leb *idx_gc;
+       long long available, outstanding, free;
+-      ubifs_assert(spin_is_locked(&c->space_lock));
++      spin_lock(&c->space_lock);
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
+-             "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
+-             c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
+-      printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
+-             "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
+-             c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth,
+-             c->freeable_cnt);
+-      printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, "
+-             "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs,
+-             c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt);
+-      printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
++      printk(KERN_ERR "(pid %d) Budgeting info: data budget sum %lld, "
++             "total budget sum %lld\n", current->pid,
++             bi->data_growth + bi->dd_growth,
++             bi->data_growth + bi->dd_growth + bi->idx_growth);
++      printk(KERN_ERR "\tbudg_data_growth %lld, budg_dd_growth %lld, "
++             "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth,
++             bi->idx_growth);
++      printk(KERN_ERR "\tmin_idx_lebs %d, old_idx_sz %llu, "
++             "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz,
++             bi->uncommitted_idx);
++      printk(KERN_ERR "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
++             bi->page_budget, bi->inode_budget, bi->dent_budget);
++      printk(KERN_ERR "\tnospace %u, nospace_rp %u\n",
++             bi->nospace, bi->nospace_rp);
++      printk(KERN_ERR "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
++             c->dark_wm, c->dead_wm, c->max_idx_node_sz);
++
++      if (bi != &c->bi)
++              /*
++               * If we are dumping saved budgeting data, do not print
++               * additional information which is about the current state, not
++               * the old one which corresponded to the saved budgeting data.
++               */
++              goto out_unlock;
++
++      printk(KERN_ERR "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
++             c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
++      printk(KERN_ERR "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
+              "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),
+              atomic_long_read(&c->dirty_zn_cnt),
+              atomic_long_read(&c->clean_zn_cnt));
+-      printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
+-             c->dark_wm, c->dead_wm, c->max_idx_node_sz);
+-      printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
++      printk(KERN_ERR "\tgc_lnum %d, ihead_lnum %d\n",
+              c->gc_lnum, c->ihead_lnum);
++
+       /* If we are in R/O mode, journal heads do not exist */
+       if (c->jheads)
+               for (i = 0; i < c->jhead_cnt; i++)
+-                      printk(KERN_DEBUG "\tjhead %s\t LEB %d\n",
++                      printk(KERN_ERR "\tjhead %s\t LEB %d\n",
+                              dbg_jhead(c->jheads[i].wbuf.jhead),
+                              c->jheads[i].wbuf.lnum);
+       for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
+               bud = rb_entry(rb, struct ubifs_bud, rb);
+-              printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum);
++              printk(KERN_ERR "\tbud LEB %d\n", bud->lnum);
+       }
+       list_for_each_entry(bud, &c->old_buds, list)
+-              printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum);
++              printk(KERN_ERR "\told bud LEB %d\n", bud->lnum);
+       list_for_each_entry(idx_gc, &c->idx_gc, list)
+-              printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
++              printk(KERN_ERR "\tGC'ed idx LEB %d unmap %d\n",
+                      idx_gc->lnum, idx_gc->unmap);
+-      printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
++      printk(KERN_ERR "\tcommit state %d\n", c->cmt_state);
+       /* Print budgeting predictions */
+-      available = ubifs_calc_available(c, c->min_idx_lebs);
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
++      available = ubifs_calc_available(c, c->bi.min_idx_lebs);
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
+       free = ubifs_get_free_space_nolock(c);
+-      printk(KERN_DEBUG "Budgeting predictions:\n");
+-      printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
++      printk(KERN_ERR "Budgeting predictions:\n");
++      printk(KERN_ERR "\tavailable: %lld, outstanding %lld, free %lld\n",
+              available, outstanding, free);
++out_unlock:
+       spin_unlock(&dbg_lock);
++      spin_unlock(&c->space_lock);
+ }
+ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+@@ -670,11 +720,11 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+               dark = ubifs_calc_dark(c, spc);
+       if (lp->flags & LPROPS_INDEX)
+-              printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
++              printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
+                      "free + dirty %-8d flags %#x (", lp->lnum, lp->free,
+                      lp->dirty, c->leb_size - spc, spc, lp->flags);
+       else
+-              printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
++              printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
+                      "free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d "
+                      "flags %#-4x (", lp->lnum, lp->free, lp->dirty,
+                      c->leb_size - spc, spc, dark, dead,
+@@ -729,7 +779,13 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+               if (bud->lnum == lp->lnum) {
+                       int head = 0;
+                       for (i = 0; i < c->jhead_cnt; i++) {
+-                              if (lp->lnum == c->jheads[i].wbuf.lnum) {
++                              /*
++                               * Note, if we are in R/O mode or in the middle
++                               * of mounting/re-mounting, the write-buffers do
++                               * not exist.
++                               */
++                              if (c->jheads &&
++                                  lp->lnum == c->jheads[i].wbuf.lnum) {
+                                       printk(KERN_CONT ", jhead %s",
+                                              dbg_jhead(i));
+                                       head = 1;
+@@ -751,7 +807,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
+       struct ubifs_lprops lp;
+       struct ubifs_lp_stats lst;
+-      printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n",
++      printk(KERN_ERR "(pid %d) start dumping LEB properties\n",
+              current->pid);
+       ubifs_get_lp_stats(c, &lst);
+       dbg_dump_lstats(&lst);
+@@ -763,7 +819,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
+               dbg_dump_lprop(c, &lp);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n",
++      printk(KERN_ERR "(pid %d) finish dumping LEB properties\n",
+              current->pid);
+ }
+@@ -772,69 +828,96 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
+       int i;
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid);
+-      printk(KERN_DEBUG "\tlpt_sz:        %lld\n", c->lpt_sz);
+-      printk(KERN_DEBUG "\tpnode_sz:      %d\n", c->pnode_sz);
+-      printk(KERN_DEBUG "\tnnode_sz:      %d\n", c->nnode_sz);
+-      printk(KERN_DEBUG "\tltab_sz:       %d\n", c->ltab_sz);
+-      printk(KERN_DEBUG "\tlsave_sz:      %d\n", c->lsave_sz);
+-      printk(KERN_DEBUG "\tbig_lpt:       %d\n", c->big_lpt);
+-      printk(KERN_DEBUG "\tlpt_hght:      %d\n", c->lpt_hght);
+-      printk(KERN_DEBUG "\tpnode_cnt:     %d\n", c->pnode_cnt);
+-      printk(KERN_DEBUG "\tnnode_cnt:     %d\n", c->nnode_cnt);
+-      printk(KERN_DEBUG "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
+-      printk(KERN_DEBUG "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
+-      printk(KERN_DEBUG "\tlsave_cnt:     %d\n", c->lsave_cnt);
+-      printk(KERN_DEBUG "\tspace_bits:    %d\n", c->space_bits);
+-      printk(KERN_DEBUG "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
+-      printk(KERN_DEBUG "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
+-      printk(KERN_DEBUG "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
+-      printk(KERN_DEBUG "\tpcnt_bits:     %d\n", c->pcnt_bits);
+-      printk(KERN_DEBUG "\tlnum_bits:     %d\n", c->lnum_bits);
+-      printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
+-      printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
++      printk(KERN_ERR "(pid %d) dumping LPT information\n", current->pid);
++      printk(KERN_ERR "\tlpt_sz:        %lld\n", c->lpt_sz);
++      printk(KERN_ERR "\tpnode_sz:      %d\n", c->pnode_sz);
++      printk(KERN_ERR "\tnnode_sz:      %d\n", c->nnode_sz);
++      printk(KERN_ERR "\tltab_sz:       %d\n", c->ltab_sz);
++      printk(KERN_ERR "\tlsave_sz:      %d\n", c->lsave_sz);
++      printk(KERN_ERR "\tbig_lpt:       %d\n", c->big_lpt);
++      printk(KERN_ERR "\tlpt_hght:      %d\n", c->lpt_hght);
++      printk(KERN_ERR "\tpnode_cnt:     %d\n", c->pnode_cnt);
++      printk(KERN_ERR "\tnnode_cnt:     %d\n", c->nnode_cnt);
++      printk(KERN_ERR "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
++      printk(KERN_ERR "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
++      printk(KERN_ERR "\tlsave_cnt:     %d\n", c->lsave_cnt);
++      printk(KERN_ERR "\tspace_bits:    %d\n", c->space_bits);
++      printk(KERN_ERR "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
++      printk(KERN_ERR "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
++      printk(KERN_ERR "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
++      printk(KERN_ERR "\tpcnt_bits:     %d\n", c->pcnt_bits);
++      printk(KERN_ERR "\tlnum_bits:     %d\n", c->lnum_bits);
++      printk(KERN_ERR "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
++      printk(KERN_ERR "\tLPT head is at %d:%d\n",
+              c->nhead_lnum, c->nhead_offs);
+-      printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n",
++      printk(KERN_ERR "\tLPT ltab is at %d:%d\n",
+              c->ltab_lnum, c->ltab_offs);
+       if (c->big_lpt)
+-              printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
++              printk(KERN_ERR "\tLPT lsave is at %d:%d\n",
+                      c->lsave_lnum, c->lsave_offs);
+       for (i = 0; i < c->lpt_lebs; i++)
+-              printk(KERN_DEBUG "\tLPT LEB %d free %d dirty %d tgc %d "
++              printk(KERN_ERR "\tLPT LEB %d free %d dirty %d tgc %d "
+                      "cmt %d\n", i + c->lpt_first, c->ltab[i].free,
+                      c->ltab[i].dirty, c->ltab[i].tgc, c->ltab[i].cmt);
+       spin_unlock(&dbg_lock);
+ }
++void dbg_dump_sleb(const struct ubifs_info *c,
++                 const struct ubifs_scan_leb *sleb, int offs)
++{
++      struct ubifs_scan_node *snod;
++
++      printk(KERN_ERR "(pid %d) start dumping scanned data from LEB %d:%d\n",
++             current->pid, sleb->lnum, offs);
++
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              cond_resched();
++              printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
++                     snod->offs, snod->len);
++              dbg_dump_node(c, snod->node);
++      }
++}
++
+ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
+ {
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
++      void *buf;
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+-      printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
++      printk(KERN_ERR "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+-      sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
++
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory for dumping LEB %d", lnum);
++              return;
++      }
++
++      sleb = ubifs_scan(c, lnum, 0, buf, 0);
+       if (IS_ERR(sleb)) {
+               ubifs_err("scan error %d", (int)PTR_ERR(sleb));
+-              return;
++              goto out;
+       }
+-      printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum,
++      printk(KERN_ERR "LEB %d has %d nodes ending at %d\n", lnum,
+              sleb->nodes_cnt, sleb->endpt);
+       list_for_each_entry(snod, &sleb->nodes, list) {
+               cond_resched();
+-              printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum,
++              printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", lnum,
+                      snod->offs, snod->len);
+               dbg_dump_node(c, snod->node);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
++      printk(KERN_ERR "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
+       ubifs_scan_destroy(sleb);
++
++out:
++      vfree(buf);
+       return;
+ }
+@@ -843,6 +926,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
+ {
+       int n;
+       const struct ubifs_zbranch *zbr;
++      char key_buf[DBG_KEY_BUF_LEN];
+       spin_lock(&dbg_lock);
+       if (znode->parent)
+@@ -850,7 +934,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
+       else
+               zbr = &c->zroot;
+-      printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
++      printk(KERN_ERR "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
+              " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs,
+              zbr->len, znode->parent, znode->iip, znode->level,
+              znode->child_cnt, znode->flags);
+@@ -860,19 +944,23 @@ void dbg_dump_znode(const struct ubifs_info *c,
+               return;
+       }
+-      printk(KERN_DEBUG "zbranches:\n");
++      printk(KERN_ERR "zbranches:\n");
+       for (n = 0; n < znode->child_cnt; n++) {
+               zbr = &znode->zbranch[n];
+               if (znode->level > 0)
+-                      printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
++                      printk(KERN_ERR "\t%d: znode %p LEB %d:%d len %d key "
+                                         "%s\n", n, zbr->znode, zbr->lnum,
+                                         zbr->offs, zbr->len,
+-                                        DBGKEY(&zbr->key));
++                                        dbg_snprintf_key(c, &zbr->key,
++                                                         key_buf,
++                                                         DBG_KEY_BUF_LEN));
+               else
+-                      printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
++                      printk(KERN_ERR "\t%d: LNC %p LEB %d:%d len %d key "
+                                         "%s\n", n, zbr->znode, zbr->lnum,
+                                         zbr->offs, zbr->len,
+-                                        DBGKEY(&zbr->key));
++                                        dbg_snprintf_key(c, &zbr->key,
++                                                         key_buf,
++                                                         DBG_KEY_BUF_LEN));
+       }
+       spin_unlock(&dbg_lock);
+ }
+@@ -881,16 +969,16 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
+ {
+       int i;
+-      printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n",
++      printk(KERN_ERR "(pid %d) start dumping heap cat %d (%d elements)\n",
+              current->pid, cat, heap->cnt);
+       for (i = 0; i < heap->cnt; i++) {
+               struct ubifs_lprops *lprops = heap->arr[i];
+-              printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d "
++              printk(KERN_ERR "\t%d. LEB %d hpos %d free %d dirty %d "
+                      "flags %d\n", i, lprops->lnum, lprops->hpos,
+                      lprops->free, lprops->dirty, lprops->flags);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid);
++      printk(KERN_ERR "(pid %d) finish dumping heap\n", current->pid);
+ }
+ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+@@ -898,15 +986,15 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+ {
+       int i;
+-      printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid);
+-      printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
++      printk(KERN_ERR "(pid %d) dumping pnode:\n", current->pid);
++      printk(KERN_ERR "\taddress %zx parent %zx cnext %zx\n",
+              (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
+-      printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
++      printk(KERN_ERR "\tflags %lu iip %d level %d num %d\n",
+              pnode->flags, iip, pnode->level, pnode->num);
+       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+               struct ubifs_lprops *lp = &pnode->lprops[i];
+-              printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n",
++              printk(KERN_ERR "\t%d: free %d dirty %d flags %d lnum %d\n",
+                      i, lp->free, lp->dirty, lp->flags, lp->lnum);
+       }
+ }
+@@ -916,20 +1004,20 @@ void dbg_dump_tnc(struct ubifs_info *c)
+       struct ubifs_znode *znode;
+       int level;
+-      printk(KERN_DEBUG "\n");
+-      printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid);
++      printk(KERN_ERR "\n");
++      printk(KERN_ERR "(pid %d) start dumping TNC tree\n", current->pid);
+       znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
+       level = znode->level;
+-      printk(KERN_DEBUG "== Level %d ==\n", level);
++      printk(KERN_ERR "== Level %d ==\n", level);
+       while (znode) {
+               if (level != znode->level) {
+                       level = znode->level;
+-                      printk(KERN_DEBUG "== Level %d ==\n", level);
++                      printk(KERN_ERR "== Level %d ==\n", level);
+               }
+               dbg_dump_znode(c, znode);
+               znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid);
++      printk(KERN_ERR "(pid %d) finish dumping TNC tree\n", current->pid);
+ }
+ static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
+@@ -961,11 +1049,41 @@ void dbg_dump_index(struct ubifs_info *c)
+ void dbg_save_space_info(struct ubifs_info *c)
+ {
+       struct ubifs_debug_info *d = c->dbg;
+-
+-      ubifs_get_lp_stats(c, &d->saved_lst);
++      int freeable_cnt;
+       spin_lock(&c->space_lock);
++      memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats));
++      memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info));
++      d->saved_idx_gc_cnt = c->idx_gc_cnt;
++
++      /*
++       * We use a dirty hack here and zero out @c->freeable_cnt, because it
++       * affects the free space calculations, and UBIFS might not know about
++       * all freeable eraseblocks. Indeed, we know about freeable eraseblocks
++       * only when we read their lprops, and we do this only lazily, upon the
++       * need. So at any given point of time @c->freeable_cnt might be not
++       * exactly accurate.
++       *
++       * Just one example about the issue we hit when we did not zero
++       * @c->freeable_cnt.
++       * 1. The file-system is mounted R/O, c->freeable_cnt is %0. We save the
++       *    amount of free space in @d->saved_free
++       * 2. We re-mount R/W, which makes UBIFS to read the "lsave"
++       *    information from flash, where we cache LEBs from various
++       *    categories ('ubifs_remount_fs()' -> 'ubifs_lpt_init()'
++       *    -> 'lpt_init_wr()' -> 'read_lsave()' -> 'ubifs_lpt_lookup()'
++       *    -> 'ubifs_get_pnode()' -> 'update_cats()'
++       *    -> 'ubifs_add_to_cat()').
++       * 3. Lsave contains a freeable eraseblock, and @c->freeable_cnt
++       *    becomes %1.
++       * 4. We calculate the amount of free space when the re-mount is
++       *    finished in 'dbg_check_space_info()' and it does not match
++       *    @d->saved_free.
++       */
++      freeable_cnt = c->freeable_cnt;
++      c->freeable_cnt = 0;
+       d->saved_free = ubifs_get_free_space_nolock(c);
++      c->freeable_cnt = freeable_cnt;
+       spin_unlock(&c->space_lock);
+ }
+@@ -982,12 +1100,15 @@ int dbg_check_space_info(struct ubifs_info *c)
+ {
+       struct ubifs_debug_info *d = c->dbg;
+       struct ubifs_lp_stats lst;
+-      long long avail, free;
++      long long free;
++      int freeable_cnt;
+       spin_lock(&c->space_lock);
+-      avail = ubifs_calc_available(c, c->min_idx_lebs);
++      freeable_cnt = c->freeable_cnt;
++      c->freeable_cnt = 0;
++      free = ubifs_get_free_space_nolock(c);
++      c->freeable_cnt = freeable_cnt;
+       spin_unlock(&c->space_lock);
+-      free = ubifs_get_free_space(c);
+       if (free != d->saved_free) {
+               ubifs_err("free space changed from %lld to %lld",
+@@ -1000,20 +1121,21 @@ int dbg_check_space_info(struct ubifs_info *c)
+ out:
+       ubifs_msg("saved lprops statistics dump");
+       dbg_dump_lstats(&d->saved_lst);
+-      ubifs_get_lp_stats(c, &lst);
+-
++      ubifs_msg("saved budgeting info dump");
++      dbg_dump_budg(c, &d->saved_bi);
++      ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
+       ubifs_msg("current lprops statistics dump");
++      ubifs_get_lp_stats(c, &lst);
+       dbg_dump_lstats(&lst);
+-
+-      spin_lock(&c->space_lock);
+-      dbg_dump_budg(c);
+-      spin_unlock(&c->space_lock);
++      ubifs_msg("current budgeting info dump");
++      dbg_dump_budg(c, &c->bi);
+       dump_stack();
+       return -EINVAL;
+ }
+ /**
+  * dbg_check_synced_i_size - check synchronized inode size.
++ * @c: UBIFS file-system description object
+  * @inode: inode to check
+  *
+  * If inode is clean, synchronized inode size has to be equivalent to current
+@@ -1021,12 +1143,12 @@ out:
+  * has to be locked). Returns %0 if synchronized inode size if correct, and
+  * %-EINVAL if not.
+  */
+-int dbg_check_synced_i_size(struct inode *inode)
++int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode)
+ {
+       int err = 0;
+       struct ubifs_inode *ui = ubifs_inode(inode);
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (!S_ISREG(inode->i_mode))
+               return 0;
+@@ -1059,7 +1181,7 @@ int dbg_check_synced_i_size(struct inode *inode)
+  * Note, it is good idea to make sure the @dir->i_mutex is locked before
+  * calling this function.
+  */
+-int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
++int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
+ {
+       unsigned int nlink = 2;
+       union ubifs_key key;
+@@ -1067,7 +1189,7 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
+       struct qstr nm = { .name = NULL };
+       loff_t size = UBIFS_INO_NODE_SZ;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (!S_ISDIR(dir->i_mode))
+@@ -1101,12 +1223,14 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
+                         "but calculated size is %llu", dir->i_ino,
+                         (unsigned long long)i_size_read(dir),
+                         (unsigned long long)size);
++              dbg_dump_inode(c, dir);
+               dump_stack();
+               return -EINVAL;
+       }
+       if (dir->i_nlink != nlink) {
+               ubifs_err("directory inode %lu has nlink %u, but calculated "
+                         "nlink is %u", dir->i_ino, dir->i_nlink, nlink);
++              dbg_dump_inode(c, dir);
+               dump_stack();
+               return -EINVAL;
+       }
+@@ -1133,6 +1257,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       int err, nlen1, nlen2, cmp;
+       struct ubifs_dent_node *dent1, *dent2;
+       union ubifs_key key;
++      char key_buf[DBG_KEY_BUF_LEN];
+       ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key));
+       dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
+@@ -1163,9 +1288,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       key_read(c, &dent1->key, &key);
+       if (keys_cmp(c, &zbr1->key, &key)) {
+               dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
+-                      zbr1->offs, DBGKEY(&key));
++                      zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
++                                                   DBG_KEY_BUF_LEN));
+               dbg_err("but it should have key %s according to tnc",
+-                      DBGKEY(&zbr1->key));
++                      dbg_snprintf_key(c, &zbr1->key, key_buf,
++                                       DBG_KEY_BUF_LEN));
+               dbg_dump_node(c, dent1);
+               goto out_free;
+       }
+@@ -1173,9 +1300,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       key_read(c, &dent2->key, &key);
+       if (keys_cmp(c, &zbr2->key, &key)) {
+               dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
+-                      zbr1->offs, DBGKEY(&key));
++                      zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
++                                                   DBG_KEY_BUF_LEN));
+               dbg_err("but it should have key %s according to tnc",
+-                      DBGKEY(&zbr2->key));
++                      dbg_snprintf_key(c, &zbr2->key, key_buf,
++                                       DBG_KEY_BUF_LEN));
+               dbg_dump_node(c, dent2);
+               goto out_free;
+       }
+@@ -1192,7 +1321,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+               dbg_err("2 xent/dent nodes with the same name");
+       else
+               dbg_err("bad order of colliding key %s",
+-                      DBGKEY(&key));
++                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+       ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
+       dbg_dump_node(c, dent1);
+@@ -1423,7 +1552,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra)
+       long clean_cnt = 0, dirty_cnt = 0;
+       int err, last;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_TNC))
++      if (!dbg_is_chk_index(c))
+               return 0;
+       ubifs_assert(mutex_is_locked(&c->tnc_mutex));
+@@ -1670,7 +1799,7 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
+       int err;
+       long long calc = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ))
++      if (!dbg_is_chk_index(c))
+               return 0;
+       err = dbg_walk_index(c, NULL, add_size, &calc);
+@@ -1751,6 +1880,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
+       struct rb_node **p, *parent = NULL;
+       struct fsck_inode *fscki;
+       ino_t inum = key_inum_flash(c, &ino->key);
++      struct inode *inode;
++      struct ubifs_inode *ui;
+       p = &fsckd->inodes.rb_node;
+       while (*p) {
+@@ -1774,19 +1905,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
+       if (!fscki)
+               return ERR_PTR(-ENOMEM);
++      inode = ilookup(c->vfs_sb, inum);
++
+       fscki->inum = inum;
+-      fscki->nlink = le32_to_cpu(ino->nlink);
+-      fscki->size = le64_to_cpu(ino->size);
+-      fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
+-      fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
+-      fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
+-      fscki->mode = le32_to_cpu(ino->mode);
++      /*
++       * If the inode is present in the VFS inode cache, use it instead of
++       * the on-flash inode which might be out-of-date. E.g., the size might
++       * be out-of-date. If we do not do this, the following may happen, for
++       * example:
++       *   1. A power cut happens
++       *   2. We mount the file-system R/O, the replay process fixes up the
++       *      inode size in the VFS cache, but on on-flash.
++       *   3. 'check_leaf()' fails because it hits a data node beyond inode
++       *      size.
++       */
++      if (!inode) {
++              fscki->nlink = le32_to_cpu(ino->nlink);
++              fscki->size = le64_to_cpu(ino->size);
++              fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
++              fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
++              fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
++              fscki->mode = le32_to_cpu(ino->mode);
++      } else {
++              ui = ubifs_inode(inode);
++              fscki->nlink = inode->i_nlink;
++              fscki->size = inode->i_size;
++              fscki->xattr_cnt = ui->xattr_cnt;
++              fscki->xattr_sz = ui->xattr_size;
++              fscki->xattr_nms = ui->xattr_names;
++              fscki->mode = inode->i_mode;
++              iput(inode);
++      }
++
+       if (S_ISDIR(fscki->mode)) {
+               fscki->calc_sz = UBIFS_INO_NODE_SZ;
+               fscki->calc_cnt = 2;
+       }
++
+       rb_link_node(&fscki->rb, parent, p);
+       rb_insert_color(&fscki->rb, &fsckd->inodes);
++
+       return fscki;
+ }
+@@ -2217,7 +2375,7 @@ int dbg_check_filesystem(struct ubifs_info *c)
+       int err;
+       struct fsck_data fsckd;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_FS))
++      if (!dbg_is_chk_fs(c))
+               return 0;
+       fsckd.inodes = RB_ROOT;
+@@ -2252,7 +2410,7 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+@@ -2319,7 +2477,7 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+@@ -2379,7 +2537,8 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+               hashb = key_block(c, &sb->key);
+               if (hasha > hashb) {
+-                      ubifs_err("larger hash %u goes before %u", hasha, hashb);
++                      ubifs_err("larger hash %u goes before %u",
++                                hasha, hashb);
+                       goto error_dump;
+               }
+       }
+@@ -2395,393 +2554,351 @@ error_dump:
+       return 0;
+ }
+-static int invocation_cnt;
+-
+-int dbg_force_in_the_gaps(void)
+-{
+-      if (!dbg_force_in_the_gaps_enabled)
+-              return 0;
+-      /* Force in-the-gaps every 8th commit */
+-      return !((invocation_cnt++) & 0x7);
+-}
+-
+-/* Failure mode for recovery testing */
+-
+-#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d))
+-
+-struct failure_mode_info {
+-      struct list_head list;
+-      struct ubifs_info *c;
+-};
+-
+-static LIST_HEAD(fmi_list);
+-static DEFINE_SPINLOCK(fmi_lock);
+-
+-static unsigned int next;
+-
+-static int simple_rand(void)
+-{
+-      if (next == 0)
+-              next = current->pid;
+-      next = next * 1103515245 + 12345;
+-      return (next >> 16) & 32767;
+-}
+-
+-static void failure_mode_init(struct ubifs_info *c)
+-{
+-      struct failure_mode_info *fmi;
+-
+-      fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
+-      if (!fmi) {
+-              ubifs_err("Failed to register failure mode - no memory");
+-              return;
+-      }
+-      fmi->c = c;
+-      spin_lock(&fmi_lock);
+-      list_add_tail(&fmi->list, &fmi_list);
+-      spin_unlock(&fmi_lock);
+-}
+-
+-static void failure_mode_exit(struct ubifs_info *c)
+-{
+-      struct failure_mode_info *fmi, *tmp;
+-
+-      spin_lock(&fmi_lock);
+-      list_for_each_entry_safe(fmi, tmp, &fmi_list, list)
+-              if (fmi->c == c) {
+-                      list_del(&fmi->list);
+-                      kfree(fmi);
+-              }
+-      spin_unlock(&fmi_lock);
+-}
+-
+-static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc)
++static inline int chance(unsigned int n, unsigned int out_of)
+ {
+-      struct failure_mode_info *fmi;
+-
+-      spin_lock(&fmi_lock);
+-      list_for_each_entry(fmi, &fmi_list, list)
+-              if (fmi->c->ubi == desc) {
+-                      struct ubifs_info *c = fmi->c;
++      return !!((random32() % out_of) + 1 <= n);
+-                      spin_unlock(&fmi_lock);
+-                      return c;
+-              }
+-      spin_unlock(&fmi_lock);
+-      return NULL;
+ }
+-static int in_failure_mode(struct ubi_volume_desc *desc)
++static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
+ {
+-      struct ubifs_info *c = dbg_find_info(desc);
+-
+-      if (c && dbg_failure_mode)
+-              return c->dbg->failure_mode;
+-      return 0;
+-}
++      struct ubifs_debug_info *d = c->dbg;
+-static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
+-{
+-      struct ubifs_info *c = dbg_find_info(desc);
+-      struct ubifs_debug_info *d;
++      ubifs_assert(dbg_is_tst_rcvry(c));
+-      if (!c || !dbg_failure_mode)
+-              return 0;
+-      d = c->dbg;
+-      if (d->failure_mode)
+-              return 1;
+-      if (!d->fail_cnt) {
+-              /* First call - decide delay to failure */
++      if (!d->pc_cnt) {
++              /* First call - decide delay to the power cut */
+               if (chance(1, 2)) {
+-                      unsigned int delay = 1 << (simple_rand() >> 11);
++                      unsigned long delay;
+                       if (chance(1, 2)) {
+-                              d->fail_delay = 1;
+-                              d->fail_timeout = jiffies +
+-                                                msecs_to_jiffies(delay);
+-                              dbg_rcvry("failing after %ums", delay);
++                              d->pc_delay = 1;
++                              /* Fail withing 1 minute */
++                              delay = random32() % 60000;
++                              d->pc_timeout = jiffies;
++                              d->pc_timeout += msecs_to_jiffies(delay);
++                              ubifs_warn("failing after %lums", delay);
+                       } else {
+-                              d->fail_delay = 2;
+-                              d->fail_cnt_max = delay;
+-                              dbg_rcvry("failing after %u calls", delay);
++                              d->pc_delay = 2;
++                              delay = random32() % 10000;
++                              /* Fail within 10000 operations */
++                              d->pc_cnt_max = delay;
++                              ubifs_warn("failing after %lu calls", delay);
+                       }
+               }
+-              d->fail_cnt += 1;
++
++              d->pc_cnt += 1;
+       }
++
+       /* Determine if failure delay has expired */
+-      if (d->fail_delay == 1) {
+-              if (time_before(jiffies, d->fail_timeout))
++      if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
+                       return 0;
+-      } else if (d->fail_delay == 2)
+-              if (d->fail_cnt++ < d->fail_cnt_max)
++      if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
+                       return 0;
++
+       if (lnum == UBIFS_SB_LNUM) {
+-              if (write) {
+-                      if (chance(1, 2))
+-                              return 0;
+-              } else if (chance(19, 20))
++              if (write && chance(1, 2))
+                       return 0;
+-              dbg_rcvry("failing in super block LEB %d", lnum);
++              if (chance(19, 20))
++                      return 0;
++              ubifs_warn("failing in super block LEB %d", lnum);
+       } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
+               if (chance(19, 20))
+                       return 0;
+-              dbg_rcvry("failing in master LEB %d", lnum);
++              ubifs_warn("failing in master LEB %d", lnum);
+       } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
+-              if (write) {
+-                      if (chance(99, 100))
+-                              return 0;
+-              } else if (chance(399, 400))
++              if (write && chance(99, 100))
++                      return 0;
++              if (chance(399, 400))
+                       return 0;
+-              dbg_rcvry("failing in log LEB %d", lnum);
++              ubifs_warn("failing in log LEB %d", lnum);
+       } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
+-              if (write) {
+-                      if (chance(7, 8))
+-                              return 0;
+-              } else if (chance(19, 20))
++              if (write && chance(7, 8))
+                       return 0;
+-              dbg_rcvry("failing in LPT LEB %d", lnum);
++              if (chance(19, 20))
++                      return 0;
++              ubifs_warn("failing in LPT LEB %d", lnum);
+       } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
+-              if (write) {
+-                      if (chance(1, 2))
+-                              return 0;
+-              } else if (chance(9, 10))
++              if (write && chance(1, 2))
+                       return 0;
+-              dbg_rcvry("failing in orphan LEB %d", lnum);
++              if (chance(9, 10))
++                      return 0;
++              ubifs_warn("failing in orphan LEB %d", lnum);
+       } else if (lnum == c->ihead_lnum) {
+               if (chance(99, 100))
+                       return 0;
+-              dbg_rcvry("failing in index head LEB %d", lnum);
++              ubifs_warn("failing in index head LEB %d", lnum);
+       } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
+               if (chance(9, 10))
+                       return 0;
+-              dbg_rcvry("failing in GC head LEB %d", lnum);
++              ubifs_warn("failing in GC head LEB %d", lnum);
+       } else if (write && !RB_EMPTY_ROOT(&c->buds) &&
+                  !ubifs_search_bud(c, lnum)) {
+               if (chance(19, 20))
+                       return 0;
+-              dbg_rcvry("failing in non-bud LEB %d", lnum);
++              ubifs_warn("failing in non-bud LEB %d", lnum);
+       } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
+                  c->cmt_state == COMMIT_RUNNING_REQUIRED) {
+               if (chance(999, 1000))
+                       return 0;
+-              dbg_rcvry("failing in bud LEB %d commit running", lnum);
++              ubifs_warn("failing in bud LEB %d commit running", lnum);
+       } else {
+               if (chance(9999, 10000))
+                       return 0;
+-              dbg_rcvry("failing in bud LEB %d commit not running", lnum);
++              ubifs_warn("failing in bud LEB %d commit not running", lnum);
+       }
+-      ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum);
+-      d->failure_mode = 1;
++
++      d->pc_happened = 1;
++      ubifs_warn("========== Power cut emulated ==========");
+       dump_stack();
+       return 1;
+ }
+-static void cut_data(const void *buf, int len)
++static void cut_data(const void *buf, unsigned int len)
+ {
+-      int flen, i;
++      unsigned int from, to, i, ffs = chance(1, 2);
+       unsigned char *p = (void *)buf;
+-      flen = (len * (long long)simple_rand()) >> 15;
+-      for (i = flen; i < len; i++)
+-              p[i] = 0xff;
+-}
++      from = random32() % (len + 1);
++      if (chance(1, 2))
++              to = random32() % (len - from + 1);
++      else
++              to = len;
+-int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+-               int len, int check)
+-{
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      return ubi_leb_read(desc, lnum, buf, offset, len, check);
++      if (from < to)
++              ubifs_warn("filled bytes %u-%u with %s", from, to - 1,
++                         ffs ? "0xFFs" : "random data");
++
++      if (ffs)
++              for (i = from; i < to; i++)
++                      p[i] = 0xFF;
++      else
++              for (i = from; i < to; i++)
++                      p[i] = random32() % 0x100;
+ }
+-int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                int offset, int len, int dtype)
++int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
++                int offs, int len, int dtype)
+ {
+       int err, failing;
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      failing = do_fail(desc, lnum, 1);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++
++      failing = power_cut_emulated(c, lnum, 1);
+       if (failing)
+               cut_data(buf, len);
+-      err = ubi_leb_write(desc, lnum, buf, offset, len, dtype);
++      err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+       if (err)
+               return err;
+       if (failing)
+-              return -EIO;
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
++int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
+                  int len, int dtype)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 1))
+-              return -EIO;
+-      err = ubi_leb_change(desc, lnum, buf, len, dtype);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 1))
++              return -EROFS;
++      err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 1))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 1))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)
++int dbg_leb_unmap(struct ubifs_info *c, int lnum)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_erase(desc, lnum);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
++      err = ubi_leb_unmap(c->ubi, lnum);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
++int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_unmap(desc, lnum);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
++      err = ubi_leb_map(c->ubi, lnum, dtype);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)
+-{
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      return ubi_is_mapped(desc, lnum);
+-}
++/*
++ * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
++ * contain the stuff specific to particular file-system mounts.
++ */
++static struct dentry *dfs_rootdir;
+-int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
++static int dfs_file_open(struct inode *inode, struct file *file)
+ {
+-      int err;
+-
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_map(desc, lnum, dtype);
+-      if (err)
+-              return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      return 0;
++      file->private_data = inode->i_private;
++      return nonseekable_open(inode, file);
+ }
+ /**
+- * ubifs_debugging_init - initialize UBIFS debugging.
+- * @c: UBIFS file-system description object
++ * provide_user_output - provide output to the user reading a debugfs file.
++ * @val: boolean value for the answer
++ * @u: the buffer to store the answer at
++ * @count: size of the buffer
++ * @ppos: position in the @u output buffer
+  *
+- * This function initializes debugging-related data for the file system.
+- * Returns zero in case of success and a negative error code in case of
++ * This is a simple helper function which stores @val boolean value in the user
++ * buffer when the user reads one of UBIFS debugfs files. Returns amount of
++ * bytes written to @u in case of success and a negative error code in case of
+  * failure.
+  */
+-int ubifs_debugging_init(struct ubifs_info *c)
++static int provide_user_output(int val, char __user *u, size_t count,
++                             loff_t *ppos)
+ {
+-      c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
+-      if (!c->dbg)
+-              return -ENOMEM;
+-
+-      c->dbg->buf = vmalloc(c->leb_size);
+-      if (!c->dbg->buf)
+-              goto out;
++      char buf[3];
+-      failure_mode_init(c);
+-      return 0;
++      if (val)
++              buf[0] = '1';
++      else
++              buf[0] = '0';
++      buf[1] = '\n';
++      buf[2] = 0x00;
+-out:
+-      kfree(c->dbg);
+-      return -ENOMEM;
++      return simple_read_from_buffer(u, count, ppos, buf, 2);
+ }
+-/**
+- * ubifs_debugging_exit - free debugging data.
+- * @c: UBIFS file-system description object
+- */
+-void ubifs_debugging_exit(struct ubifs_info *c)
++static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
++                           loff_t *ppos)
+ {
+-      failure_mode_exit(c);
+-      vfree(c->dbg->buf);
+-      kfree(c->dbg);
+-}
++      struct dentry *dent = file->f_path.dentry;
++      struct ubifs_info *c = file->private_data;
++      struct ubifs_debug_info *d = c->dbg;
++      int val;
++
++      if (dent == d->dfs_chk_gen)
++              val = d->chk_gen;
++      else if (dent == d->dfs_chk_index)
++              val = d->chk_index;
++      else if (dent == d->dfs_chk_orph)
++              val = d->chk_orph;
++      else if (dent == d->dfs_chk_lprops)
++              val = d->chk_lprops;
++      else if (dent == d->dfs_chk_fs)
++              val = d->chk_fs;
++      else if (dent == d->dfs_tst_rcvry)
++              val = d->tst_rcvry;
++      else
++              return -EINVAL;
+-/*
+- * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
+- * contain the stuff specific to particular file-system mounts.
+- */
+-static struct dentry *dfs_rootdir;
++      return provide_user_output(val, u, count, ppos);
++}
+ /**
+- * dbg_debugfs_init - initialize debugfs file-system.
++ * interpret_user_input - interpret user debugfs file input.
++ * @u: user-provided buffer with the input
++ * @count: buffer size
+  *
+- * UBIFS uses debugfs file-system to expose various debugging knobs to
+- * user-space. This function creates "ubifs" directory in the debugfs
+- * file-system. Returns zero in case of success and a negative error code in
+- * case of failure.
++ * This is a helper function which interpret user input to a boolean UBIFS
++ * debugfs file. Returns %0 or %1 in case of success and a negative error code
++ * in case of failure.
+  */
+-int dbg_debugfs_init(void)
++static int interpret_user_input(const char __user *u, size_t count)
+ {
+-      dfs_rootdir = debugfs_create_dir("ubifs", NULL);
+-      if (IS_ERR(dfs_rootdir)) {
+-              int err = PTR_ERR(dfs_rootdir);
+-              ubifs_err("cannot create \"ubifs\" debugfs directory, "
+-                        "error %d\n", err);
+-              return err;
+-      }
++      size_t buf_size;
++      char buf[8];
+-      return 0;
+-}
++      buf_size = min_t(size_t, count, (sizeof(buf) - 1));
++      if (copy_from_user(buf, u, buf_size))
++              return -EFAULT;
+-/**
+- * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
+- */
+-void dbg_debugfs_exit(void)
+-{
+-      debugfs_remove(dfs_rootdir);
+-}
++      if (buf[0] == '1')
++              return 1;
++      else if (buf[0] == '0')
++              return 0;
+-static int open_debugfs_file(struct inode *inode, struct file *file)
+-{
+-      file->private_data = inode->i_private;
+-      return 0;
++      return -EINVAL;
+ }
+-static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
+-                                size_t count, loff_t *ppos)
++static ssize_t dfs_file_write(struct file *file, const char __user *u,
++                            size_t count, loff_t *ppos)
+ {
+       struct ubifs_info *c = file->private_data;
+       struct ubifs_debug_info *d = c->dbg;
++      struct dentry *dent = file->f_path.dentry;
++      int val;
+-      if (file->f_path.dentry == d->dfs_dump_lprops)
++      /*
++       * TODO: this is racy - the file-system might have already been
++       * unmounted and we'd oops in this case. The plan is to fix it with
++       * help of 'iterate_supers_type()' which we should have in v3.0: when
++       * a debugfs opened, we rember FS's UUID in file->private_data. Then
++       * whenever we access the FS via a debugfs file, we iterate all UBIFS
++       * superblocks and fine the one with the same UUID, and take the
++       * locking right.
++       *
++       * The other way to go suggested by Al Viro is to create a separate
++       * 'ubifs-debug' file-system instead.
++       */
++      if (file->f_path.dentry == d->dfs_dump_lprops) {
+               dbg_dump_lprops(c);
+-      else if (file->f_path.dentry == d->dfs_dump_budg) {
+-              spin_lock(&c->space_lock);
+-              dbg_dump_budg(c);
+-              spin_unlock(&c->space_lock);
+-      } else if (file->f_path.dentry == d->dfs_dump_tnc) {
++              return count;
++      }
++      if (file->f_path.dentry == d->dfs_dump_budg) {
++              dbg_dump_budg(c, &c->bi);
++              return count;
++      }
++      if (file->f_path.dentry == d->dfs_dump_tnc) {
+               mutex_lock(&c->tnc_mutex);
+               dbg_dump_tnc(c);
+               mutex_unlock(&c->tnc_mutex);
+-      } else
++              return count;
++      }
++
++      val = interpret_user_input(u, count);
++      if (val < 0)
++              return val;
++
++      if (dent == d->dfs_chk_gen)
++              d->chk_gen = val;
++      else if (dent == d->dfs_chk_index)
++              d->chk_index = val;
++      else if (dent == d->dfs_chk_orph)
++              d->chk_orph = val;
++      else if (dent == d->dfs_chk_lprops)
++              d->chk_lprops = val;
++      else if (dent == d->dfs_chk_fs)
++              d->chk_fs = val;
++      else if (dent == d->dfs_tst_rcvry)
++              d->tst_rcvry = val;
++      else
+               return -EINVAL;
+-      *ppos += count;
+       return count;
+ }
+ static const struct file_operations dfs_fops = {
+-      .open = open_debugfs_file,
+-      .write = write_debugfs_file,
++      .open = dfs_file_open,
++      .read = dfs_file_read,
++      .write = dfs_file_write,
+       .owner = THIS_MODULE,
+-      .llseek = default_llseek,
++      .llseek = no_llseek,
+ };
+ /**
+@@ -2798,46 +2915,94 @@ static const struct file_operations dfs_fops = {
+  */
+ int dbg_debugfs_init_fs(struct ubifs_info *c)
+ {
+-      int err;
++      int err, n;
+       const char *fname;
+       struct dentry *dent;
+       struct ubifs_debug_info *d = c->dbg;
+-      sprintf(d->dfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
+-      d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir);
+-      if (IS_ERR(d->dfs_dir)) {
+-              err = PTR_ERR(d->dfs_dir);
+-              ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+-                        d->dfs_dir_name, err);
++      n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
++                   c->vi.ubi_num, c->vi.vol_id);
++      if (n == UBIFS_DFS_DIR_LEN) {
++              /* The array size is too small */
++              fname = UBIFS_DFS_DIR_NAME;
++              dent = ERR_PTR(-EINVAL);
+               goto out;
+       }
++      fname = d->dfs_dir_name;
++      dent = debugfs_create_dir(fname, dfs_rootdir);
++      if (IS_ERR_OR_NULL(dent))
++              goto out;
++      d->dfs_dir = dent;
++
+       fname = "dump_lprops";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_lprops = dent;
+       fname = "dump_budg";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_budg = dent;
+       fname = "dump_tnc";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_tnc = dent;
++      fname = "chk_general";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_gen = dent;
++
++      fname = "chk_index";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_index = dent;
++
++      fname = "chk_orphans";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_orph = dent;
++
++      fname = "chk_lprops";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_lprops = dent;
++
++      fname = "chk_fs";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_fs = dent;
++
++      fname = "tst_recovery";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_tst_rcvry = dent;
++
+       return 0;
+ out_remove:
+-      err = PTR_ERR(dent);
+-      ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+-                fname, err);
+       debugfs_remove_recursive(d->dfs_dir);
+ out:
++      err = dent ? PTR_ERR(dent) : -ENODEV;
++      ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
++                fname, err);
+       return err;
+ }
+@@ -2850,4 +3015,179 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c)
+       debugfs_remove_recursive(c->dbg->dfs_dir);
+ }
++struct ubifs_global_debug_info ubifs_dbg;
++
++static struct dentry *dfs_chk_gen;
++static struct dentry *dfs_chk_index;
++static struct dentry *dfs_chk_orph;
++static struct dentry *dfs_chk_lprops;
++static struct dentry *dfs_chk_fs;
++static struct dentry *dfs_tst_rcvry;
++
++static ssize_t dfs_global_file_read(struct file *file, char __user *u,
++                                  size_t count, loff_t *ppos)
++{
++      struct dentry *dent = file->f_path.dentry;
++      int val;
++
++      if (dent == dfs_chk_gen)
++              val = ubifs_dbg.chk_gen;
++      else if (dent == dfs_chk_index)
++              val = ubifs_dbg.chk_index;
++      else if (dent == dfs_chk_orph)
++              val = ubifs_dbg.chk_orph;
++      else if (dent == dfs_chk_lprops)
++              val = ubifs_dbg.chk_lprops;
++      else if (dent == dfs_chk_fs)
++              val = ubifs_dbg.chk_fs;
++      else if (dent == dfs_tst_rcvry)
++              val = ubifs_dbg.tst_rcvry;
++      else
++              return -EINVAL;
++
++      return provide_user_output(val, u, count, ppos);
++}
++
++static ssize_t dfs_global_file_write(struct file *file, const char __user *u,
++                                   size_t count, loff_t *ppos)
++{
++      struct dentry *dent = file->f_path.dentry;
++      int val;
++
++      val = interpret_user_input(u, count);
++      if (val < 0)
++              return val;
++
++      if (dent == dfs_chk_gen)
++              ubifs_dbg.chk_gen = val;
++      else if (dent == dfs_chk_index)
++              ubifs_dbg.chk_index = val;
++      else if (dent == dfs_chk_orph)
++              ubifs_dbg.chk_orph = val;
++      else if (dent == dfs_chk_lprops)
++              ubifs_dbg.chk_lprops = val;
++      else if (dent == dfs_chk_fs)
++              ubifs_dbg.chk_fs = val;
++      else if (dent == dfs_tst_rcvry)
++              ubifs_dbg.tst_rcvry = val;
++      else
++              return -EINVAL;
++
++      return count;
++}
++
++static const struct file_operations dfs_global_fops = {
++      .read = dfs_global_file_read,
++      .write = dfs_global_file_write,
++      .owner = THIS_MODULE,
++      .llseek = no_llseek,
++};
++
++/**
++ * dbg_debugfs_init - initialize debugfs file-system.
++ *
++ * UBIFS uses debugfs file-system to expose various debugging knobs to
++ * user-space. This function creates "ubifs" directory in the debugfs
++ * file-system. Returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++int dbg_debugfs_init(void)
++{
++      int err;
++      const char *fname;
++      struct dentry *dent;
++
++      fname = "ubifs";
++      dent = debugfs_create_dir(fname, NULL);
++      if (IS_ERR_OR_NULL(dent))
++              goto out;
++      dfs_rootdir = dent;
++
++      fname = "chk_general";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_gen = dent;
++
++      fname = "chk_index";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_index = dent;
++
++      fname = "chk_orphans";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_orph = dent;
++
++      fname = "chk_lprops";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_lprops = dent;
++
++      fname = "chk_fs";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_fs = dent;
++
++      fname = "tst_recovery";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_tst_rcvry = dent;
++
++      return 0;
++
++out_remove:
++      debugfs_remove_recursive(dfs_rootdir);
++out:
++      err = dent ? PTR_ERR(dent) : -ENODEV;
++      ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
++                fname, err);
++      return err;
++}
++
++/**
++ * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
++ */
++void dbg_debugfs_exit(void)
++{
++      debugfs_remove_recursive(dfs_rootdir);
++}
++
++/**
++ * ubifs_debugging_init - initialize UBIFS debugging.
++ * @c: UBIFS file-system description object
++ *
++ * This function initializes debugging-related data for the file system.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubifs_debugging_init(struct ubifs_info *c)
++{
++      c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
++      if (!c->dbg)
++              return -ENOMEM;
++
++      return 0;
++}
++
++/**
++ * ubifs_debugging_exit - free debugging data.
++ * @c: UBIFS file-system description object
++ */
++void ubifs_debugging_exit(struct ubifs_info *c)
++{
++      kfree(c->dbg);
++}
++
+ #endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
+index 555ba13..13917ce 100644
+--- a/fs/ubifs/debug.h
++++ b/fs/ubifs/debug.h
+@@ -31,17 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
+ #ifdef CONFIG_UBIFS_FS_DEBUG
++/*
++ * The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
++ * + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
++ */
++#define UBIFS_DFS_DIR_NAME "ubi%d_%d"
++#define UBIFS_DFS_DIR_LEN  (3 + 1 + 2*2 + 1)
++
+ /**
+  * ubifs_debug_info - per-FS debugging information.
+- * @buf: a buffer of LEB size, used for various purposes
+  * @old_zroot: old index root - used by 'dbg_check_old_index()'
+  * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
+  * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
+- * @failure_mode: failure mode for recovery testing
+- * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
+- * @fail_timeout: time in jiffies when delay of failure mode expires
+- * @fail_cnt: current number of calls to failure mode I/O functions
+- * @fail_cnt_max: number of calls by which to delay failure mode
++ *
++ * @pc_happened: non-zero if an emulated power cut happened
++ * @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
++ * @pc_timeout: time in jiffies when delay of failure mode expires
++ * @pc_cnt: current number of calls to failure mode I/O functions
++ * @pc_cnt_max: number of calls by which to delay failure mode
++ *
+  * @chk_lpt_sz: used by LPT tree size checker
+  * @chk_lpt_sz2: used by LPT tree size checker
+  * @chk_lpt_wastage: used by LPT tree size checker
+@@ -51,24 +59,40 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
+  * @new_ihead_offs: used by debugging to check @c->ihead_offs
+  *
+  * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
+- * @saved_free: saved free space (used by 'dbg_save_space_info()')
++ * @saved_bi: saved budgeting information
++ * @saved_free: saved amount of free space
++ * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
++ *
++ * @chk_gen: if general extra checks are enabled
++ * @chk_index: if index xtra checks are enabled
++ * @chk_orph: if orphans extra checks are enabled
++ * @chk_lprops: if lprops extra checks are enabled
++ * @chk_fs: if UBIFS contents extra checks are enabled
++ * @tst_rcvry: if UBIFS recovery testing mode enabled
+  *
+- * dfs_dir_name: name of debugfs directory containing this file-system's files
+- * dfs_dir: direntry object of the file-system debugfs directory
+- * dfs_dump_lprops: "dump lprops" debugfs knob
+- * dfs_dump_budg: "dump budgeting information" debugfs knob
+- * dfs_dump_tnc: "dump TNC" debugfs knob
++ * @dfs_dir_name: name of debugfs directory containing this file-system's files
++ * @dfs_dir: direntry object of the file-system debugfs directory
++ * @dfs_dump_lprops: "dump lprops" debugfs knob
++ * @dfs_dump_budg: "dump budgeting information" debugfs knob
++ * @dfs_dump_tnc: "dump TNC" debugfs knob
++ * @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks
++ * @dfs_chk_index: debugfs knob to enable UBIFS index extra checks
++ * @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks
++ * @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
++ * @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
++ * @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
+  */
+ struct ubifs_debug_info {
+-      void *buf;
+       struct ubifs_zbranch old_zroot;
+       int old_zroot_level;
+       unsigned long long old_zroot_sqnum;
+-      int failure_mode;
+-      int fail_delay;
+-      unsigned long fail_timeout;
+-      unsigned int fail_cnt;
+-      unsigned int fail_cnt_max;
++
++      int pc_happened;
++      int pc_delay;
++      unsigned long pc_timeout;
++      unsigned int pc_cnt;
++      unsigned int pc_cnt_max;
++
+       long long chk_lpt_sz;
+       long long chk_lpt_sz2;
+       long long chk_lpt_wastage;
+@@ -78,13 +102,47 @@ struct ubifs_debug_info {
+       int new_ihead_offs;
+       struct ubifs_lp_stats saved_lst;
++      struct ubifs_budg_info saved_bi;
+       long long saved_free;
++      int saved_idx_gc_cnt;
++
++      unsigned int chk_gen:1;
++      unsigned int chk_index:1;
++      unsigned int chk_orph:1;
++      unsigned int chk_lprops:1;
++      unsigned int chk_fs:1;
++      unsigned int tst_rcvry:1;
+-      char dfs_dir_name[100];
++      char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1];
+       struct dentry *dfs_dir;
+       struct dentry *dfs_dump_lprops;
+       struct dentry *dfs_dump_budg;
+       struct dentry *dfs_dump_tnc;
++      struct dentry *dfs_chk_gen;
++      struct dentry *dfs_chk_index;
++      struct dentry *dfs_chk_orph;
++      struct dentry *dfs_chk_lprops;
++      struct dentry *dfs_chk_fs;
++      struct dentry *dfs_tst_rcvry;
++};
++
++/**
++ * ubifs_global_debug_info - global (not per-FS) UBIFS debugging information.
++ *
++ * @chk_gen: if general extra checks are enabled
++ * @chk_index: if index xtra checks are enabled
++ * @chk_orph: if orphans extra checks are enabled
++ * @chk_lprops: if lprops extra checks are enabled
++ * @chk_fs: if UBIFS contents extra checks are enabled
++ * @tst_rcvry: if UBIFS recovery testing mode enabled
++ */
++struct ubifs_global_debug_info {
++      unsigned int chk_gen:1;
++      unsigned int chk_index:1;
++      unsigned int chk_orph:1;
++      unsigned int chk_lprops:1;
++      unsigned int chk_fs:1;
++      unsigned int tst_rcvry:1;
+ };
+ #define ubifs_assert(expr) do {                                                \
+@@ -103,173 +161,90 @@ struct ubifs_debug_info {
+       }                                                                      \
+ } while (0)
+-#define dbg_dump_stack() do {                                                  \
+-      if (!dbg_failure_mode)                                                 \
+-              dump_stack();                                                  \
+-} while (0)
+-
+-/* Generic debugging messages */
+-#define dbg_msg(fmt, ...) do {                                                 \
+-      spin_lock(&dbg_lock);                                                  \
+-      printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
+-             __func__, ##__VA_ARGS__);                                       \
+-      spin_unlock(&dbg_lock);                                                \
+-} while (0)
+-
+-#define dbg_do_msg(typ, fmt, ...) do {                                         \
+-      if (ubifs_msg_flags & typ)                                             \
+-              dbg_msg(fmt, ##__VA_ARGS__);                                   \
+-} while (0)
++#define dbg_dump_stack() dump_stack()
+ #define dbg_err(fmt, ...) do {                                                 \
+-      spin_lock(&dbg_lock);                                                  \
+       ubifs_err(fmt, ##__VA_ARGS__);                                         \
+-      spin_unlock(&dbg_lock);                                                \
+ } while (0)
+-const char *dbg_key_str0(const struct ubifs_info *c,
+-                       const union ubifs_key *key);
+-const char *dbg_key_str1(const struct ubifs_info *c,
+-                       const union ubifs_key *key);
++#define ubifs_dbg_msg(type, fmt, ...) \
++      pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
+-/*
+- * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
+- * macros.
+- */
+-#define DBGKEY(key) dbg_key_str0(c, (key))
+-#define DBGKEY1(key) dbg_key_str1(c, (key))
++#define DBG_KEY_BUF_LEN 32
++#define ubifs_dbg_msg_key(type, key, fmt, ...) do {                            \
++      char __tmp_key_buf[DBG_KEY_BUF_LEN];                                   \
++      pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__,             \
++               dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN));    \
++} while (0)
+-/* General messages */
+-#define dbg_gen(fmt, ...)   dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
++/* Just a debugging messages not related to any specific UBIFS subsystem */
++#define dbg_msg(fmt, ...)                                                      \
++      printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
++             __func__, ##__VA_ARGS__)
++/* General messages */
++#define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
+ /* Additional journal messages */
+-#define dbg_jnl(fmt, ...)   dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
+-
++#define dbg_jnl(fmt, ...)   ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__)
++#define dbg_jnlk(key, fmt, ...) \
++      ubifs_dbg_msg_key("jnl", key, fmt, ##__VA_ARGS__)
+ /* Additional TNC messages */
+-#define dbg_tnc(fmt, ...)   dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
+-
++#define dbg_tnc(fmt, ...)   ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__)
++#define dbg_tnck(key, fmt, ...) \
++      ubifs_dbg_msg_key("tnc", key, fmt, ##__VA_ARGS__)
+ /* Additional lprops messages */
+-#define dbg_lp(fmt, ...)    dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
+-
++#define dbg_lp(fmt, ...)    ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__)
+ /* Additional LEB find messages */
+-#define dbg_find(fmt, ...)  dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
+-
++#define dbg_find(fmt, ...)  ubifs_dbg_msg("find", fmt, ##__VA_ARGS__)
+ /* Additional mount messages */
+-#define dbg_mnt(fmt, ...)   dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
+-
++#define dbg_mnt(fmt, ...)   ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__)
++#define dbg_mntk(key, fmt, ...) \
++      ubifs_dbg_msg_key("mnt", key, fmt, ##__VA_ARGS__)
+ /* Additional I/O messages */
+-#define dbg_io(fmt, ...)    dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
+-
++#define dbg_io(fmt, ...)    ubifs_dbg_msg("io", fmt, ##__VA_ARGS__)
+ /* Additional commit messages */
+-#define dbg_cmt(fmt, ...)   dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
+-
++#define dbg_cmt(fmt, ...)   ubifs_dbg_msg("cmt", fmt, ##__VA_ARGS__)
+ /* Additional budgeting messages */
+-#define dbg_budg(fmt, ...)  dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
+-
++#define dbg_budg(fmt, ...)  ubifs_dbg_msg("budg", fmt, ##__VA_ARGS__)
+ /* Additional log messages */
+-#define dbg_log(fmt, ...)   dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
+-
++#define dbg_log(fmt, ...)   ubifs_dbg_msg("log", fmt, ##__VA_ARGS__)
+ /* Additional gc messages */
+-#define dbg_gc(fmt, ...)    dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
+-
++#define dbg_gc(fmt, ...)    ubifs_dbg_msg("gc", fmt, ##__VA_ARGS__)
+ /* Additional scan messages */
+-#define dbg_scan(fmt, ...)  dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
+-
++#define dbg_scan(fmt, ...)  ubifs_dbg_msg("scan", fmt, ##__VA_ARGS__)
+ /* Additional recovery messages */
+-#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
++#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
+-/*
+- * Debugging message type flags (must match msg_type_names in debug.c).
+- *
+- * UBIFS_MSG_GEN: general messages
+- * UBIFS_MSG_JNL: journal messages
+- * UBIFS_MSG_MNT: mount messages
+- * UBIFS_MSG_CMT: commit messages
+- * UBIFS_MSG_FIND: LEB find messages
+- * UBIFS_MSG_BUDG: budgeting messages
+- * UBIFS_MSG_GC: garbage collection messages
+- * UBIFS_MSG_TNC: TNC messages
+- * UBIFS_MSG_LP: lprops messages
+- * UBIFS_MSG_IO: I/O messages
+- * UBIFS_MSG_LOG: log messages
+- * UBIFS_MSG_SCAN: scan messages
+- * UBIFS_MSG_RCVRY: recovery messages
+- */
+-enum {
+-      UBIFS_MSG_GEN   = 0x1,
+-      UBIFS_MSG_JNL   = 0x2,
+-      UBIFS_MSG_MNT   = 0x4,
+-      UBIFS_MSG_CMT   = 0x8,
+-      UBIFS_MSG_FIND  = 0x10,
+-      UBIFS_MSG_BUDG  = 0x20,
+-      UBIFS_MSG_GC    = 0x40,
+-      UBIFS_MSG_TNC   = 0x80,
+-      UBIFS_MSG_LP    = 0x100,
+-      UBIFS_MSG_IO    = 0x200,
+-      UBIFS_MSG_LOG   = 0x400,
+-      UBIFS_MSG_SCAN  = 0x800,
+-      UBIFS_MSG_RCVRY = 0x1000,
+-};
+-
+-/* Debugging message type flags for each default debug message level */
+-#define UBIFS_MSG_LVL_0 0
+-#define UBIFS_MSG_LVL_1 0x1
+-#define UBIFS_MSG_LVL_2 0x7f
+-#define UBIFS_MSG_LVL_3 0xffff
+-
+-/*
+- * Debugging check flags (must match chk_names in debug.c).
+- *
+- * UBIFS_CHK_GEN: general checks
+- * UBIFS_CHK_TNC: check TNC
+- * UBIFS_CHK_IDX_SZ: check index size
+- * UBIFS_CHK_ORPH: check orphans
+- * UBIFS_CHK_OLD_IDX: check the old index
+- * UBIFS_CHK_LPROPS: check lprops
+- * UBIFS_CHK_FS: check the file-system
+- */
+-enum {
+-      UBIFS_CHK_GEN     = 0x1,
+-      UBIFS_CHK_TNC     = 0x2,
+-      UBIFS_CHK_IDX_SZ  = 0x4,
+-      UBIFS_CHK_ORPH    = 0x8,
+-      UBIFS_CHK_OLD_IDX = 0x10,
+-      UBIFS_CHK_LPROPS  = 0x20,
+-      UBIFS_CHK_FS      = 0x40,
+-};
++extern struct ubifs_global_debug_info ubifs_dbg;
+-/*
+- * Special testing flags (must match tst_names in debug.c).
+- *
+- * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
+- * UBIFS_TST_RCVRY: failure mode for recovery testing
+- */
+-enum {
+-      UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
+-      UBIFS_TST_RCVRY             = 0x4,
+-};
+-
+-#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1
+-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2
+-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3
+-#else
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0
+-#endif
+-
+-#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS
+-#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff
+-#else
+-#define UBIFS_CHK_FLAGS_DEFAULT 0
+-#endif
+-
+-extern spinlock_t dbg_lock;
+-
+-extern unsigned int ubifs_msg_flags;
+-extern unsigned int ubifs_chk_flags;
+-extern unsigned int ubifs_tst_flags;
++static inline int dbg_is_chk_gen(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen);
++}
++static inline int dbg_is_chk_index(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_index || c->dbg->chk_index);
++}
++static inline int dbg_is_chk_orph(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph);
++}
++static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops);
++}
++static inline int dbg_is_chk_fs(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs);
++}
++static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry);
++}
++static inline int dbg_is_power_cut(const struct ubifs_info *c)
++{
++      return !!c->dbg->pc_happened;
++}
+ int ubifs_debugging_init(struct ubifs_info *c);
+ void ubifs_debugging_exit(struct ubifs_info *c);
+@@ -280,17 +255,21 @@ const char *dbg_cstate(int cmt_state);
+ const char *dbg_jhead(int jhead);
+ const char *dbg_get_key_dump(const struct ubifs_info *c,
+                            const union ubifs_key *key);
+-void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
++const char *dbg_snprintf_key(const struct ubifs_info *c,
++                           const union ubifs_key *key, char *buffer, int len);
++void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
+ void dbg_dump_node(const struct ubifs_info *c, const void *node);
+ void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
+                      int offs);
+ void dbg_dump_budget_req(const struct ubifs_budget_req *req);
+ void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
+-void dbg_dump_budg(struct ubifs_info *c);
++void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
+ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
+ void dbg_dump_lprops(struct ubifs_info *c);
+ void dbg_dump_lpt_info(struct ubifs_info *c);
+ void dbg_dump_leb(const struct ubifs_info *c, int lnum);
++void dbg_dump_sleb(const struct ubifs_info *c,
++                 const struct ubifs_scan_leb *sleb, int offs);
+ void dbg_dump_znode(const struct ubifs_info *c,
+                   const struct ubifs_znode *znode);
+ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat);
+@@ -313,14 +292,13 @@ int dbg_check_cats(struct ubifs_info *c);
+ int dbg_check_ltab(struct ubifs_info *c);
+ int dbg_chk_lpt_free_spc(struct ubifs_info *c);
+ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len);
+-int dbg_check_synced_i_size(struct inode *inode);
+-int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
++int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode);
++int dbg_check_dir(struct ubifs_info *c, const struct inode *dir);
+ int dbg_check_tnc(struct ubifs_info *c, int extra);
+ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
+ int dbg_check_filesystem(struct ubifs_info *c);
+ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
+                   int add_pos);
+-int dbg_check_lprops(struct ubifs_info *c);
+ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
+                       int row, int col);
+ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+@@ -328,57 +306,12 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
+ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
+-/* Force the use of in-the-gaps method for testing */
+-
+-#define dbg_force_in_the_gaps_enabled \
+-      (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS)
+-
+-int dbg_force_in_the_gaps(void);
+-
+-/* Failure mode for recovery testing */
+-
+-#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
+-
+-#ifndef UBIFS_DBG_PRESERVE_UBI
+-
+-#define ubi_leb_read   dbg_leb_read
+-#define ubi_leb_write  dbg_leb_write
+-#define ubi_leb_change dbg_leb_change
+-#define ubi_leb_erase  dbg_leb_erase
+-#define ubi_leb_unmap  dbg_leb_unmap
+-#define ubi_is_mapped  dbg_is_mapped
+-#define ubi_leb_map    dbg_leb_map
+-
+-#endif
+-
+-int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+-               int len, int check);
+-int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                int offset, int len, int dtype);
+-int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                 int len, int dtype);
+-int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum);
+-int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum);
+-int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum);
+-int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
+-
+-static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf,
+-                         int offset, int len)
+-{
+-      return dbg_leb_read(desc, lnum, buf, offset, len, 0);
+-}
+-
+-static inline int dbg_write(struct ubi_volume_desc *desc, int lnum,
+-                          const void *buf, int offset, int len)
+-{
+-      return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
+-}
+-
+-static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
+-                                  const void *buf, int len)
+-{
+-      return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
+-}
++int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                int len, int dtype);
++int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                 int dtype);
++int dbg_leb_unmap(struct ubifs_info *c, int lnum);
++int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
+ /* Debugfs-related stuff */
+ int dbg_debugfs_init(void);
+@@ -390,116 +323,158 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
+ /* Use "if (0)" to make compiler check arguments even if debugging is off */
+ #define ubifs_assert(expr)  do {                                               \
+-      if (0 && (expr))                                                       \
++      if (0)                                                                 \
+               printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+                      __func__, __LINE__, current->pid);                      \
+ } while (0)
+-#define dbg_err(fmt, ...)   do {                                               \
+-      if (0)                                                                 \
+-              ubifs_err(fmt, ##__VA_ARGS__);                                 \
++#define dbg_err(fmt, ...)   do {                   \
++      if (0)                                     \
++              ubifs_err(fmt, ##__VA_ARGS__);     \
+ } while (0)
+-#define dbg_msg(fmt, ...) do {                                                 \
+-      if (0)                                                                 \
+-              printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n",         \
+-                     current->pid, __func__, ##__VA_ARGS__);                 \
++#define DBGKEY(key)  ((char *)(key))
++#define DBGKEY1(key) ((char *)(key))
++
++#define ubifs_dbg_msg(fmt, ...) do {               \
++      if (0)                                     \
++              pr_debug(fmt "\n", ##__VA_ARGS__); \
+ } while (0)
+ #define dbg_dump_stack()
+ #define ubifs_assert_cmt_locked(c)
+-#define dbg_gen(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_jnl(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_tnc(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_lp(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_find(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_mnt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_io(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_cmt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_budg(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_log(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_gc(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_scan(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-
+-#define DBGKEY(key)  ((char *)(key))
+-#define DBGKEY1(key) ((char *)(key))
+-
+-static inline int ubifs_debugging_init(struct ubifs_info *c)  { return 0; }
+-static inline void ubifs_debugging_exit(struct ubifs_info *c) {}
+-static inline const char *dbg_ntype(int type)                 { return ""; }
+-static inline const char *dbg_cstate(int cmt_state)           { return ""; }
+-static inline const char *dbg_jhead(int jhead)                        { return ""; }
+-static inline const char *dbg_get_key_dump(const struct ubifs_info *c,
+-                           const union ubifs_key *key)        { return ""; }
+-static inline void dbg_dump_inode(const struct ubifs_info *c,
+-      const struct inode *inode) {}
++#define dbg_msg(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_gen(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_jnl(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_jnlk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_tnc(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_tnck(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_lp(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_find(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_mnt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_mntk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_io(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_cmt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_budg(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_log(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_gc(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_scan(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_rcvry(fmt, ...)     ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++
++static inline int ubifs_debugging_init(struct ubifs_info *c)      { return 0; }
++static inline void ubifs_debugging_exit(struct ubifs_info *c)     { return; }
++static inline const char *dbg_ntype(int type)                     { return ""; }
++static inline const char *dbg_cstate(int cmt_state)               { return ""; }
++static inline const char *dbg_jhead(int jhead)                    { return ""; }
++static inline const char *
++dbg_get_key_dump(const struct ubifs_info *c,
++               const union ubifs_key *key)                      { return ""; }
++static inline const char *
++dbg_snprintf_key(const struct ubifs_info *c,
++               const union ubifs_key *key, char *buffer,
++               int len)                                         { return ""; }
++static inline void dbg_dump_inode(struct ubifs_info *c,
++                                const struct inode *inode)      { return; }
+ static inline void dbg_dump_node(const struct ubifs_info *c,
+-      const void *node)                                       {}
++                               const void *node)                { return; }
+ static inline void dbg_dump_lpt_node(const struct ubifs_info *c,
+-      void *node, int lnum, int offs)                         {}
+-static inline void dbg_dump_budget_req(const struct ubifs_budget_req *req) {}
+-static inline void dbg_dump_lstats(const struct ubifs_lp_stats *lst) {}
+-static inline void dbg_dump_budg(struct ubifs_info *c)                {}
++                                   void *node, int lnum,
++                                   int offs)                    { return; }
++static inline void
++dbg_dump_budget_req(const struct ubifs_budget_req *req)           { return; }
++static inline void
++dbg_dump_lstats(const struct ubifs_lp_stats *lst)                 { return; }
++static inline void
++dbg_dump_budg(struct ubifs_info *c,
++            const struct ubifs_budg_info *bi)                   { return; }
+ static inline void dbg_dump_lprop(const struct ubifs_info *c,
+-      const struct ubifs_lprops *lp)                          {}
+-static inline void dbg_dump_lprops(struct ubifs_info *c)      {}
+-static inline void dbg_dump_lpt_info(struct ubifs_info *c)    {}
+-static inline void dbg_dump_leb(const struct ubifs_info *c, int lnum) {}
+-static inline void dbg_dump_znode(const struct ubifs_info *c,
+-                  const struct ubifs_znode *znode)            {}
++                                const struct ubifs_lprops *lp)  { return; }
++static inline void dbg_dump_lprops(struct ubifs_info *c)          { return; }
++static inline void dbg_dump_lpt_info(struct ubifs_info *c)        { return; }
++static inline void dbg_dump_leb(const struct ubifs_info *c,
++                              int lnum)                         { return; }
++static inline void
++dbg_dump_sleb(const struct ubifs_info *c,
++            const struct ubifs_scan_leb *sleb, int offs)        { return; }
++static inline void
++dbg_dump_znode(const struct ubifs_info *c,
++             const struct ubifs_znode *znode)                   { return; }
+ static inline void dbg_dump_heap(struct ubifs_info *c,
+-      struct ubifs_lpt_heap *heap, int cat)                   {}
++                               struct ubifs_lpt_heap *heap,
++                               int cat)                         { return; }
+ static inline void dbg_dump_pnode(struct ubifs_info *c,
+-      struct ubifs_pnode *pnode, struct ubifs_nnode *parent, int iip) {}
+-static inline void dbg_dump_tnc(struct ubifs_info *c)         {}
+-static inline void dbg_dump_index(struct ubifs_info *c)               {}
+-static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c) {}
++                                struct ubifs_pnode *pnode,
++                                struct ubifs_nnode *parent,
++                                int iip)                        { return; }
++static inline void dbg_dump_tnc(struct ubifs_info *c)             { return; }
++static inline void dbg_dump_index(struct ubifs_info *c)           { return; }
++static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c)  { return; }
+ static inline int dbg_walk_index(struct ubifs_info *c,
+-      dbg_leaf_callback leaf_cb, dbg_znode_callback znode_cb, void *priv)
+-                                                              { return 0; }
+-
+-/* Checking functions */
+-static inline void dbg_save_space_info(struct ubifs_info *c)  {}
+-static inline int dbg_check_space_info(struct ubifs_info *c)  { return 0; }
+-static inline int dbg_check_lprops(struct ubifs_info *c)      { return 0; }
+-static inline int dbg_old_index_check_init(struct ubifs_info *c,
+-      struct ubifs_zbranch *zroot)                            { return 0; }
+-static inline int dbg_check_old_index(struct ubifs_info *c,
+-      struct ubifs_zbranch *zroot)                            { return 0; }
+-static inline int dbg_check_cats(struct ubifs_info *c)                { return 0; }
+-static inline int dbg_check_ltab(struct ubifs_info *c)                { return 0; }
+-static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)  { return 0; }
++                               dbg_leaf_callback leaf_cb,
++                               dbg_znode_callback znode_cb,
++                               void *priv)                      { return 0; }
++static inline void dbg_save_space_info(struct ubifs_info *c)      { return; }
++static inline int dbg_check_space_info(struct ubifs_info *c)      { return 0; }
++static inline int dbg_check_lprops(struct ubifs_info *c)          { return 0; }
++static inline int
++dbg_old_index_check_init(struct ubifs_info *c,
++                       struct ubifs_zbranch *zroot)             { return 0; }
++static inline int
++dbg_check_old_index(struct ubifs_info *c,
++                  struct ubifs_zbranch *zroot)                  { return 0; }
++static inline int dbg_check_cats(struct ubifs_info *c)            { return 0; }
++static inline int dbg_check_ltab(struct ubifs_info *c)            { return 0; }
++static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)      { return 0; }
+ static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
+-      int action, int len)                                    { return 0; }
+-static inline int dbg_check_synced_i_size(struct inode *inode)        { return 0; }
+-static inline int dbg_check_dir_size(struct ubifs_info *c,
+-      const struct inode *dir)                                { return 0; }
+-static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; }
++                               int action, int len)             { return 0; }
++static inline int
++dbg_check_synced_i_size(const struct ubifs_info *c,
++                      struct inode *inode)                      { return 0; }
++static inline int dbg_check_dir(struct ubifs_info *c,
++                              const struct inode *dir)          { return 0; }
++static inline int dbg_check_tnc(struct ubifs_info *c, int extra)  { return 0; }
+ static inline int dbg_check_idx_size(struct ubifs_info *c,
+-      long long idx_size)                                     { return 0; }
+-static inline int dbg_check_filesystem(struct ubifs_info *c)  { return 0; }
++                                   long long idx_size)          { return 0; }
++static inline int dbg_check_filesystem(struct ubifs_info *c)      { return 0; }
+ static inline void dbg_check_heap(struct ubifs_info *c,
+-      struct ubifs_lpt_heap *heap, int cat, int add_pos)      {}
++                                struct ubifs_lpt_heap *heap,
++                                int cat, int add_pos)           { return; }
+ static inline int dbg_check_lpt_nodes(struct ubifs_info *c,
+-      struct ubifs_cnode *cnode, int row, int col)            { return 0; }
++      struct ubifs_cnode *cnode, int row, int col)              { return 0; }
+ static inline int dbg_check_inode_size(struct ubifs_info *c,
+-      const struct inode *inode, loff_t size)                 { return 0; }
+-static inline int dbg_check_data_nodes_order(struct ubifs_info *c,
+-      struct list_head *head)                                 { return 0; }
+-static inline int dbg_check_nondata_nodes_order(struct ubifs_info *c,
+-      struct list_head *head)                                 { return 0; }
+-
+-#define dbg_force_in_the_gaps_enabled                         0
+-static inline int dbg_force_in_the_gaps(void)                 { return 0; }
+-#define dbg_failure_mode                                      0
+-
+-static inline int dbg_debugfs_init(void)                      { return 0; }
+-static inline void dbg_debugfs_exit(void)                     {}
+-static inline int dbg_debugfs_init_fs(struct ubifs_info *c)   { return 0; }
+-static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)   { return 0; }
++                                     const struct inode *inode,
++                                     loff_t size)               { return 0; }
++static inline int
++dbg_check_data_nodes_order(struct ubifs_info *c,
++                         struct list_head *head)                { return 0; }
++static inline int
++dbg_check_nondata_nodes_order(struct ubifs_info *c,
++                            struct list_head *head)             { return 0; }
++
++static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
++                              const void *buf, int offset,
++                              int len, int dtype)               { return 0; }
++static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
++                               const void *buf, int len,
++                               int dtype)                       { return 0; }
++static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum)   { return 0; }
++static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
++                            int dtype)                          { return 0; }
++
++static inline int dbg_is_chk_gen(const struct ubifs_info *c)      { return 0; }
++static inline int dbg_is_chk_index(const struct ubifs_info *c)    { return 0; }
++static inline int dbg_is_chk_orph(const struct ubifs_info *c)     { return 0; }
++static inline int dbg_is_chk_lprops(const struct ubifs_info *c)   { return 0; }
++static inline int dbg_is_chk_fs(const struct ubifs_info *c)       { return 0; }
++static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)    { return 0; }
++static inline int dbg_is_power_cut(const struct ubifs_info *c)    { return 0; }
++
++static inline int dbg_debugfs_init(void)                          { return 0; }
++static inline void dbg_debugfs_exit(void)                         { return; }
++static inline int dbg_debugfs_init_fs(struct ubifs_info *c)       { return 0; }
++static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)       { return 0; }
+ #endif /* !CONFIG_UBIFS_FS_DEBUG */
+ #endif /* !__UBIFS_DEBUG_H__ */
+diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
+index 14f64b6..9c5e3c5 100644
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -102,7 +102,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+        * UBIFS has to fully control "clean <-> dirty" transitions of inodes
+        * to make budgeting work.
+        */
+-      inode->i_flags |= (S_NOCMTIME);
++      inode->i_flags |= S_NOCMTIME;
+       inode_init_owner(inode, dir, mode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime =
+@@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+-static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
++static int dbg_check_name(const struct ubifs_info *c,
++                        const struct ubifs_dent_node *dent,
++                        const struct qstr *nm)
+ {
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (le16_to_cpu(dent->nlen) != nm->len)
+               return -EINVAL;
+@@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
+ #else
+-#define dbg_check_name(dent, nm) 0
++#define dbg_check_name(c, dent, nm) 0
+ #endif
+@@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
+               goto out;
+       }
+-      if (dbg_check_name(dent, &dentry->d_name)) {
++      if (dbg_check_name(c, dent, &dentry->d_name)) {
+               err = -EINVAL;
+               goto out;
+       }
+@@ -540,7 +542,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
+        if (inode->i_nlink == 0)
+                return -ENOENT;
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -595,7 +597,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
+               inode->i_nlink, dir->i_ino);
+       ubifs_assert(mutex_is_locked(&dir->i_mutex));
+       ubifs_assert(mutex_is_locked(&inode->i_mutex));
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -621,7 +623,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
+               ubifs_release_budget(c, &req);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return 0;
+@@ -711,7 +713,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
+               ubifs_release_budget(c, &req);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return 0;
+diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
+index d77db7e..7cf738a 100644
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -212,7 +212,7 @@ static void release_new_page_budget(struct ubifs_info *c)
+  */
+ static void release_existing_page_budget(struct ubifs_info *c)
+ {
+-      struct ubifs_budget_req req = { .dd_growth = c->page_budget};
++      struct ubifs_budget_req req = { .dd_growth = c->bi.page_budget};
+       ubifs_release_budget(c, &req);
+ }
+@@ -448,10 +448,12 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
+               if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) {
+                       /*
+                        * We change whole page so no need to load it. But we
+-                       * have to set the @PG_checked flag to make the further
+-                       * code know that the page is new. This might be not
+-                       * true, but it is better to budget more than to read
+-                       * the page from the media.
++                       * do not know whether this page exists on the media or
++                       * not, so we assume the latter because it requires
++                       * larger budget. The assumption is that it is better
++                       * to budget a bit more than to read the page from the
++                       * media. Thus, we are setting the @PG_checked flag
++                       * here.
+                        */
+                       SetPageChecked(page);
+                       skipped_read = 1;
+@@ -559,6 +561,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping,
+               dbg_gen("copied %d instead of %d, read page and repeat",
+                       copied, len);
+               cancel_budget(c, page, ui, appending);
++              ClearPageChecked(page);
+               /*
+                * Return 0 to force VFS to repeat the whole operation, or the
+@@ -968,11 +971,11 @@ static int do_writepage(struct page *page, int len)
+  * the page locked, and it locks @ui_mutex. However, write-back does take inode
+  * @i_mutex, which means other VFS operations may be run on this inode at the
+  * same time. And the problematic one is truncation to smaller size, from where
+- * we have to call 'truncate_setsize()', which first changes @inode->i_size, then
+- * drops the truncated pages. And while dropping the pages, it takes the page
+- * lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' with
+- * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
+- * means that @inode->i_size is changed while @ui_mutex is unlocked.
++ * we have to call 'truncate_setsize()', which first changes @inode->i_size,
++ * then drops the truncated pages. And while dropping the pages, it takes the
++ * page lock. This means that 'do_truncation()' cannot call 'truncate_setsize()'
++ * with @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'.
++ * This means that @inode->i_size is changed while @ui_mutex is unlocked.
+  *
+  * XXX(truncate): with the new truncate sequence this is not true anymore,
+  * and the calls to truncate_setsize can be move around freely.  They should
+@@ -1186,7 +1189,7 @@ out_budg:
+       if (budgeted)
+               ubifs_release_budget(c, &req);
+       else {
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return err;
+@@ -1260,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
+       if (err)
+               return err;
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -1309,6 +1312,13 @@ int ubifs_fsync(struct file *file, int datasync)
+       dbg_gen("syncing inode %lu", inode->i_ino);
++      if (c->ro_mount)
++              /*
++               * For some really strange reasons VFS does not filter out
++               * 'fsync()' for R/O mounted file-systems as per 2.6.39.
++               */
++              return 0;
++
+       /*
+        * VFS has already synchronized dirty pages for this inode. Synchronize
+        * the inode unless this is a 'datasync()' call.
+@@ -1426,10 +1436,11 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
+ }
+ /*
+- * mmap()d file has taken write protection fault and is being made
+- * writable. UBIFS must ensure page is budgeted for.
++ * mmap()d file has taken write protection fault and is being made writable.
++ * UBIFS must ensure page is budgeted for.
+  */
+-static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
++static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma,
++                               struct vm_fault *vmf)
+ {
+       struct page *page = vmf->page;
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+@@ -1530,7 +1541,6 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+       int err;
+-      /* 'generic_file_mmap()' takes care of NOMMU case */
+       err = generic_file_mmap(file, vma);
+       if (err)
+               return err;
+diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
+index 1d54383..2559d17 100644
+--- a/fs/ubifs/find.c
++++ b/fs/ubifs/find.c
+@@ -252,8 +252,8 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+                * But if the index takes fewer LEBs than it is reserved for it,
+                * this function must avoid picking those reserved LEBs.
+                */
+-              if (c->min_idx_lebs >= c->lst.idx_lebs) {
+-                      rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++              if (c->bi.min_idx_lebs >= c->lst.idx_lebs) {
++                      rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
+                       exclude_index = 1;
+               }
+               spin_unlock(&c->space_lock);
+@@ -276,7 +276,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+                       pick_free = 0;
+       } else {
+               spin_lock(&c->space_lock);
+-              exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs);
++              exclude_index = (c->bi.min_idx_lebs >= c->lst.idx_lebs);
+               spin_unlock(&c->space_lock);
+       }
+@@ -501,8 +501,8 @@ int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *offs,
+       /* Check if there are enough empty LEBs for commit */
+       spin_lock(&c->space_lock);
+-      if (c->min_idx_lebs > c->lst.idx_lebs)
+-              rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++      if (c->bi.min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
+       else
+               rsvd_idx_lebs = 0;
+       lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
+index 151f108..ded29f6 100644
+--- a/fs/ubifs/gc.c
++++ b/fs/ubifs/gc.c
+@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c)
+       if (err)
+               return err;
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (err)
++              return err;
++
+       err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
+       if (err)
+               return err;
+@@ -118,7 +122,7 @@ static int switch_gc_head(struct ubifs_info *c)
+  * This function compares data nodes @a and @b. Returns %1 if @a has greater
+  * inode or block number, and %-1 otherwise.
+  */
+-int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
++static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+ {
+       ino_t inuma, inumb;
+       struct ubifs_info *c = priv;
+@@ -161,7 +165,8 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+  * first and sorted by length in descending order. Directory entry nodes go
+  * after inode nodes and are sorted in ascending hash valuer order.
+  */
+-int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
++static int nondata_nodes_cmp(void *priv, struct list_head *a,
++                           struct list_head *b)
+ {
+       ino_t inuma, inumb;
+       struct ubifs_info *c = priv;
+@@ -473,6 +478,37 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
+       ubifs_assert(c->gc_lnum != lnum);
+       ubifs_assert(wbuf->lnum != lnum);
++      if (lp->free + lp->dirty == c->leb_size) {
++              /* Special case - a free LEB  */
++              dbg_gc("LEB %d is free, return it", lp->lnum);
++              ubifs_assert(!(lp->flags & LPROPS_INDEX));
++
++              if (lp->free != c->leb_size) {
++                      /*
++                       * Write buffers must be sync'd before unmapping
++                       * freeable LEBs, because one of them may contain data
++                       * which obsoletes something in 'lp->pnum'.
++                       */
++                      err = gc_sync_wbufs(c);
++                      if (err)
++                              return err;
++                      err = ubifs_change_one_lp(c, lp->lnum, c->leb_size,
++                                                0, 0, 0, 0);
++                      if (err)
++                              return err;
++              }
++              err = ubifs_leb_unmap(c, lp->lnum);
++              if (err)
++                      return err;
++
++              if (c->gc_lnum == -1) {
++                      c->gc_lnum = lnum;
++                      return LEB_RETAINED;
++              }
++
++              return LEB_FREED;
++      }
++
+       /*
+        * We scan the entire LEB even though we only really need to scan up to
+        * (c->leb_size - lp->free).
+@@ -682,37 +718,6 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
+                      "(min. space %d)", lp.lnum, lp.free, lp.dirty,
+                      lp.free + lp.dirty, min_space);
+-              if (lp.free + lp.dirty == c->leb_size) {
+-                      /* An empty LEB was returned */
+-                      dbg_gc("LEB %d is free, return it", lp.lnum);
+-                      /*
+-                       * ubifs_find_dirty_leb() doesn't return freeable index
+-                       * LEBs.
+-                       */
+-                      ubifs_assert(!(lp.flags & LPROPS_INDEX));
+-                      if (lp.free != c->leb_size) {
+-                              /*
+-                               * Write buffers must be sync'd before
+-                               * unmapping freeable LEBs, because one of them
+-                               * may contain data which obsoletes something
+-                               * in 'lp.pnum'.
+-                               */
+-                              ret = gc_sync_wbufs(c);
+-                              if (ret)
+-                                      goto out;
+-                              ret = ubifs_change_one_lp(c, lp.lnum,
+-                                                        c->leb_size, 0, 0, 0,
+-                                                        0);
+-                              if (ret)
+-                                      goto out;
+-                      }
+-                      ret = ubifs_leb_unmap(c, lp.lnum);
+-                      if (ret)
+-                              goto out;
+-                      ret = lp.lnum;
+-                      break;
+-              }
+-
+               space_before = c->leb_size - wbuf->offs - wbuf->used;
+               if (wbuf->lnum == -1)
+                       space_before = 0;
+diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
+index d821731..9228950 100644
+--- a/fs/ubifs/io.c
++++ b/fs/ubifs/io.c
+@@ -31,6 +31,26 @@
+  * buffer is full or when it is not used for some time (by timer). This is
+  * similar to the mechanism is used by JFFS2.
+  *
++ * UBIFS distinguishes between minimum write size (@c->min_io_size) and maximum
++ * write size (@c->max_write_size). The latter is the maximum amount of bytes
++ * the underlying flash is able to program at a time, and writing in
++ * @c->max_write_size units should presumably be faster. Obviously,
++ * @c->min_io_size <= @c->max_write_size. Write-buffers are of
++ * @c->max_write_size bytes in size for maximum performance. However, when a
++ * write-buffer is flushed, only the portion of it (aligned to @c->min_io_size
++ * boundary) which contains data is written, not the whole write-buffer,
++ * because this is more space-efficient.
++ *
++ * This optimization adds few complications to the code. Indeed, on the one
++ * hand, we want to write in optimal @c->max_write_size bytes chunks, which
++ * also means aligning writes at the @c->max_write_size bytes offsets. On the
++ * other hand, we do not want to waste space when synchronizing the write
++ * buffer, so during synchronization we writes in smaller chunks. And this makes
++ * the next write offset to be not aligned to @c->max_write_size bytes. So the
++ * have to make sure that the write-buffer offset (@wbuf->offs) becomes aligned
++ * to @c->max_write_size bytes again. We do this by temporarily shrinking
++ * write-buffer size (@wbuf->size).
++ *
+  * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
+  * mutexes defined inside these objects. Since sometimes upper-level code
+  * has to lock the write-buffer (e.g. journal space reservation code), many
+@@ -46,8 +66,8 @@
+  * UBIFS uses padding when it pads to the next min. I/O unit. In this case it
+  * uses padding nodes or padding bytes, if the padding node does not fit.
+  *
+- * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes
+- * every time they are read from the flash media.
++ * All UBIFS nodes are protected by CRC checksums and UBIFS checks CRC when
++ * they are read from the flash media.
+  */
+ #include <linux/crc32.h>
+@@ -66,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
+               c->no_chk_data_crc = 0;
+               c->vfs_sb->s_flags |= MS_RDONLY;
+               ubifs_warn("switched to read-only mode, error %d", err);
++              dump_stack();
++      }
++}
++
++/*
++ * Below are simple wrappers over UBI I/O functions which include some
++ * additional checks and UBIFS debugging stuff. See corresponding UBI function
++ * for more information.
++ */
++
++int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
++                 int len, int even_ebadmsg)
++{
++      int err;
++
++      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      /*
++       * In case of %-EBADMSG print the error message only if the
++       * @even_ebadmsg is true.
++       */
++      if (err && (err != -EBADMSG || even_ebadmsg)) {
++              ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
++                        len, lnum, offs, err);
+               dbg_dump_stack();
+       }
++      return err;
++}
++
++int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                  int len, int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
++      else
++              err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
++      if (err) {
++              ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
++                        len, lnum, offs, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                   int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
++      else
++              err = dbg_leb_change(c, lnum, buf, len, dtype);
++      if (err) {
++              ubifs_err("changing %d bytes in LEB %d failed, error %d",
++                        len, lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_unmap(c->ubi, lnum);
++      else
++              err = dbg_leb_unmap(c, lnum);
++      if (err) {
++              ubifs_err("unmap LEB %d failed, error %d", lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_map(c->ubi, lnum, dtype);
++      else
++              err = dbg_leb_map(c, lnum, dtype);
++      if (err) {
++              ubifs_err("mapping LEB %d failed, error %d", lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
++{
++      int err;
++
++      err = ubi_is_mapped(c->ubi, lnum);
++      if (err < 0) {
++              ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
++                        lnum, err);
++              dbg_dump_stack();
++      }
++      return err;
+ }
+ /**
+@@ -88,8 +225,12 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
+  * This function may skip data nodes CRC checking if @c->no_chk_data_crc is
+  * true, which is controlled by corresponding UBIFS mount option. However, if
+  * @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
+- * checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
+- * ignored and CRC is checked.
++ * checked. Similarly, if @c->mounting or @c->remounting_rw is true (we are
++ * mounting or re-mounting to R/W mode), @c->no_chk_data_crc is ignored and CRC
++ * is checked. This is because during mounting or re-mounting from R/O mode to
++ * R/W mode we may read journal nodes (when replying the journal or doing the
++ * recovery) and the journal nodes may potentially be corrupted, so checking is
++ * required.
+  *
+  * This function returns zero in case of success and %-EUCLEAN in case of bad
+  * CRC or magic.
+@@ -131,8 +272,8 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+                  node_len > c->ranges[type].max_len)
+               goto out_len;
+-      if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
+-           c->no_chk_data_crc)
++      if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->mounting &&
++          !c->remounting_rw && c->no_chk_data_crc)
+               return 0;
+       crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+@@ -343,11 +484,17 @@ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
+  *
+  * This function synchronizes write-buffer @buf and returns zero in case of
+  * success or a negative error code in case of failure.
++ *
++ * Note, although write-buffers are of @c->max_write_size, this function does
++ * not necessarily writes all @c->max_write_size bytes to the flash. Instead,
++ * if the write-buffer is only partially filled with data, only the used part
++ * of the write-buffer (aligned on @c->min_io_size boundary) is synchronized.
++ * This way we waste less space.
+  */
+ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+ {
+       struct ubifs_info *c = wbuf->c;
+-      int err, dirt;
++      int err, dirt, sync_len;
+       cancel_wbuf_timer_nolock(wbuf);
+       if (!wbuf->used || wbuf->lnum == -1)
+@@ -357,27 +504,49 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+       dbg_io("LEB %d:%d, %d bytes, jhead %s",
+              wbuf->lnum, wbuf->offs, wbuf->used, dbg_jhead(wbuf->jhead));
+       ubifs_assert(!(wbuf->avail & 7));
+-      ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
++      ubifs_assert(wbuf->offs + wbuf->size <= c->leb_size);
++      ubifs_assert(wbuf->size >= c->min_io_size);
++      ubifs_assert(wbuf->size <= c->max_write_size);
++      ubifs_assert(wbuf->size % c->min_io_size == 0);
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
+       if (c->ro_error)
+               return -EROFS;
+-      ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail);
+-      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
+-                          c->min_io_size, wbuf->dtype);
+-      if (err) {
+-              ubifs_err("cannot write %d bytes to LEB %d:%d",
+-                        c->min_io_size, wbuf->lnum, wbuf->offs);
+-              dbg_dump_stack();
++      /*
++       * Do not write whole write buffer but write only the minimum necessary
++       * amount of min. I/O units.
++       */
++      sync_len = ALIGN(wbuf->used, c->min_io_size);
++      dirt = sync_len - wbuf->used;
++      if (dirt)
++              ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
++      err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
++                            wbuf->dtype);
++      if (err)
+               return err;
+-      }
+-
+-      dirt = wbuf->avail;
+       spin_lock(&wbuf->lock);
+-      wbuf->offs += c->min_io_size;
+-      wbuf->avail = c->min_io_size;
++      wbuf->offs += sync_len;
++      /*
++       * Now @wbuf->offs is not necessarily aligned to @c->max_write_size.
++       * But our goal is to optimize writes and make sure we write in
++       * @c->max_write_size chunks and to @c->max_write_size-aligned offset.
++       * Thus, if @wbuf->offs is not aligned to @c->max_write_size now, make
++       * sure that @wbuf->offs + @wbuf->size is aligned to
++       * @c->max_write_size. This way we make sure that after next
++       * write-buffer flush we are again at the optimal offset (aligned to
++       * @c->max_write_size).
++       */
++      if (c->leb_size - wbuf->offs < c->max_write_size)
++              wbuf->size = c->leb_size - wbuf->offs;
++      else if (wbuf->offs & (c->max_write_size - 1))
++              wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
++      else
++              wbuf->size = c->max_write_size;
++      wbuf->avail = wbuf->size;
+       wbuf->used = 0;
+       wbuf->next_ino = 0;
+       spin_unlock(&wbuf->lock);
+@@ -396,8 +565,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+  * @dtype: data type
+  *
+  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
+- * The write-buffer is synchronized if it is not empty. Returns zero in case of
+- * success and a negative error code in case of failure.
++ * The write-buffer has to be empty. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+                          int dtype)
+@@ -409,18 +578,18 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+       ubifs_assert(offs >= 0 && offs <= c->leb_size);
+       ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
+       ubifs_assert(lnum != wbuf->lnum);
+-
+-      if (wbuf->used > 0) {
+-              int err = ubifs_wbuf_sync_nolock(wbuf);
+-
+-              if (err)
+-                      return err;
+-      }
++      ubifs_assert(wbuf->used == 0);
+       spin_lock(&wbuf->lock);
+       wbuf->lnum = lnum;
+       wbuf->offs = offs;
+-      wbuf->avail = c->min_io_size;
++      if (c->leb_size - wbuf->offs < c->max_write_size)
++              wbuf->size = c->leb_size - wbuf->offs;
++      else if (wbuf->offs & (c->max_write_size - 1))
++              wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
++      else
++              wbuf->size = c->max_write_size;
++      wbuf->avail = wbuf->size;
+       wbuf->used = 0;
+       spin_unlock(&wbuf->lock);
+       wbuf->dtype = dtype;
+@@ -500,8 +669,9 @@ out_timers:
+  *
+  * This function writes data to flash via write-buffer @wbuf. This means that
+  * the last piece of the node won't reach the flash media immediately if it
+- * does not take whole minimal I/O unit. Instead, the node will sit in RAM
+- * until the write-buffer is synchronized (e.g., by timer).
++ * does not take whole max. write unit (@c->max_write_size). Instead, the node
++ * will sit in RAM until the write-buffer is synchronized (e.g., by timer, or
++ * because more data are appended to the write-buffer).
+  *
+  * This function returns zero in case of success and a negative error code in
+  * case of failure. If the node cannot be written because there is no more
+@@ -510,7 +680,7 @@ out_timers:
+ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+ {
+       struct ubifs_info *c = wbuf->c;
+-      int err, written, n, aligned_len = ALIGN(len, 8), offs;
++      int err, written, n, aligned_len = ALIGN(len, 8);
+       dbg_io("%d bytes (%s) to jhead %s wbuf at LEB %d:%d", len,
+              dbg_ntype(((struct ubifs_ch *)buf)->node_type),
+@@ -518,9 +688,15 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+       ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
+       ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
+       ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
+-      ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size);
++      ubifs_assert(wbuf->avail > 0 && wbuf->avail <= wbuf->size);
++      ubifs_assert(wbuf->size >= c->min_io_size);
++      ubifs_assert(wbuf->size <= c->max_write_size);
++      ubifs_assert(wbuf->size % c->min_io_size == 0);
+       ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      ubifs_assert(!c->space_fixup);
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
+       if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
+               err = -ENOSPC;
+@@ -542,15 +718,19 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+               if (aligned_len == wbuf->avail) {
+                       dbg_io("flush jhead %s wbuf to LEB %d:%d",
+                              dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
+-                      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
+-                                          wbuf->offs, c->min_io_size,
+-                                          wbuf->dtype);
++                      err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
++                                            wbuf->offs, wbuf->size,
++                                            wbuf->dtype);
+                       if (err)
+                               goto out;
+                       spin_lock(&wbuf->lock);
+-                      wbuf->offs += c->min_io_size;
+-                      wbuf->avail = c->min_io_size;
++                      wbuf->offs += wbuf->size;
++                      if (c->leb_size - wbuf->offs >= c->max_write_size)
++                              wbuf->size = c->max_write_size;
++                      else
++                              wbuf->size = c->leb_size - wbuf->offs;
++                      wbuf->avail = wbuf->size;
+                       wbuf->used = 0;
+                       wbuf->next_ino = 0;
+                       spin_unlock(&wbuf->lock);
+@@ -564,39 +744,63 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+               goto exit;
+       }
+-      /*
+-       * The node is large enough and does not fit entirely within current
+-       * minimal I/O unit. We have to fill and flush write-buffer and switch
+-       * to the next min. I/O unit.
+-       */
+-      dbg_io("flush jhead %s wbuf to LEB %d:%d",
+-             dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
+-      memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
+-      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
+-                          c->min_io_size, wbuf->dtype);
+-      if (err)
+-              goto out;
++      written = 0;
++
++      if (wbuf->used) {
++              /*
++               * The node is large enough and does not fit entirely within
++               * current available space. We have to fill and flush
++               * write-buffer and switch to the next max. write unit.
++               */
++              dbg_io("flush jhead %s wbuf to LEB %d:%d",
++                     dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
++              memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
++              err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
++                                    wbuf->size, wbuf->dtype);
++              if (err)
++                      goto out;
++
++              wbuf->offs += wbuf->size;
++              len -= wbuf->avail;
++              aligned_len -= wbuf->avail;
++              written += wbuf->avail;
++      } else if (wbuf->offs & (c->max_write_size - 1)) {
++              /*
++               * The write-buffer offset is not aligned to
++               * @c->max_write_size and @wbuf->size is less than
++               * @c->max_write_size. Write @wbuf->size bytes to make sure the
++               * following writes are done in optimal @c->max_write_size
++               * chunks.
++               */
++              dbg_io("write %d bytes to LEB %d:%d",
++                     wbuf->size, wbuf->lnum, wbuf->offs);
++              err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
++                                    wbuf->size, wbuf->dtype);
++              if (err)
++                      goto out;
+-      offs = wbuf->offs + c->min_io_size;
+-      len -= wbuf->avail;
+-      aligned_len -= wbuf->avail;
+-      written = wbuf->avail;
++              wbuf->offs += wbuf->size;
++              len -= wbuf->size;
++              aligned_len -= wbuf->size;
++              written += wbuf->size;
++      }
+       /*
+-       * The remaining data may take more whole min. I/O units, so write the
+-       * remains multiple to min. I/O unit size directly to the flash media.
++       * The remaining data may take more whole max. write units, so write the
++       * remains multiple to max. write unit size directly to the flash media.
+        * We align node length to 8-byte boundary because we anyway flash wbuf
+        * if the remaining space is less than 8 bytes.
+        */
+-      n = aligned_len >> c->min_io_shift;
++      n = aligned_len >> c->max_write_shift;
+       if (n) {
+-              n <<= c->min_io_shift;
+-              dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
+-              err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
+-                                  wbuf->dtype);
++              n <<= c->max_write_shift;
++              dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
++                     wbuf->offs);
++              err = ubifs_leb_write(c, wbuf->lnum, buf + written,
++                                    wbuf->offs, n, wbuf->dtype);
+               if (err)
+                       goto out;
+-              offs += n;
++              wbuf->offs += n;
+               aligned_len -= n;
+               len -= n;
+               written += n;
+@@ -606,14 +810,17 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+       if (aligned_len)
+               /*
+                * And now we have what's left and what does not take whole
+-               * min. I/O unit, so write it to the write-buffer and we are
++               * max. write unit, so write it to the write-buffer and we are
+                * done.
+                */
+               memcpy(wbuf->buf, buf + written, len);
+-      wbuf->offs = offs;
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              wbuf->size = c->max_write_size;
++      else
++              wbuf->size = c->leb_size - wbuf->offs;
++      wbuf->avail = wbuf->size - aligned_len;
+       wbuf->used = aligned_len;
+-      wbuf->avail = c->min_io_size - aligned_len;
+       wbuf->next_ino = 0;
+       spin_unlock(&wbuf->lock);
+@@ -666,18 +873,15 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
+       ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+       ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      ubifs_assert(!c->space_fixup);
+       if (c->ro_error)
+               return -EROFS;
+       ubifs_prepare_node(c, buf, len, 1);
+-      err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype);
+-      if (err) {
+-              ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
+-                        buf_len, lnum, offs, err);
++      err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
++      if (err)
+               dbg_dump_node(c, buf);
+-              dbg_dump_stack();
+-      }
+       return err;
+ }
+@@ -729,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+       if (rlen > 0) {
+               /* Read everything that goes before write-buffer */
+-              err = ubi_read(c->ubi, lnum, buf, offs, rlen);
+-              if (err && err != -EBADMSG) {
+-                      ubifs_err("failed to read node %d from LEB %d:%d, "
+-                                "error %d", type, lnum, offs, err);
+-                      dbg_dump_stack();
++              err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
++              if (err && err != -EBADMSG)
+                       return err;
+-              }
+       }
+       if (type != ch->node_type) {
+@@ -790,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+       ubifs_assert(!(offs & 7) && offs < c->leb_size);
+       ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
+-      if (err && err != -EBADMSG) {
+-              ubifs_err("cannot read node %d from LEB %d:%d, error %d",
+-                        type, lnum, offs, err);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
++      if (err && err != -EBADMSG)
+               return err;
+-      }
+       if (type != ch->node_type) {
+               ubifs_err("bad node type (%d but expected %d)",
+@@ -837,11 +1034,11 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
+ {
+       size_t size;
+-      wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
++      wbuf->buf = kmalloc(c->max_write_size, GFP_KERNEL);
+       if (!wbuf->buf)
+               return -ENOMEM;
+-      size = (c->min_io_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
++      size = (c->max_write_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
+       wbuf->inodes = kmalloc(size, GFP_KERNEL);
+       if (!wbuf->inodes) {
+               kfree(wbuf->buf);
+@@ -851,7 +1048,14 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
+       wbuf->used = 0;
+       wbuf->lnum = wbuf->offs = -1;
+-      wbuf->avail = c->min_io_size;
++      /*
++       * If the LEB starts at the max. write size aligned address, then
++       * write-buffer size has to be set to @c->max_write_size. Otherwise,
++       * set it to something smaller so that it ends at the closest max.
++       * write size boundary.
++       */
++      size = c->max_write_size - (c->leb_start % c->max_write_size);
++      wbuf->avail = wbuf->size = size;
+       wbuf->dtype = UBI_UNKNOWN;
+       wbuf->sync_callback = NULL;
+       mutex_init(&wbuf->io_mutex);
+diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
+index 914f1bd..2f438ab 100644
+--- a/fs/ubifs/journal.c
++++ b/fs/ubifs/journal.c
+@@ -141,14 +141,8 @@ again:
+        * LEB with some empty space.
+        */
+       lnum = ubifs_find_free_space(c, len, &offs, squeeze);
+-      if (lnum >= 0) {
+-              /* Found an LEB, add it to the journal head */
+-              err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
+-              if (err)
+-                      goto out_return;
+-              /* A new bud was successfully allocated and added to the log */
++      if (lnum >= 0)
+               goto out;
+-      }
+       err = lnum;
+       if (err != -ENOSPC)
+@@ -203,12 +197,23 @@ again:
+               return 0;
+       }
+-      err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
+-      if (err)
+-              goto out_return;
+       offs = 0;
+ out:
++      /*
++       * Make sure we synchronize the write-buffer before we add the new bud
++       * to the log. Otherwise we may have a power cut after the log
++       * reference node for the last bud (@lnum) is written but before the
++       * write-buffer data are written to the next-to-last bud
++       * (@wbuf->lnum). And the effect would be that the recovery would see
++       * that there is corruption in the next-to-last bud.
++       */
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (err)
++              goto out_return;
++      err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
++      if (err)
++              goto out_return;
+       err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
+       if (err)
+               goto out_unlock;
+@@ -380,10 +385,8 @@ out:
+       if (err == -ENOSPC) {
+               /* This are some budgeting problems, print useful information */
+               down_write(&c->commit_sem);
+-              spin_lock(&c->space_lock);
+               dbg_dump_stack();
+-              dbg_dump_budg(c);
+-              spin_unlock(&c->space_lock);
++              dbg_dump_budg(c, &c->bi);
+               dbg_dump_lprops(c);
+               cmt_retries = dbg_check_lprops(c);
+               up_write(&c->commit_sem);
+@@ -666,6 +669,7 @@ out_free:
+ out_release:
+       release_head(c, BASEHD);
++      kfree(dent);
+ out_ro:
+       ubifs_ro_mode(c, err);
+       if (last_reference)
+@@ -690,17 +694,26 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+ {
+       struct ubifs_data_node *data;
+       int err, lnum, offs, compr_type, out_len;
+-      int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR;
++      int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
+       struct ubifs_inode *ui = ubifs_inode(inode);
+-      dbg_jnl("ino %lu, blk %u, len %d, key %s",
+-              (unsigned long)key_inum(c, key), key_block(c, key), len,
+-              DBGKEY(key));
++      dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
++              (unsigned long)key_inum(c, key), key_block(c, key), len);
+       ubifs_assert(len <= UBIFS_BLOCK_SIZE);
+-      data = kmalloc(dlen, GFP_NOFS);
+-      if (!data)
+-              return -ENOMEM;
++      data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
++      if (!data) {
++              /*
++               * Fall-back to the write reserve buffer. Note, we might be
++               * currently on the memory reclaim path, when the kernel is
++               * trying to free some memory by writing out dirty pages. The
++               * write reserve buffer helps us to guarantee that we are
++               * always able to write the data.
++               */
++              allocated = 0;
++              mutex_lock(&c->write_reserve_mutex);
++              data = c->write_reserve_buf;
++      }
+       data->ch.node_type = UBIFS_DATA_NODE;
+       key_write(c, key, &data->key);
+@@ -736,7 +749,10 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+               goto out_ro;
+       finish_reservation(c);
+-      kfree(data);
++      if (!allocated)
++              mutex_unlock(&c->write_reserve_mutex);
++      else
++              kfree(data);
+       return 0;
+ out_release:
+@@ -745,7 +761,10 @@ out_ro:
+       ubifs_ro_mode(c, err);
+       finish_reservation(c);
+ out_free:
+-      kfree(data);
++      if (!allocated)
++              mutex_unlock(&c->write_reserve_mutex);
++      else
++              kfree(data);
+       return err;
+ }
+@@ -1157,7 +1176,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
+               dn = (void *)trun + UBIFS_TRUN_NODE_SZ;
+               blk = new_size >> UBIFS_BLOCK_SHIFT;
+               data_key_init(c, &key, inum, blk);
+-              dbg_jnl("last block key %s", DBGKEY(&key));
++              dbg_jnlk(&key, "last block key ");
+               err = ubifs_tnc_lookup(c, &key, dn);
+               if (err == -ENOENT)
+                       dlen = 0; /* Not found (so it is a hole) */
+diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
+index 4d0cb12..f9fd068 100644
+--- a/fs/ubifs/log.c
++++ b/fs/ubifs/log.c
+@@ -100,20 +100,6 @@ struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
+ }
+ /**
+- * next_log_lnum - switch to the next log LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: current log LEB
+- */
+-static inline int next_log_lnum(const struct ubifs_info *c, int lnum)
+-{
+-      lnum += 1;
+-      if (lnum > c->log_last)
+-              lnum = UBIFS_LOG_LNUM;
+-
+-      return lnum;
+-}
+-
+-/**
+  * empty_log_bytes - calculate amount of empty space in the log.
+  * @c: UBIFS file-system description object
+  */
+@@ -175,26 +161,6 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
+ }
+ /**
+- * ubifs_create_buds_lists - create journal head buds lists for remount rw.
+- * @c: UBIFS file-system description object
+- */
+-void ubifs_create_buds_lists(struct ubifs_info *c)
+-{
+-      struct rb_node *p;
+-
+-      spin_lock(&c->buds_lock);
+-      p = rb_first(&c->buds);
+-      while (p) {
+-              struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb);
+-              struct ubifs_jhead *jhead = &c->jheads[bud->jhead];
+-
+-              list_add_tail(&bud->list, &jhead->buds_list);
+-              p = rb_next(p);
+-      }
+-      spin_unlock(&c->buds_lock);
+-}
+-
+-/**
+  * ubifs_add_bud_to_log - add a new bud to the log.
+  * @c: UBIFS file-system description object
+  * @jhead: journal head the bud belongs to
+@@ -277,7 +243,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+       ref->jhead = cpu_to_le32(jhead);
+       if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -296,7 +262,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+                * an unclean reboot, because the target LEB might have been
+                * unmapped, but not yet physically erased.
+                */
+-              err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM);
++              err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
+               if (err)
+                       goto out_unlock;
+       }
+@@ -317,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+       return 0;
+ out_unlock:
+-      if (err != -EAGAIN)
+-              ubifs_ro_mode(c, err);
+       mutex_unlock(&c->log_mutex);
+       kfree(ref);
+       kfree(bud);
+@@ -445,7 +409,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
+       /* Switch to the next log LEB */
+       if (c->lhead_offs) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -466,7 +430,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
+       c->lhead_offs += len;
+       if (c->lhead_offs == c->leb_size) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -553,7 +517,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
+       }
+       mutex_lock(&c->log_mutex);
+       for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
+-           lnum = next_log_lnum(c, lnum)) {
++           lnum = ubifs_next_log_lnum(c, lnum)) {
+               dbg_log("unmap log LEB %d", lnum);
+               err = ubifs_leb_unmap(c, lnum);
+               if (err)
+@@ -662,7 +626,7 @@ static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
+               err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
+               if (err)
+                       return err;
+-              *lnum = next_log_lnum(c, *lnum);
++              *lnum = ubifs_next_log_lnum(c, *lnum);
+               *offs = 0;
+       }
+       memcpy(buf + *offs, node, len);
+@@ -732,7 +696,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
+               ubifs_scan_destroy(sleb);
+               if (lnum == c->lhead_lnum)
+                       break;
+-              lnum = next_log_lnum(c, lnum);
++              lnum = ubifs_next_log_lnum(c, lnum);
+       }
+       if (offs) {
+               int sz = ALIGN(offs, c->min_io_size);
+@@ -752,7 +716,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
+       /* Unmap remaining LEBs */
+       lnum = write_lnum;
+       do {
+-              lnum = next_log_lnum(c, lnum);
++              lnum = ubifs_next_log_lnum(c, lnum);
+               err = ubifs_leb_unmap(c, lnum);
+               if (err)
+                       return err;
+@@ -786,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
+       struct ubifs_bud *bud;
+       long long bud_bytes = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       spin_lock(&c->buds_lock);
+diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
+index 4d4ca38..f8a181e 100644
+--- a/fs/ubifs/lprops.c
++++ b/fs/ubifs/lprops.c
+@@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
+       pnode = (struct ubifs_pnode *)container_of(lprops - pos,
+                                                  struct ubifs_pnode,
+                                                  lprops[0]);
+-      return !test_bit(COW_ZNODE, &pnode->flags) &&
++      return !test_bit(COW_CNODE, &pnode->flags) &&
+              test_bit(DIRTY_CNODE, &pnode->flags);
+ }
+@@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
+       struct list_head *pos;
+       int i, cat;
+-      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++      if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
+               return 0;
+       list_for_each_entry(lprops, &c->empty_list, list) {
+@@ -958,7 +958,7 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
+ {
+       int i = 0, j, err = 0;
+-      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++      if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
+               return;
+       for (i = 0; i < heap->cnt; i++) {
+@@ -1007,21 +1007,11 @@ out:
+ }
+ /**
+- * struct scan_check_data - data provided to scan callback function.
+- * @lst: LEB properties statistics
+- * @err: error code
+- */
+-struct scan_check_data {
+-      struct ubifs_lp_stats lst;
+-      int err;
+-};
+-
+-/**
+  * scan_check_cb - scan callback.
+  * @c: the UBIFS file-system description object
+  * @lp: LEB properties to scan
+  * @in_tree: whether the LEB properties are in main memory
+- * @data: information passed to and from the caller of the scan
++ * @lst: lprops statistics to update
+  *
+  * This function returns a code that indicates whether the scan should continue
+  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
+@@ -1030,12 +1020,12 @@ struct scan_check_data {
+  */
+ static int scan_check_cb(struct ubifs_info *c,
+                        const struct ubifs_lprops *lp, int in_tree,
+-                       struct scan_check_data *data)
++                       struct ubifs_lp_stats *lst)
+ {
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
+-      struct ubifs_lp_stats *lst = &data->lst;
+-      int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty;
++      int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
++      void *buf = NULL;
+       cat = lp->flags & LPROPS_CAT_MASK;
+       if (cat != LPROPS_UNCAT) {
+@@ -1043,7 +1033,7 @@ static int scan_check_cb(struct ubifs_info *c,
+               if (cat != (lp->flags & LPROPS_CAT_MASK)) {
+                       ubifs_err("bad LEB category %d expected %d",
+                                 (lp->flags & LPROPS_CAT_MASK), cat);
+-                      goto out;
++                      return -EINVAL;
+               }
+       }
+@@ -1077,7 +1067,7 @@ static int scan_check_cb(struct ubifs_info *c,
+                       }
+                       if (!found) {
+                               ubifs_err("bad LPT list (category %d)", cat);
+-                              goto out;
++                              return -EINVAL;
+                       }
+               }
+       }
+@@ -1089,36 +1079,40 @@ static int scan_check_cb(struct ubifs_info *c,
+               if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
+                   lp != heap->arr[lp->hpos]) {
+                       ubifs_err("bad LPT heap (category %d)", cat);
+-                      goto out;
++                      return -EINVAL;
+               }
+       }
+-      sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
+-      if (IS_ERR(sleb)) {
+-              /*
+-               * After an unclean unmount, empty and freeable LEBs
+-               * may contain garbage.
+-               */
+-              if (lp->free == c->leb_size) {
+-                      ubifs_err("scan errors were in empty LEB "
+-                                "- continuing checking");
+-                      lst->empty_lebs += 1;
+-                      lst->total_free += c->leb_size;
+-                      lst->total_dark += ubifs_calc_dark(c, c->leb_size);
+-                      return LPT_SCAN_CONTINUE;
+-              }
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf)
++              return -ENOMEM;
+-              if (lp->free + lp->dirty == c->leb_size &&
+-                  !(lp->flags & LPROPS_INDEX)) {
+-                      ubifs_err("scan errors were in freeable LEB "
+-                                "- continuing checking");
+-                      lst->total_free  += lp->free;
+-                      lst->total_dirty += lp->dirty;
+-                      lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
+-                      return LPT_SCAN_CONTINUE;
++      /*
++       * After an unclean unmount, empty and freeable LEBs
++       * may contain garbage - do not scan them.
++       */
++      if (lp->free == c->leb_size) {
++              lst->empty_lebs += 1;
++              lst->total_free += c->leb_size;
++              lst->total_dark += ubifs_calc_dark(c, c->leb_size);
++              return LPT_SCAN_CONTINUE;
++      }
++      if (lp->free + lp->dirty == c->leb_size &&
++          !(lp->flags & LPROPS_INDEX)) {
++              lst->total_free  += lp->free;
++              lst->total_dirty += lp->dirty;
++              lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
++              return LPT_SCAN_CONTINUE;
++      }
++
++      sleb = ubifs_scan(c, lnum, 0, buf, 0);
++      if (IS_ERR(sleb)) {
++              ret = PTR_ERR(sleb);
++              if (ret == -EUCLEAN) {
++                      dbg_dump_lprops(c);
++                      dbg_dump_budg(c, &c->bi);
+               }
+-              data->err = PTR_ERR(sleb);
+-              return LPT_SCAN_STOP;
++              goto out;
+       }
+       is_idx = -1;
+@@ -1236,6 +1230,7 @@ static int scan_check_cb(struct ubifs_info *c,
+       }
+       ubifs_scan_destroy(sleb);
++      vfree(buf);
+       return LPT_SCAN_CONTINUE;
+ out_print:
+@@ -1245,9 +1240,10 @@ out_print:
+       dbg_dump_leb(c, lnum);
+ out_destroy:
+       ubifs_scan_destroy(sleb);
++      ret = -EINVAL;
+ out:
+-      data->err = -EINVAL;
+-      return LPT_SCAN_STOP;
++      vfree(buf);
++      return ret;
+ }
+ /**
+@@ -1264,10 +1260,9 @@ out:
+ int dbg_check_lprops(struct ubifs_info *c)
+ {
+       int i, err;
+-      struct scan_check_data data;
+-      struct ubifs_lp_stats *lst = &data.lst;
++      struct ubifs_lp_stats lst;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       /*
+@@ -1280,29 +1275,23 @@ int dbg_check_lprops(struct ubifs_info *c)
+                       return err;
+       }
+-      memset(lst, 0, sizeof(struct ubifs_lp_stats));
+-
+-      data.err = 0;
++      memset(&lst, 0, sizeof(struct ubifs_lp_stats));
+       err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
+                                   (ubifs_lpt_scan_callback)scan_check_cb,
+-                                  &data);
++                                  &lst);
+       if (err && err != -ENOSPC)
+               goto out;
+-      if (data.err) {
+-              err = data.err;
+-              goto out;
+-      }
+-      if (lst->empty_lebs != c->lst.empty_lebs ||
+-          lst->idx_lebs != c->lst.idx_lebs ||
+-          lst->total_free != c->lst.total_free ||
+-          lst->total_dirty != c->lst.total_dirty ||
+-          lst->total_used != c->lst.total_used) {
++      if (lst.empty_lebs != c->lst.empty_lebs ||
++          lst.idx_lebs != c->lst.idx_lebs ||
++          lst.total_free != c->lst.total_free ||
++          lst.total_dirty != c->lst.total_dirty ||
++          lst.total_used != c->lst.total_used) {
+               ubifs_err("bad overall accounting");
+               ubifs_err("calculated: empty_lebs %d, idx_lebs %d, "
+                         "total_free %lld, total_dirty %lld, total_used %lld",
+-                        lst->empty_lebs, lst->idx_lebs, lst->total_free,
+-                        lst->total_dirty, lst->total_used);
++                        lst.empty_lebs, lst.idx_lebs, lst.total_free,
++                        lst.total_dirty, lst.total_used);
+               ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, "
+                         "total_free %lld, total_dirty %lld, total_used %lld",
+                         c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
+@@ -1311,11 +1300,11 @@ int dbg_check_lprops(struct ubifs_info *c)
+               goto out;
+       }
+-      if (lst->total_dead != c->lst.total_dead ||
+-          lst->total_dark != c->lst.total_dark) {
++      if (lst.total_dead != c->lst.total_dead ||
++          lst.total_dark != c->lst.total_dark) {
+               ubifs_err("bad dead/dark space accounting");
+               ubifs_err("calculated: total_dead %lld, total_dark %lld",
+-                        lst->total_dead, lst->total_dark);
++                        lst.total_dead, lst.total_dark);
+               ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
+                         c->lst.total_dead, c->lst.total_dark);
+               err = -EINVAL;
+diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
+index 72775d3..66d59d0 100644
+--- a/fs/ubifs/lpt.c
++++ b/fs/ubifs/lpt.c
+@@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+-                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                           UBI_SHORTTERM);
++                      err = ubifs_leb_change(c, lnum++, buf, alen,
++                                             UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+@@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                               set_ltab(c, lnum, c->leb_size - alen,
+                                           alen - len);
+                               memset(p, 0xff, alen - len);
+-                              err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                                   UBI_SHORTTERM);
++                              err = ubifs_leb_change(c, lnum++, buf, alen,
++                                                     UBI_SHORTTERM);
+                               if (err)
+                                       goto out;
+                               p = buf;
+@@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+-                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                           UBI_SHORTTERM);
++                      err = ubifs_leb_change(c, lnum++, buf, alen,
++                                             UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+@@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+               alen = ALIGN(len, c->min_io_size);
+               set_ltab(c, lnum, c->leb_size - alen, alen - len);
+               memset(p, 0xff, alen - len);
+-              err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM);
++              err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
+               if (err)
+                       goto out;
+               p = buf;
+@@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+       /* Write remaining buffer */
+       memset(p, 0xff, alen - len);
+-      err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
+       if (err)
+               goto out;
+@@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+               if (c->big_lpt)
+                       nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+       } else {
+-              err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
++              err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
+               if (err)
+                       goto out;
+               err = ubifs_unpack_nnode(c, buf, nnode);
+@@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+ out:
+       ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
++      dbg_dump_stack();
+       kfree(nnode);
+       return err;
+ }
+@@ -1270,10 +1271,9 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+       lnum = branch->lnum;
+       offs = branch->offs;
+       pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+-      if (!pnode) {
+-              err = -ENOMEM;
+-              goto out;
+-      }
++      if (!pnode)
++              return -ENOMEM;
++
+       if (lnum == 0) {
+               /*
+                * This pnode was not written which just means that the LEB
+@@ -1291,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+                       lprops->flags = ubifs_categorize_lprops(c, lprops);
+               }
+       } else {
+-              err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
++              err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
+               if (err)
+                       goto out;
+               err = unpack_pnode(c, buf, pnode);
+@@ -1313,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+ out:
+       ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
+       dbg_dump_pnode(c, pnode, parent, iip);
++      dbg_dump_stack();
+       dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
+       kfree(pnode);
+       return err;
+@@ -1332,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
+       buf = vmalloc(c->ltab_sz);
+       if (!buf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
++      err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
+       if (err)
+               goto out;
+       err = unpack_ltab(c, buf);
+@@ -1355,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
+       buf = vmalloc(c->lsave_sz);
+       if (!buf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
++      err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
++                           c->lsave_sz, 1);
+       if (err)
+               goto out;
+       err = unpack_lsave(c, buf);
+@@ -1815,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
+               if (c->big_lpt)
+                       nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+       } else {
+-              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
+-                             c->nnode_sz);
++              err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
++                                   c->nnode_sz, 1);
+               if (err)
+                       return ERR_PTR(err);
+               err = ubifs_unpack_nnode(c, buf, nnode);
+@@ -1884,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
+               ubifs_assert(branch->lnum >= c->lpt_first &&
+                            branch->lnum <= c->lpt_last);
+               ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
+-              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
+-                             c->pnode_sz);
++              err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
++                                   c->pnode_sz, 1);
+               if (err)
+                       return ERR_PTR(err);
+               err = unpack_pnode(c, buf, pnode);
+@@ -1984,12 +1986,11 @@ again:
+                               if (path[h].in_tree)
+                                       continue;
+-                              nnode = kmalloc(sz, GFP_NOFS);
++                              nnode = kmemdup(&path[h].nnode, sz, GFP_NOFS);
+                               if (!nnode) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
+-                              memcpy(nnode, &path[h].nnode, sz);
+                               parent = nnode->parent;
+                               parent->nbranch[nnode->iip].nnode = nnode;
+                               path[h].ptr.nnode = nnode;
+@@ -2002,12 +2003,11 @@ again:
+                               const size_t sz = sizeof(struct ubifs_pnode);
+                               struct ubifs_nnode *parent;
+-                              pnode = kmalloc(sz, GFP_NOFS);
++                              pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS);
+                               if (!pnode) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
+-                              memcpy(pnode, &path[h].pnode, sz);
+                               parent = pnode->parent;
+                               parent->nbranch[pnode->iip].pnode = pnode;
+                               path[h].ptr.pnode = pnode;
+@@ -2225,7 +2225,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
+       struct ubifs_cnode *cn;
+       int num, iip = 0, err;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       while (cnode) {
+diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
+index 5c90dec..cddd6bd 100644
+--- a/fs/ubifs/lpt_commit.c
++++ b/fs/ubifs/lpt_commit.c
+@@ -27,8 +27,15 @@
+ #include <linux/crc16.h>
+ #include <linux/slab.h>
++#include <linux/random.h>
+ #include "ubifs.h"
++#ifdef CONFIG_UBIFS_FS_DEBUG
++static int dbg_populate_lsave(struct ubifs_info *c);
++#else
++#define dbg_populate_lsave(c) 0
++#endif
++
+ /**
+  * first_dirty_cnode - find first dirty cnode.
+  * @c: UBIFS file-system description object
+@@ -110,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
+               return 0;
+       cnt += 1;
+       while (1) {
+-              ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags));
+-              __set_bit(COW_ZNODE, &cnode->flags);
++              ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
++              __set_bit(COW_CNODE, &cnode->flags);
+               cnext = next_dirty_cnode(cnode);
+               if (!cnext) {
+                       cnode->cnext = c->lpt_cnext;
+@@ -459,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
+                */
+               clear_bit(DIRTY_CNODE, &cnode->flags);
+               smp_mb__before_clear_bit();
+-              clear_bit(COW_ZNODE, &cnode->flags);
++              clear_bit(COW_CNODE, &cnode->flags);
+               smp_mb__after_clear_bit();
+               offs += len;
+               dbg_chk_lpt_sz(c, 1, len);
+@@ -586,7 +593,7 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
+                       if (nnode->nbranch[iip].lnum)
+                               break;
+               }
+-       } while (iip >= UBIFS_LPT_FANOUT);
++      } while (iip >= UBIFS_LPT_FANOUT);
+       /* Go right */
+       nnode = ubifs_get_nnode(c, nnode, iip);
+@@ -815,6 +822,10 @@ static void populate_lsave(struct ubifs_info *c)
+               c->lpt_drty_flgs |= LSAVE_DIRTY;
+               ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
+       }
++
++      if (dbg_populate_lsave(c))
++              return;
++
+       list_for_each_entry(lprops, &c->empty_list, list) {
+               c->lsave[cnt++] = lprops->lnum;
+               if (cnt >= c->lsave_cnt)
+@@ -1150,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
+       void *buf = c->lpt_buf;
+       dbg_lp("LEB %d", lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              ubifs_err("cannot read LEB %d, error %d", lnum, err);
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
+               return err;
+-      }
++
+       while (1) {
+               if (!is_a_node(c, buf, len)) {
+                       int pad_len;
+@@ -1628,29 +1639,35 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
+ {
+       int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
+       int ret;
+-      void *buf = c->dbg->buf;
++      void *buf, *p;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+-      dbg_lp("LEB %d", lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
+-              return err;
++      buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory for ltab checking");
++              return 0;
+       }
++
++      dbg_lp("LEB %d", lnum);
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
++              goto out;
++
+       while (1) {
+-              if (!is_a_node(c, buf, len)) {
++              if (!is_a_node(c, p, len)) {
+                       int i, pad_len;
+-                      pad_len = get_pad_len(c, buf, len);
++                      pad_len = get_pad_len(c, p, len);
+                       if (pad_len) {
+-                              buf += pad_len;
++                              p += pad_len;
+                               len -= pad_len;
+                               dirty += pad_len;
+                               continue;
+                       }
+-                      if (!dbg_is_all_ff(buf, len)) {
++                      if (!dbg_is_all_ff(p, len)) {
+                               dbg_msg("invalid empty space in LEB %d at %d",
+                                       lnum, c->leb_size - len);
+                               err = -EINVAL;
+@@ -1668,16 +1685,21 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
+                                       lnum, dirty, c->ltab[i].dirty);
+                               err = -EINVAL;
+                       }
+-                      return err;
++                      goto out;
+               }
+-              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_type = get_lpt_node_type(c, p, &node_num);
+               node_len = get_lpt_node_len(c, node_type);
+               ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len);
+               if (ret == 1)
+                       dirty += node_len;
+-              buf += node_len;
++              p += node_len;
+               len -= node_len;
+       }
++
++      err = 0;
++out:
++      vfree(buf);
++      return err;
+ }
+ /**
+@@ -1690,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
+ {
+       int lnum, err, i, cnt;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       /* Bring the entire tree into memory */
+@@ -1733,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
+       long long free = 0;
+       int i;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       for (i = 0; i < c->lpt_lebs; i++) {
+@@ -1775,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+       long long chk_lpt_sz, lpt_sz;
+       int err = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       switch (action) {
+@@ -1870,25 +1892,30 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+ {
+       int err, len = c->leb_size, node_type, node_num, node_len, offs;
+-      void *buf = c->dbg->buf;
++      void *buf, *p;
+       printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              ubifs_err("cannot read LEB %d, error %d", lnum, err);
++      buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory to dump LPT");
+               return;
+       }
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
++              goto out;
++
+       while (1) {
+               offs = c->leb_size - len;
+-              if (!is_a_node(c, buf, len)) {
++              if (!is_a_node(c, p, len)) {
+                       int pad_len;
+-                      pad_len = get_pad_len(c, buf, len);
++                      pad_len = get_pad_len(c, p, len);
+                       if (pad_len) {
+                               printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n",
+                                      lnum, offs, pad_len);
+-                              buf += pad_len;
++                              p += pad_len;
+                               len -= pad_len;
+                               continue;
+                       }
+@@ -1898,7 +1925,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       break;
+               }
+-              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_type = get_lpt_node_type(c, p, &node_num);
+               switch (node_type) {
+               case UBIFS_LPT_PNODE:
+               {
+@@ -1923,7 +1950,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       else
+                               printk(KERN_DEBUG "LEB %d:%d, nnode, ",
+                                      lnum, offs);
+-                      err = ubifs_unpack_nnode(c, buf, &nnode);
++                      err = ubifs_unpack_nnode(c, p, &nnode);
+                       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+                               printk(KERN_CONT "%d:%d", nnode.nbranch[i].lnum,
+                                      nnode.nbranch[i].offs);
+@@ -1944,15 +1971,18 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       break;
+               default:
+                       ubifs_err("LPT node type %d not recognized", node_type);
+-                      return;
++                      goto out;
+               }
+-              buf += node_len;
++              p += node_len;
+               len -= node_len;
+       }
+       printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
++out:
++      vfree(buf);
++      return;
+ }
+ /**
+@@ -1974,4 +2004,47 @@ void dbg_dump_lpt_lebs(const struct ubifs_info *c)
+              current->pid);
+ }
++/**
++ * dbg_populate_lsave - debugging version of 'populate_lsave()'
++ * @c: UBIFS file-system description object
++ *
++ * This is a debugging version for 'populate_lsave()' which populates lsave
++ * with random LEBs instead of useful LEBs, which is good for test coverage.
++ * Returns zero if lsave has not been populated (this debugging feature is
++ * disabled) an non-zero if lsave has been populated.
++ */
++static int dbg_populate_lsave(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++      int i;
++
++      if (!dbg_is_chk_gen(c))
++              return 0;
++      if (random32() & 3)
++              return 0;
++
++      for (i = 0; i < c->lsave_cnt; i++)
++              c->lsave[i] = c->main_first;
++
++      list_for_each_entry(lprops, &c->empty_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++      list_for_each_entry(lprops, &c->freeable_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++      list_for_each_entry(lprops, &c->frdi_idx_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++
++      heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++      heap = &c->lpt_heap[LPROPS_DIRTY - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++      heap = &c->lpt_heap[LPROPS_FREE - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++
++      return 1;
++}
++
+ #endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
+index 21f47af..278c238 100644
+--- a/fs/ubifs/master.c
++++ b/fs/ubifs/master.c
+@@ -148,7 +148,7 @@ static int validate_master(const struct ubifs_info *c)
+       }
+       main_sz = (long long)c->main_lebs * c->leb_size;
+-      if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
++      if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
+               err = 9;
+               goto out;
+       }
+@@ -218,7 +218,7 @@ static int validate_master(const struct ubifs_info *c)
+       }
+       if (c->lst.total_dead + c->lst.total_dark +
+-          c->lst.total_used + c->old_idx_sz > main_sz) {
++          c->lst.total_used + c->bi.old_idx_sz > main_sz) {
+               err = 21;
+               goto out;
+       }
+@@ -286,7 +286,7 @@ int ubifs_read_master(struct ubifs_info *c)
+       c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
+       c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
+       c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
+-      c->old_idx_sz      = le64_to_cpu(c->mst_node->index_size);
++      c->bi.old_idx_sz   = le64_to_cpu(c->mst_node->index_size);
+       c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
+       c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
+       c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
+@@ -305,7 +305,7 @@ int ubifs_read_master(struct ubifs_info *c)
+       c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
+       c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
+-      c->calc_idx_sz = c->old_idx_sz;
++      c->calc_idx_sz = c->bi.old_idx_sz;
+       if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
+               c->no_orphs = 1;
+diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
+index c3de04d..ee7cb5e 100644
+--- a/fs/ubifs/misc.h
++++ b/fs/ubifs/misc.h
+@@ -39,6 +39,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
+ }
+ /**
++ * ubifs_zn_obsolete - check if znode is obsolete.
++ * @znode: znode to check
++ *
++ * This helper function returns %1 if @znode is obsolete and %0 otherwise.
++ */
++static inline int ubifs_zn_obsolete(const struct ubifs_znode *znode)
++{
++      return !!test_bit(OBSOLETE_ZNODE, &znode->flags);
++}
++
++/**
++ * ubifs_zn_cow - check if znode has to be copied on write.
++ * @znode: znode to check
++ *
++ * This helper function returns %1 if @znode is has COW flag set and %0
++ * otherwise.
++ */
++static inline int ubifs_zn_cow(const struct ubifs_znode *znode)
++{
++      return !!test_bit(COW_ZNODE, &znode->flags);
++}
++
++/**
+  * ubifs_wake_up_bgt - wake up background thread.
+  * @c: UBIFS file-system description object
+  */
+@@ -122,86 +145,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
+ }
+ /**
+- * ubifs_leb_unmap - unmap an LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to unmap
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_unmap(c->ubi, lnum);
+-      if (err) {
+-              ubifs_err("unmap LEB %d failed, error %d", lnum, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+- * ubifs_leb_write - write to a LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to write
+- * @buf: buffer to write from
+- * @offs: offset within LEB to write to
+- * @len: length to write
+- * @dtype: data type
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
+-                                const void *buf, int offs, int len, int dtype)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+-      if (err) {
+-              ubifs_err("writing %d bytes at %d:%d, error %d",
+-                        len, lnum, offs, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+- * ubifs_leb_change - atomic LEB change.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to write
+- * @buf: buffer to write from
+- * @len: length to write
+- * @dtype: data type
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
+-                                 const void *buf, int len, int dtype)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+-      if (err) {
+-              ubifs_err("changing %d bytes in LEB %d, error %d",
+-                        len, lnum, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+  * ubifs_encode_dev - encode device node IDs.
+  * @dev: UBIFS device node information
+  * @rdev: device IDs to encode
+@@ -340,4 +283,21 @@ static inline void ubifs_release_lprops(struct ubifs_info *c)
+       mutex_unlock(&c->lp_mutex);
+ }
++/**
++ * ubifs_next_log_lnum - switch to the next log LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: current log LEB
++ *
++ * This helper function returns the log LEB number which goes next after LEB
++ * 'lnum'.
++ */
++static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
++{
++      lnum += 1;
++      if (lnum > c->log_last)
++              lnum = UBIFS_LOG_LNUM;
++
++      return lnum;
++}
++
+ #endif /* __UBIFS_MISC_H__ */
+diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
+index 82009c7..c542c73 100644
+--- a/fs/ubifs/orphan.c
++++ b/fs/ubifs/orphan.c
+@@ -673,7 +673,8 @@ static int kill_orphans(struct ubifs_info *c)
+               sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
+               if (IS_ERR(sleb)) {
+                       if (PTR_ERR(sleb) == -EUCLEAN)
+-                              sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
++                              sleb = ubifs_recover_leb(c, lnum, 0,
++                                                       c->sbuf, -1);
+                       if (IS_ERR(sleb)) {
+                               err = PTR_ERR(sleb);
+                               break;
+@@ -892,15 +893,22 @@ static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb)
+ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
+ {
+       int lnum, err = 0;
++      void *buf;
+       /* Check no-orphans flag and skip this if no orphans */
+       if (c->no_orphs)
+               return 0;
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory to check orphans");
++              return 0;
++      }
++
+       for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+               struct ubifs_scan_leb *sleb;
+-              sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
++              sleb = ubifs_scan(c, lnum, 0, buf, 0);
+               if (IS_ERR(sleb)) {
+                       err = PTR_ERR(sleb);
+                       break;
+@@ -912,6 +920,7 @@ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
+                       break;
+       }
++      vfree(buf);
+       return err;
+ }
+@@ -920,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
+       struct check_info ci;
+       int err;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_ORPH))
++      if (!dbg_is_chk_orph(c))
+               return 0;
+       ci.last_ino = 0;
+diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
+index 77e9b87..2a935b3 100644
+--- a/fs/ubifs/recovery.c
++++ b/fs/ubifs/recovery.c
+@@ -28,6 +28,23 @@
+  * UBIFS always cleans away all remnants of an unclean un-mount, so that
+  * errors do not accumulate. However UBIFS defers recovery if it is mounted
+  * read-only, and the flash is not modified in that case.
++ *
++ * The general UBIFS approach to the recovery is that it recovers from
++ * corruptions which could be caused by power cuts, but it refuses to recover
++ * from corruption caused by other reasons. And UBIFS tries to distinguish
++ * between these 2 reasons of corruptions and silently recover in the former
++ * case and loudly complain in the latter case.
++ *
++ * UBIFS writes only to erased LEBs, so it writes only to the flash space
++ * containing only 0xFFs. UBIFS also always writes strictly from the beginning
++ * of the LEB to the end. And UBIFS assumes that the underlying flash media
++ * writes in @c->max_write_size bytes at a time.
++ *
++ * Hence, if UBIFS finds a corrupted node at offset X, it expects only the min.
++ * I/O unit corresponding to offset X to contain corrupted data, all the
++ * following min. I/O units have to contain empty space (all 0xFFs). If this is
++ * not true, the corruption cannot be the result of a power cut, and UBIFS
++ * refuses to mount.
+  */
+ #include <linux/crc32.h>
+@@ -100,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
+       if (!sbuf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
++      err = ubifs_leb_read(c, lnum, sbuf, 0, c->leb_size, 0);
+       if (err && err != -EBADMSG)
+               goto out_free;
+@@ -196,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
+       mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
+       ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
+-      err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
+       if (err)
+               goto out;
+-      err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
+       if (err)
+               goto out;
+ out:
+@@ -257,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
+                               if (cor1)
+                                       goto out_err;
+                               mst = mst1;
+-                      } else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
++                      } else if (offs1 == 0 &&
++                                 c->leb_size - offs2 - sz < sz) {
+                               /* 1st LEB was unmapped and written, 2nd not */
+                               if (cor1)
+                                       goto out_err;
+@@ -300,6 +318,32 @@ int ubifs_recover_master_node(struct ubifs_info *c)
+                       goto out_free;
+               }
+               memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
++
++              /*
++               * We had to recover the master node, which means there was an
++               * unclean reboot. However, it is possible that the master node
++               * is clean at this point, i.e., %UBIFS_MST_DIRTY is not set.
++               * E.g., consider the following chain of events:
++               *
++               * 1. UBIFS was cleanly unmounted, so the master node is clean
++               * 2. UBIFS is being mounted R/W and starts changing the master
++               *    node in the first (%UBIFS_MST_LNUM). A power cut happens,
++               *    so this LEB ends up with some amount of garbage at the
++               *    end.
++               * 3. UBIFS is being mounted R/O. We reach this place and
++               *    recover the master node from the second LEB
++               *    (%UBIFS_MST_LNUM + 1). But we cannot update the media
++               *    because we are being mounted R/O. We have to defer the
++               *    operation.
++               * 4. However, this master node (@c->mst_node) is marked as
++               *    clean (since the step 1). And if we just return, the
++               *    mount code will be confused and won't recover the master
++               *    node when it is re-mounter R/W later.
++               *
++               *    Thus, to force the recovery by marking the master node as
++               *    dirty.
++               */
++              c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+       } else {
+               /* Write the recovered master node */
+               c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;
+@@ -362,8 +406,9 @@ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
+  * @offs: offset to check
+  *
+  * This function returns %1 if @offs was in the last write to the LEB whose data
+- * is in @buf, otherwise %0 is returned.  The determination is made by checking
+- * for subsequent empty space starting from the next @c->min_io_size boundary.
++ * is in @buf, otherwise %0 is returned. The determination is made by checking
++ * for subsequent empty space starting from the next @c->max_write_size
++ * boundary.
+  */
+ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+ {
+@@ -371,10 +416,10 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+       uint8_t *p;
+       /*
+-       * Round up to the next @c->min_io_size boundary i.e. @offs is in the
+-       * last wbuf written. After that should be empty space.
++       * Round up to the next @c->max_write_size boundary i.e. @offs is in
++       * the last wbuf written. After that should be empty space.
+        */
+-      empty_offs = ALIGN(offs + 1, c->min_io_size);
++      empty_offs = ALIGN(offs + 1, c->max_write_size);
+       check_len = c->leb_size - empty_offs;
+       p = buf + empty_offs - offs;
+       return is_empty(p, check_len);
+@@ -429,7 +474,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+       int skip, dlen = le32_to_cpu(ch->len);
+       /* Check for empty space after the corrupt node's common header */
+-      skip = ALIGN(offs + UBIFS_CH_SZ, c->min_io_size) - offs;
++      skip = ALIGN(offs + UBIFS_CH_SZ, c->max_write_size) - offs;
+       if (is_empty(buf + skip, len - skip))
+               return 1;
+       /*
+@@ -441,7 +486,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+               return 0;
+       }
+       /* Now we know the corrupt node's length we can skip over it */
+-      skip = ALIGN(offs + dlen, c->min_io_size) - offs;
++      skip = ALIGN(offs + dlen, c->max_write_size) - offs;
+       /* After which there should be empty space */
+       if (is_empty(buf + skip, len - skip))
+               return 1;
+@@ -495,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+                       int len = ALIGN(endpt, c->min_io_size);
+                       if (start) {
+-                              err = ubi_read(c->ubi, lnum, sleb->buf, 0,
+-                                             start);
++                              err = ubifs_leb_read(c, lnum, sleb->buf, 0,
++                                                   start, 1);
+                               if (err)
+                                       return err;
+                       }
+@@ -510,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+                                       ubifs_pad(c, buf, pad_len);
+                               }
+                       }
+-                      err = ubi_leb_change(c->ubi, lnum, sleb->buf, len,
+-                                           UBI_UNKNOWN);
++                      err = ubifs_leb_change(c, lnum, sleb->buf, len,
++                                             UBI_UNKNOWN);
+                       if (err)
+                               return err;
+               }
+@@ -520,16 +565,15 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ }
+ /**
+- * drop_incomplete_group - drop nodes from an incomplete group.
++ * drop_last_group - drop the last group of nodes.
+  * @sleb: scanned LEB information
+  * @offs: offset of dropped nodes is returned here
+  *
+- * This function returns %1 if nodes are dropped and %0 otherwise.
++ * This is a helper function for 'ubifs_recover_leb()' which drops the last
++ * group of nodes of the scanned LEB.
+  */
+-static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
++static void drop_last_group(struct ubifs_scan_leb *sleb, int *offs)
+ {
+-      int dropped = 0;
+-
+       while (!list_empty(&sleb->nodes)) {
+               struct ubifs_scan_node *snod;
+               struct ubifs_ch *ch;
+@@ -538,15 +582,40 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+                                 list);
+               ch = snod->node;
+               if (ch->group_type != UBIFS_IN_NODE_GROUP)
+-                      return dropped;
+-              dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
++                      break;
++
++              dbg_rcvry("dropping grouped node at %d:%d",
++                        sleb->lnum, snod->offs);
++              *offs = snod->offs;
++              list_del(&snod->list);
++              kfree(snod);
++              sleb->nodes_cnt -= 1;
++      }
++}
++
++/**
++ * drop_last_node - drop the last node.
++ * @sleb: scanned LEB information
++ * @offs: offset of dropped nodes is returned here
++ * @grouped: non-zero if whole group of nodes have to be dropped
++ *
++ * This is a helper function for 'ubifs_recover_leb()' which drops the last
++ * node of the scanned LEB.
++ */
++static void drop_last_node(struct ubifs_scan_leb *sleb, int *offs)
++{
++      struct ubifs_scan_node *snod;
++
++      if (!list_empty(&sleb->nodes)) {
++              snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
++                                list);
++
++              dbg_rcvry("dropping last node at %d:%d", sleb->lnum, snod->offs);
+               *offs = snod->offs;
+               list_del(&snod->list);
+               kfree(snod);
+               sleb->nodes_cnt -= 1;
+-              dropped = 1;
+       }
+-      return dropped;
+ }
+ /**
+@@ -555,7 +624,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+  * @lnum: LEB number
+  * @offs: offset
+  * @sbuf: LEB-sized buffer to use
+- * @grouped: nodes may be grouped for recovery
++ * @jhead: journal head number this LEB belongs to (%-1 if the LEB does not
++ *         belong to any journal head)
+  *
+  * This function does a scan of a LEB, but caters for errors that might have
+  * been caused by the unclean unmount from which we are attempting to recover.
+@@ -563,25 +633,21 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+  * found, and a negative error code in case of failure.
+  */
+ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+-                                       int offs, void *sbuf, int grouped)
++                                       int offs, void *sbuf, int jhead)
+ {
+-      int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
+-      int empty_chkd = 0, start = offs;
++      int ret = 0, err, len = c->leb_size - offs, start = offs, min_io_unit;
++      int grouped = jhead == -1 ? 0 : c->jheads[jhead].grouped;
+       struct ubifs_scan_leb *sleb;
+       void *buf = sbuf + offs;
+-      dbg_rcvry("%d:%d", lnum, offs);
++      dbg_rcvry("%d:%d, jhead %d, grouped %d", lnum, offs, jhead, grouped);
+       sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+       if (IS_ERR(sleb))
+               return sleb;
+-      if (sleb->ecc)
+-              need_clean = 1;
+-
++      ubifs_assert(len >= 8);
+       while (len >= 8) {
+-              int ret;
+-
+               dbg_scan("look at LEB %d:%d (%d bytes left)",
+                        lnum, offs, len);
+@@ -591,8 +657,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+                * Scan quietly until there is an error from which we cannot
+                * recover
+                */
+-              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+-
++              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+               if (ret == SCANNED_A_NODE) {
+                       /* A valid node, and not a padding node */
+                       struct ubifs_ch *ch = buf;
+@@ -605,104 +670,127 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+                       offs += node_len;
+                       buf += node_len;
+                       len -= node_len;
+-                      continue;
+-              }
+-
+-              if (ret > 0) {
++              } else if (ret > 0) {
+                       /* Padding bytes or a valid padding node */
+                       offs += ret;
+                       buf += ret;
+                       len -= ret;
+-                      continue;
+-              }
+-
+-              if (ret == SCANNED_EMPTY_SPACE) {
+-                      if (!is_empty(buf, len)) {
+-                              if (!is_last_write(c, buf, offs))
+-                                      break;
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                      }
+-                      empty_chkd = 1;
++              } else if (ret == SCANNED_EMPTY_SPACE ||
++                         ret == SCANNED_GARBAGE     ||
++                         ret == SCANNED_A_BAD_PAD_NODE ||
++                         ret == SCANNED_A_CORRUPT_NODE) {
++                      dbg_rcvry("found corruption (%d) at %d:%d",
++                                ret, lnum, offs);
+                       break;
+-              }
+-
+-              if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
+-                      if (is_last_write(c, buf, offs)) {
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                              empty_chkd = 1;
+-                              break;
+-                      }
+-
+-              if (ret == SCANNED_A_CORRUPT_NODE)
+-                      if (no_more_nodes(c, buf, len, lnum, offs)) {
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                              empty_chkd = 1;
+-                              break;
+-                      }
+-
+-              if (quiet) {
+-                      /* Redo the last scan but noisily */
+-                      quiet = 0;
+-                      continue;
+-              }
+-
+-              switch (ret) {
+-              case SCANNED_GARBAGE:
+-                      dbg_err("garbage");
+-                      goto corrupted;
+-              case SCANNED_A_CORRUPT_NODE:
+-              case SCANNED_A_BAD_PAD_NODE:
+-                      dbg_err("bad node");
+-                      goto corrupted;
+-              default:
+-                      dbg_err("unknown");
++              } else {
++                      dbg_err("unexpected return value %d", ret);
+                       err = -EINVAL;
+                       goto error;
+               }
+       }
+-      if (!empty_chkd && !is_empty(buf, len)) {
+-              if (is_last_write(c, buf, offs)) {
+-                      clean_buf(c, &buf, lnum, &offs, &len);
+-                      need_clean = 1;
+-              } else {
++      if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE) {
++              if (!is_last_write(c, buf, offs))
++                      goto corrupted_rescan;
++      } else if (ret == SCANNED_A_CORRUPT_NODE) {
++              if (!no_more_nodes(c, buf, len, lnum, offs))
++                      goto corrupted_rescan;
++      } else if (!is_empty(buf, len)) {
++              if (!is_last_write(c, buf, offs)) {
+                       int corruption = first_non_ff(buf, len);
++                      /*
++                       * See header comment for this file for more
++                       * explanations about the reasons we have this check.
++                       */
+                       ubifs_err("corrupt empty space LEB %d:%d, corruption "
+                                 "starts at %d", lnum, offs, corruption);
+                       /* Make sure we dump interesting non-0xFF data */
+-                      offs = corruption;
++                      offs += corruption;
+                       buf += corruption;
+                       goto corrupted;
+               }
+       }
+-      /* Drop nodes from incomplete group */
+-      if (grouped && drop_incomplete_group(sleb, &offs)) {
+-              buf = sbuf + offs;
+-              len = c->leb_size - offs;
+-              clean_buf(c, &buf, lnum, &offs, &len);
+-              need_clean = 1;
+-      }
++      min_io_unit = round_down(offs, c->min_io_size);
++      if (grouped)
++              /*
++               * If nodes are grouped, always drop the incomplete group at
++               * the end.
++               */
++              drop_last_group(sleb, &offs);
+-      if (offs % c->min_io_size) {
+-              clean_buf(c, &buf, lnum, &offs, &len);
+-              need_clean = 1;
++      if (jhead == GCHD) {
++              /*
++               * If this LEB belongs to the GC head then while we are in the
++               * middle of the same min. I/O unit keep dropping nodes. So
++               * basically, what we want is to make sure that the last min.
++               * I/O unit where we saw the corruption is dropped completely
++               * with all the uncorrupted nodes which may possibly sit there.
++               *
++               * In other words, let's name the min. I/O unit where the
++               * corruption starts B, and the previous min. I/O unit A. The
++               * below code tries to deal with a situation when half of B
++               * contains valid nodes or the end of a valid node, and the
++               * second half of B contains corrupted data or garbage. This
++               * means that UBIFS had been writing to B just before the power
++               * cut happened. I do not know how realistic is this scenario
++               * that half of the min. I/O unit had been written successfully
++               * and the other half not, but this is possible in our 'failure
++               * mode emulation' infrastructure at least.
++               *
++               * So what is the problem, why we need to drop those nodes? Why
++               * can't we just clean-up the second half of B by putting a
++               * padding node there? We can, and this works fine with one
++               * exception which was reproduced with power cut emulation
++               * testing and happens extremely rarely.
++               *
++               * Imagine the file-system is full, we run GC which starts
++               * moving valid nodes from LEB X to LEB Y (obviously, LEB Y is
++               * the current GC head LEB). The @c->gc_lnum is -1, which means
++               * that GC will retain LEB X and will try to continue. Imagine
++               * that LEB X is currently the dirtiest LEB, and the amount of
++               * used space in LEB Y is exactly the same as amount of free
++               * space in LEB X.
++               *
++               * And a power cut happens when nodes are moved from LEB X to
++               * LEB Y. We are here trying to recover LEB Y which is the GC
++               * head LEB. We find the min. I/O unit B as described above.
++               * Then we clean-up LEB Y by padding min. I/O unit. And later
++               * 'ubifs_rcvry_gc_commit()' function fails, because it cannot
++               * find a dirty LEB which could be GC'd into LEB Y! Even LEB X
++               * does not match because the amount of valid nodes there does
++               * not fit the free space in LEB Y any more! And this is
++               * because of the padding node which we added to LEB Y. The
++               * user-visible effect of this which I once observed and
++               * analysed is that we cannot mount the file-system with
++               * -ENOSPC error.
++               *
++               * So obviously, to make sure that situation does not happen we
++               * should free min. I/O unit B in LEB Y completely and the last
++               * used min. I/O unit in LEB Y should be A. This is basically
++               * what the below code tries to do.
++               */
++              while (offs > min_io_unit)
++                      drop_last_node(sleb, &offs);
+       }
++      buf = sbuf + offs;
++      len = c->leb_size - offs;
++
++      clean_buf(c, &buf, lnum, &offs, &len);
+       ubifs_end_scan(c, sleb, lnum, offs);
+-      if (need_clean) {
+-              err = fix_unclean_leb(c, sleb, start);
+-              if (err)
+-                      goto error;
+-      }
++      err = fix_unclean_leb(c, sleb, start);
++      if (err)
++              goto error;
+       return sleb;
++corrupted_rescan:
++      /* Re-scan the corrupted data with verbose messages */
++      dbg_err("corruptio %d", ret);
++      ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ corrupted:
+       ubifs_scanned_corruption(c, lnum, offs, buf);
+       err = -EUCLEAN;
+@@ -733,7 +821,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
+               return -ENOMEM;
+       if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
+               goto out_err;
+-      err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
++      err = ubifs_leb_read(c, lnum, (void *)cs_node, offs,
++                           UBIFS_CS_NODE_SZ, 0);
+       if (err && err != -EBADMSG)
+               goto out_free;
+       ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
+@@ -819,7 +908,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+               }
+               ubifs_scan_destroy(sleb);
+       }
+-      return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
++      return ubifs_recover_leb(c, lnum, offs, sbuf, -1);
+ }
+ /**
+@@ -833,15 +922,10 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+-                      void *sbuf)
++static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
+ {
+-      int len, err;
++      int len = c->max_write_size, err;
+-      if (c->min_io_size > 1)
+-              len = c->min_io_size;
+-      else
+-              len = 512;
+       if (offs + len > c->leb_size)
+               len = c->leb_size - offs;
+@@ -849,15 +933,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+               return 0;
+       /* Read at the head location and check it is empty flash */
+-      err = ubi_read(c->ubi, lnum, sbuf, offs, len);
++      err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
+       if (err || !is_empty(sbuf, len)) {
+               dbg_rcvry("cleaning head at %d:%d", lnum, offs);
+               if (offs == 0)
+                       return ubifs_leb_unmap(c, lnum);
+-              err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
++              err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
+               if (err)
+                       return err;
+-              return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
++              return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
+       }
+       return 0;
+@@ -880,7 +964,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
++int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
+ {
+       int err;
+@@ -900,7 +984,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+ }
+ /**
+- *  clean_an_unclean_leb - read and write a LEB to remove corruption.
++ * clean_an_unclean_leb - read and write a LEB to remove corruption.
+  * @c: UBIFS file-system description object
+  * @ucleb: unclean LEB information
+  * @sbuf: LEB-sized buffer to use
+@@ -911,7 +995,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-static int clean_an_unclean_leb(const struct ubifs_info *c,
++static int clean_an_unclean_leb(struct ubifs_info *c,
+                               struct ubifs_unclean_leb *ucleb, void *sbuf)
+ {
+       int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
+@@ -927,7 +1011,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+               return 0;
+       }
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
+       if (err && err != -EBADMSG)
+               return err;
+@@ -987,7 +1071,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+       }
+       /* Write back the LEB atomically */
+-      err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
++      err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
+       if (err)
+               return err;
+@@ -1007,7 +1091,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
++int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
+ {
+       dbg_rcvry("recovery");
+       while (!list_empty(&c->unclean_leb_list)) {
+@@ -1026,6 +1110,53 @@ int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
+ }
+ /**
++ * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty
++ * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns
++ * zero in case of success and a negative error code in case of failure.
++ */
++static int grab_empty_leb(struct ubifs_info *c)
++{
++      int lnum, err;
++
++      /*
++       * Note, it is very important to first search for an empty LEB and then
++       * run the commit, not vice-versa. The reason is that there might be
++       * only one empty LEB at the moment, the one which has been the
++       * @c->gc_lnum just before the power cut happened. During the regular
++       * UBIFS operation (not now) @c->gc_lnum is marked as "taken", so no
++       * one but GC can grab it. But at this moment this single empty LEB is
++       * not marked as taken, so if we run commit - what happens? Right, the
++       * commit will grab it and write the index there. Remember that the
++       * index always expands as long as there is free space, and it only
++       * starts consolidating when we run out of space.
++       *
++       * IOW, if we run commit now, we might not be able to find a free LEB
++       * after this.
++       */
++      lnum = ubifs_find_free_leb_for_idx(c);
++      if (lnum < 0) {
++              dbg_err("could not find an empty LEB");
++              dbg_dump_lprops(c);
++              dbg_dump_budg(c, &c->bi);
++              return lnum;
++      }
++
++      /* Reset the index flag */
++      err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
++                                LPROPS_INDEX, 0);
++      if (err)
++              return err;
++
++      c->gc_lnum = lnum;
++      dbg_rcvry("found empty LEB %d, run commit", lnum);
++
++      return ubifs_run_commit(c);
++}
++
++/**
+  * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit.
+  * @c: UBIFS file-system description object
+  *
+@@ -1047,71 +1178,26 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+ {
+       struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
+       struct ubifs_lprops lp;
+-      int lnum, err;
++      int err;
++
++      dbg_rcvry("GC head LEB %d, offs %d", wbuf->lnum, wbuf->offs);
+       c->gc_lnum = -1;
+-      if (wbuf->lnum == -1) {
+-              dbg_rcvry("no GC head LEB");
+-              goto find_free;
+-      }
+-      /*
+-       * See whether the used space in the dirtiest LEB fits in the GC head
+-       * LEB.
+-       */
+-      if (wbuf->offs == c->leb_size) {
+-              dbg_rcvry("no room in GC head LEB");
+-              goto find_free;
+-      }
++      if (wbuf->lnum == -1 || wbuf->offs == c->leb_size)
++              return grab_empty_leb(c);
++
+       err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
+       if (err) {
+-              /*
+-               * There are no dirty or empty LEBs subject to here being
+-               * enough for the index. Try to use
+-               * 'ubifs_find_free_leb_for_idx()', which will return any empty
+-               * LEBs (ignoring index requirements). If the index then
+-               * doesn't have enough LEBs the recovery commit will fail -
+-               * which is the  same result anyway i.e. recovery fails. So
+-               * there is no problem ignoring index  requirements and just
+-               * grabbing a free LEB since we have already established there
+-               * is not a dirty LEB we could have used instead.
+-               */
+-              if (err == -ENOSPC) {
+-                      dbg_rcvry("could not find a dirty LEB");
+-                      goto find_free;
+-              }
+-              return err;
+-      }
+-      ubifs_assert(!(lp.flags & LPROPS_INDEX));
+-      lnum = lp.lnum;
+-      if (lp.free + lp.dirty == c->leb_size) {
+-              /* An empty LEB was returned */
+-              if (lp.free != c->leb_size) {
+-                      err = ubifs_change_one_lp(c, lnum, c->leb_size,
+-                                                0, 0, 0, 0);
+-                      if (err)
+-                              return err;
+-              }
+-              err = ubifs_leb_unmap(c, lnum);
+-              if (err)
+-                      return err;
+-              c->gc_lnum = lnum;
+-              dbg_rcvry("allocated LEB %d for GC", lnum);
+-              /* Run the commit */
+-              dbg_rcvry("committing");
+-              return ubifs_run_commit(c);
+-      }
+-      /*
+-       * There was no empty LEB so the used space in the dirtiest LEB must fit
+-       * in the GC head LEB.
+-       */
+-      if (lp.free + lp.dirty < wbuf->offs) {
+-              dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d",
+-                        lnum, wbuf->lnum, wbuf->offs);
+-              err = ubifs_return_leb(c, lnum);
+-              if (err)
++              if (err != -ENOSPC)
+                       return err;
+-              goto find_free;
++
++              dbg_rcvry("could not find a dirty LEB");
++              return grab_empty_leb(c);
+       }
++
++      ubifs_assert(!(lp.flags & LPROPS_INDEX));
++      ubifs_assert(lp.free + lp.dirty >= wbuf->offs);
++
+       /*
+        * We run the commit before garbage collection otherwise subsequent
+        * mounts will see the GC and orphan deletion in a different order.
+@@ -1120,11 +1206,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+       err = ubifs_run_commit(c);
+       if (err)
+               return err;
+-      /*
+-       * The data in the dirtiest LEB fits in the GC head LEB, so do the GC
+-       * - use locking to keep 'ubifs_assert()' happy.
+-       */
+-      dbg_rcvry("GC'ing LEB %d", lnum);
++
++      dbg_rcvry("GC'ing LEB %d", lp.lnum);
+       mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
+       err = ubifs_garbage_collect_leb(c, &lp);
+       if (err >= 0) {
+@@ -1140,37 +1223,17 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+                       err = -EINVAL;
+               return err;
+       }
+-      if (err != LEB_RETAINED) {
+-              dbg_err("GC returned %d", err);
++
++      ubifs_assert(err == LEB_RETAINED);
++      if (err != LEB_RETAINED)
+               return -EINVAL;
+-      }
++
+       err = ubifs_leb_unmap(c, c->gc_lnum);
+       if (err)
+               return err;
+-      dbg_rcvry("allocated LEB %d for GC", lnum);
+-      return 0;
+-find_free:
+-      /*
+-       * There is no GC head LEB or the free space in the GC head LEB is too
+-       * small, or there are not dirty LEBs. Allocate gc_lnum by calling
+-       * 'ubifs_find_free_leb_for_idx()' so GC is not run.
+-       */
+-      lnum = ubifs_find_free_leb_for_idx(c);
+-      if (lnum < 0) {
+-              dbg_err("could not find an empty LEB");
+-              return lnum;
+-      }
+-      /* And reset the index flag */
+-      err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+-                                LPROPS_INDEX, 0);
+-      if (err)
+-              return err;
+-      c->gc_lnum = lnum;
+-      dbg_rcvry("allocated LEB %d for GC", lnum);
+-      /* Run the commit */
+-      dbg_rcvry("committing");
+-      return ubifs_run_commit(c);
++      dbg_rcvry("allocated LEB %d for GC", lp.lnum);
++      return 0;
+ }
+ /**
+@@ -1393,7 +1456,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
+       if (i_size >= e->d_size)
+               return 0;
+       /* Read the LEB */
+-      err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size);
++      err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
+       if (err)
+               goto out;
+       /* Change the size field and recalculate the CRC */
+@@ -1409,10 +1472,10 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
+               len -= 1;
+       len = ALIGN(len + 1, c->min_io_size);
+       /* Atomically write the fixed LEB back again */
+-      err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
++      err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
+       if (err)
+               goto out;
+-      dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ",
++      dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
+                 (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
+       return 0;
+@@ -1461,20 +1524,27 @@ int ubifs_recover_size(struct ubifs_info *c)
+                               e->i_size = le64_to_cpu(ino->size);
+                       }
+               }
++
+               if (e->exists && e->i_size < e->d_size) {
+-                      if (!e->inode && c->ro_mount) {
++                      if (c->ro_mount) {
+                               /* Fix the inode size and pin it in memory */
+                               struct inode *inode;
++                              struct ubifs_inode *ui;
++
++                              ubifs_assert(!e->inode);
+                               inode = ubifs_iget(c->vfs_sb, e->inum);
+                               if (IS_ERR(inode))
+                                       return PTR_ERR(inode);
++
++                              ui = ubifs_inode(inode);
+                               if (inode->i_size < e->d_size) {
+                                       dbg_rcvry("ino %lu size %lld -> %lld",
+                                                 (unsigned long)e->inum,
+-                                                e->d_size, inode->i_size);
++                                                inode->i_size, e->d_size);
+                                       inode->i_size = e->d_size;
+-                                      ubifs_inode(inode)->ui_size = e->d_size;
++                                      ui->ui_size = e->d_size;
++                                      ui->synced_i_size = e->d_size;
+                                       e->inode = inode;
+                                       this = rb_next(this);
+                                       continue;
+@@ -1489,9 +1559,11 @@ int ubifs_recover_size(struct ubifs_info *c)
+                                       iput(e->inode);
+                       }
+               }
++
+               this = rb_next(this);
+               rb_erase(&e->rb, &c->size_tree);
+               kfree(e);
+       }
++
+       return 0;
+ }
+diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
+index eed0fcf..b007637 100644
+--- a/fs/ubifs/replay.c
++++ b/fs/ubifs/replay.c
+@@ -33,43 +33,32 @@
+  */
+ #include "ubifs.h"
+-
+-/*
+- * Replay flags.
+- *
+- * REPLAY_DELETION: node was deleted
+- * REPLAY_REF: node is a reference node
+- */
+-enum {
+-      REPLAY_DELETION = 1,
+-      REPLAY_REF = 2,
+-};
++#include <linux/list_sort.h>
+ /**
+- * struct replay_entry - replay tree entry.
++ * struct replay_entry - replay list entry.
+  * @lnum: logical eraseblock number of the node
+  * @offs: node offset
+  * @len: node length
++ * @deletion: non-zero if this entry corresponds to a node deletion
+  * @sqnum: node sequence number
+- * @flags: replay flags
+- * @rb: links the replay tree
++ * @list: links the replay list
+  * @key: node key
+  * @nm: directory entry name
+  * @old_size: truncation old size
+  * @new_size: truncation new size
+- * @free: amount of free space in a bud
+- * @dirty: amount of dirty space in a bud from padding and deletion nodes
+  *
+- * UBIFS journal replay must compare node sequence numbers, which means it must
+- * build a tree of node information to insert into the TNC.
++ * The replay process first scans all buds and builds the replay list, then
++ * sorts the replay list in nodes sequence number order, and then inserts all
++ * the replay entries to the TNC.
+  */
+ struct replay_entry {
+       int lnum;
+       int offs;
+       int len;
++      unsigned int deletion:1;
+       unsigned long long sqnum;
+-      int flags;
+-      struct rb_node rb;
++      struct list_head list;
+       union ubifs_key key;
+       union {
+               struct qstr nm;
+@@ -77,10 +66,6 @@ struct replay_entry {
+                       loff_t old_size;
+                       loff_t new_size;
+               };
+-              struct {
+-                      int free;
+-                      int dirty;
+-              };
+       };
+ };
+@@ -88,57 +73,64 @@ struct replay_entry {
+  * struct bud_entry - entry in the list of buds to replay.
+  * @list: next bud in the list
+  * @bud: bud description object
+- * @free: free bytes in the bud
+  * @sqnum: reference node sequence number
++ * @free: free bytes in the bud
++ * @dirty: dirty bytes in the bud
+  */
+ struct bud_entry {
+       struct list_head list;
+       struct ubifs_bud *bud;
+-      int free;
+       unsigned long long sqnum;
++      int free;
++      int dirty;
+ };
+ /**
+  * set_bud_lprops - set free and dirty space used by a bud.
+  * @c: UBIFS file-system description object
+- * @r: replay entry of bud
++ * @b: bud entry which describes the bud
++ *
++ * This function makes sure the LEB properties of bud @b are set correctly
++ * after the replay. Returns zero in case of success and a negative error code
++ * in case of failure.
+  */
+-static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
++static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
+ {
+       const struct ubifs_lprops *lp;
+       int err = 0, dirty;
+       ubifs_get_lprops(c);
+-      lp = ubifs_lpt_lookup_dirty(c, r->lnum);
++      lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
+       if (IS_ERR(lp)) {
+               err = PTR_ERR(lp);
+               goto out;
+       }
+       dirty = lp->dirty;
+-      if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
++      if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+               /*
+                * The LEB was added to the journal with a starting offset of
+                * zero which means the LEB must have been empty. The LEB
+-               * property values should be lp->free == c->leb_size and
+-               * lp->dirty == 0, but that is not the case. The reason is that
+-               * the LEB was garbage collected. The garbage collector resets
+-               * the free and dirty space without recording it anywhere except
+-               * lprops, so if there is not a commit then lprops does not have
+-               * that information next time the file system is mounted.
++               * property values should be @lp->free == @c->leb_size and
++               * @lp->dirty == 0, but that is not the case. The reason is that
++               * the LEB had been garbage collected before it became the bud,
++               * and there was not commit inbetween. The garbage collector
++               * resets the free and dirty space without recording it
++               * anywhere except lprops, so if there was no commit then
++               * lprops does not have that information.
+                *
+                * We do not need to adjust free space because the scan has told
+                * us the exact value which is recorded in the replay entry as
+-               * r->free.
++               * @b->free.
+                *
+                * However we do need to subtract from the dirty space the
+                * amount of space that the garbage collector reclaimed, which
+                * is the whole LEB minus the amount of space that was free.
+                */
+-              dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++              dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
+                       lp->free, lp->dirty);
+-              dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++              dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
+                       lp->free, lp->dirty);
+               dirty -= c->leb_size - lp->free;
+               /*
+@@ -150,21 +142,48 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+                */
+               if (dirty != 0)
+                       dbg_msg("LEB %d lp: %d free %d dirty "
+-                              "replay: %d free %d dirty", r->lnum, lp->free,
+-                              lp->dirty, r->free, r->dirty);
++                              "replay: %d free %d dirty", b->bud->lnum,
++                              lp->free, lp->dirty, b->free, b->dirty);
+       }
+-      lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
++      lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
+                            lp->flags | LPROPS_TAKEN, 0);
+       if (IS_ERR(lp)) {
+               err = PTR_ERR(lp);
+               goto out;
+       }
++
++      /* Make sure the journal head points to the latest bud */
++      err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
++                                   b->bud->lnum, c->leb_size - b->free,
++                                   UBI_SHORTTERM);
++
+ out:
+       ubifs_release_lprops(c);
+       return err;
+ }
+ /**
++ * set_buds_lprops - set free and dirty space for all replayed buds.
++ * @c: UBIFS file-system description object
++ *
++ * This function sets LEB properties for all replayed buds. Returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++static int set_buds_lprops(struct ubifs_info *c)
++{
++      struct bud_entry *b;
++      int err;
++
++      list_for_each_entry(b, &c->replay_buds, list) {
++              err = set_bud_lprops(c, b);
++              if (err)
++                      return err;
++      }
++
++      return 0;
++}
++
++/**
+  * trun_remove_range - apply a replay entry for a truncation to the TNC.
+  * @c: UBIFS file-system description object
+  * @r: replay entry of truncation
+@@ -200,24 +219,22 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
+  */
+ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+ {
+-      int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
++      int err;
+-      dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
+-              r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
++      dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ",
++               r->lnum, r->offs, r->len, r->deletion, r->sqnum);
+       /* Set c->replay_sqnum to help deal with dangling branches. */
+       c->replay_sqnum = r->sqnum;
+-      if (r->flags & REPLAY_REF)
+-              err = set_bud_lprops(c, r);
+-      else if (is_hash_key(c, &r->key)) {
+-              if (deletion)
++      if (is_hash_key(c, &r->key)) {
++              if (r->deletion)
+                       err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
+               else
+                       err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
+                                              r->len, &r->nm);
+       } else {
+-              if (deletion)
++              if (r->deletion)
+                       switch (key_type(c, &r->key)) {
+                       case UBIFS_INO_KEY:
+                       {
+@@ -240,7 +257,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+                       return err;
+               if (c->need_recovery)
+-                      err = ubifs_recover_size_accum(c, &r->key, deletion,
++                      err = ubifs_recover_size_accum(c, &r->key, r->deletion,
+                                                      r->new_size);
+       }
+@@ -248,68 +265,77 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+ }
+ /**
+- * destroy_replay_tree - destroy the replay.
+- * @c: UBIFS file-system description object
++ * replay_entries_cmp - compare 2 replay entries.
++ * @priv: UBIFS file-system description object
++ * @a: first replay entry
++ * @a: second replay entry
+  *
+- * Destroy the replay tree.
++ * This is a comparios function for 'list_sort()' which compares 2 replay
++ * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has
++ * greater sequence number and %-1 otherwise.
+  */
+-static void destroy_replay_tree(struct ubifs_info *c)
++static int replay_entries_cmp(void *priv, struct list_head *a,
++                            struct list_head *b)
+ {
+-      struct rb_node *this = c->replay_tree.rb_node;
+-      struct replay_entry *r;
+-
+-      while (this) {
+-              if (this->rb_left) {
+-                      this = this->rb_left;
+-                      continue;
+-              } else if (this->rb_right) {
+-                      this = this->rb_right;
+-                      continue;
+-              }
+-              r = rb_entry(this, struct replay_entry, rb);
+-              this = rb_parent(this);
+-              if (this) {
+-                      if (this->rb_left == &r->rb)
+-                              this->rb_left = NULL;
+-                      else
+-                              this->rb_right = NULL;
+-              }
+-              if (is_hash_key(c, &r->key))
+-                      kfree(r->nm.name);
+-              kfree(r);
+-      }
+-      c->replay_tree = RB_ROOT;
++      struct replay_entry *ra, *rb;
++
++      cond_resched();
++      if (a == b)
++              return 0;
++
++      ra = list_entry(a, struct replay_entry, list);
++      rb = list_entry(b, struct replay_entry, list);
++      ubifs_assert(ra->sqnum != rb->sqnum);
++      if (ra->sqnum > rb->sqnum)
++              return 1;
++      return -1;
+ }
+ /**
+- * apply_replay_tree - apply the replay tree to the TNC.
++ * apply_replay_list - apply the replay list to the TNC.
+  * @c: UBIFS file-system description object
+  *
+- * Apply the replay tree.
+- * Returns zero in case of success and a negative error code in case of
+- * failure.
++ * Apply all entries in the replay list to the TNC. Returns zero in case of
++ * success and a negative error code in case of failure.
+  */
+-static int apply_replay_tree(struct ubifs_info *c)
++static int apply_replay_list(struct ubifs_info *c)
+ {
+-      struct rb_node *this = rb_first(&c->replay_tree);
++      struct replay_entry *r;
++      int err;
+-      while (this) {
+-              struct replay_entry *r;
+-              int err;
++      list_sort(c, &c->replay_list, &replay_entries_cmp);
++      list_for_each_entry(r, &c->replay_list, list) {
+               cond_resched();
+-              r = rb_entry(this, struct replay_entry, rb);
+               err = apply_replay_entry(c, r);
+               if (err)
+                       return err;
+-              this = rb_next(this);
+       }
++
+       return 0;
+ }
+ /**
+- * insert_node - insert a node to the replay tree.
++ * destroy_replay_list - destroy the replay.
++ * @c: UBIFS file-system description object
++ *
++ * Destroy the replay list.
++ */
++static void destroy_replay_list(struct ubifs_info *c)
++{
++      struct replay_entry *r, *tmp;
++
++      list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
++              if (is_hash_key(c, &r->key))
++                      kfree(r->nm.name);
++              list_del(&r->list);
++              kfree(r);
++      }
++}
++
++/**
++ * insert_node - insert a node to the replay list
+  * @c: UBIFS file-system description object
+  * @lnum: node logical eraseblock number
+  * @offs: node offset
+@@ -321,39 +347,25 @@ static int apply_replay_tree(struct ubifs_info *c)
+  * @old_size: truncation old size
+  * @new_size: truncation new size
+  *
+- * This function inserts a scanned non-direntry node to the replay tree. The
+- * replay tree is an RB-tree containing @struct replay_entry elements which are
+- * indexed by the sequence number. The replay tree is applied at the very end
+- * of the replay process. Since the tree is sorted in sequence number order,
+- * the older modifications are applied first. This function returns zero in
+- * case of success and a negative error code in case of failure.
++ * This function inserts a scanned non-direntry node to the replay list. The
++ * replay list contains @struct replay_entry elements, and we sort this list in
++ * sequence number order before applying it. The replay list is applied at the
++ * very end of the replay process. Since the list is sorted in sequence number
++ * order, the older modifications are applied first. This function returns zero
++ * in case of success and a negative error code in case of failure.
+  */
+ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+                      union ubifs_key *key, unsigned long long sqnum,
+                      int deletion, int *used, loff_t old_size,
+                      loff_t new_size)
+ {
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+       struct replay_entry *r;
++      dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
++
+       if (key_inum(c, key) >= c->highest_inum)
+               c->highest_inum = key_inum(c, key);
+-      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              } else if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay");
+-              return -EINVAL;
+-      }
+-
+       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+       if (!r)
+               return -ENOMEM;
+@@ -363,19 +375,18 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+       r->lnum = lnum;
+       r->offs = offs;
+       r->len = len;
++      r->deletion = !!deletion;
+       r->sqnum = sqnum;
+-      r->flags = (deletion ? REPLAY_DELETION : 0);
++      key_copy(c, key, &r->key);
+       r->old_size = old_size;
+       r->new_size = new_size;
+-      key_copy(c, key, &r->key);
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
++      list_add_tail(&r->list, &c->replay_list);
+       return 0;
+ }
+ /**
+- * insert_dent - insert a directory entry node into the replay tree.
++ * insert_dent - insert a directory entry node into the replay list.
+  * @c: UBIFS file-system description object
+  * @lnum: node logical eraseblock number
+  * @offs: node offset
+@@ -387,43 +398,25 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+  * @deletion: non-zero if this is a deletion
+  * @used: number of bytes in use in a LEB
+  *
+- * This function inserts a scanned directory entry node to the replay tree.
+- * Returns zero in case of success and a negative error code in case of
+- * failure.
+- *
+- * This function is also used for extended attribute entries because they are
+- * implemented as directory entry nodes.
++ * This function inserts a scanned directory entry node or an extended
++ * attribute entry to the replay list. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+                      union ubifs_key *key, const char *name, int nlen,
+                      unsigned long long sqnum, int deletion, int *used)
+ {
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+       struct replay_entry *r;
+       char *nbuf;
++      dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
+       if (key_inum(c, key) >= c->highest_inum)
+               c->highest_inum = key_inum(c, key);
+-      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              }
+-              if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay");
+-              return -EINVAL;
+-      }
+-
+       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+       if (!r)
+               return -ENOMEM;
++
+       nbuf = kmalloc(nlen + 1, GFP_KERNEL);
+       if (!nbuf) {
+               kfree(r);
+@@ -435,17 +428,15 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+       r->lnum = lnum;
+       r->offs = offs;
+       r->len = len;
++      r->deletion = !!deletion;
+       r->sqnum = sqnum;
++      key_copy(c, key, &r->key);
+       r->nm.len = nlen;
+       memcpy(nbuf, name, nlen);
+       nbuf[nlen] = '\0';
+       r->nm.name = nbuf;
+-      r->flags = (deletion ? REPLAY_DELETION : 0);
+-      key_copy(c, key, &r->key);
+-      ubifs_assert(!*p);
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
++      list_add_tail(&r->list, &c->replay_list);
+       return 0;
+ }
+@@ -482,29 +473,90 @@ int ubifs_validate_entry(struct ubifs_info *c,
+ }
+ /**
++ * is_last_bud - check if the bud is the last in the journal head.
++ * @c: UBIFS file-system description object
++ * @bud: bud description object
++ *
++ * This function checks if bud @bud is the last bud in its journal head. This
++ * information is then used by 'replay_bud()' to decide whether the bud can
++ * have corruptions or not. Indeed, only last buds can be corrupted by power
++ * cuts. Returns %1 if this is the last bud, and %0 if not.
++ */
++static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
++{
++      struct ubifs_jhead *jh = &c->jheads[bud->jhead];
++      struct ubifs_bud *next;
++      uint32_t data;
++      int err;
++
++      if (list_is_last(&bud->list, &jh->buds_list))
++              return 1;
++
++      /*
++       * The following is a quirk to make sure we work correctly with UBIFS
++       * images used with older UBIFS.
++       *
++       * Normally, the last bud will be the last in the journal head's list
++       * of bud. However, there is one exception if the UBIFS image belongs
++       * to older UBIFS. This is fairly unlikely: one would need to use old
++       * UBIFS, then have a power cut exactly at the right point, and then
++       * try to mount this image with new UBIFS.
++       *
++       * The exception is: it is possible to have 2 buds A and B, A goes
++       * before B, and B is the last, bud B is contains no data, and bud A is
++       * corrupted at the end. The reason is that in older versions when the
++       * journal code switched the next bud (from A to B), it first added a
++       * log reference node for the new bud (B), and only after this it
++       * synchronized the write-buffer of current bud (A). But later this was
++       * changed and UBIFS started to always synchronize the write-buffer of
++       * the bud (A) before writing the log reference for the new bud (B).
++       *
++       * But because older UBIFS always synchronized A's write-buffer before
++       * writing to B, we can recognize this exceptional situation but
++       * checking the contents of bud B - if it is empty, then A can be
++       * treated as the last and we can recover it.
++       *
++       * TODO: remove this piece of code in a couple of years (today it is
++       * 16.05.2011).
++       */
++      next = list_entry(bud->list.next, struct ubifs_bud, list);
++      if (!list_is_last(&next->list, &jh->buds_list))
++              return 0;
++
++      err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
++      if (err)
++              return 0;
++
++      return data == 0xFFFFFFFF;
++}
++
++/**
+  * replay_bud - replay a bud logical eraseblock.
+  * @c: UBIFS file-system description object
+- * @lnum: bud logical eraseblock number to replay
+- * @offs: bud start offset
+- * @jhead: journal head to which this bud belongs
+- * @free: amount of free space in the bud is returned here
+- * @dirty: amount of dirty space from padding and deletion nodes is returned
+- * here
++ * @b: bud entry which describes the bud
+  *
+- * This function returns zero in case of success and a negative error code in
+- * case of failure.
++ * This function replays bud @bud, recovers it if needed, and adds all nodes
++ * from this bud to the replay list. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+-static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+-                    int *free, int *dirty)
++static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
+ {
+-      int err = 0, used = 0;
++      int is_last = is_last_bud(c, b->bud);
++      int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
+-      struct ubifs_bud *bud;
+-      dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
+-      if (c->need_recovery)
+-              sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
++      dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d",
++              lnum, b->bud->jhead, offs, is_last);
++
++      if (c->need_recovery && is_last)
++              /*
++               * Recover only last LEBs in the journal heads, because power
++               * cuts may cause corruptions only in these LEBs, because only
++               * these LEBs could possibly be written to at the power cut
++               * time.
++               */
++              sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead);
+       else
+               sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
+       if (IS_ERR(sleb))
+@@ -620,19 +672,13 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+                       goto out;
+       }
+-      bud = ubifs_search_bud(c, lnum);
+-      if (!bud)
+-              BUG();
+-
++      ubifs_assert(ubifs_search_bud(c, lnum));
+       ubifs_assert(sleb->endpt - offs >= used);
+       ubifs_assert(sleb->endpt % c->min_io_size == 0);
+-      if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount)
+-              err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum,
+-                                           sleb->endpt, UBI_SHORTTERM);
+-
+-      *dirty = sleb->endpt - offs - used;
+-      *free = c->leb_size - sleb->endpt;
++      b->dirty = sleb->endpt - offs - used;
++      b->free = c->leb_size - sleb->endpt;
++      dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, b->dirty, b->free);
+ out:
+       ubifs_scan_destroy(sleb);
+@@ -646,55 +692,6 @@ out_dump:
+ }
+ /**
+- * insert_ref_node - insert a reference node to the replay tree.
+- * @c: UBIFS file-system description object
+- * @lnum: node logical eraseblock number
+- * @offs: node offset
+- * @sqnum: sequence number
+- * @free: amount of free space in bud
+- * @dirty: amount of dirty space from padding and deletion nodes
+- *
+- * This function inserts a reference node to the replay tree and returns zero
+- * in case of success or a negative error code in case of failure.
+- */
+-static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+-                         unsigned long long sqnum, int free, int dirty)
+-{
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+-      struct replay_entry *r;
+-
+-      dbg_mnt("add ref LEB %d:%d", lnum, offs);
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              } else if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay tree");
+-              return -EINVAL;
+-      }
+-
+-      r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+-      if (!r)
+-              return -ENOMEM;
+-
+-      r->lnum = lnum;
+-      r->offs = offs;
+-      r->sqnum = sqnum;
+-      r->flags = REPLAY_REF;
+-      r->free = free;
+-      r->dirty = dirty;
+-
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
+-      return 0;
+-}
+-
+-/**
+  * replay_buds - replay all buds.
+  * @c: UBIFS file-system description object
+  *
+@@ -704,17 +701,16 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+ static int replay_buds(struct ubifs_info *c)
+ {
+       struct bud_entry *b;
+-      int err, uninitialized_var(free), uninitialized_var(dirty);
++      int err;
++      unsigned long long prev_sqnum = 0;
+       list_for_each_entry(b, &c->replay_buds, list) {
+-              err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
+-                               &free, &dirty);
+-              if (err)
+-                      return err;
+-              err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
+-                                    free, dirty);
++              err = replay_bud(c, b);
+               if (err)
+                       return err;
++
++              ubifs_assert(b->sqnum > prev_sqnum);
++              prev_sqnum = b->sqnum;
+       }
+       return 0;
+@@ -1054,25 +1050,29 @@ int ubifs_replay_journal(struct ubifs_info *c)
+       if (err)
+               goto out;
+-      err = apply_replay_tree(c);
++      err = apply_replay_list(c);
++      if (err)
++              goto out;
++
++      err = set_buds_lprops(c);
+       if (err)
+               goto out;
+       /*
+-       * UBIFS budgeting calculations use @c->budg_uncommitted_idx variable
+-       * to roughly estimate index growth. Things like @c->min_idx_lebs
++       * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
++       * to roughly estimate index growth. Things like @c->bi.min_idx_lebs
+        * depend on it. This means we have to initialize it to make sure
+        * budgeting works properly.
+        */
+-      c->budg_uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
+-      c->budg_uncommitted_idx *= c->max_idx_node_sz;
++      c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
++      c->bi.uncommitted_idx *= c->max_idx_node_sz;
+       ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
+       dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
+               "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
+               (unsigned long)c->highest_inum);
+ out:
+-      destroy_replay_tree(c);
++      destroy_replay_list(c);
+       destroy_bud_list(c);
+       c->replaying = 0;
+       return err;
+diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
+index bf31b47..771f7fb 100644
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -247,7 +247,7 @@ static int create_default_filesystem(struct ubifs_info *c)
+       mst->total_dirty = cpu_to_le64(tmp64);
+       /*  The indexing LEB does not contribute to dark space */
+-      tmp64 = (c->main_lebs - 1) * c->dark_wm;
++      tmp64 = ((long long)(c->main_lebs - 1) * c->dark_wm);
+       mst->total_dark = cpu_to_le64(tmp64);
+       mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
+@@ -410,13 +410,23 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+       }
+       if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
+-              err = 7;
++              ubifs_err("too few main LEBs count %d, must be at least %d",
++                        c->main_lebs, UBIFS_MIN_MAIN_LEBS);
+               goto failed;
+       }
+-      if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
+-          c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
+-              err = 8;
++      max_bytes = (long long)c->leb_size * UBIFS_MIN_BUD_LEBS;
++      if (c->max_bud_bytes < max_bytes) {
++              ubifs_err("too small journal (%lld bytes), must be at least "
++                        "%lld bytes",  c->max_bud_bytes, max_bytes);
++              goto failed;
++      }
++
++      max_bytes = (long long)c->leb_size * c->main_lebs;
++      if (c->max_bud_bytes > max_bytes) {
++              ubifs_err("too large journal size (%lld bytes), only %lld bytes"
++                        "available in the main area",
++                        c->max_bud_bytes, max_bytes);
+               goto failed;
+       }
+@@ -450,7 +460,6 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+               goto failed;
+       }
+-      max_bytes = c->main_lebs * (long long)c->leb_size;
+       if (c->rp_size < 0 || max_bytes < c->rp_size) {
+               err = 14;
+               goto failed;
+@@ -475,7 +484,8 @@ failed:
+  * @c: UBIFS file-system description object
+  *
+  * This function returns a pointer to the superblock node or a negative error
+- * code.
++ * code. Note, the user of this function is responsible of kfree()'ing the
++ * returned superblock buffer.
+  */
+ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
+ {
+@@ -616,6 +626,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
+       c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
+       memcpy(&c->uuid, &sup->uuid, 16);
+       c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
++      c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+       /* Automatically increase file system size to the maximum size */
+       c->old_leb_cnt = c->leb_cnt;
+@@ -650,3 +661,152 @@ out:
+       kfree(sup);
+       return err;
+ }
++
++/**
++ * fixup_leb - fixup/unmap an LEB containing free space.
++ * @c: UBIFS file-system description object
++ * @lnum: the LEB number to fix up
++ * @len: number of used bytes in LEB (starting at offset 0)
++ *
++ * This function reads the contents of the given LEB number @lnum, then fixes
++ * it up, so that empty min. I/O units in the end of LEB are actually erased on
++ * flash (rather than being just all-0xff real data). If the LEB is completely
++ * empty, it is simply unmapped.
++ */
++static int fixup_leb(struct ubifs_info *c, int lnum, int len)
++{
++      int err;
++
++      ubifs_assert(len >= 0);
++      ubifs_assert(len % c->min_io_size == 0);
++      ubifs_assert(len < c->leb_size);
++
++      if (len == 0) {
++              dbg_mnt("unmap empty LEB %d", lnum);
++              return ubifs_leb_unmap(c, lnum);
++      }
++
++      dbg_mnt("fixup LEB %d, data len %d", lnum, len);
++      err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
++      if (err)
++              return err;
++
++      return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
++}
++
++/**
++ * fixup_free_space - find & remap all LEBs containing free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function walks through all LEBs in the filesystem and fiexes up those
++ * containing free/empty space.
++ */
++static int fixup_free_space(struct ubifs_info *c)
++{
++      int lnum, err = 0;
++      struct ubifs_lprops *lprops;
++
++      ubifs_get_lprops(c);
++
++      /* Fixup LEBs in the master area */
++      for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) {
++              err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz);
++              if (err)
++                      goto out;
++      }
++
++      /* Unmap unused log LEBs */
++      lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
++      while (lnum != c->ltail_lnum) {
++              err = fixup_leb(c, lnum, 0);
++              if (err)
++                      goto out;
++              lnum = ubifs_next_log_lnum(c, lnum);
++      }
++
++      /* Fixup the current log head */
++      err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
++      if (err)
++              goto out;
++
++      /* Fixup LEBs in the LPT area */
++      for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
++              int free = c->ltab[lnum - c->lpt_first].free;
++
++              if (free > 0) {
++                      err = fixup_leb(c, lnum, c->leb_size - free);
++                      if (err)
++                              goto out;
++              }
++      }
++
++      /* Unmap LEBs in the orphans area */
++      for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
++              err = fixup_leb(c, lnum, 0);
++              if (err)
++                      goto out;
++      }
++
++      /* Fixup LEBs in the main area */
++      for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
++              lprops = ubifs_lpt_lookup(c, lnum);
++              if (IS_ERR(lprops)) {
++                      err = PTR_ERR(lprops);
++                      goto out;
++              }
++
++              if (lprops->free > 0) {
++                      err = fixup_leb(c, lnum, c->leb_size - lprops->free);
++                      if (err)
++                              goto out;
++              }
++      }
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * ubifs_fixup_free_space - find & fix all LEBs with free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function fixes up LEBs containing free space on first mount, if the
++ * appropriate flag was set when the FS was created. Each LEB with one or more
++ * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure
++ * the free space is actually erased. E.g., this is necessary for some NAND
++ * chips, since the free space may have been programmed like real "0xff" data
++ * (generating a non-0xff ECC), causing future writes to the not-really-erased
++ * NAND pages to behave badly. After the space is fixed up, the superblock flag
++ * is cleared, so that this is skipped for all future mounts.
++ */
++int ubifs_fixup_free_space(struct ubifs_info *c)
++{
++      int err;
++      struct ubifs_sb_node *sup;
++
++      ubifs_assert(c->space_fixup);
++      ubifs_assert(!c->ro_mount);
++
++      ubifs_msg("start fixing up free space");
++
++      err = fixup_free_space(c);
++      if (err)
++              return err;
++
++      sup = ubifs_read_sb_node(c);
++      if (IS_ERR(sup))
++              return PTR_ERR(sup);
++
++      /* Free-space fixup is no longer required */
++      c->space_fixup = 0;
++      sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
++
++      err = ubifs_write_sb_node(c, sup);
++      kfree(sup);
++      if (err)
++              return err;
++
++      ubifs_msg("free space fixup complete");
++      return err;
++}
+diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
+index 3e1ee57..37383e8 100644
+--- a/fs/ubifs/scan.c
++++ b/fs/ubifs/scan.c
+@@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+       INIT_LIST_HEAD(&sleb->nodes);
+       sleb->buf = sbuf;
+-      err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
++      err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
+       if (err && err != -EBADMSG) {
+               ubifs_err("cannot read %d bytes from LEB %d:%d,"
+                         " error %d", c->leb_size - offs, lnum, offs, err);
+@@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
+       int len;
+       ubifs_err("corruption at LEB %d:%d", lnum, offs);
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+       len = c->leb_size - offs;
+       if (len > 8192)
+@@ -328,7 +328,7 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+               if (!quiet)
+                       ubifs_err("empty space starts at non-aligned offset %d",
+                                 offs);
+-              goto corrupted;;
++              goto corrupted;
+       }
+       ubifs_end_scan(c, sleb, lnum, offs);
+diff --git a/fs/ubifs/shrinker.c b/fs/ubifs/shrinker.c
+index 46961c0..d8f5d0f 100644
+--- a/fs/ubifs/shrinker.c
++++ b/fs/ubifs/shrinker.c
+@@ -283,7 +283,11 @@ int ubifs_shrinker(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+       long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
+       if (nr == 0)
+-              return clean_zn_cnt;
++              /*
++               * Due to the way UBIFS updates the clean znode counter it may
++               * temporarily be negative.
++               */
++              return clean_zn_cnt >= 0 ? clean_zn_cnt : 1;
+       if (!clean_zn_cnt) {
+               /*
+diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
+index 91fac54..83651cd 100644
+--- a/fs/ubifs/super.c
++++ b/fs/ubifs/super.c
+@@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+       if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
+               return 4;
+-      if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG)
++      if (ui->xattr && !S_ISREG(inode->i_mode))
+               return 5;
+       if (!ubifs_compr_present(ui->compr_type)) {
+@@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+                          ubifs_compr_name(ui->compr_type));
+       }
+-      err = dbg_check_dir_size(c, inode);
++      err = dbg_check_dir(c, inode);
+       return err;
+ }
+@@ -367,7 +367,7 @@ out:
+               ubifs_release_dirty_inode_budget(c, ui);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+ done:
+@@ -504,9 +504,12 @@ static int init_constants_early(struct ubifs_info *c)
+       c->leb_cnt = c->vi.size;
+       c->leb_size = c->vi.usable_leb_size;
++      c->leb_start = c->di.leb_start;
+       c->half_leb_size = c->leb_size / 2;
+       c->min_io_size = c->di.min_io_size;
+       c->min_io_shift = fls(c->min_io_size) - 1;
++      c->max_write_size = c->di.max_write_size;
++      c->max_write_shift = fls(c->max_write_size) - 1;
+       if (c->leb_size < UBIFS_MIN_LEB_SZ) {
+               ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
+@@ -526,6 +529,18 @@ static int init_constants_early(struct ubifs_info *c)
+       }
+       /*
++       * Maximum write size has to be greater or equivalent to min. I/O
++       * size, and be multiple of min. I/O size.
++       */
++      if (c->max_write_size < c->min_io_size ||
++          c->max_write_size % c->min_io_size ||
++          !is_power_of_2(c->max_write_size)) {
++              ubifs_err("bad write buffer size %d for %d min. I/O unit",
++                        c->max_write_size, c->min_io_size);
++              return -EINVAL;
++      }
++
++      /*
+        * UBIFS aligns all node to 8-byte boundary, so to make function in
+        * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is
+        * less than 8.
+@@ -533,6 +548,10 @@ static int init_constants_early(struct ubifs_info *c)
+       if (c->min_io_size < 8) {
+               c->min_io_size = 8;
+               c->min_io_shift = 3;
++              if (c->max_write_size < c->min_io_size) {
++                      c->max_write_size = c->min_io_size;
++                      c->max_write_shift = c->min_io_shift;
++              }
+       }
+       c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+@@ -667,11 +686,11 @@ static int init_constants_sb(struct ubifs_info *c)
+        * be compressed and direntries are of the maximum size.
+        *
+        * Note, data, which may be stored in inodes is budgeted separately, so
+-       * it is not included into 'c->inode_budget'.
++       * it is not included into 'c->bi.inode_budget'.
+        */
+-      c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
+-      c->inode_budget = UBIFS_INO_NODE_SZ;
+-      c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
++      c->bi.page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
++      c->bi.inode_budget = UBIFS_INO_NODE_SZ;
++      c->bi.dent_budget = UBIFS_MAX_DENT_NODE_SZ;
+       /*
+        * When the amount of flash space used by buds becomes
+@@ -715,7 +734,7 @@ static void init_constants_master(struct ubifs_info *c)
+ {
+       long long tmp64;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->report_rp_size = ubifs_reported_space(c, c->rp_size);
+       /*
+@@ -784,15 +803,18 @@ static int alloc_wbufs(struct ubifs_info *c)
+               c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
+               c->jheads[i].wbuf.jhead = i;
++              c->jheads[i].grouped = 1;
+       }
+       c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
+       /*
+        * Garbage Collector head likely contains long-term data and
+-       * does not need to be synchronized by timer.
++       * does not need to be synchronized by timer. Also GC head nodes are
++       * not grouped.
+        */
+       c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
+       c->jheads[GCHD].wbuf.no_timer = 1;
++      c->jheads[GCHD].grouped = 0;
+       return 0;
+ }
+@@ -884,7 +906,7 @@ static int check_volume_empty(struct ubifs_info *c)
+       c->empty = 1;
+       for (lnum = 0; lnum < c->leb_cnt; lnum++) {
+-              err = ubi_is_mapped(c->ubi, lnum);
++              err = ubifs_is_mapped(c, lnum);
+               if (unlikely(err < 0))
+                       return err;
+               if (err == 1) {
+@@ -1117,8 +1139,8 @@ static int check_free_space(struct ubifs_info *c)
+ {
+       ubifs_assert(c->dark_wm > 0);
+       if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
+-              ubifs_err("insufficient free space to mount in read/write mode");
+-              dbg_dump_budg(c);
++              ubifs_err("insufficient free space to mount in R/W mode");
++              dbg_dump_budg(c, &c->bi);
+               dbg_dump_lprops(c);
+               return -ENOSPC;
+       }
+@@ -1194,11 +1216,14 @@ static int mount_ubifs(struct ubifs_info *c)
+       if (c->bulk_read == 1)
+               bu_init(c);
+-      /*
+-       * We have to check all CRCs, even for data nodes, when we mount the FS
+-       * (specifically, when we are replaying).
+-       */
+-      c->always_chk_crc = 1;
++      if (!c->ro_mount) {
++              c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
++                                             GFP_KERNEL);
++              if (!c->write_reserve_buf)
++                      goto out_free;
++      }
++
++      c->mounting = 1;
+       err = ubifs_read_superblock(c);
+       if (err)
+@@ -1227,12 +1252,12 @@ static int mount_ubifs(struct ubifs_info *c)
+               goto out_free;
+       }
++      err = alloc_wbufs(c);
++      if (err)
++              goto out_cbuf;
++
+       sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
+       if (!c->ro_mount) {
+-              err = alloc_wbufs(c);
+-              if (err)
+-                      goto out_cbuf;
+-
+               /* Create background thread */
+               c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
+               if (IS_ERR(c->bgt)) {
+@@ -1254,12 +1279,25 @@ static int mount_ubifs(struct ubifs_info *c)
+       if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
+               ubifs_msg("recovery needed");
+               c->need_recovery = 1;
+-              if (!c->ro_mount) {
+-                      err = ubifs_recover_inl_heads(c, c->sbuf);
+-                      if (err)
+-                              goto out_master;
+-              }
+-      } else if (!c->ro_mount) {
++      }
++
++      if (c->need_recovery && !c->ro_mount) {
++              err = ubifs_recover_inl_heads(c, c->sbuf);
++              if (err)
++                      goto out_master;
++      }
++
++      err = ubifs_lpt_init(c, 1, !c->ro_mount);
++      if (err)
++              goto out_master;
++
++      if (!c->ro_mount && c->space_fixup) {
++              err = ubifs_fixup_free_space(c);
++              if (err)
++                      goto out_master;
++      }
++
++      if (!c->ro_mount) {
+               /*
+                * Set the "dirty" flag so that if we reboot uncleanly we
+                * will notice this immediately on the next mount.
+@@ -1267,14 +1305,10 @@ static int mount_ubifs(struct ubifs_info *c)
+               c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+               err = ubifs_write_master(c);
+               if (err)
+-                      goto out_master;
++                      goto out_lpt;
+       }
+-      err = ubifs_lpt_init(c, 1, !c->ro_mount);
+-      if (err)
+-              goto out_lpt;
+-
+-      err = dbg_check_idx_size(c, c->old_idx_sz);
++      err = dbg_check_idx_size(c, c->bi.old_idx_sz);
+       if (err)
+               goto out_lpt;
+@@ -1283,7 +1317,7 @@ static int mount_ubifs(struct ubifs_info *c)
+               goto out_journal;
+       /* Calculate 'min_idx_lebs' after journal replay */
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
+       if (err)
+@@ -1374,7 +1408,7 @@ static int mount_ubifs(struct ubifs_info *c)
+       if (err)
+               goto out_infos;
+-      c->always_chk_crc = 0;
++      c->mounting = 0;
+       ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
+                 c->vi.ubi_num, c->vi.vol_id, c->vi.name);
+@@ -1395,6 +1429,7 @@ static int mount_ubifs(struct ubifs_info *c)
+       dbg_msg("compiled on:         " __DATE__ " at " __TIME__);
+       dbg_msg("min. I/O unit size:  %d bytes", c->min_io_size);
++      dbg_msg("max. write size:     %d bytes", c->max_write_size);
+       dbg_msg("LEB size:            %d bytes (%d KiB)",
+               c->leb_size, c->leb_size >> 10);
+       dbg_msg("data journal heads:  %d",
+@@ -1411,7 +1446,8 @@ static int mount_ubifs(struct ubifs_info *c)
+               c->main_lebs, c->main_first, c->leb_cnt - 1);
+       dbg_msg("index LEBs:          %d", c->lst.idx_lebs);
+       dbg_msg("total index bytes:   %lld (%lld KiB, %lld MiB)",
+-              c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
++              c->bi.old_idx_sz, c->bi.old_idx_sz >> 10,
++              c->bi.old_idx_sz >> 20);
+       dbg_msg("key hash type:       %d", c->key_hash_type);
+       dbg_msg("tree fanout:         %d", c->fanout);
+       dbg_msg("reserved GC LEB:     %d", c->gc_lnum);
+@@ -1424,9 +1460,9 @@ static int mount_ubifs(struct ubifs_info *c)
+               UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
+       dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
+               UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
+-      dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu",
+-              UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+-              UBIFS_MAX_DENT_NODE_SZ);
++      dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu, idx %d",
++              UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
++              UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout));
+       dbg_msg("dead watermark:      %d", c->dead_wm);
+       dbg_msg("dark watermark:      %d", c->dark_wm);
+       dbg_msg("LEB overhead:        %d", c->leb_overhead);
+@@ -1466,6 +1502,7 @@ out_wbufs:
+ out_cbuf:
+       kfree(c->cbuf);
+ out_free:
++      kfree(c->write_reserve_buf);
+       kfree(c->bu.buf);
+       vfree(c->ileb_buf);
+       vfree(c->sbuf);
+@@ -1504,6 +1541,7 @@ static void ubifs_umount(struct ubifs_info *c)
+       kfree(c->cbuf);
+       kfree(c->rcvrd_mst_node);
+       kfree(c->mst_node);
++      kfree(c->write_reserve_buf);
+       kfree(c->bu.buf);
+       vfree(c->ileb_buf);
+       vfree(c->sbuf);
+@@ -1535,7 +1573,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+       mutex_lock(&c->umount_mutex);
+       dbg_save_space_info(c);
+       c->remounting_rw = 1;
+-      c->always_chk_crc = 1;
++      c->ro_mount = 0;
+       err = check_free_space(c);
+       if (err)
+@@ -1551,6 +1589,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+               }
+               sup->leb_cnt = cpu_to_le32(c->leb_cnt);
+               err = ubifs_write_sb_node(c, sup);
++              kfree(sup);
+               if (err)
+                       goto out;
+       }
+@@ -1590,16 +1629,14 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+               goto out;
+       }
+-      err = ubifs_lpt_init(c, 0, 1);
+-      if (err)
++      c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
++      if (!c->write_reserve_buf)
+               goto out;
+-      err = alloc_wbufs(c);
++      err = ubifs_lpt_init(c, 0, 1);
+       if (err)
+               goto out;
+-      ubifs_create_buds_lists(c);
+-
+       /* Create background thread */
+       c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
+       if (IS_ERR(c->bgt)) {
+@@ -1634,20 +1671,37 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+       if (err)
+               goto out;
++      dbg_gen("re-mounted read-write");
++      c->remounting_rw = 0;
++
+       if (c->need_recovery) {
+               c->need_recovery = 0;
+               ubifs_msg("deferred recovery completed");
++      } else {
++              /*
++               * Do not run the debugging space check if the were doing
++               * recovery, because when we saved the information we had the
++               * file-system in a state where the TNC and lprops has been
++               * modified in memory, but all the I/O operations (including a
++               * commit) were deferred. So the file-system was in
++               * "non-committed" state. Now the file-system is in committed
++               * state, and of course the amount of free space will change
++               * because, for example, the old index size was imprecise.
++               */
++              err = dbg_check_space_info(c);
++      }
++
++      if (c->space_fixup) {
++              err = ubifs_fixup_free_space(c);
++              if (err)
++                      goto out;
+       }
+-      dbg_gen("re-mounted read-write");
+-      c->ro_mount = 0;
+-      c->remounting_rw = 0;
+-      c->always_chk_crc = 0;
+-      err = dbg_check_space_info(c);
+       mutex_unlock(&c->umount_mutex);
+       return err;
+ out:
++      c->ro_mount = 1;
+       vfree(c->orph_buf);
+       c->orph_buf = NULL;
+       if (c->bgt) {
+@@ -1655,11 +1709,12 @@ out:
+               c->bgt = NULL;
+       }
+       free_wbufs(c);
++      kfree(c->write_reserve_buf);
++      c->write_reserve_buf = NULL;
+       vfree(c->ileb_buf);
+       c->ileb_buf = NULL;
+       ubifs_lpt_free(c, 1);
+       c->remounting_rw = 0;
+-      c->always_chk_crc = 0;
+       mutex_unlock(&c->umount_mutex);
+       return err;
+ }
+@@ -1696,9 +1751,10 @@ static void ubifs_remount_ro(struct ubifs_info *c)
+       if (err)
+               ubifs_ro_mode(c, err);
+-      free_wbufs(c);
+       vfree(c->orph_buf);
+       c->orph_buf = NULL;
++      kfree(c->write_reserve_buf);
++      c->write_reserve_buf = NULL;
+       vfree(c->ileb_buf);
+       c->ileb_buf = NULL;
+       ubifs_lpt_free(c, 1);
+@@ -1722,10 +1778,11 @@ static void ubifs_put_super(struct super_block *sb)
+        * of the media. For example, there will be dirty inodes if we failed
+        * to write them back because of I/O errors.
+        */
+-      ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
+-      ubifs_assert(c->budg_idx_growth == 0);
+-      ubifs_assert(c->budg_dd_growth == 0);
+-      ubifs_assert(c->budg_data_growth == 0);
++      if (!c->ro_error) {
++              ubifs_assert(c->bi.idx_growth == 0);
++              ubifs_assert(c->bi.dd_growth == 0);
++              ubifs_assert(c->bi.data_growth == 0);
++      }
+       /*
+        * The 'c->umount_lock' prevents races between UBIFS memory shrinker
+@@ -1929,6 +1986,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+       mutex_init(&c->mst_mutex);
+       mutex_init(&c->umount_mutex);
+       mutex_init(&c->bu_mutex);
++      mutex_init(&c->write_reserve_mutex);
+       init_waitqueue_head(&c->cmt_wq);
+       c->buds = RB_ROOT;
+       c->old_idx = RB_ROOT;
+@@ -1946,6 +2004,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+       INIT_LIST_HEAD(&c->old_buds);
+       INIT_LIST_HEAD(&c->orph_list);
+       INIT_LIST_HEAD(&c->orph_new);
++      c->no_chk_data_crc = 1;
+       c->vfs_sb = sb;
+       c->highest_inum = UBIFS_FIRST_INO;
+diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
+index ad9cf01..16ad84d 100644
+--- a/fs/ubifs/tnc.c
++++ b/fs/ubifs/tnc.c
+@@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
+       __set_bit(DIRTY_ZNODE, &zn->flags);
+       __clear_bit(COW_ZNODE, &zn->flags);
+-      ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++      ubifs_assert(!ubifs_zn_obsolete(znode));
+       __set_bit(OBSOLETE_ZNODE, &znode->flags);
+       if (znode->level != 0) {
+@@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
+       struct ubifs_znode *zn;
+       int err;
+-      if (!test_bit(COW_ZNODE, &znode->flags)) {
++      if (!ubifs_zn_cow(znode)) {
+               /* znode is not being committed */
+               if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
+                       atomic_long_inc(&c->dirty_zn_cnt);
+@@ -344,12 +344,11 @@ static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+               return err;
+       }
+-      lnc_node = kmalloc(zbr->len, GFP_NOFS);
++      lnc_node = kmemdup(node, zbr->len, GFP_NOFS);
+       if (!lnc_node)
+               /* We don't have to have the cache, so no error */
+               return 0;
+-      memcpy(lnc_node, node, zbr->len);
+       zbr->leaf = lnc_node;
+       return 0;
+ }
+@@ -447,8 +446,11 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+  *
+  * Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
+  * is true (it is controlled by corresponding mount option). However, if
+- * @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
+- * checked.
++ * @c->mounting or @c->remounting_rw is true (we are mounting or re-mounting to
++ * R/W mode), @c->no_chk_data_crc is ignored and CRC is checked. This is
++ * because during mounting or re-mounting from R/O mode to R/W mode we may read
++ * journal nodes (when replying the journal or doing the recovery) and the
++ * journal nodes may potentially be corrupted, so checking is required.
+  */
+ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+                        int len, int lnum, int offs)
+@@ -459,7 +461,7 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+       dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
+       if (err) {
+               ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
+                         type, lnum, offs, err);
+@@ -476,7 +478,8 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+       if (node_len != len)
+               return 0;
+-      if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
++      if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting &&
++          !c->remounting_rw)
+               return 1;
+       crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+@@ -502,7 +505,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+ {
+       int ret;
+-      dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
++      dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
+       ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
+                           zbr->offs);
+@@ -516,8 +519,8 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+                       ret = 0;
+       }
+       if (ret == 0 && c->replaying)
+-              dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
+-                      zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
++              dbg_mntk(key, "dangling branch LEB %d:%d len %d, key ",
++                      zbr->lnum, zbr->offs, zbr->len);
+       return ret;
+ }
+@@ -992,9 +995,9 @@ static int fallible_resolve_collision(struct ubifs_info *c,
+       if (adding || !o_znode)
+               return 0;
+-      dbg_mnt("dangling match LEB %d:%d len %d %s",
++      dbg_mntk(key, "dangling match LEB %d:%d len %d key ",
+               o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
+-              o_znode->zbranch[o_n].len, DBGKEY(key));
++              o_znode->zbranch[o_n].len);
+       *zn = o_znode;
+       *n = o_n;
+       return 1;
+@@ -1176,7 +1179,7 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       unsigned long time = get_seconds();
+-      dbg_tnc("search key %s", DBGKEY(key));
++      dbg_tnck(key, "search key ");
+       ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
+       znode = c->zroot.znode;
+@@ -1312,7 +1315,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       unsigned long time = get_seconds();
+-      dbg_tnc("search and dirty key %s", DBGKEY(key));
++      dbg_tnck(key, "search and dirty key ");
+       znode = c->zroot.znode;
+       if (unlikely(!znode)) {
+@@ -1662,7 +1665,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
+       if (!overlap) {
+               /* We may safely unlock the write-buffer and read the data */
+               spin_unlock(&wbuf->lock);
+-              return ubi_read(c->ubi, lnum, buf, offs, len);
++              return ubifs_leb_read(c, lnum, buf, offs, len, 0);
+       }
+       /* Don't read under wbuf */
+@@ -1676,7 +1679,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
+       if (rlen > 0)
+               /* Read everything that goes before write-buffer */
+-              return ubi_read(c->ubi, lnum, buf, offs, rlen);
++              return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
+       return 0;
+ }
+@@ -1719,8 +1722,8 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
+       if (!keys_eq(c, &zbr->key, &key1)) {
+               ubifs_err("bad key in node at LEB %d:%d",
+                         zbr->lnum, zbr->offs);
+-              dbg_tnc("looked for key %s found node's key %s",
+-                      DBGKEY(&zbr->key), DBGKEY1(&key1));
++              dbg_tnck(&zbr->key, "looked for key ");
++              dbg_tnck(&key1, "found node's key ");
+               goto out_err;
+       }
+@@ -1763,7 +1766,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+       if (wbuf)
+               err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
+       else
+-              err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
++              err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
+       /* Check for a race with GC */
+       if (maybe_leb_gced(c, lnum, bu->gc_seq))
+@@ -1773,7 +1776,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+               ubifs_err("failed to read from LEB %d:%d, error %d",
+                         lnum, offs, err);
+               dbg_dump_stack();
+-              dbg_tnc("key %s", DBGKEY(&bu->key));
++              dbg_tnck(&bu->key, "key ");
+               return err;
+       }
+@@ -1808,7 +1811,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+       int found, n, err;
+       struct ubifs_znode *znode;
+-      dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
++      dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
+       mutex_lock(&c->tnc_mutex);
+       found = ubifs_lookup_level0(c, key, &znode, &n);
+       if (!found) {
+@@ -1982,8 +1985,7 @@ again:
+       zp = znode->parent;
+       if (znode->child_cnt < c->fanout) {
+               ubifs_assert(n != c->fanout);
+-              dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
+-                      DBGKEY(key));
++              dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level);
+               insert_zbranch(znode, zbr, n);
+@@ -1998,7 +2000,7 @@ again:
+        * Unfortunately, @znode does not have more empty slots and we have to
+        * split it.
+        */
+-      dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
++      dbg_tnck(key, "splitting level %d, key ", znode->level);
+       if (znode->alt)
+               /*
+@@ -2092,7 +2094,7 @@ do_split:
+       }
+       /* Insert new key and branch */
+-      dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
++      dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level);
+       insert_zbranch(zi, zbr, n);
+@@ -2168,7 +2170,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
++      dbg_tnck(key, "%d:%d, len %d, key ", lnum, offs, len);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (!found) {
+               struct ubifs_zbranch zbr;
+@@ -2217,8 +2219,8 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
+-              old_offs, lnum, offs, len, DBGKEY(key));
++      dbg_tnck(key, "old LEB %d:%d, new LEB %d:%d, len %d, key ", old_lnum,
++               old_offs, lnum, offs, len);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2300,8 +2302,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
+-              DBGKEY(key));
++      dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
++               lnum, offs, nm->len, nm->name);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2394,7 +2396,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+       /* Delete without merge for now */
+       ubifs_assert(znode->level == 0);
+       ubifs_assert(n >= 0 && n < c->fanout);
+-      dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
++      dbg_tnck(&znode->zbranch[n].key, "deleting key ");
+       zbr = &znode->zbranch[n];
+       lnc_free(zbr);
+@@ -2419,7 +2421,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+        */
+       do {
+-              ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++              ubifs_assert(!ubifs_zn_obsolete(znode));
+               ubifs_assert(ubifs_zn_dirty(znode));
+               zp = znode->parent;
+@@ -2475,9 +2477,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+                       c->zroot.offs = zbr->offs;
+                       c->zroot.len = zbr->len;
+                       c->zroot.znode = znode;
+-                      ubifs_assert(!test_bit(OBSOLETE_ZNODE,
+-                                   &zp->flags));
+-                      ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
++                      ubifs_assert(!ubifs_zn_obsolete(zp));
++                      ubifs_assert(ubifs_zn_dirty(zp));
+                       atomic_long_dec(&c->dirty_zn_cnt);
+                       if (zp->cnext) {
+@@ -2505,7 +2506,7 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("key %s", DBGKEY(key));
++      dbg_tnck(key, "key ");
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2536,7 +2537,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
++      dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
+       err = lookup_level0_dirty(c, key, &znode, &n);
+       if (err < 0)
+               goto out_unlock;
+@@ -2553,11 +2554,11 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+               if (err) {
+                       /* Ensure the znode is dirtied */
+                       if (znode->cnext || !ubifs_zn_dirty(znode)) {
+-                                  znode = dirty_cow_bottom_up(c, znode);
+-                                  if (IS_ERR(znode)) {
+-                                          err = PTR_ERR(znode);
+-                                          goto out_unlock;
+-                                  }
++                              znode = dirty_cow_bottom_up(c, znode);
++                              if (IS_ERR(znode)) {
++                                      err = PTR_ERR(znode);
++                                      goto out_unlock;
++                              }
+                       }
+                       err = tnc_delete(c, znode, n);
+               }
+@@ -2651,7 +2652,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
+                               dbg_dump_znode(c, znode);
+                               goto out_unlock;
+                       }
+-                      dbg_tnc("removing %s", DBGKEY(key));
++                      dbg_tnck(key, "removing key ");
+               }
+               if (k) {
+                       for (i = n + 1 + k; i < znode->child_cnt; i++)
+@@ -2771,7 +2772,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
+       struct ubifs_zbranch *zbr;
+       union ubifs_key *dkey;
+-      dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
++      dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
+       ubifs_assert(is_hash_key(c, key));
+       mutex_lock(&c->tnc_mutex);
+@@ -2861,7 +2862,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
+               struct ubifs_znode *znode = cnext;
+               cnext = cnext->cnext;
+-              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++              if (ubifs_zn_obsolete(znode))
+                       kfree(znode);
+       } while (cnext && cnext != c->cnext);
+ }
+@@ -2872,12 +2873,13 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
+  */
+ void ubifs_tnc_close(struct ubifs_info *c)
+ {
+-      long clean_freed;
+-
+       tnc_destroy_cnext(c);
+       if (c->zroot.znode) {
+-              clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
+-              atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt);
++              long n;
++
++              ubifs_destroy_tnc_subtree(c->zroot.znode);
++              n = atomic_long_read(&c->clean_zn_cnt);
++              atomic_long_sub(n, &ubifs_clean_zn_cnt);
+       }
+       kfree(c->gap_lebs);
+       kfree(c->ilebs);
+@@ -3296,7 +3298,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+       if (!S_ISREG(inode->i_mode))
+               return 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+@@ -3329,12 +3331,13 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+ out_dump:
+       block = key_block(c, key);
+-      ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
+-                "(data key %s)", (unsigned long)inode->i_ino, size,
+-                ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
++      ubifs_err("inode %lu has size %lld, but there are data at offset %lld",
++                (unsigned long)inode->i_ino, size,
++                ((loff_t)block) << UBIFS_BLOCK_SHIFT);
++      mutex_unlock(&c->tnc_mutex);
+       dbg_dump_inode(c, inode);
+       dbg_dump_stack();
+-      err = -EINVAL;
++      return -EINVAL;
+ out_unlock:
+       mutex_unlock(&c->tnc_mutex);
+diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
+index 53288e5..4c15f07 100644
+--- a/fs/ubifs/tnc_commit.c
++++ b/fs/ubifs/tnc_commit.c
+@@ -22,6 +22,7 @@
+ /* This file implements TNC functions for committing */
++#include <linux/random.h>
+ #include "ubifs.h"
+ /**
+@@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
+       atomic_long_dec(&c->dirty_zn_cnt);
+       ubifs_assert(ubifs_zn_dirty(znode));
+-      ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
++      ubifs_assert(ubifs_zn_cow(znode));
++      /*
++       * Note, unlike 'write_index()' we do not add memory barriers here
++       * because this function is called with @c->tnc_mutex locked.
++       */
+       __clear_bit(DIRTY_ZNODE, &znode->flags);
+       __clear_bit(COW_ZNODE, &znode->flags);
+@@ -377,15 +382,13 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
+                               c->gap_lebs = NULL;
+                               return err;
+                       }
+-                      if (!dbg_force_in_the_gaps_enabled) {
++                      if (!dbg_is_chk_index(c)) {
+                               /*
+                                * Do not print scary warnings if the debugging
+                                * option which forces in-the-gaps is enabled.
+                                */
+-                              ubifs_err("out of space");
+-                              spin_lock(&c->space_lock);
+-                              dbg_dump_budg(c);
+-                              spin_unlock(&c->space_lock);
++                              ubifs_warn("out of space");
++                              dbg_dump_budg(c, &c->bi);
+                               dbg_dump_lprops(c);
+                       }
+                       /* Try to commit anyway */
+@@ -493,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
+               else
+                       next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+-              if (c->min_io_size == 1) {
+-                      buf_offs += ALIGN(len, 8);
+-                      if (next_len) {
+-                              if (buf_offs + next_len <= c->leb_size)
+-                                      continue;
+-                              err = ubifs_update_one_lp(c, lnum, 0,
+-                                              c->leb_size - buf_offs, 0, 0);
+-                              if (err)
+-                                      return err;
+-                              lnum = -1;
+-                              continue;
+-                      }
+-                      err = ubifs_update_one_lp(c, lnum,
+-                                      c->leb_size - buf_offs, 0, 0, 0);
+-                      if (err)
+-                              return err;
+-                      break;
+-              }
+-
+               /* Update buffer positions */
+               wlen = used + len;
+               used += ALIGN(len, 8);
+@@ -660,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
+       }
+       cnt += 1;
+       while (1) {
+-              ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
++              ubifs_assert(!ubifs_zn_cow(znode));
+               __set_bit(COW_ZNODE, &znode->flags);
+               znode->alt = 0;
+               cnext = find_next_dirty(znode);
+@@ -706,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
+               c->ilebs[c->ileb_cnt++] = lnum;
+               dbg_cmt("LEB %d", lnum);
+       }
+-      if (dbg_force_in_the_gaps())
++      if (dbg_is_chk_index(c) && !(random32() & 7))
+               return -ENOSPC;
+       return 0;
+ }
+@@ -796,16 +780,16 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+       spin_lock(&c->space_lock);
+       /*
+        * Although we have not finished committing yet, update size of the
+-       * committed index ('c->old_idx_sz') and zero out the index growth
++       * committed index ('c->bi.old_idx_sz') and zero out the index growth
+        * budget. It is OK to do this now, because we've reserved all the
+        * space which is needed to commit the index, and it is save for the
+        * budgeting subsystem to assume the index is already committed,
+        * even though it is not.
+        */
+-      ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+-      c->old_idx_sz = c->calc_idx_sz;
+-      c->budg_uncommitted_idx = 0;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
++      c->bi.old_idx_sz = c->calc_idx_sz;
++      c->bi.uncommitted_idx = 0;
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       spin_unlock(&c->space_lock);
+       mutex_unlock(&c->tnc_mutex);
+@@ -832,7 +816,7 @@ static int write_index(struct ubifs_info *c)
+       struct ubifs_idx_node *idx;
+       struct ubifs_znode *znode, *cnext;
+       int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
+-      int avail, wlen, err, lnum_pos = 0;
++      int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
+       cnext = c->enext;
+       if (!cnext)
+@@ -909,7 +893,7 @@ static int write_index(struct ubifs_info *c)
+               cnext = znode->cnext;
+               ubifs_assert(ubifs_zn_dirty(znode));
+-              ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
++              ubifs_assert(ubifs_zn_cow(znode));
+               /*
+                * It is important that other threads should see %DIRTY_ZNODE
+@@ -924,6 +908,28 @@ static int write_index(struct ubifs_info *c)
+               clear_bit(COW_ZNODE, &znode->flags);
+               smp_mb__after_clear_bit();
++              /*
++               * We have marked the znode as clean but have not updated the
++               * @c->clean_zn_cnt counter. If this znode becomes dirty again
++               * before 'free_obsolete_znodes()' is called, then
++               * @c->clean_zn_cnt will be decremented before it gets
++               * incremented (resulting in 2 decrements for the same znode).
++               * This means that @c->clean_zn_cnt may become negative for a
++               * while.
++               *
++               * Q: why we cannot increment @c->clean_zn_cnt?
++               * A: because we do not have the @c->tnc_mutex locked, and the
++               *    following code would be racy and buggy:
++               *
++               *    if (!ubifs_zn_obsolete(znode)) {
++               *            atomic_long_inc(&c->clean_zn_cnt);
++               *            atomic_long_inc(&ubifs_clean_zn_cnt);
++               *    }
++               *
++               *    Thus, we just delay the @c->clean_zn_cnt update until we
++               *    have the mutex locked.
++               */
++
+               /* Do not access znode from this point on */
+               /* Update buffer positions */
+@@ -940,65 +946,38 @@ static int write_index(struct ubifs_info *c)
+               else
+                       next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+-              if (c->min_io_size == 1) {
+-                      /*
+-                       * Write the prepared index node immediately if there is
+-                       * no minimum IO size
+-                       */
+-                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+-                                            wlen, UBI_SHORTTERM);
+-                      if (err)
+-                              return err;
+-                      buf_offs += ALIGN(wlen, 8);
+-                      if (next_len) {
+-                              used = 0;
+-                              avail = buf_len;
+-                              if (buf_offs + next_len > c->leb_size) {
+-                                      err = ubifs_update_one_lp(c, lnum,
+-                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
+-                                      if (err)
+-                                              return err;
+-                                      lnum = -1;
+-                              }
++              nxt_offs = buf_offs + used + next_len;
++              if (next_len && nxt_offs <= c->leb_size) {
++                      if (avail > 0)
+                               continue;
+-                      }
++                      else
++                              blen = buf_len;
+               } else {
+-                      int blen, nxt_offs = buf_offs + used + next_len;
+-
+-                      if (next_len && nxt_offs <= c->leb_size) {
+-                              if (avail > 0)
+-                                      continue;
+-                              else
+-                                      blen = buf_len;
+-                      } else {
+-                              wlen = ALIGN(wlen, 8);
+-                              blen = ALIGN(wlen, c->min_io_size);
+-                              ubifs_pad(c, c->cbuf + wlen, blen - wlen);
+-                      }
+-                      /*
+-                       * The buffer is full or there are no more znodes
+-                       * to do
+-                       */
+-                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+-                                            blen, UBI_SHORTTERM);
+-                      if (err)
+-                              return err;
+-                      buf_offs += blen;
+-                      if (next_len) {
+-                              if (nxt_offs > c->leb_size) {
+-                                      err = ubifs_update_one_lp(c, lnum,
+-                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
+-                                      if (err)
+-                                              return err;
+-                                      lnum = -1;
+-                              }
+-                              used -= blen;
+-                              if (used < 0)
+-                                      used = 0;
+-                              avail = buf_len - used;
+-                              memmove(c->cbuf, c->cbuf + blen, used);
+-                              continue;
++                      wlen = ALIGN(wlen, 8);
++                      blen = ALIGN(wlen, c->min_io_size);
++                      ubifs_pad(c, c->cbuf + wlen, blen - wlen);
++              }
++
++              /* The buffer is full or there are no more znodes to do */
++              err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
++                                    UBI_SHORTTERM);
++              if (err)
++                      return err;
++              buf_offs += blen;
++              if (next_len) {
++                      if (nxt_offs > c->leb_size) {
++                              err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
++                                                        0, LPROPS_TAKEN);
++                              if (err)
++                                      return err;
++                              lnum = -1;
+                       }
++                      used -= blen;
++                      if (used < 0)
++                              used = 0;
++                      avail = buf_len - used;
++                      memmove(c->cbuf, c->cbuf + blen, used);
++                      continue;
+               }
+               break;
+       }
+@@ -1031,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
+       do {
+               znode = cnext;
+               cnext = znode->cnext;
+-              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++              if (ubifs_zn_obsolete(znode))
+                       kfree(znode);
+               else {
+                       znode->cnext = NULL;
+diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
+index b48db99..dc28fe6 100644
+--- a/fs/ubifs/tnc_misc.c
++++ b/fs/ubifs/tnc_misc.c
+@@ -328,8 +328,8 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
+               case UBIFS_XENT_KEY:
+                       break;
+               default:
+-                      dbg_msg("bad key type at slot %d: %s", i,
+-                              DBGKEY(&zbr->key));
++                      dbg_msg("bad key type at slot %d: %d",
++                              i, key_type(c, &zbr->key));
+                       err = 3;
+                       goto out_dump;
+               }
+@@ -475,7 +475,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+                                     zbr->offs);
+       if (err) {
+-              dbg_tnc("key %s", DBGKEY(key));
++              dbg_tnck(key, "key ");
+               return err;
+       }
+@@ -484,8 +484,8 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+       if (!keys_eq(c, key, &key1)) {
+               ubifs_err("bad key in node at LEB %d:%d",
+                         zbr->lnum, zbr->offs);
+-              dbg_tnc("looked for key %s found node's key %s",
+-                      DBGKEY(key), DBGKEY1(&key1));
++              dbg_tnck(key, "looked for key ");
++              dbg_tnck(&key1, "but found node's key ");
+               dbg_dump_node(c, node);
+               return -EINVAL;
+       }
+diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
+index 191ca78..e24380c 100644
+--- a/fs/ubifs/ubifs-media.h
++++ b/fs/ubifs/ubifs-media.h
+@@ -408,9 +408,11 @@ enum {
+  * Superblock flags.
+  *
+  * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
++ * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
+  */
+ enum {
+       UBIFS_FLG_BIGLPT = 0x02,
++      UBIFS_FLG_SPACE_FIXUP = 0x04,
+ };
+ /**
+@@ -434,7 +436,7 @@ struct ubifs_ch {
+       __u8 node_type;
+       __u8 group_type;
+       __u8 padding[2];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * union ubifs_dev_desc - device node descriptor.
+@@ -448,7 +450,7 @@ struct ubifs_ch {
+ union ubifs_dev_desc {
+       __le32 new;
+       __le64 huge;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_ino_node - inode node.
+@@ -509,7 +511,7 @@ struct ubifs_ino_node {
+       __le16 compr_type;
+       __u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
+       __u8 data[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_dent_node - directory entry node.
+@@ -534,7 +536,7 @@ struct ubifs_dent_node {
+       __le16 nlen;
+       __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
+       __u8 name[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_data_node - data node.
+@@ -555,7 +557,7 @@ struct ubifs_data_node {
+       __le16 compr_type;
+       __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
+       __u8 data[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_trun_node - truncation node.
+@@ -575,7 +577,7 @@ struct ubifs_trun_node {
+       __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
+       __le64 old_size;
+       __le64 new_size;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_pad_node - padding node.
+@@ -586,7 +588,7 @@ struct ubifs_trun_node {
+ struct ubifs_pad_node {
+       struct ubifs_ch ch;
+       __le32 pad_len;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_sb_node - superblock node.
+@@ -644,7 +646,7 @@ struct ubifs_sb_node {
+       __u8 uuid[16];
+       __le32 ro_compat_version;
+       __u8 padding2[3968];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_mst_node - master node.
+@@ -711,7 +713,7 @@ struct ubifs_mst_node {
+       __le32 idx_lebs;
+       __le32 leb_cnt;
+       __u8 padding[344];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_ref_node - logical eraseblock reference node.
+@@ -727,7 +729,7 @@ struct ubifs_ref_node {
+       __le32 offs;
+       __le32 jhead;
+       __u8 padding[28];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_branch - key/reference/length branch
+@@ -741,7 +743,7 @@ struct ubifs_branch {
+       __le32 offs;
+       __le32 len;
+       __u8 key[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_idx_node - indexing node.
+@@ -755,7 +757,7 @@ struct ubifs_idx_node {
+       __le16 child_cnt;
+       __le16 level;
+       __u8 branches[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_cs_node - commit start node.
+@@ -765,7 +767,7 @@ struct ubifs_idx_node {
+ struct ubifs_cs_node {
+       struct ubifs_ch ch;
+       __le64 cmt_no;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_orph_node - orphan node.
+@@ -777,6 +779,6 @@ struct ubifs_orph_node {
+       struct ubifs_ch ch;
+       __le64 cmt_no;
+       __le64 inos[];
+-} __attribute__ ((packed));
++} __packed;
+ #endif /* __UBIFS_MEDIA_H__ */
+diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
+index 381d6b2..caf9e4b 100644
+--- a/fs/ubifs/ubifs.h
++++ b/fs/ubifs/ubifs.h
+@@ -84,9 +84,6 @@
+ #define INUM_WARN_WATERMARK 0xFFF00000
+ #define INUM_WATERMARK      0xFFFFFF00
+-/* Largest key size supported in this implementation */
+-#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
+-
+ /* Maximum number of entries in each LPT (LEB category) heap */
+ #define LPT_HEAP_SZ 256
+@@ -151,6 +148,12 @@
+  */
+ #define WORST_COMPR_FACTOR 2
++/*
++ * How much memory is needed for a buffer where we comress a data node.
++ */
++#define COMPRESSED_DATA_NODE_BUF_SZ \
++      (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
++
+ /* Maximum expected tree height for use by bottom_up_buf */
+ #define BOTTOM_UP_HEIGHT 64
+@@ -224,14 +227,14 @@ enum {
+  * LPT cnode flag bits.
+  *
+  * DIRTY_CNODE: cnode is dirty
+- * COW_CNODE: cnode is being committed and must be copied before writing
+  * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
+- * so it can (and must) be freed when the commit is finished
++ *                 so it can (and must) be freed when the commit is finished
++ * COW_CNODE: cnode is being committed and must be copied before writing
+  */
+ enum {
+       DIRTY_CNODE    = 0,
+-      COW_CNODE      = 1,
+-      OBSOLETE_CNODE = 2,
++      OBSOLETE_CNODE = 1,
++      COW_CNODE      = 2,
+ };
+ /*
+@@ -271,10 +274,10 @@ struct ubifs_old_idx {
+ /* The below union makes it easier to deal with keys */
+ union ubifs_key {
+-      uint8_t u8[CUR_MAX_KEY_LEN];
+-      uint32_t u32[CUR_MAX_KEY_LEN/4];
+-      uint64_t u64[CUR_MAX_KEY_LEN/8];
+-      __le32 j32[CUR_MAX_KEY_LEN/4];
++      uint8_t u8[UBIFS_SK_LEN];
++      uint32_t u32[UBIFS_SK_LEN/4];
++      uint64_t u64[UBIFS_SK_LEN/8];
++      __le32 j32[UBIFS_SK_LEN/4];
+ };
+ /**
+@@ -383,9 +386,9 @@ struct ubifs_gced_idx_leb {
+  * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
+  * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
+  * make sure @inode->i_size is always changed under @ui_mutex, because it
+- * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would deadlock
+- * with 'ubifs_writepage()' (see file.c). All the other inode fields are
+- * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
++ * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would
++ * deadlock with 'ubifs_writepage()' (see file.c). All the other inode fields
++ * are changed under @ui_mutex, so they do not need "shadow" fields. Note, one
+  * could consider to rework locking and base it on "shadow" fields.
+  */
+ struct ubifs_inode {
+@@ -646,6 +649,7 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
+  * @offs: write-buffer offset in this logical eraseblock
+  * @avail: number of bytes available in the write-buffer
+  * @used:  number of used bytes in the write-buffer
++ * @size: write-buffer size (in [@c->min_io_size, @c->max_write_size] range)
+  * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
+  * %UBI_UNKNOWN)
+  * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
+@@ -680,6 +684,7 @@ struct ubifs_wbuf {
+       int offs;
+       int avail;
+       int used;
++      int size;
+       int dtype;
+       int jhead;
+       int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
+@@ -714,12 +719,14 @@ struct ubifs_bud {
+  * struct ubifs_jhead - journal head.
+  * @wbuf: head's write-buffer
+  * @buds_list: list of bud LEBs belonging to this journal head
++ * @grouped: non-zero if UBIFS groups nodes when writing to this journal head
+  *
+  * Note, the @buds list is protected by the @c->buds_lock.
+  */
+ struct ubifs_jhead {
+       struct ubifs_wbuf wbuf;
+       struct list_head buds_list;
++      unsigned int grouped:1;
+ };
+ /**
+@@ -929,6 +936,40 @@ struct ubifs_mount_opts {
+       unsigned int compr_type:2;
+ };
++/**
++ * struct ubifs_budg_info - UBIFS budgeting information.
++ * @idx_growth: amount of bytes budgeted for index growth
++ * @data_growth: amount of bytes budgeted for cached data
++ * @dd_growth: amount of bytes budgeted for cached data that will make
++ *             other data dirty
++ * @uncommitted_idx: amount of bytes were budgeted for growth of the index, but
++ *                   which still have to be taken into account because the index
++ *                   has not been committed so far
++ * @old_idx_sz: size of index on flash
++ * @min_idx_lebs: minimum number of LEBs required for the index
++ * @nospace: non-zero if the file-system does not have flash space (used as
++ *           optimization)
++ * @nospace_rp: the same as @nospace, but additionally means that even reserved
++ *              pool is full
++ * @page_budget: budget for a page (constant, nenver changed after mount)
++ * @inode_budget: budget for an inode (constant, nenver changed after mount)
++ * @dent_budget: budget for a directory entry (constant, nenver changed after
++ *               mount)
++ */
++struct ubifs_budg_info {
++      long long idx_growth;
++      long long data_growth;
++      long long dd_growth;
++      long long uncommitted_idx;
++      unsigned long long old_idx_sz;
++      int min_idx_lebs;
++      unsigned int nospace:1;
++      unsigned int nospace_rp:1;
++      int page_budget;
++      int inode_budget;
++      int dent_budget;
++};
++
+ struct ubifs_debug_info;
+ /**
+@@ -972,6 +1013,7 @@ struct ubifs_debug_info;
+  * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
+  *
+  * @big_lpt: flag that LPT is too big to write whole during commit
++ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
+  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
+  *                   recovery)
+  * @bulk_read: enable bulk-reads
+@@ -1003,6 +1045,11 @@ struct ubifs_debug_info;
+  * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu
+  * @bu: pre-allocated bulk-read information
+  *
++ * @write_reserve_mutex: protects @write_reserve_buf
++ * @write_reserve_buf: on the write path we allocate memory, which might
++ *                     sometimes be unavailable, in which case we use this
++ *                     write reserve buffer
++ *
+  * @log_lebs: number of logical eraseblocks in the log
+  * @log_bytes: log size in bytes
+  * @log_last: last LEB of the log
+@@ -1024,7 +1071,12 @@ struct ubifs_debug_info;
+  *
+  * @min_io_size: minimal input/output unit size
+  * @min_io_shift: number of bits in @min_io_size minus one
++ * @max_write_size: maximum amount of bytes the underlying flash can write at a
++ *                  time (MTD write buffer size)
++ * @max_write_shift: number of bits in @max_write_size minus one
+  * @leb_size: logical eraseblock size in bytes
++ * @leb_start: starting offset of logical eraseblocks within physical
++ *             eraseblocks
+  * @half_leb_size: half LEB size
+  * @idx_leb_size: how many bytes of an LEB are effectively available when it is
+  *                used to store indexing nodes (@leb_size - @max_idx_node_sz)
+@@ -1039,32 +1091,14 @@ struct ubifs_debug_info;
+  * @dirty_zn_cnt: number of dirty znodes
+  * @clean_zn_cnt: number of clean znodes
+  *
+- * @budg_idx_growth: amount of bytes budgeted for index growth
+- * @budg_data_growth: amount of bytes budgeted for cached data
+- * @budg_dd_growth: amount of bytes budgeted for cached data that will make
+- *                  other data dirty
+- * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
+- *                        but which still have to be taken into account because
+- *                        the index has not been committed so far
+- * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
+- *              @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
+- *              @nospace, and @nospace_rp;
+- * @min_idx_lebs: minimum number of LEBs required for the index
+- * @old_idx_sz: size of index on flash
++ * @space_lock: protects @bi and @lst
++ * @lst: lprops statistics
++ * @bi: budgeting information
+  * @calc_idx_sz: temporary variable which is used to calculate new index size
+  *               (contains accurate new index size at end of TNC commit start)
+- * @lst: lprops statistics
+- * @nospace: non-zero if the file-system does not have flash space (used as
+- *           optimization)
+- * @nospace_rp: the same as @nospace, but additionally means that even reserved
+- *              pool is full
+- *
+- * @page_budget: budget for a page
+- * @inode_budget: budget for an inode
+- * @dent_budget: budget for a directory entry
+  *
+  * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
+- * I/O unit
++ *                 I/O unit
+  * @mst_node_alsz: master node aligned size
+  * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
+  * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
+@@ -1166,22 +1200,20 @@ struct ubifs_debug_info;
+  * @rp_uid: reserved pool user ID
+  * @rp_gid: reserved pool group ID
+  *
+- * @empty: if the UBI device is empty
+- * @replay_tree: temporary tree used during journal replay
++ * @empty: %1 if the UBI device is empty
++ * @need_recovery: %1 if the file-system needs recovery
++ * @replaying: %1 during journal replay
++ * @mounting: %1 while mounting
++ * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
+  * @replay_list: temporary list used during journal replay
+  * @replay_buds: list of buds to replay
+  * @cs_sqnum: sequence number of first node in the log (commit start node)
+  * @replay_sqnum: sequence number of node currently being replayed
+- * @need_recovery: file-system needs recovery
+- * @replaying: set to %1 during journal replay
+  * @unclean_leb_list: LEBs to recover when re-mounting R/O mounted FS to R/W
+  *                    mode
+  * @rcvrd_mst_node: recovered master node to write when re-mounting R/O mounted
+  *                  FS to R/W mode
+  * @size_tree: inode size information for recovery
+- * @remounting_rw: set while re-mounting from R/O mode to R/W mode
+- * @always_chk_crc: always check CRCs (while mounting and remounting to R/W
+- *                  mode)
+  * @mount_opts: UBIFS-specific mount options
+  *
+  * @dbg: debugging-related information
+@@ -1221,6 +1253,7 @@ struct ubifs_info {
+       wait_queue_head_t cmt_wq;
+       unsigned int big_lpt:1;
++      unsigned int space_fixup:1;
+       unsigned int no_chk_data_crc:1;
+       unsigned int bulk_read:1;
+       unsigned int default_compr:2;
+@@ -1250,6 +1283,9 @@ struct ubifs_info {
+       struct mutex bu_mutex;
+       struct bu_info bu;
++      struct mutex write_reserve_mutex;
++      void *write_reserve_buf;
++
+       int log_lebs;
+       long long log_bytes;
+       int log_last;
+@@ -1271,7 +1307,10 @@ struct ubifs_info {
+       int min_io_size;
+       int min_io_shift;
++      int max_write_size;
++      int max_write_shift;
+       int leb_size;
++      int leb_start;
+       int half_leb_size;
+       int idx_leb_size;
+       int leb_cnt;
+@@ -1285,21 +1324,10 @@ struct ubifs_info {
+       atomic_long_t dirty_zn_cnt;
+       atomic_long_t clean_zn_cnt;
+-      long long budg_idx_growth;
+-      long long budg_data_growth;
+-      long long budg_dd_growth;
+-      long long budg_uncommitted_idx;
+       spinlock_t space_lock;
+-      int min_idx_lebs;
+-      unsigned long long old_idx_sz;
+-      unsigned long long calc_idx_sz;
+       struct ubifs_lp_stats lst;
+-      unsigned int nospace:1;
+-      unsigned int nospace_rp:1;
+-
+-      int page_budget;
+-      int inode_budget;
+-      int dent_budget;
++      struct ubifs_budg_info bi;
++      unsigned long long calc_idx_sz;
+       int ref_node_alsz;
+       int mst_node_alsz;
+@@ -1402,19 +1430,18 @@ struct ubifs_info {
+       gid_t rp_gid;
+       /* The below fields are used only during mounting and re-mounting */
+-      int empty;
+-      struct rb_root replay_tree;
++      unsigned int empty:1;
++      unsigned int need_recovery:1;
++      unsigned int replaying:1;
++      unsigned int mounting:1;
++      unsigned int remounting_rw:1;
+       struct list_head replay_list;
+       struct list_head replay_buds;
+       unsigned long long cs_sqnum;
+       unsigned long long replay_sqnum;
+-      int need_recovery;
+-      int replaying;
+       struct list_head unclean_leb_list;
+       struct ubifs_mst_node *rcvrd_mst_node;
+       struct rb_root size_tree;
+-      int remounting_rw;
+-      int always_chk_crc;
+       struct ubifs_mount_opts mount_opts;
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+@@ -1438,6 +1465,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+ /* io.c */
+ void ubifs_ro_mode(struct ubifs_info *c, int err);
++int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
++                 int len, int even_ebadmsg);
++int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                  int len, int dtype);
++int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                   int dtype);
++int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
++int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
++int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
+ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
+ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+                          int dtype);
+@@ -1605,6 +1641,7 @@ int ubifs_write_master(struct ubifs_info *c);
+ int ubifs_read_superblock(struct ubifs_info *c);
+ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
+ int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
++int ubifs_fixup_free_space(struct ubifs_info *c);
+ /* replay.c */
+ int ubifs_validate_entry(struct ubifs_info *c,
+@@ -1713,11 +1750,11 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
+ int ubifs_recover_master_node(struct ubifs_info *c);
+ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
+ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+-                                       int offs, void *sbuf, int grouped);
++                                       int offs, void *sbuf, int jhead);
+ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+                                            int offs, void *sbuf);
+-int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
+-int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
++int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
++int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
+ int ubifs_rcvry_gc_commit(struct ubifs_info *c);
+ int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
+                            int deletion, loff_t new_size);
+diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
+index c74400f..2fdc4fa 100644
+--- a/fs/ubifs/xattr.c
++++ b/fs/ubifs/xattr.c
+@@ -79,9 +79,9 @@ enum {
+       SECURITY_XATTR,
+ };
+-static const struct inode_operations none_inode_operations;
+-static const struct address_space_operations none_address_operations;
+-static const struct file_operations none_file_operations;
++static const struct inode_operations empty_iops;
++static const struct file_operations empty_fops;
++static struct address_space_operations empty_aops;
+ /**
+  * create_xattr - create an extended attribute.
+@@ -130,20 +130,19 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
+       }
+       /* Re-define all operations to be "nothing" */
+-      inode->i_mapping->a_ops = &none_address_operations;
+-      inode->i_op = &none_inode_operations;
+-      inode->i_fop = &none_file_operations;
++      inode->i_mapping->a_ops = &empty_aops;
++      inode->i_op = &empty_iops;
++      inode->i_fop = &empty_fops;
+       inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA;
+       ui = ubifs_inode(inode);
+       ui->xattr = 1;
+       ui->flags |= UBIFS_XATTR_FL;
+-      ui->data = kmalloc(size, GFP_NOFS);
++      ui->data = kmemdup(value, size, GFP_NOFS);
+       if (!ui->data) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+-      memcpy(ui->data, value, size);
+       inode->i_size = ui->ui_size = size;
+       ui->data_len = size;
+@@ -204,12 +203,11 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
+               return err;
+       kfree(ui->data);
+-      ui->data = kmalloc(size, GFP_NOFS);
++      ui->data = kmemdup(value, size, GFP_NOFS);
+       if (!ui->data) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+-      memcpy(ui->data, value, size);
+       inode->i_size = ui->ui_size = size;
+       ui->data_len = size;
+diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
+index b31bd9e..db4836b 100644
+--- a/include/linux/mtd/ubi.h
++++ b/include/linux/mtd/ubi.h
+@@ -21,7 +21,7 @@
+ #ifndef __LINUX_UBI_H__
+ #define __LINUX_UBI_H__
+-#include <asm/ioctl.h>
++#include <linux/ioctl.h>
+ #include <linux/types.h>
+ #include <mtd/ubi-user.h>
+@@ -87,7 +87,7 @@ enum {
+  * physical eraseblock size and on how much bytes UBI headers consume. But
+  * because of the volume alignment (@alignment), the usable size of logical
+  * eraseblocks if a volume may be less. The following equation is true:
+- *    @usable_leb_size = LEB size - (LEB size mod @alignment),
++ *    @usable_leb_size = LEB size - (LEB size mod @alignment),
+  * where LEB size is the logical eraseblock size defined by the UBI device.
+  *
+  * The alignment is multiple to the minimal flash input/output unit size or %1
+@@ -116,29 +116,53 @@ struct ubi_volume_info {
+  * struct ubi_device_info - UBI device description data structure.
+  * @ubi_num: ubi device number
+  * @leb_size: logical eraseblock size on this UBI device
++ * @leb_start: starting offset of logical eraseblocks within physical
++ *             eraseblocks
+  * @min_io_size: minimal I/O unit size
++ * @max_write_size: maximum amount of bytes the underlying flash can write at a
++ *                  time (MTD write buffer size)
+  * @ro_mode: if this device is in read-only mode
+  * @cdev: UBI character device major and minor numbers
+  *
+  * Note, @leb_size is the logical eraseblock size offered by the UBI device.
+  * Volumes of this UBI device may have smaller logical eraseblock size if their
+  * alignment is not equivalent to %1.
++ *
++ * The @max_write_size field describes flash write maximum write unit. For
++ * example, NOR flash allows for changing individual bytes, so @min_io_size is
++ * %1. However, it does not mean than NOR flash has to write data byte-by-byte.
++ * Instead, CFI NOR flashes have a write-buffer of, e.g., 64 bytes, and when
++ * writing large chunks of data, they write 64-bytes at a time. Obviously, this
++ * improves write throughput.
++ *
++ * Also, the MTD device may have N interleaved (striped) flash chips
++ * underneath, in which case @min_io_size can be physical min. I/O size of
++ * single flash chip, while @max_write_size can be N * @min_io_size.
++ *
++ * The @max_write_size field is always greater or equivalent to @min_io_size.
++ * E.g., some NOR flashes may have (@min_io_size = 1, @max_write_size = 64). In
++ * contrast, NAND flashes usually have @min_io_size = @max_write_size = NAND
++ * page size.
+  */
+ struct ubi_device_info {
+       int ubi_num;
+       int leb_size;
++      int leb_start;
+       int min_io_size;
++      int max_write_size;
+       int ro_mode;
+       dev_t cdev;
+ };
+ /*
+- * enum - volume notification types.
+- * @UBI_VOLUME_ADDED: volume has been added
+- * @UBI_VOLUME_REMOVED: start volume volume
+- * @UBI_VOLUME_RESIZED: volume size has been re-sized
+- * @UBI_VOLUME_RENAMED: volume name has been re-named
+- * @UBI_VOLUME_UPDATED: volume name has been updated
++ * Volume notification types.
++ * @UBI_VOLUME_ADDED: a volume has been added (an UBI device was attached or a
++ *                    volume was created)
++ * @UBI_VOLUME_REMOVED: a volume has been removed (an UBI device was detached
++ *                    or a volume was removed)
++ * @UBI_VOLUME_RESIZED: a volume has been re-sized
++ * @UBI_VOLUME_RENAMED: a volume has been re-named
++ * @UBI_VOLUME_UPDATED: data has been written to a volume
+  *
+  * These constants define which type of event has happened when a volume
+  * notification function is invoked.
diff --git a/recipes/linux/linux-vuduo2-3.1.1/ubifs_packport.patch b/recipes/linux/linux-vuduo2-3.1.1/ubifs_packport.patch
new file mode 100644 (file)
index 0000000..193c5e6
--- /dev/null
@@ -0,0 +1,9138 @@
+diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
+index 830e3f7..f8b0160 100644
+--- a/fs/ubifs/Kconfig
++++ b/fs/ubifs/Kconfig
+@@ -44,29 +44,17 @@ config UBIFS_FS_ZLIB
+ # Debugging-related stuff
+ config UBIFS_FS_DEBUG
+-      bool "Enable debugging"
++      bool "Enable debugging support"
+       depends on UBIFS_FS
+       select DEBUG_FS
+-      select KALLSYMS_ALL
+-      help
+-        This option enables UBIFS debugging.
+-
+-config UBIFS_FS_DEBUG_MSG_LVL
+-      int "Default message level (0 = no extra messages, 3 = lots)"
+-      depends on UBIFS_FS_DEBUG
+-      default "0"
+-      help
+-        This controls the amount of debugging messages produced by UBIFS.
+-        If reporting bugs, please try to have available a full dump of the
+-        messages at level 1 while the misbehaviour was occurring. Level 2
+-        may become necessary if level 1 messages were not enough to find the
+-        bug. Generally Level 3 should be avoided.
+-
+-config UBIFS_FS_DEBUG_CHKS
+-      bool "Enable extra checks"
+-      depends on UBIFS_FS_DEBUG
+-      help
+-        If extra checks are enabled UBIFS will check the consistency of its
+-        internal data structures during operation. However, UBIFS performance
+-        is dramatically slower when this option is selected especially if the
+-        file system is large.
++      select KALLSYMS
++      help
++        This option enables UBIFS debugging support. It makes sure various
++        assertions, self-checks, debugging messages and test modes are compiled
++        in (this all is compiled out otherwise). Assertions are light-weight
++        and this option also enables them. Self-checks, debugging messages and
++        test modes are switched off by default. Thus, it is safe and actually
++        recommended to have debugging support enabled, and it should not slow
++        down UBIFS. You can then further enable / disable individual  debugging
++        features using UBIFS module parameters and the corresponding sysfs
++        interfaces.
+diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
+index c8ff0d1..02c73e7 100644
+--- a/fs/ubifs/budget.c
++++ b/fs/ubifs/budget.c
+@@ -106,7 +106,7 @@ static long long get_liability(struct ubifs_info *c)
+       long long liab;
+       spin_lock(&c->space_lock);
+-      liab = c->budg_idx_growth + c->budg_data_growth + c->budg_dd_growth;
++      liab = c->bi.idx_growth + c->bi.data_growth + c->bi.dd_growth;
+       spin_unlock(&c->space_lock);
+       return liab;
+ }
+@@ -180,7 +180,7 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
+       int idx_lebs;
+       long long idx_size;
+-      idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
++      idx_size = c->bi.old_idx_sz + c->bi.idx_growth + c->bi.uncommitted_idx;
+       /* And make sure we have thrice the index size of space reserved */
+       idx_size += idx_size << 1;
+       /*
+@@ -292,13 +292,13 @@ static int can_use_rp(struct ubifs_info *c)
+  * budgeted index space to the size of the current index, multiplies this by 3,
+  * and makes sure this does not exceed the amount of free LEBs.
+  *
+- * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables:
++ * Notes about @c->bi.min_idx_lebs and @c->lst.idx_lebs variables:
+  * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might
+  *    be large, because UBIFS does not do any index consolidation as long as
+  *    there is free space. IOW, the index may take a lot of LEBs, but the LEBs
+  *    will contain a lot of dirt.
+- * o @c->min_idx_lebs is the number of LEBS the index presumably takes. IOW,
+- *    the index may be consolidated to take up to @c->min_idx_lebs LEBs.
++ * o @c->bi.min_idx_lebs is the number of LEBS the index presumably takes. IOW,
++ *    the index may be consolidated to take up to @c->bi.min_idx_lebs LEBs.
+  *
+  * This function returns zero in case of success, and %-ENOSPC in case of
+  * failure.
+@@ -343,13 +343,13 @@ static int do_budget_space(struct ubifs_info *c)
+              c->lst.taken_empty_lebs;
+       if (unlikely(rsvd_idx_lebs > lebs)) {
+               dbg_budg("out of indexing space: min_idx_lebs %d (old %d), "
+-                       "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs,
++                       "rsvd_idx_lebs %d", min_idx_lebs, c->bi.min_idx_lebs,
+                        rsvd_idx_lebs);
+               return -ENOSPC;
+       }
+       available = ubifs_calc_available(c, min_idx_lebs);
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
+       if (unlikely(available < outstanding)) {
+               dbg_budg("out of data space: available %lld, outstanding %lld",
+@@ -360,7 +360,7 @@ static int do_budget_space(struct ubifs_info *c)
+       if (available - outstanding <= c->rp_size && !can_use_rp(c))
+               return -ENOSPC;
+-      c->min_idx_lebs = min_idx_lebs;
++      c->bi.min_idx_lebs = min_idx_lebs;
+       return 0;
+ }
+@@ -393,11 +393,11 @@ static int calc_data_growth(const struct ubifs_info *c,
+ {
+       int data_growth;
+-      data_growth = req->new_ino  ? c->inode_budget : 0;
++      data_growth = req->new_ino  ? c->bi.inode_budget : 0;
+       if (req->new_page)
+-              data_growth += c->page_budget;
++              data_growth += c->bi.page_budget;
+       if (req->new_dent)
+-              data_growth += c->dent_budget;
++              data_growth += c->bi.dent_budget;
+       data_growth += req->new_ino_d;
+       return data_growth;
+ }
+@@ -413,12 +413,12 @@ static int calc_dd_growth(const struct ubifs_info *c,
+ {
+       int dd_growth;
+-      dd_growth = req->dirtied_page ? c->page_budget : 0;
++      dd_growth = req->dirtied_page ? c->bi.page_budget : 0;
+       if (req->dirtied_ino)
+-              dd_growth += c->inode_budget << (req->dirtied_ino - 1);
++              dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1);
+       if (req->mod_dent)
+-              dd_growth += c->dent_budget;
++              dd_growth += c->bi.dent_budget;
+       dd_growth += req->dirtied_ino_d;
+       return dd_growth;
+ }
+@@ -460,19 +460,19 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
+ again:
+       spin_lock(&c->space_lock);
+-      ubifs_assert(c->budg_idx_growth >= 0);
+-      ubifs_assert(c->budg_data_growth >= 0);
+-      ubifs_assert(c->budg_dd_growth >= 0);
++      ubifs_assert(c->bi.idx_growth >= 0);
++      ubifs_assert(c->bi.data_growth >= 0);
++      ubifs_assert(c->bi.dd_growth >= 0);
+-      if (unlikely(c->nospace) && (c->nospace_rp || !can_use_rp(c))) {
++      if (unlikely(c->bi.nospace) && (c->bi.nospace_rp || !can_use_rp(c))) {
+               dbg_budg("no space");
+               spin_unlock(&c->space_lock);
+               return -ENOSPC;
+       }
+-      c->budg_idx_growth += idx_growth;
+-      c->budg_data_growth += data_growth;
+-      c->budg_dd_growth += dd_growth;
++      c->bi.idx_growth += idx_growth;
++      c->bi.data_growth += data_growth;
++      c->bi.dd_growth += dd_growth;
+       err = do_budget_space(c);
+       if (likely(!err)) {
+@@ -484,9 +484,9 @@ again:
+       }
+       /* Restore the old values */
+-      c->budg_idx_growth -= idx_growth;
+-      c->budg_data_growth -= data_growth;
+-      c->budg_dd_growth -= dd_growth;
++      c->bi.idx_growth -= idx_growth;
++      c->bi.data_growth -= data_growth;
++      c->bi.dd_growth -= dd_growth;
+       spin_unlock(&c->space_lock);
+       if (req->fast) {
+@@ -506,9 +506,9 @@ again:
+                       goto again;
+               }
+               dbg_budg("FS is full, -ENOSPC");
+-              c->nospace = 1;
++              c->bi.nospace = 1;
+               if (can_use_rp(c) || c->rp_size == 0)
+-                      c->nospace_rp = 1;
++                      c->bi.nospace_rp = 1;
+               smp_wmb();
+       } else
+               ubifs_err("cannot budget space, error %d", err);
+@@ -523,8 +523,8 @@ again:
+  * This function releases the space budgeted by 'ubifs_budget_space()'. Note,
+  * since the index changes (which were budgeted for in @req->idx_growth) will
+  * only be written to the media on commit, this function moves the index budget
+- * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be
+- * zeroed by the commit operation.
++ * from @c->bi.idx_growth to @c->bi.uncommitted_idx. The latter will be zeroed
++ * by the commit operation.
+  */
+ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
+ {
+@@ -553,23 +553,23 @@ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
+       if (!req->data_growth && !req->dd_growth)
+               return;
+-      c->nospace = c->nospace_rp = 0;
++      c->bi.nospace = c->bi.nospace_rp = 0;
+       smp_wmb();
+       spin_lock(&c->space_lock);
+-      c->budg_idx_growth -= req->idx_growth;
+-      c->budg_uncommitted_idx += req->idx_growth;
+-      c->budg_data_growth -= req->data_growth;
+-      c->budg_dd_growth -= req->dd_growth;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+-
+-      ubifs_assert(c->budg_idx_growth >= 0);
+-      ubifs_assert(c->budg_data_growth >= 0);
+-      ubifs_assert(c->budg_dd_growth >= 0);
+-      ubifs_assert(c->min_idx_lebs < c->main_lebs);
+-      ubifs_assert(!(c->budg_idx_growth & 7));
+-      ubifs_assert(!(c->budg_data_growth & 7));
+-      ubifs_assert(!(c->budg_dd_growth & 7));
++      c->bi.idx_growth -= req->idx_growth;
++      c->bi.uncommitted_idx += req->idx_growth;
++      c->bi.data_growth -= req->data_growth;
++      c->bi.dd_growth -= req->dd_growth;
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++
++      ubifs_assert(c->bi.idx_growth >= 0);
++      ubifs_assert(c->bi.data_growth >= 0);
++      ubifs_assert(c->bi.dd_growth >= 0);
++      ubifs_assert(c->bi.min_idx_lebs < c->main_lebs);
++      ubifs_assert(!(c->bi.idx_growth & 7));
++      ubifs_assert(!(c->bi.data_growth & 7));
++      ubifs_assert(!(c->bi.dd_growth & 7));
+       spin_unlock(&c->space_lock);
+ }
+@@ -586,13 +586,13 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
+ {
+       spin_lock(&c->space_lock);
+       /* Release the index growth reservation */
+-      c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
++      c->bi.idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       /* Release the data growth reservation */
+-      c->budg_data_growth -= c->page_budget;
++      c->bi.data_growth -= c->bi.page_budget;
+       /* Increase the dirty data growth reservation instead */
+-      c->budg_dd_growth += c->page_budget;
++      c->bi.dd_growth += c->bi.page_budget;
+       /* And re-calculate the indexing space reservation */
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       spin_unlock(&c->space_lock);
+ }
+@@ -612,7 +612,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
+       memset(&req, 0, sizeof(struct ubifs_budget_req));
+       /* The "no space" flags will be cleared because dd_growth is > 0 */
+-      req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
++      req.dd_growth = c->bi.inode_budget + ALIGN(ui->data_len, 8);
+       ubifs_release_budget(c, &req);
+ }
+@@ -682,9 +682,9 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
+       int rsvd_idx_lebs, lebs;
+       long long available, outstanding, free;
+-      ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
+-      available = ubifs_calc_available(c, c->min_idx_lebs);
++      ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
++      available = ubifs_calc_available(c, c->bi.min_idx_lebs);
+       /*
+        * When reporting free space to user-space, UBIFS guarantees that it is
+@@ -697,8 +697,8 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
+        * Note, the calculations below are similar to what we have in
+        * 'do_budget_space()', so refer there for comments.
+        */
+-      if (c->min_idx_lebs > c->lst.idx_lebs)
+-              rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs;
++      if (c->bi.min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
+       else
+               rsvd_idx_lebs = 0;
+       lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
+index 02429d8..fb3b5c8 100644
+--- a/fs/ubifs/commit.c
++++ b/fs/ubifs/commit.c
+@@ -48,6 +48,56 @@
+ #include <linux/slab.h>
+ #include "ubifs.h"
++/*
++ * nothing_to_commit - check if there is nothing to commit.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function which checks if there is anything to commit. It is
++ * used as an optimization to avoid starting the commit if it is not really
++ * necessary. Indeed, the commit operation always assumes flash I/O (e.g.,
++ * writing the commit start node to the log), and it is better to avoid doing
++ * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is
++ * nothing to commit, it is more optimal to avoid any flash I/O.
++ *
++ * This function has to be called with @c->commit_sem locked for writing -
++ * this function does not take LPT/TNC locks because the @c->commit_sem
++ * guarantees that we have exclusive access to the TNC and LPT data structures.
++ *
++ * This function returns %1 if there is nothing to commit and %0 otherwise.
++ */
++static int nothing_to_commit(struct ubifs_info *c)
++{
++      /*
++       * During mounting or remounting from R/O mode to R/W mode we may
++       * commit for various recovery-related reasons.
++       */
++      if (c->mounting || c->remounting_rw)
++              return 0;
++
++      /*
++       * If the root TNC node is dirty, we definitely have something to
++       * commit.
++       */
++      if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
++              return 0;
++
++      /*
++       * Even though the TNC is clean, the LPT tree may have dirty nodes. For
++       * example, this may happen if the budgeting subsystem invoked GC to
++       * make some free space, and the GC found an LEB with only dirty and
++       * free space. In this case GC would just change the lprops of this
++       * LEB (by turning all space into free space) and unmap it.
++       */
++      if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags))
++              return 0;
++
++      ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0);
++      ubifs_assert(c->dirty_pn_cnt == 0);
++      ubifs_assert(c->dirty_nn_cnt == 0);
++
++      return 1;
++}
++
+ /**
+  * do_commit - commit the journal.
+  * @c: UBIFS file-system description object
+@@ -70,6 +120,12 @@ static int do_commit(struct ubifs_info *c)
+               goto out_up;
+       }
++      if (nothing_to_commit(c)) {
++              up_write(&c->commit_sem);
++              err = 0;
++              goto out_cancel;
++      }
++
+       /* Sync all write buffers (necessary for recovery) */
+       for (i = 0; i < c->jhead_cnt; i++) {
+               err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+@@ -126,7 +182,7 @@ static int do_commit(struct ubifs_info *c)
+       c->mst_node->root_len    = cpu_to_le32(zroot.len);
+       c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
+       c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
+-      c->mst_node->index_size  = cpu_to_le64(c->old_idx_sz);
++      c->mst_node->index_size  = cpu_to_le64(c->bi.old_idx_sz);
+       c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
+       c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
+       c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
+@@ -162,12 +218,12 @@ static int do_commit(struct ubifs_info *c)
+       if (err)
+               goto out;
++out_cancel:
+       spin_lock(&c->cs_lock);
+       c->cmt_state = COMMIT_RESTING;
+       wake_up(&c->cmt_wq);
+       dbg_cmt("commit end");
+       spin_unlock(&c->cs_lock);
+-
+       return 0;
+ out_up:
+@@ -362,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
+       spin_lock(&c->cs_lock);
+       if (c->cmt_state == COMMIT_BROKEN) {
+-              err = -EINVAL;
++              err = -EROFS;
+               goto out;
+       }
+@@ -388,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
+        * re-check it.
+        */
+       if (c->cmt_state == COMMIT_BROKEN) {
+-              err = -EINVAL;
++              err = -EROFS;
+               goto out_cmt_unlock;
+       }
+@@ -520,8 +576,8 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+       struct idx_node *i;
+       size_t sz;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX))
+-              goto out;
++      if (!dbg_is_chk_index(c))
++              return 0;
+       INIT_LIST_HEAD(&list);
+diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
+index 0bee4db..1934084 100644
+--- a/fs/ubifs/debug.c
++++ b/fs/ubifs/debug.c
+@@ -27,33 +27,16 @@
+  * various local functions of those subsystems.
+  */
+-#define UBIFS_DBG_PRESERVE_UBI
+-
+-#include "ubifs.h"
+ #include <linux/module.h>
+-#include <linux/moduleparam.h>
+ #include <linux/debugfs.h>
+ #include <linux/math64.h>
+-#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/random.h>
++#include "ubifs.h"
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+-DEFINE_SPINLOCK(dbg_lock);
+-
+-static char dbg_key_buf0[128];
+-static char dbg_key_buf1[128];
+-
+-unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT;
+-unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT;
+-unsigned int ubifs_tst_flags;
+-
+-module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
+-module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
+-module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
+-
+-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
+-MODULE_PARM_DESC(debug_chks, "Debug check flags");
+-MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
++static DEFINE_SPINLOCK(dbg_lock);
+ static const char *get_key_fmt(int fmt)
+ {
+@@ -95,8 +78,30 @@ static const char *get_key_type(int type)
+       }
+ }
+-static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+-                      char *buffer)
++static const char *get_dent_type(int type)
++{
++      switch (type) {
++      case UBIFS_ITYPE_REG:
++              return "file";
++      case UBIFS_ITYPE_DIR:
++              return "dir";
++      case UBIFS_ITYPE_LNK:
++              return "symlink";
++      case UBIFS_ITYPE_BLK:
++              return "blkdev";
++      case UBIFS_ITYPE_CHR:
++              return "char dev";
++      case UBIFS_ITYPE_FIFO:
++              return "fifo";
++      case UBIFS_ITYPE_SOCK:
++              return "socket";
++      default:
++              return "unknown/invalid type";
++      }
++}
++
++const char *dbg_snprintf_key(const struct ubifs_info *c,
++                           const union ubifs_key *key, char *buffer, int len)
+ {
+       char *p = buffer;
+       int type = key_type(c, key);
+@@ -104,45 +109,34 @@ static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+       if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
+               switch (type) {
+               case UBIFS_INO_KEY:
+-                      sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
+-                             get_key_type(type));
++                      len -= snprintf(p, len, "(%lu, %s)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type));
+                       break;
+               case UBIFS_DENT_KEY:
+               case UBIFS_XENT_KEY:
+-                      sprintf(p, "(%lu, %s, %#08x)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type), key_hash(c, key));
++                      len -= snprintf(p, len, "(%lu, %s, %#08x)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type), key_hash(c, key));
+                       break;
+               case UBIFS_DATA_KEY:
+-                      sprintf(p, "(%lu, %s, %u)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type), key_block(c, key));
++                      len -= snprintf(p, len, "(%lu, %s, %u)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type), key_block(c, key));
+                       break;
+               case UBIFS_TRUN_KEY:
+-                      sprintf(p, "(%lu, %s)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type));
++                      len -= snprintf(p, len, "(%lu, %s)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type));
+                       break;
+               default:
+-                      sprintf(p, "(bad key type: %#08x, %#08x)",
+-                              key->u32[0], key->u32[1]);
++                      len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
++                                      key->u32[0], key->u32[1]);
+               }
+       } else
+-              sprintf(p, "bad key format %d", c->key_fmt);
+-}
+-
+-const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
+-{
+-      /* dbg_lock must be held */
+-      sprintf_key(c, key, dbg_key_buf0);
+-      return dbg_key_buf0;
+-}
+-
+-const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
+-{
+-      /* dbg_lock must be held */
+-      sprintf_key(c, key, dbg_key_buf1);
+-      return dbg_key_buf1;
++              len -= snprintf(p, len, "bad key format %d", c->key_fmt);
++      ubifs_assert(len > 0);
++      return p;
+ }
+ const char *dbg_ntype(int type)
+@@ -227,53 +221,83 @@ const char *dbg_jhead(int jhead)
+ static void dump_ch(const struct ubifs_ch *ch)
+ {
+-      printk(KERN_DEBUG "\tmagic          %#x\n", le32_to_cpu(ch->magic));
+-      printk(KERN_DEBUG "\tcrc            %#x\n", le32_to_cpu(ch->crc));
+-      printk(KERN_DEBUG "\tnode_type      %d (%s)\n", ch->node_type,
++      printk(KERN_ERR "\tmagic          %#x\n", le32_to_cpu(ch->magic));
++      printk(KERN_ERR "\tcrc            %#x\n", le32_to_cpu(ch->crc));
++      printk(KERN_ERR "\tnode_type      %d (%s)\n", ch->node_type,
+              dbg_ntype(ch->node_type));
+-      printk(KERN_DEBUG "\tgroup_type     %d (%s)\n", ch->group_type,
++      printk(KERN_ERR "\tgroup_type     %d (%s)\n", ch->group_type,
+              dbg_gtype(ch->group_type));
+-      printk(KERN_DEBUG "\tsqnum          %llu\n",
++      printk(KERN_ERR "\tsqnum          %llu\n",
+              (unsigned long long)le64_to_cpu(ch->sqnum));
+-      printk(KERN_DEBUG "\tlen            %u\n", le32_to_cpu(ch->len));
++      printk(KERN_ERR "\tlen            %u\n", le32_to_cpu(ch->len));
+ }
+-void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode)
++void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
+ {
+       const struct ubifs_inode *ui = ubifs_inode(inode);
++      struct qstr nm = { .name = NULL };
++      union ubifs_key key;
++      struct ubifs_dent_node *dent, *pdent = NULL;
++      int count = 2;
+-      printk(KERN_DEBUG "Dump in-memory inode:");
+-      printk(KERN_DEBUG "\tinode          %lu\n", inode->i_ino);
+-      printk(KERN_DEBUG "\tsize           %llu\n",
++      printk(KERN_ERR "Dump in-memory inode:");
++      printk(KERN_ERR "\tinode          %lu\n", inode->i_ino);
++      printk(KERN_ERR "\tsize           %llu\n",
+              (unsigned long long)i_size_read(inode));
+-      printk(KERN_DEBUG "\tnlink          %u\n", inode->i_nlink);
+-      printk(KERN_DEBUG "\tuid            %u\n", (unsigned int)inode->i_uid);
+-      printk(KERN_DEBUG "\tgid            %u\n", (unsigned int)inode->i_gid);
+-      printk(KERN_DEBUG "\tatime          %u.%u\n",
++      printk(KERN_ERR "\tnlink          %u\n", inode->i_nlink);
++      printk(KERN_ERR "\tuid            %u\n", (unsigned int)inode->i_uid);
++      printk(KERN_ERR "\tgid            %u\n", (unsigned int)inode->i_gid);
++      printk(KERN_ERR "\tatime          %u.%u\n",
+              (unsigned int)inode->i_atime.tv_sec,
+              (unsigned int)inode->i_atime.tv_nsec);
+-      printk(KERN_DEBUG "\tmtime          %u.%u\n",
++      printk(KERN_ERR "\tmtime          %u.%u\n",
+              (unsigned int)inode->i_mtime.tv_sec,
+              (unsigned int)inode->i_mtime.tv_nsec);
+-      printk(KERN_DEBUG "\tctime          %u.%u\n",
++      printk(KERN_ERR "\tctime          %u.%u\n",
+              (unsigned int)inode->i_ctime.tv_sec,
+              (unsigned int)inode->i_ctime.tv_nsec);
+-      printk(KERN_DEBUG "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
+-      printk(KERN_DEBUG "\txattr_size     %u\n", ui->xattr_size);
+-      printk(KERN_DEBUG "\txattr_cnt      %u\n", ui->xattr_cnt);
+-      printk(KERN_DEBUG "\txattr_names    %u\n", ui->xattr_names);
+-      printk(KERN_DEBUG "\tdirty          %u\n", ui->dirty);
+-      printk(KERN_DEBUG "\txattr          %u\n", ui->xattr);
+-      printk(KERN_DEBUG "\tbulk_read      %u\n", ui->xattr);
+-      printk(KERN_DEBUG "\tsynced_i_size  %llu\n",
++      printk(KERN_ERR "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
++      printk(KERN_ERR "\txattr_size     %u\n", ui->xattr_size);
++      printk(KERN_ERR "\txattr_cnt      %u\n", ui->xattr_cnt);
++      printk(KERN_ERR "\txattr_names    %u\n", ui->xattr_names);
++      printk(KERN_ERR "\tdirty          %u\n", ui->dirty);
++      printk(KERN_ERR "\txattr          %u\n", ui->xattr);
++      printk(KERN_ERR "\tbulk_read      %u\n", ui->xattr);
++      printk(KERN_ERR "\tsynced_i_size  %llu\n",
+              (unsigned long long)ui->synced_i_size);
+-      printk(KERN_DEBUG "\tui_size        %llu\n",
++      printk(KERN_ERR "\tui_size        %llu\n",
+              (unsigned long long)ui->ui_size);
+-      printk(KERN_DEBUG "\tflags          %d\n", ui->flags);
+-      printk(KERN_DEBUG "\tcompr_type     %d\n", ui->compr_type);
+-      printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read);
+-      printk(KERN_DEBUG "\tread_in_a_row  %lu\n", ui->read_in_a_row);
+-      printk(KERN_DEBUG "\tdata_len       %d\n", ui->data_len);
++      printk(KERN_ERR "\tflags          %d\n", ui->flags);
++      printk(KERN_ERR "\tcompr_type     %d\n", ui->compr_type);
++      printk(KERN_ERR "\tlast_page_read %lu\n", ui->last_page_read);
++      printk(KERN_ERR "\tread_in_a_row  %lu\n", ui->read_in_a_row);
++      printk(KERN_ERR "\tdata_len       %d\n", ui->data_len);
++
++      if (!S_ISDIR(inode->i_mode))
++              return;
++
++      printk(KERN_ERR "List of directory entries:\n");
++      ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
++
++      lowest_dent_key(c, &key, inode->i_ino);
++      while (1) {
++              dent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (IS_ERR(dent)) {
++                      if (PTR_ERR(dent) != -ENOENT)
++                              printk(KERN_ERR "error %ld\n", PTR_ERR(dent));
++                      break;
++              }
++
++              printk(KERN_ERR "\t%d: %s (%s)\n",
++                     count++, dent->name, get_dent_type(dent->type));
++
++              nm.name = dent->name;
++              nm.len = le16_to_cpu(dent->nlen);
++              kfree(pdent);
++              pdent = dent;
++              key_read(c, &dent->key, &key);
++      }
++      kfree(pdent);
+ }
+ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+@@ -281,14 +305,15 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       int i, n;
+       union ubifs_key key;
+       const struct ubifs_ch *ch = node;
++      char key_buf[DBG_KEY_BUF_LEN];
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+       /* If the magic is incorrect, just hexdump the first bytes */
+       if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) {
+-              printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ);
+-              print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
++              printk(KERN_ERR "Not a node, first %zu bytes:", UBIFS_CH_SZ);
++              print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1,
+                              (void *)node, UBIFS_CH_SZ, 1);
+               return;
+       }
+@@ -301,7 +326,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_pad_node *pad = node;
+-              printk(KERN_DEBUG "\tpad_len        %u\n",
++              printk(KERN_ERR "\tpad_len        %u\n",
+                      le32_to_cpu(pad->pad_len));
+               break;
+       }
+@@ -310,48 +335,50 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_sb_node *sup = node;
+               unsigned int sup_flags = le32_to_cpu(sup->flags);
+-              printk(KERN_DEBUG "\tkey_hash       %d (%s)\n",
++              printk(KERN_ERR "\tkey_hash       %d (%s)\n",
+                      (int)sup->key_hash, get_key_hash(sup->key_hash));
+-              printk(KERN_DEBUG "\tkey_fmt        %d (%s)\n",
++              printk(KERN_ERR "\tkey_fmt        %d (%s)\n",
+                      (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
+-              printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
+-              printk(KERN_DEBUG "\t  big_lpt      %u\n",
++              printk(KERN_ERR "\tflags          %#x\n", sup_flags);
++              printk(KERN_ERR "\t  big_lpt      %u\n",
+                      !!(sup_flags & UBIFS_FLG_BIGLPT));
+-              printk(KERN_DEBUG "\tmin_io_size    %u\n",
++              printk(KERN_ERR "\t  space_fixup  %u\n",
++                     !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
++              printk(KERN_ERR "\tmin_io_size    %u\n",
+                      le32_to_cpu(sup->min_io_size));
+-              printk(KERN_DEBUG "\tleb_size       %u\n",
++              printk(KERN_ERR "\tleb_size       %u\n",
+                      le32_to_cpu(sup->leb_size));
+-              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++              printk(KERN_ERR "\tleb_cnt        %u\n",
+                      le32_to_cpu(sup->leb_cnt));
+-              printk(KERN_DEBUG "\tmax_leb_cnt    %u\n",
++              printk(KERN_ERR "\tmax_leb_cnt    %u\n",
+                      le32_to_cpu(sup->max_leb_cnt));
+-              printk(KERN_DEBUG "\tmax_bud_bytes  %llu\n",
++              printk(KERN_ERR "\tmax_bud_bytes  %llu\n",
+                      (unsigned long long)le64_to_cpu(sup->max_bud_bytes));
+-              printk(KERN_DEBUG "\tlog_lebs       %u\n",
++              printk(KERN_ERR "\tlog_lebs       %u\n",
+                      le32_to_cpu(sup->log_lebs));
+-              printk(KERN_DEBUG "\tlpt_lebs       %u\n",
++              printk(KERN_ERR "\tlpt_lebs       %u\n",
+                      le32_to_cpu(sup->lpt_lebs));
+-              printk(KERN_DEBUG "\torph_lebs      %u\n",
++              printk(KERN_ERR "\torph_lebs      %u\n",
+                      le32_to_cpu(sup->orph_lebs));
+-              printk(KERN_DEBUG "\tjhead_cnt      %u\n",
++              printk(KERN_ERR "\tjhead_cnt      %u\n",
+                      le32_to_cpu(sup->jhead_cnt));
+-              printk(KERN_DEBUG "\tfanout         %u\n",
++              printk(KERN_ERR "\tfanout         %u\n",
+                      le32_to_cpu(sup->fanout));
+-              printk(KERN_DEBUG "\tlsave_cnt      %u\n",
++              printk(KERN_ERR "\tlsave_cnt      %u\n",
+                      le32_to_cpu(sup->lsave_cnt));
+-              printk(KERN_DEBUG "\tdefault_compr  %u\n",
++              printk(KERN_ERR "\tdefault_compr  %u\n",
+                      (int)le16_to_cpu(sup->default_compr));
+-              printk(KERN_DEBUG "\trp_size        %llu\n",
++              printk(KERN_ERR "\trp_size        %llu\n",
+                      (unsigned long long)le64_to_cpu(sup->rp_size));
+-              printk(KERN_DEBUG "\trp_uid         %u\n",
++              printk(KERN_ERR "\trp_uid         %u\n",
+                      le32_to_cpu(sup->rp_uid));
+-              printk(KERN_DEBUG "\trp_gid         %u\n",
++              printk(KERN_ERR "\trp_gid         %u\n",
+                      le32_to_cpu(sup->rp_gid));
+-              printk(KERN_DEBUG "\tfmt_version    %u\n",
++              printk(KERN_ERR "\tfmt_version    %u\n",
+                      le32_to_cpu(sup->fmt_version));
+-              printk(KERN_DEBUG "\ttime_gran      %u\n",
++              printk(KERN_ERR "\ttime_gran      %u\n",
+                      le32_to_cpu(sup->time_gran));
+-              printk(KERN_DEBUG "\tUUID           %pUB\n",
++              printk(KERN_ERR "\tUUID           %pUB\n",
+                      sup->uuid);
+               break;
+       }
+@@ -359,61 +386,61 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_mst_node *mst = node;
+-              printk(KERN_DEBUG "\thighest_inum   %llu\n",
++              printk(KERN_ERR "\thighest_inum   %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->highest_inum));
+-              printk(KERN_DEBUG "\tcommit number  %llu\n",
++              printk(KERN_ERR "\tcommit number  %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->cmt_no));
+-              printk(KERN_DEBUG "\tflags          %#x\n",
++              printk(KERN_ERR "\tflags          %#x\n",
+                      le32_to_cpu(mst->flags));
+-              printk(KERN_DEBUG "\tlog_lnum       %u\n",
++              printk(KERN_ERR "\tlog_lnum       %u\n",
+                      le32_to_cpu(mst->log_lnum));
+-              printk(KERN_DEBUG "\troot_lnum      %u\n",
++              printk(KERN_ERR "\troot_lnum      %u\n",
+                      le32_to_cpu(mst->root_lnum));
+-              printk(KERN_DEBUG "\troot_offs      %u\n",
++              printk(KERN_ERR "\troot_offs      %u\n",
+                      le32_to_cpu(mst->root_offs));
+-              printk(KERN_DEBUG "\troot_len       %u\n",
++              printk(KERN_ERR "\troot_len       %u\n",
+                      le32_to_cpu(mst->root_len));
+-              printk(KERN_DEBUG "\tgc_lnum        %u\n",
++              printk(KERN_ERR "\tgc_lnum        %u\n",
+                      le32_to_cpu(mst->gc_lnum));
+-              printk(KERN_DEBUG "\tihead_lnum     %u\n",
++              printk(KERN_ERR "\tihead_lnum     %u\n",
+                      le32_to_cpu(mst->ihead_lnum));
+-              printk(KERN_DEBUG "\tihead_offs     %u\n",
++              printk(KERN_ERR "\tihead_offs     %u\n",
+                      le32_to_cpu(mst->ihead_offs));
+-              printk(KERN_DEBUG "\tindex_size     %llu\n",
++              printk(KERN_ERR "\tindex_size     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->index_size));
+-              printk(KERN_DEBUG "\tlpt_lnum       %u\n",
++              printk(KERN_ERR "\tlpt_lnum       %u\n",
+                      le32_to_cpu(mst->lpt_lnum));
+-              printk(KERN_DEBUG "\tlpt_offs       %u\n",
++              printk(KERN_ERR "\tlpt_offs       %u\n",
+                      le32_to_cpu(mst->lpt_offs));
+-              printk(KERN_DEBUG "\tnhead_lnum     %u\n",
++              printk(KERN_ERR "\tnhead_lnum     %u\n",
+                      le32_to_cpu(mst->nhead_lnum));
+-              printk(KERN_DEBUG "\tnhead_offs     %u\n",
++              printk(KERN_ERR "\tnhead_offs     %u\n",
+                      le32_to_cpu(mst->nhead_offs));
+-              printk(KERN_DEBUG "\tltab_lnum      %u\n",
++              printk(KERN_ERR "\tltab_lnum      %u\n",
+                      le32_to_cpu(mst->ltab_lnum));
+-              printk(KERN_DEBUG "\tltab_offs      %u\n",
++              printk(KERN_ERR "\tltab_offs      %u\n",
+                      le32_to_cpu(mst->ltab_offs));
+-              printk(KERN_DEBUG "\tlsave_lnum     %u\n",
++              printk(KERN_ERR "\tlsave_lnum     %u\n",
+                      le32_to_cpu(mst->lsave_lnum));
+-              printk(KERN_DEBUG "\tlsave_offs     %u\n",
++              printk(KERN_ERR "\tlsave_offs     %u\n",
+                      le32_to_cpu(mst->lsave_offs));
+-              printk(KERN_DEBUG "\tlscan_lnum     %u\n",
++              printk(KERN_ERR "\tlscan_lnum     %u\n",
+                      le32_to_cpu(mst->lscan_lnum));
+-              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++              printk(KERN_ERR "\tleb_cnt        %u\n",
+                      le32_to_cpu(mst->leb_cnt));
+-              printk(KERN_DEBUG "\tempty_lebs     %u\n",
++              printk(KERN_ERR "\tempty_lebs     %u\n",
+                      le32_to_cpu(mst->empty_lebs));
+-              printk(KERN_DEBUG "\tidx_lebs       %u\n",
++              printk(KERN_ERR "\tidx_lebs       %u\n",
+                      le32_to_cpu(mst->idx_lebs));
+-              printk(KERN_DEBUG "\ttotal_free     %llu\n",
++              printk(KERN_ERR "\ttotal_free     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_free));
+-              printk(KERN_DEBUG "\ttotal_dirty    %llu\n",
++              printk(KERN_ERR "\ttotal_dirty    %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dirty));
+-              printk(KERN_DEBUG "\ttotal_used     %llu\n",
++              printk(KERN_ERR "\ttotal_used     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_used));
+-              printk(KERN_DEBUG "\ttotal_dead     %llu\n",
++              printk(KERN_ERR "\ttotal_dead     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dead));
+-              printk(KERN_DEBUG "\ttotal_dark     %llu\n",
++              printk(KERN_ERR "\ttotal_dark     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dark));
+               break;
+       }
+@@ -421,11 +448,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_ref_node *ref = node;
+-              printk(KERN_DEBUG "\tlnum           %u\n",
++              printk(KERN_ERR "\tlnum           %u\n",
+                      le32_to_cpu(ref->lnum));
+-              printk(KERN_DEBUG "\toffs           %u\n",
++              printk(KERN_ERR "\toffs           %u\n",
+                      le32_to_cpu(ref->offs));
+-              printk(KERN_DEBUG "\tjhead          %u\n",
++              printk(KERN_ERR "\tjhead          %u\n",
+                      le32_to_cpu(ref->jhead));
+               break;
+       }
+@@ -434,39 +461,40 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_ino_node *ino = node;
+               key_read(c, &ino->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tcreat_sqnum    %llu\n",
+                      (unsigned long long)le64_to_cpu(ino->creat_sqnum));
+-              printk(KERN_DEBUG "\tsize           %llu\n",
++              printk(KERN_ERR "\tsize           %llu\n",
+                      (unsigned long long)le64_to_cpu(ino->size));
+-              printk(KERN_DEBUG "\tnlink          %u\n",
++              printk(KERN_ERR "\tnlink          %u\n",
+                      le32_to_cpu(ino->nlink));
+-              printk(KERN_DEBUG "\tatime          %lld.%u\n",
++              printk(KERN_ERR "\tatime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->atime_sec),
+                      le32_to_cpu(ino->atime_nsec));
+-              printk(KERN_DEBUG "\tmtime          %lld.%u\n",
++              printk(KERN_ERR "\tmtime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->mtime_sec),
+                      le32_to_cpu(ino->mtime_nsec));
+-              printk(KERN_DEBUG "\tctime          %lld.%u\n",
++              printk(KERN_ERR "\tctime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->ctime_sec),
+                      le32_to_cpu(ino->ctime_nsec));
+-              printk(KERN_DEBUG "\tuid            %u\n",
++              printk(KERN_ERR "\tuid            %u\n",
+                      le32_to_cpu(ino->uid));
+-              printk(KERN_DEBUG "\tgid            %u\n",
++              printk(KERN_ERR "\tgid            %u\n",
+                      le32_to_cpu(ino->gid));
+-              printk(KERN_DEBUG "\tmode           %u\n",
++              printk(KERN_ERR "\tmode           %u\n",
+                      le32_to_cpu(ino->mode));
+-              printk(KERN_DEBUG "\tflags          %#x\n",
++              printk(KERN_ERR "\tflags          %#x\n",
+                      le32_to_cpu(ino->flags));
+-              printk(KERN_DEBUG "\txattr_cnt      %u\n",
++              printk(KERN_ERR "\txattr_cnt      %u\n",
+                      le32_to_cpu(ino->xattr_cnt));
+-              printk(KERN_DEBUG "\txattr_size     %u\n",
++              printk(KERN_ERR "\txattr_size     %u\n",
+                      le32_to_cpu(ino->xattr_size));
+-              printk(KERN_DEBUG "\txattr_names    %u\n",
++              printk(KERN_ERR "\txattr_names    %u\n",
+                      le32_to_cpu(ino->xattr_names));
+-              printk(KERN_DEBUG "\tcompr_type     %#x\n",
++              printk(KERN_ERR "\tcompr_type     %#x\n",
+                      (int)le16_to_cpu(ino->compr_type));
+-              printk(KERN_DEBUG "\tdata len       %u\n",
++              printk(KERN_ERR "\tdata len       %u\n",
+                      le32_to_cpu(ino->data_len));
+               break;
+       }
+@@ -477,15 +505,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               int nlen = le16_to_cpu(dent->nlen);
+               key_read(c, &dent->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tinum           %llu\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tinum           %llu\n",
+                      (unsigned long long)le64_to_cpu(dent->inum));
+-              printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
+-              printk(KERN_DEBUG "\tnlen           %d\n", nlen);
+-              printk(KERN_DEBUG "\tname           ");
++              printk(KERN_ERR "\ttype           %d\n", (int)dent->type);
++              printk(KERN_ERR "\tnlen           %d\n", nlen);
++              printk(KERN_ERR "\tname           ");
+               if (nlen > UBIFS_MAX_NLEN)
+-                      printk(KERN_DEBUG "(bad name length, not printing, "
++                      printk(KERN_ERR "(bad name length, not printing, "
+                                         "bad or corrupted node)");
+               else {
+                       for (i = 0; i < nlen && dent->name[i]; i++)
+@@ -501,15 +530,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
+               key_read(c, &dn->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tsize           %u\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tsize           %u\n",
+                      le32_to_cpu(dn->size));
+-              printk(KERN_DEBUG "\tcompr_typ      %d\n",
++              printk(KERN_ERR "\tcompr_typ      %d\n",
+                      (int)le16_to_cpu(dn->compr_type));
+-              printk(KERN_DEBUG "\tdata size      %d\n",
++              printk(KERN_ERR "\tdata size      %d\n",
+                      dlen);
+-              printk(KERN_DEBUG "\tdata:\n");
+-              print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1,
++              printk(KERN_ERR "\tdata:\n");
++              print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
+                              (void *)&dn->data, dlen, 0);
+               break;
+       }
+@@ -517,11 +547,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_trun_node *trun = node;
+-              printk(KERN_DEBUG "\tinum           %u\n",
++              printk(KERN_ERR "\tinum           %u\n",
+                      le32_to_cpu(trun->inum));
+-              printk(KERN_DEBUG "\told_size       %llu\n",
++              printk(KERN_ERR "\told_size       %llu\n",
+                      (unsigned long long)le64_to_cpu(trun->old_size));
+-              printk(KERN_DEBUG "\tnew_size       %llu\n",
++              printk(KERN_ERR "\tnew_size       %llu\n",
+                      (unsigned long long)le64_to_cpu(trun->new_size));
+               break;
+       }
+@@ -530,19 +560,21 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_idx_node *idx = node;
+               n = le16_to_cpu(idx->child_cnt);
+-              printk(KERN_DEBUG "\tchild_cnt      %d\n", n);
+-              printk(KERN_DEBUG "\tlevel          %d\n",
++              printk(KERN_ERR "\tchild_cnt      %d\n", n);
++              printk(KERN_ERR "\tlevel          %d\n",
+                      (int)le16_to_cpu(idx->level));
+-              printk(KERN_DEBUG "\tBranches:\n");
++              printk(KERN_ERR "\tBranches:\n");
+               for (i = 0; i < n && i < c->fanout - 1; i++) {
+                       const struct ubifs_branch *br;
+                       br = ubifs_idx_branch(c, idx, i);
+                       key_read(c, &br->key, &key);
+-                      printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
++                      printk(KERN_ERR "\t%d: LEB %d:%d len %d key %s\n",
+                              i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
+-                             le32_to_cpu(br->len), DBGKEY(&key));
++                             le32_to_cpu(br->len),
++                             dbg_snprintf_key(c, &key, key_buf,
++                                              DBG_KEY_BUF_LEN));
+               }
+               break;
+       }
+@@ -552,20 +584,20 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_orph_node *orph = node;
+-              printk(KERN_DEBUG "\tcommit number  %llu\n",
++              printk(KERN_ERR "\tcommit number  %llu\n",
+                      (unsigned long long)
+                               le64_to_cpu(orph->cmt_no) & LLONG_MAX);
+-              printk(KERN_DEBUG "\tlast node flag %llu\n",
++              printk(KERN_ERR "\tlast node flag %llu\n",
+                      (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
+               n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
+-              printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n);
++              printk(KERN_ERR "\t%d orphan inode numbers:\n", n);
+               for (i = 0; i < n; i++)
+-                      printk(KERN_DEBUG "\t  ino %llu\n",
++                      printk(KERN_ERR "\t  ino %llu\n",
+                              (unsigned long long)le64_to_cpu(orph->inos[i]));
+               break;
+       }
+       default:
+-              printk(KERN_DEBUG "node type %d was not recognized\n",
++              printk(KERN_ERR "node type %d was not recognized\n",
+                      (int)ch->node_type);
+       }
+       spin_unlock(&dbg_lock);
+@@ -574,16 +606,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+ {
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n",
++      printk(KERN_ERR "Budgeting request: new_ino %d, dirtied_ino %d\n",
+              req->new_ino, req->dirtied_ino);
+-      printk(KERN_DEBUG "\tnew_ino_d   %d, dirtied_ino_d %d\n",
++      printk(KERN_ERR "\tnew_ino_d   %d, dirtied_ino_d %d\n",
+              req->new_ino_d, req->dirtied_ino_d);
+-      printk(KERN_DEBUG "\tnew_page    %d, dirtied_page %d\n",
++      printk(KERN_ERR "\tnew_page    %d, dirtied_page %d\n",
+              req->new_page, req->dirtied_page);
+-      printk(KERN_DEBUG "\tnew_dent    %d, mod_dent     %d\n",
++      printk(KERN_ERR "\tnew_dent    %d, mod_dent     %d\n",
+              req->new_dent, req->mod_dent);
+-      printk(KERN_DEBUG "\tidx_growth  %d\n", req->idx_growth);
+-      printk(KERN_DEBUG "\tdata_growth %d dd_growth     %d\n",
++      printk(KERN_ERR "\tidx_growth  %d\n", req->idx_growth);
++      printk(KERN_ERR "\tdata_growth %d dd_growth     %d\n",
+              req->data_growth, req->dd_growth);
+       spin_unlock(&dbg_lock);
+ }
+@@ -591,18 +623,18 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+ void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
+ {
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, "
++      printk(KERN_ERR "(pid %d) Lprops statistics: empty_lebs %d, "
+              "idx_lebs  %d\n", current->pid, lst->empty_lebs, lst->idx_lebs);
+-      printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
++      printk(KERN_ERR "\ttaken_empty_lebs %d, total_free %lld, "
+              "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
+              lst->total_dirty);
+-      printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, "
++      printk(KERN_ERR "\ttotal_used %lld, total_dark %lld, "
+              "total_dead %lld\n", lst->total_used, lst->total_dark,
+              lst->total_dead);
+       spin_unlock(&dbg_lock);
+ }
+-void dbg_dump_budg(struct ubifs_info *c)
++void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
+ {
+       int i;
+       struct rb_node *rb;
+@@ -610,51 +642,69 @@ void dbg_dump_budg(struct ubifs_info *c)
+       struct ubifs_gced_idx_leb *idx_gc;
+       long long available, outstanding, free;
+-      ubifs_assert(spin_is_locked(&c->space_lock));
++      spin_lock(&c->space_lock);
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
+-             "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
+-             c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
+-      printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
+-             "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
+-             c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth,
+-             c->freeable_cnt);
+-      printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, "
+-             "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs,
+-             c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt);
+-      printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
++      printk(KERN_ERR "(pid %d) Budgeting info: data budget sum %lld, "
++             "total budget sum %lld\n", current->pid,
++             bi->data_growth + bi->dd_growth,
++             bi->data_growth + bi->dd_growth + bi->idx_growth);
++      printk(KERN_ERR "\tbudg_data_growth %lld, budg_dd_growth %lld, "
++             "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth,
++             bi->idx_growth);
++      printk(KERN_ERR "\tmin_idx_lebs %d, old_idx_sz %llu, "
++             "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz,
++             bi->uncommitted_idx);
++      printk(KERN_ERR "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
++             bi->page_budget, bi->inode_budget, bi->dent_budget);
++      printk(KERN_ERR "\tnospace %u, nospace_rp %u\n",
++             bi->nospace, bi->nospace_rp);
++      printk(KERN_ERR "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
++             c->dark_wm, c->dead_wm, c->max_idx_node_sz);
++
++      if (bi != &c->bi)
++              /*
++               * If we are dumping saved budgeting data, do not print
++               * additional information which is about the current state, not
++               * the old one which corresponded to the saved budgeting data.
++               */
++              goto out_unlock;
++
++      printk(KERN_ERR "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
++             c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
++      printk(KERN_ERR "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
+              "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),
+              atomic_long_read(&c->dirty_zn_cnt),
+              atomic_long_read(&c->clean_zn_cnt));
+-      printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
+-             c->dark_wm, c->dead_wm, c->max_idx_node_sz);
+-      printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
++      printk(KERN_ERR "\tgc_lnum %d, ihead_lnum %d\n",
+              c->gc_lnum, c->ihead_lnum);
++
+       /* If we are in R/O mode, journal heads do not exist */
+       if (c->jheads)
+               for (i = 0; i < c->jhead_cnt; i++)
+-                      printk(KERN_DEBUG "\tjhead %s\t LEB %d\n",
++                      printk(KERN_ERR "\tjhead %s\t LEB %d\n",
+                              dbg_jhead(c->jheads[i].wbuf.jhead),
+                              c->jheads[i].wbuf.lnum);
+       for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
+               bud = rb_entry(rb, struct ubifs_bud, rb);
+-              printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum);
++              printk(KERN_ERR "\tbud LEB %d\n", bud->lnum);
+       }
+       list_for_each_entry(bud, &c->old_buds, list)
+-              printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum);
++              printk(KERN_ERR "\told bud LEB %d\n", bud->lnum);
+       list_for_each_entry(idx_gc, &c->idx_gc, list)
+-              printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
++              printk(KERN_ERR "\tGC'ed idx LEB %d unmap %d\n",
+                      idx_gc->lnum, idx_gc->unmap);
+-      printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
++      printk(KERN_ERR "\tcommit state %d\n", c->cmt_state);
+       /* Print budgeting predictions */
+-      available = ubifs_calc_available(c, c->min_idx_lebs);
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
++      available = ubifs_calc_available(c, c->bi.min_idx_lebs);
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
+       free = ubifs_get_free_space_nolock(c);
+-      printk(KERN_DEBUG "Budgeting predictions:\n");
+-      printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
++      printk(KERN_ERR "Budgeting predictions:\n");
++      printk(KERN_ERR "\tavailable: %lld, outstanding %lld, free %lld\n",
+              available, outstanding, free);
++out_unlock:
+       spin_unlock(&dbg_lock);
++      spin_unlock(&c->space_lock);
+ }
+ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+@@ -670,11 +720,11 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+               dark = ubifs_calc_dark(c, spc);
+       if (lp->flags & LPROPS_INDEX)
+-              printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
++              printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
+                      "free + dirty %-8d flags %#x (", lp->lnum, lp->free,
+                      lp->dirty, c->leb_size - spc, spc, lp->flags);
+       else
+-              printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
++              printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
+                      "free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d "
+                      "flags %#-4x (", lp->lnum, lp->free, lp->dirty,
+                      c->leb_size - spc, spc, dark, dead,
+@@ -729,7 +779,13 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+               if (bud->lnum == lp->lnum) {
+                       int head = 0;
+                       for (i = 0; i < c->jhead_cnt; i++) {
+-                              if (lp->lnum == c->jheads[i].wbuf.lnum) {
++                              /*
++                               * Note, if we are in R/O mode or in the middle
++                               * of mounting/re-mounting, the write-buffers do
++                               * not exist.
++                               */
++                              if (c->jheads &&
++                                  lp->lnum == c->jheads[i].wbuf.lnum) {
+                                       printk(KERN_CONT ", jhead %s",
+                                              dbg_jhead(i));
+                                       head = 1;
+@@ -751,7 +807,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
+       struct ubifs_lprops lp;
+       struct ubifs_lp_stats lst;
+-      printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n",
++      printk(KERN_ERR "(pid %d) start dumping LEB properties\n",
+              current->pid);
+       ubifs_get_lp_stats(c, &lst);
+       dbg_dump_lstats(&lst);
+@@ -763,7 +819,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
+               dbg_dump_lprop(c, &lp);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n",
++      printk(KERN_ERR "(pid %d) finish dumping LEB properties\n",
+              current->pid);
+ }
+@@ -772,69 +828,96 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
+       int i;
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid);
+-      printk(KERN_DEBUG "\tlpt_sz:        %lld\n", c->lpt_sz);
+-      printk(KERN_DEBUG "\tpnode_sz:      %d\n", c->pnode_sz);
+-      printk(KERN_DEBUG "\tnnode_sz:      %d\n", c->nnode_sz);
+-      printk(KERN_DEBUG "\tltab_sz:       %d\n", c->ltab_sz);
+-      printk(KERN_DEBUG "\tlsave_sz:      %d\n", c->lsave_sz);
+-      printk(KERN_DEBUG "\tbig_lpt:       %d\n", c->big_lpt);
+-      printk(KERN_DEBUG "\tlpt_hght:      %d\n", c->lpt_hght);
+-      printk(KERN_DEBUG "\tpnode_cnt:     %d\n", c->pnode_cnt);
+-      printk(KERN_DEBUG "\tnnode_cnt:     %d\n", c->nnode_cnt);
+-      printk(KERN_DEBUG "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
+-      printk(KERN_DEBUG "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
+-      printk(KERN_DEBUG "\tlsave_cnt:     %d\n", c->lsave_cnt);
+-      printk(KERN_DEBUG "\tspace_bits:    %d\n", c->space_bits);
+-      printk(KERN_DEBUG "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
+-      printk(KERN_DEBUG "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
+-      printk(KERN_DEBUG "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
+-      printk(KERN_DEBUG "\tpcnt_bits:     %d\n", c->pcnt_bits);
+-      printk(KERN_DEBUG "\tlnum_bits:     %d\n", c->lnum_bits);
+-      printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
+-      printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
++      printk(KERN_ERR "(pid %d) dumping LPT information\n", current->pid);
++      printk(KERN_ERR "\tlpt_sz:        %lld\n", c->lpt_sz);
++      printk(KERN_ERR "\tpnode_sz:      %d\n", c->pnode_sz);
++      printk(KERN_ERR "\tnnode_sz:      %d\n", c->nnode_sz);
++      printk(KERN_ERR "\tltab_sz:       %d\n", c->ltab_sz);
++      printk(KERN_ERR "\tlsave_sz:      %d\n", c->lsave_sz);
++      printk(KERN_ERR "\tbig_lpt:       %d\n", c->big_lpt);
++      printk(KERN_ERR "\tlpt_hght:      %d\n", c->lpt_hght);
++      printk(KERN_ERR "\tpnode_cnt:     %d\n", c->pnode_cnt);
++      printk(KERN_ERR "\tnnode_cnt:     %d\n", c->nnode_cnt);
++      printk(KERN_ERR "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
++      printk(KERN_ERR "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
++      printk(KERN_ERR "\tlsave_cnt:     %d\n", c->lsave_cnt);
++      printk(KERN_ERR "\tspace_bits:    %d\n", c->space_bits);
++      printk(KERN_ERR "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
++      printk(KERN_ERR "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
++      printk(KERN_ERR "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
++      printk(KERN_ERR "\tpcnt_bits:     %d\n", c->pcnt_bits);
++      printk(KERN_ERR "\tlnum_bits:     %d\n", c->lnum_bits);
++      printk(KERN_ERR "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
++      printk(KERN_ERR "\tLPT head is at %d:%d\n",
+              c->nhead_lnum, c->nhead_offs);
+-      printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n",
++      printk(KERN_ERR "\tLPT ltab is at %d:%d\n",
+              c->ltab_lnum, c->ltab_offs);
+       if (c->big_lpt)
+-              printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
++              printk(KERN_ERR "\tLPT lsave is at %d:%d\n",
+                      c->lsave_lnum, c->lsave_offs);
+       for (i = 0; i < c->lpt_lebs; i++)
+-              printk(KERN_DEBUG "\tLPT LEB %d free %d dirty %d tgc %d "
++              printk(KERN_ERR "\tLPT LEB %d free %d dirty %d tgc %d "
+                      "cmt %d\n", i + c->lpt_first, c->ltab[i].free,
+                      c->ltab[i].dirty, c->ltab[i].tgc, c->ltab[i].cmt);
+       spin_unlock(&dbg_lock);
+ }
++void dbg_dump_sleb(const struct ubifs_info *c,
++                 const struct ubifs_scan_leb *sleb, int offs)
++{
++      struct ubifs_scan_node *snod;
++
++      printk(KERN_ERR "(pid %d) start dumping scanned data from LEB %d:%d\n",
++             current->pid, sleb->lnum, offs);
++
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              cond_resched();
++              printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
++                     snod->offs, snod->len);
++              dbg_dump_node(c, snod->node);
++      }
++}
++
+ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
+ {
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
++      void *buf;
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+-      printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
++      printk(KERN_ERR "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+-      sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
++
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory for dumping LEB %d", lnum);
++              return;
++      }
++
++      sleb = ubifs_scan(c, lnum, 0, buf, 0);
+       if (IS_ERR(sleb)) {
+               ubifs_err("scan error %d", (int)PTR_ERR(sleb));
+-              return;
++              goto out;
+       }
+-      printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum,
++      printk(KERN_ERR "LEB %d has %d nodes ending at %d\n", lnum,
+              sleb->nodes_cnt, sleb->endpt);
+       list_for_each_entry(snod, &sleb->nodes, list) {
+               cond_resched();
+-              printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum,
++              printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", lnum,
+                      snod->offs, snod->len);
+               dbg_dump_node(c, snod->node);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
++      printk(KERN_ERR "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
+       ubifs_scan_destroy(sleb);
++
++out:
++      vfree(buf);
+       return;
+ }
+@@ -843,6 +926,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
+ {
+       int n;
+       const struct ubifs_zbranch *zbr;
++      char key_buf[DBG_KEY_BUF_LEN];
+       spin_lock(&dbg_lock);
+       if (znode->parent)
+@@ -850,7 +934,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
+       else
+               zbr = &c->zroot;
+-      printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
++      printk(KERN_ERR "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
+              " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs,
+              zbr->len, znode->parent, znode->iip, znode->level,
+              znode->child_cnt, znode->flags);
+@@ -860,19 +944,23 @@ void dbg_dump_znode(const struct ubifs_info *c,
+               return;
+       }
+-      printk(KERN_DEBUG "zbranches:\n");
++      printk(KERN_ERR "zbranches:\n");
+       for (n = 0; n < znode->child_cnt; n++) {
+               zbr = &znode->zbranch[n];
+               if (znode->level > 0)
+-                      printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
++                      printk(KERN_ERR "\t%d: znode %p LEB %d:%d len %d key "
+                                         "%s\n", n, zbr->znode, zbr->lnum,
+                                         zbr->offs, zbr->len,
+-                                        DBGKEY(&zbr->key));
++                                        dbg_snprintf_key(c, &zbr->key,
++                                                         key_buf,
++                                                         DBG_KEY_BUF_LEN));
+               else
+-                      printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
++                      printk(KERN_ERR "\t%d: LNC %p LEB %d:%d len %d key "
+                                         "%s\n", n, zbr->znode, zbr->lnum,
+                                         zbr->offs, zbr->len,
+-                                        DBGKEY(&zbr->key));
++                                        dbg_snprintf_key(c, &zbr->key,
++                                                         key_buf,
++                                                         DBG_KEY_BUF_LEN));
+       }
+       spin_unlock(&dbg_lock);
+ }
+@@ -881,16 +969,16 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
+ {
+       int i;
+-      printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n",
++      printk(KERN_ERR "(pid %d) start dumping heap cat %d (%d elements)\n",
+              current->pid, cat, heap->cnt);
+       for (i = 0; i < heap->cnt; i++) {
+               struct ubifs_lprops *lprops = heap->arr[i];
+-              printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d "
++              printk(KERN_ERR "\t%d. LEB %d hpos %d free %d dirty %d "
+                      "flags %d\n", i, lprops->lnum, lprops->hpos,
+                      lprops->free, lprops->dirty, lprops->flags);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid);
++      printk(KERN_ERR "(pid %d) finish dumping heap\n", current->pid);
+ }
+ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+@@ -898,15 +986,15 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+ {
+       int i;
+-      printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid);
+-      printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
++      printk(KERN_ERR "(pid %d) dumping pnode:\n", current->pid);
++      printk(KERN_ERR "\taddress %zx parent %zx cnext %zx\n",
+              (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
+-      printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
++      printk(KERN_ERR "\tflags %lu iip %d level %d num %d\n",
+              pnode->flags, iip, pnode->level, pnode->num);
+       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+               struct ubifs_lprops *lp = &pnode->lprops[i];
+-              printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n",
++              printk(KERN_ERR "\t%d: free %d dirty %d flags %d lnum %d\n",
+                      i, lp->free, lp->dirty, lp->flags, lp->lnum);
+       }
+ }
+@@ -916,20 +1004,20 @@ void dbg_dump_tnc(struct ubifs_info *c)
+       struct ubifs_znode *znode;
+       int level;
+-      printk(KERN_DEBUG "\n");
+-      printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid);
++      printk(KERN_ERR "\n");
++      printk(KERN_ERR "(pid %d) start dumping TNC tree\n", current->pid);
+       znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
+       level = znode->level;
+-      printk(KERN_DEBUG "== Level %d ==\n", level);
++      printk(KERN_ERR "== Level %d ==\n", level);
+       while (znode) {
+               if (level != znode->level) {
+                       level = znode->level;
+-                      printk(KERN_DEBUG "== Level %d ==\n", level);
++                      printk(KERN_ERR "== Level %d ==\n", level);
+               }
+               dbg_dump_znode(c, znode);
+               znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid);
++      printk(KERN_ERR "(pid %d) finish dumping TNC tree\n", current->pid);
+ }
+ static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
+@@ -961,11 +1049,41 @@ void dbg_dump_index(struct ubifs_info *c)
+ void dbg_save_space_info(struct ubifs_info *c)
+ {
+       struct ubifs_debug_info *d = c->dbg;
+-
+-      ubifs_get_lp_stats(c, &d->saved_lst);
++      int freeable_cnt;
+       spin_lock(&c->space_lock);
++      memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats));
++      memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info));
++      d->saved_idx_gc_cnt = c->idx_gc_cnt;
++
++      /*
++       * We use a dirty hack here and zero out @c->freeable_cnt, because it
++       * affects the free space calculations, and UBIFS might not know about
++       * all freeable eraseblocks. Indeed, we know about freeable eraseblocks
++       * only when we read their lprops, and we do this only lazily, upon the
++       * need. So at any given point of time @c->freeable_cnt might be not
++       * exactly accurate.
++       *
++       * Just one example about the issue we hit when we did not zero
++       * @c->freeable_cnt.
++       * 1. The file-system is mounted R/O, c->freeable_cnt is %0. We save the
++       *    amount of free space in @d->saved_free
++       * 2. We re-mount R/W, which makes UBIFS to read the "lsave"
++       *    information from flash, where we cache LEBs from various
++       *    categories ('ubifs_remount_fs()' -> 'ubifs_lpt_init()'
++       *    -> 'lpt_init_wr()' -> 'read_lsave()' -> 'ubifs_lpt_lookup()'
++       *    -> 'ubifs_get_pnode()' -> 'update_cats()'
++       *    -> 'ubifs_add_to_cat()').
++       * 3. Lsave contains a freeable eraseblock, and @c->freeable_cnt
++       *    becomes %1.
++       * 4. We calculate the amount of free space when the re-mount is
++       *    finished in 'dbg_check_space_info()' and it does not match
++       *    @d->saved_free.
++       */
++      freeable_cnt = c->freeable_cnt;
++      c->freeable_cnt = 0;
+       d->saved_free = ubifs_get_free_space_nolock(c);
++      c->freeable_cnt = freeable_cnt;
+       spin_unlock(&c->space_lock);
+ }
+@@ -982,12 +1100,15 @@ int dbg_check_space_info(struct ubifs_info *c)
+ {
+       struct ubifs_debug_info *d = c->dbg;
+       struct ubifs_lp_stats lst;
+-      long long avail, free;
++      long long free;
++      int freeable_cnt;
+       spin_lock(&c->space_lock);
+-      avail = ubifs_calc_available(c, c->min_idx_lebs);
++      freeable_cnt = c->freeable_cnt;
++      c->freeable_cnt = 0;
++      free = ubifs_get_free_space_nolock(c);
++      c->freeable_cnt = freeable_cnt;
+       spin_unlock(&c->space_lock);
+-      free = ubifs_get_free_space(c);
+       if (free != d->saved_free) {
+               ubifs_err("free space changed from %lld to %lld",
+@@ -1000,20 +1121,21 @@ int dbg_check_space_info(struct ubifs_info *c)
+ out:
+       ubifs_msg("saved lprops statistics dump");
+       dbg_dump_lstats(&d->saved_lst);
+-      ubifs_get_lp_stats(c, &lst);
+-
++      ubifs_msg("saved budgeting info dump");
++      dbg_dump_budg(c, &d->saved_bi);
++      ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
+       ubifs_msg("current lprops statistics dump");
++      ubifs_get_lp_stats(c, &lst);
+       dbg_dump_lstats(&lst);
+-
+-      spin_lock(&c->space_lock);
+-      dbg_dump_budg(c);
+-      spin_unlock(&c->space_lock);
++      ubifs_msg("current budgeting info dump");
++      dbg_dump_budg(c, &c->bi);
+       dump_stack();
+       return -EINVAL;
+ }
+ /**
+  * dbg_check_synced_i_size - check synchronized inode size.
++ * @c: UBIFS file-system description object
+  * @inode: inode to check
+  *
+  * If inode is clean, synchronized inode size has to be equivalent to current
+@@ -1021,12 +1143,12 @@ out:
+  * has to be locked). Returns %0 if synchronized inode size if correct, and
+  * %-EINVAL if not.
+  */
+-int dbg_check_synced_i_size(struct inode *inode)
++int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode)
+ {
+       int err = 0;
+       struct ubifs_inode *ui = ubifs_inode(inode);
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (!S_ISREG(inode->i_mode))
+               return 0;
+@@ -1059,7 +1181,7 @@ int dbg_check_synced_i_size(struct inode *inode)
+  * Note, it is good idea to make sure the @dir->i_mutex is locked before
+  * calling this function.
+  */
+-int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
++int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
+ {
+       unsigned int nlink = 2;
+       union ubifs_key key;
+@@ -1067,7 +1189,7 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
+       struct qstr nm = { .name = NULL };
+       loff_t size = UBIFS_INO_NODE_SZ;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (!S_ISDIR(dir->i_mode))
+@@ -1101,12 +1223,14 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
+                         "but calculated size is %llu", dir->i_ino,
+                         (unsigned long long)i_size_read(dir),
+                         (unsigned long long)size);
++              dbg_dump_inode(c, dir);
+               dump_stack();
+               return -EINVAL;
+       }
+       if (dir->i_nlink != nlink) {
+               ubifs_err("directory inode %lu has nlink %u, but calculated "
+                         "nlink is %u", dir->i_ino, dir->i_nlink, nlink);
++              dbg_dump_inode(c, dir);
+               dump_stack();
+               return -EINVAL;
+       }
+@@ -1133,6 +1257,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       int err, nlen1, nlen2, cmp;
+       struct ubifs_dent_node *dent1, *dent2;
+       union ubifs_key key;
++      char key_buf[DBG_KEY_BUF_LEN];
+       ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key));
+       dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
+@@ -1163,9 +1288,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       key_read(c, &dent1->key, &key);
+       if (keys_cmp(c, &zbr1->key, &key)) {
+               dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
+-                      zbr1->offs, DBGKEY(&key));
++                      zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
++                                                   DBG_KEY_BUF_LEN));
+               dbg_err("but it should have key %s according to tnc",
+-                      DBGKEY(&zbr1->key));
++                      dbg_snprintf_key(c, &zbr1->key, key_buf,
++                                       DBG_KEY_BUF_LEN));
+               dbg_dump_node(c, dent1);
+               goto out_free;
+       }
+@@ -1173,9 +1300,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       key_read(c, &dent2->key, &key);
+       if (keys_cmp(c, &zbr2->key, &key)) {
+               dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
+-                      zbr1->offs, DBGKEY(&key));
++                      zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
++                                                   DBG_KEY_BUF_LEN));
+               dbg_err("but it should have key %s according to tnc",
+-                      DBGKEY(&zbr2->key));
++                      dbg_snprintf_key(c, &zbr2->key, key_buf,
++                                       DBG_KEY_BUF_LEN));
+               dbg_dump_node(c, dent2);
+               goto out_free;
+       }
+@@ -1192,7 +1321,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+               dbg_err("2 xent/dent nodes with the same name");
+       else
+               dbg_err("bad order of colliding key %s",
+-                      DBGKEY(&key));
++                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+       ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
+       dbg_dump_node(c, dent1);
+@@ -1423,7 +1552,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra)
+       long clean_cnt = 0, dirty_cnt = 0;
+       int err, last;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_TNC))
++      if (!dbg_is_chk_index(c))
+               return 0;
+       ubifs_assert(mutex_is_locked(&c->tnc_mutex));
+@@ -1670,7 +1799,7 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
+       int err;
+       long long calc = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ))
++      if (!dbg_is_chk_index(c))
+               return 0;
+       err = dbg_walk_index(c, NULL, add_size, &calc);
+@@ -1751,6 +1880,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
+       struct rb_node **p, *parent = NULL;
+       struct fsck_inode *fscki;
+       ino_t inum = key_inum_flash(c, &ino->key);
++      struct inode *inode;
++      struct ubifs_inode *ui;
+       p = &fsckd->inodes.rb_node;
+       while (*p) {
+@@ -1774,19 +1905,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
+       if (!fscki)
+               return ERR_PTR(-ENOMEM);
++      inode = ilookup(c->vfs_sb, inum);
++
+       fscki->inum = inum;
+-      fscki->nlink = le32_to_cpu(ino->nlink);
+-      fscki->size = le64_to_cpu(ino->size);
+-      fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
+-      fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
+-      fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
+-      fscki->mode = le32_to_cpu(ino->mode);
++      /*
++       * If the inode is present in the VFS inode cache, use it instead of
++       * the on-flash inode which might be out-of-date. E.g., the size might
++       * be out-of-date. If we do not do this, the following may happen, for
++       * example:
++       *   1. A power cut happens
++       *   2. We mount the file-system R/O, the replay process fixes up the
++       *      inode size in the VFS cache, but on on-flash.
++       *   3. 'check_leaf()' fails because it hits a data node beyond inode
++       *      size.
++       */
++      if (!inode) {
++              fscki->nlink = le32_to_cpu(ino->nlink);
++              fscki->size = le64_to_cpu(ino->size);
++              fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
++              fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
++              fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
++              fscki->mode = le32_to_cpu(ino->mode);
++      } else {
++              ui = ubifs_inode(inode);
++              fscki->nlink = inode->i_nlink;
++              fscki->size = inode->i_size;
++              fscki->xattr_cnt = ui->xattr_cnt;
++              fscki->xattr_sz = ui->xattr_size;
++              fscki->xattr_nms = ui->xattr_names;
++              fscki->mode = inode->i_mode;
++              iput(inode);
++      }
++
+       if (S_ISDIR(fscki->mode)) {
+               fscki->calc_sz = UBIFS_INO_NODE_SZ;
+               fscki->calc_cnt = 2;
+       }
++
+       rb_link_node(&fscki->rb, parent, p);
+       rb_insert_color(&fscki->rb, &fsckd->inodes);
++
+       return fscki;
+ }
+@@ -2217,7 +2375,7 @@ int dbg_check_filesystem(struct ubifs_info *c)
+       int err;
+       struct fsck_data fsckd;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_FS))
++      if (!dbg_is_chk_fs(c))
+               return 0;
+       fsckd.inodes = RB_ROOT;
+@@ -2252,7 +2410,7 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+@@ -2319,7 +2477,7 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+@@ -2379,7 +2537,8 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+               hashb = key_block(c, &sb->key);
+               if (hasha > hashb) {
+-                      ubifs_err("larger hash %u goes before %u", hasha, hashb);
++                      ubifs_err("larger hash %u goes before %u",
++                                hasha, hashb);
+                       goto error_dump;
+               }
+       }
+@@ -2395,393 +2554,351 @@ error_dump:
+       return 0;
+ }
+-static int invocation_cnt;
+-
+-int dbg_force_in_the_gaps(void)
+-{
+-      if (!dbg_force_in_the_gaps_enabled)
+-              return 0;
+-      /* Force in-the-gaps every 8th commit */
+-      return !((invocation_cnt++) & 0x7);
+-}
+-
+-/* Failure mode for recovery testing */
+-
+-#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d))
+-
+-struct failure_mode_info {
+-      struct list_head list;
+-      struct ubifs_info *c;
+-};
+-
+-static LIST_HEAD(fmi_list);
+-static DEFINE_SPINLOCK(fmi_lock);
+-
+-static unsigned int next;
+-
+-static int simple_rand(void)
+-{
+-      if (next == 0)
+-              next = current->pid;
+-      next = next * 1103515245 + 12345;
+-      return (next >> 16) & 32767;
+-}
+-
+-static void failure_mode_init(struct ubifs_info *c)
+-{
+-      struct failure_mode_info *fmi;
+-
+-      fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
+-      if (!fmi) {
+-              ubifs_err("Failed to register failure mode - no memory");
+-              return;
+-      }
+-      fmi->c = c;
+-      spin_lock(&fmi_lock);
+-      list_add_tail(&fmi->list, &fmi_list);
+-      spin_unlock(&fmi_lock);
+-}
+-
+-static void failure_mode_exit(struct ubifs_info *c)
+-{
+-      struct failure_mode_info *fmi, *tmp;
+-
+-      spin_lock(&fmi_lock);
+-      list_for_each_entry_safe(fmi, tmp, &fmi_list, list)
+-              if (fmi->c == c) {
+-                      list_del(&fmi->list);
+-                      kfree(fmi);
+-              }
+-      spin_unlock(&fmi_lock);
+-}
+-
+-static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc)
++static inline int chance(unsigned int n, unsigned int out_of)
+ {
+-      struct failure_mode_info *fmi;
+-
+-      spin_lock(&fmi_lock);
+-      list_for_each_entry(fmi, &fmi_list, list)
+-              if (fmi->c->ubi == desc) {
+-                      struct ubifs_info *c = fmi->c;
++      return !!((random32() % out_of) + 1 <= n);
+-                      spin_unlock(&fmi_lock);
+-                      return c;
+-              }
+-      spin_unlock(&fmi_lock);
+-      return NULL;
+ }
+-static int in_failure_mode(struct ubi_volume_desc *desc)
++static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
+ {
+-      struct ubifs_info *c = dbg_find_info(desc);
+-
+-      if (c && dbg_failure_mode)
+-              return c->dbg->failure_mode;
+-      return 0;
+-}
++      struct ubifs_debug_info *d = c->dbg;
+-static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
+-{
+-      struct ubifs_info *c = dbg_find_info(desc);
+-      struct ubifs_debug_info *d;
++      ubifs_assert(dbg_is_tst_rcvry(c));
+-      if (!c || !dbg_failure_mode)
+-              return 0;
+-      d = c->dbg;
+-      if (d->failure_mode)
+-              return 1;
+-      if (!d->fail_cnt) {
+-              /* First call - decide delay to failure */
++      if (!d->pc_cnt) {
++              /* First call - decide delay to the power cut */
+               if (chance(1, 2)) {
+-                      unsigned int delay = 1 << (simple_rand() >> 11);
++                      unsigned long delay;
+                       if (chance(1, 2)) {
+-                              d->fail_delay = 1;
+-                              d->fail_timeout = jiffies +
+-                                                msecs_to_jiffies(delay);
+-                              dbg_rcvry("failing after %ums", delay);
++                              d->pc_delay = 1;
++                              /* Fail withing 1 minute */
++                              delay = random32() % 60000;
++                              d->pc_timeout = jiffies;
++                              d->pc_timeout += msecs_to_jiffies(delay);
++                              ubifs_warn("failing after %lums", delay);
+                       } else {
+-                              d->fail_delay = 2;
+-                              d->fail_cnt_max = delay;
+-                              dbg_rcvry("failing after %u calls", delay);
++                              d->pc_delay = 2;
++                              delay = random32() % 10000;
++                              /* Fail within 10000 operations */
++                              d->pc_cnt_max = delay;
++                              ubifs_warn("failing after %lu calls", delay);
+                       }
+               }
+-              d->fail_cnt += 1;
++
++              d->pc_cnt += 1;
+       }
++
+       /* Determine if failure delay has expired */
+-      if (d->fail_delay == 1) {
+-              if (time_before(jiffies, d->fail_timeout))
++      if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
+                       return 0;
+-      } else if (d->fail_delay == 2)
+-              if (d->fail_cnt++ < d->fail_cnt_max)
++      if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
+                       return 0;
++
+       if (lnum == UBIFS_SB_LNUM) {
+-              if (write) {
+-                      if (chance(1, 2))
+-                              return 0;
+-              } else if (chance(19, 20))
++              if (write && chance(1, 2))
+                       return 0;
+-              dbg_rcvry("failing in super block LEB %d", lnum);
++              if (chance(19, 20))
++                      return 0;
++              ubifs_warn("failing in super block LEB %d", lnum);
+       } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
+               if (chance(19, 20))
+                       return 0;
+-              dbg_rcvry("failing in master LEB %d", lnum);
++              ubifs_warn("failing in master LEB %d", lnum);
+       } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
+-              if (write) {
+-                      if (chance(99, 100))
+-                              return 0;
+-              } else if (chance(399, 400))
++              if (write && chance(99, 100))
++                      return 0;
++              if (chance(399, 400))
+                       return 0;
+-              dbg_rcvry("failing in log LEB %d", lnum);
++              ubifs_warn("failing in log LEB %d", lnum);
+       } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
+-              if (write) {
+-                      if (chance(7, 8))
+-                              return 0;
+-              } else if (chance(19, 20))
++              if (write && chance(7, 8))
+                       return 0;
+-              dbg_rcvry("failing in LPT LEB %d", lnum);
++              if (chance(19, 20))
++                      return 0;
++              ubifs_warn("failing in LPT LEB %d", lnum);
+       } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
+-              if (write) {
+-                      if (chance(1, 2))
+-                              return 0;
+-              } else if (chance(9, 10))
++              if (write && chance(1, 2))
+                       return 0;
+-              dbg_rcvry("failing in orphan LEB %d", lnum);
++              if (chance(9, 10))
++                      return 0;
++              ubifs_warn("failing in orphan LEB %d", lnum);
+       } else if (lnum == c->ihead_lnum) {
+               if (chance(99, 100))
+                       return 0;
+-              dbg_rcvry("failing in index head LEB %d", lnum);
++              ubifs_warn("failing in index head LEB %d", lnum);
+       } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
+               if (chance(9, 10))
+                       return 0;
+-              dbg_rcvry("failing in GC head LEB %d", lnum);
++              ubifs_warn("failing in GC head LEB %d", lnum);
+       } else if (write && !RB_EMPTY_ROOT(&c->buds) &&
+                  !ubifs_search_bud(c, lnum)) {
+               if (chance(19, 20))
+                       return 0;
+-              dbg_rcvry("failing in non-bud LEB %d", lnum);
++              ubifs_warn("failing in non-bud LEB %d", lnum);
+       } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
+                  c->cmt_state == COMMIT_RUNNING_REQUIRED) {
+               if (chance(999, 1000))
+                       return 0;
+-              dbg_rcvry("failing in bud LEB %d commit running", lnum);
++              ubifs_warn("failing in bud LEB %d commit running", lnum);
+       } else {
+               if (chance(9999, 10000))
+                       return 0;
+-              dbg_rcvry("failing in bud LEB %d commit not running", lnum);
++              ubifs_warn("failing in bud LEB %d commit not running", lnum);
+       }
+-      ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum);
+-      d->failure_mode = 1;
++
++      d->pc_happened = 1;
++      ubifs_warn("========== Power cut emulated ==========");
+       dump_stack();
+       return 1;
+ }
+-static void cut_data(const void *buf, int len)
++static void cut_data(const void *buf, unsigned int len)
+ {
+-      int flen, i;
++      unsigned int from, to, i, ffs = chance(1, 2);
+       unsigned char *p = (void *)buf;
+-      flen = (len * (long long)simple_rand()) >> 15;
+-      for (i = flen; i < len; i++)
+-              p[i] = 0xff;
+-}
++      from = random32() % (len + 1);
++      if (chance(1, 2))
++              to = random32() % (len - from + 1);
++      else
++              to = len;
+-int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+-               int len, int check)
+-{
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      return ubi_leb_read(desc, lnum, buf, offset, len, check);
++      if (from < to)
++              ubifs_warn("filled bytes %u-%u with %s", from, to - 1,
++                         ffs ? "0xFFs" : "random data");
++
++      if (ffs)
++              for (i = from; i < to; i++)
++                      p[i] = 0xFF;
++      else
++              for (i = from; i < to; i++)
++                      p[i] = random32() % 0x100;
+ }
+-int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                int offset, int len, int dtype)
++int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
++                int offs, int len, int dtype)
+ {
+       int err, failing;
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      failing = do_fail(desc, lnum, 1);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++
++      failing = power_cut_emulated(c, lnum, 1);
+       if (failing)
+               cut_data(buf, len);
+-      err = ubi_leb_write(desc, lnum, buf, offset, len, dtype);
++      err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+       if (err)
+               return err;
+       if (failing)
+-              return -EIO;
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
++int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
+                  int len, int dtype)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 1))
+-              return -EIO;
+-      err = ubi_leb_change(desc, lnum, buf, len, dtype);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 1))
++              return -EROFS;
++      err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 1))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 1))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)
++int dbg_leb_unmap(struct ubifs_info *c, int lnum)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_erase(desc, lnum);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
++      err = ubi_leb_unmap(c->ubi, lnum);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
++int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_unmap(desc, lnum);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
++      err = ubi_leb_map(c->ubi, lnum, dtype);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)
+-{
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      return ubi_is_mapped(desc, lnum);
+-}
++/*
++ * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
++ * contain the stuff specific to particular file-system mounts.
++ */
++static struct dentry *dfs_rootdir;
+-int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
++static int dfs_file_open(struct inode *inode, struct file *file)
+ {
+-      int err;
+-
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_map(desc, lnum, dtype);
+-      if (err)
+-              return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      return 0;
++      file->private_data = inode->i_private;
++      return nonseekable_open(inode, file);
+ }
+ /**
+- * ubifs_debugging_init - initialize UBIFS debugging.
+- * @c: UBIFS file-system description object
++ * provide_user_output - provide output to the user reading a debugfs file.
++ * @val: boolean value for the answer
++ * @u: the buffer to store the answer at
++ * @count: size of the buffer
++ * @ppos: position in the @u output buffer
+  *
+- * This function initializes debugging-related data for the file system.
+- * Returns zero in case of success and a negative error code in case of
++ * This is a simple helper function which stores @val boolean value in the user
++ * buffer when the user reads one of UBIFS debugfs files. Returns amount of
++ * bytes written to @u in case of success and a negative error code in case of
+  * failure.
+  */
+-int ubifs_debugging_init(struct ubifs_info *c)
++static int provide_user_output(int val, char __user *u, size_t count,
++                             loff_t *ppos)
+ {
+-      c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
+-      if (!c->dbg)
+-              return -ENOMEM;
+-
+-      c->dbg->buf = vmalloc(c->leb_size);
+-      if (!c->dbg->buf)
+-              goto out;
++      char buf[3];
+-      failure_mode_init(c);
+-      return 0;
++      if (val)
++              buf[0] = '1';
++      else
++              buf[0] = '0';
++      buf[1] = '\n';
++      buf[2] = 0x00;
+-out:
+-      kfree(c->dbg);
+-      return -ENOMEM;
++      return simple_read_from_buffer(u, count, ppos, buf, 2);
+ }
+-/**
+- * ubifs_debugging_exit - free debugging data.
+- * @c: UBIFS file-system description object
+- */
+-void ubifs_debugging_exit(struct ubifs_info *c)
++static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
++                           loff_t *ppos)
+ {
+-      failure_mode_exit(c);
+-      vfree(c->dbg->buf);
+-      kfree(c->dbg);
+-}
++      struct dentry *dent = file->f_path.dentry;
++      struct ubifs_info *c = file->private_data;
++      struct ubifs_debug_info *d = c->dbg;
++      int val;
++
++      if (dent == d->dfs_chk_gen)
++              val = d->chk_gen;
++      else if (dent == d->dfs_chk_index)
++              val = d->chk_index;
++      else if (dent == d->dfs_chk_orph)
++              val = d->chk_orph;
++      else if (dent == d->dfs_chk_lprops)
++              val = d->chk_lprops;
++      else if (dent == d->dfs_chk_fs)
++              val = d->chk_fs;
++      else if (dent == d->dfs_tst_rcvry)
++              val = d->tst_rcvry;
++      else
++              return -EINVAL;
+-/*
+- * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
+- * contain the stuff specific to particular file-system mounts.
+- */
+-static struct dentry *dfs_rootdir;
++      return provide_user_output(val, u, count, ppos);
++}
+ /**
+- * dbg_debugfs_init - initialize debugfs file-system.
++ * interpret_user_input - interpret user debugfs file input.
++ * @u: user-provided buffer with the input
++ * @count: buffer size
+  *
+- * UBIFS uses debugfs file-system to expose various debugging knobs to
+- * user-space. This function creates "ubifs" directory in the debugfs
+- * file-system. Returns zero in case of success and a negative error code in
+- * case of failure.
++ * This is a helper function which interpret user input to a boolean UBIFS
++ * debugfs file. Returns %0 or %1 in case of success and a negative error code
++ * in case of failure.
+  */
+-int dbg_debugfs_init(void)
++static int interpret_user_input(const char __user *u, size_t count)
+ {
+-      dfs_rootdir = debugfs_create_dir("ubifs", NULL);
+-      if (IS_ERR(dfs_rootdir)) {
+-              int err = PTR_ERR(dfs_rootdir);
+-              ubifs_err("cannot create \"ubifs\" debugfs directory, "
+-                        "error %d\n", err);
+-              return err;
+-      }
++      size_t buf_size;
++      char buf[8];
+-      return 0;
+-}
++      buf_size = min_t(size_t, count, (sizeof(buf) - 1));
++      if (copy_from_user(buf, u, buf_size))
++              return -EFAULT;
+-/**
+- * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
+- */
+-void dbg_debugfs_exit(void)
+-{
+-      debugfs_remove(dfs_rootdir);
+-}
++      if (buf[0] == '1')
++              return 1;
++      else if (buf[0] == '0')
++              return 0;
+-static int open_debugfs_file(struct inode *inode, struct file *file)
+-{
+-      file->private_data = inode->i_private;
+-      return 0;
++      return -EINVAL;
+ }
+-static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
+-                                size_t count, loff_t *ppos)
++static ssize_t dfs_file_write(struct file *file, const char __user *u,
++                            size_t count, loff_t *ppos)
+ {
+       struct ubifs_info *c = file->private_data;
+       struct ubifs_debug_info *d = c->dbg;
++      struct dentry *dent = file->f_path.dentry;
++      int val;
+-      if (file->f_path.dentry == d->dfs_dump_lprops)
++      /*
++       * TODO: this is racy - the file-system might have already been
++       * unmounted and we'd oops in this case. The plan is to fix it with
++       * help of 'iterate_supers_type()' which we should have in v3.0: when
++       * a debugfs opened, we rember FS's UUID in file->private_data. Then
++       * whenever we access the FS via a debugfs file, we iterate all UBIFS
++       * superblocks and fine the one with the same UUID, and take the
++       * locking right.
++       *
++       * The other way to go suggested by Al Viro is to create a separate
++       * 'ubifs-debug' file-system instead.
++       */
++      if (file->f_path.dentry == d->dfs_dump_lprops) {
+               dbg_dump_lprops(c);
+-      else if (file->f_path.dentry == d->dfs_dump_budg) {
+-              spin_lock(&c->space_lock);
+-              dbg_dump_budg(c);
+-              spin_unlock(&c->space_lock);
+-      } else if (file->f_path.dentry == d->dfs_dump_tnc) {
++              return count;
++      }
++      if (file->f_path.dentry == d->dfs_dump_budg) {
++              dbg_dump_budg(c, &c->bi);
++              return count;
++      }
++      if (file->f_path.dentry == d->dfs_dump_tnc) {
+               mutex_lock(&c->tnc_mutex);
+               dbg_dump_tnc(c);
+               mutex_unlock(&c->tnc_mutex);
+-      } else
++              return count;
++      }
++
++      val = interpret_user_input(u, count);
++      if (val < 0)
++              return val;
++
++      if (dent == d->dfs_chk_gen)
++              d->chk_gen = val;
++      else if (dent == d->dfs_chk_index)
++              d->chk_index = val;
++      else if (dent == d->dfs_chk_orph)
++              d->chk_orph = val;
++      else if (dent == d->dfs_chk_lprops)
++              d->chk_lprops = val;
++      else if (dent == d->dfs_chk_fs)
++              d->chk_fs = val;
++      else if (dent == d->dfs_tst_rcvry)
++              d->tst_rcvry = val;
++      else
+               return -EINVAL;
+-      *ppos += count;
+       return count;
+ }
+ static const struct file_operations dfs_fops = {
+-      .open = open_debugfs_file,
+-      .write = write_debugfs_file,
++      .open = dfs_file_open,
++      .read = dfs_file_read,
++      .write = dfs_file_write,
+       .owner = THIS_MODULE,
+-      .llseek = default_llseek,
++      .llseek = no_llseek,
+ };
+ /**
+@@ -2798,46 +2915,94 @@ static const struct file_operations dfs_fops = {
+  */
+ int dbg_debugfs_init_fs(struct ubifs_info *c)
+ {
+-      int err;
++      int err, n;
+       const char *fname;
+       struct dentry *dent;
+       struct ubifs_debug_info *d = c->dbg;
+-      sprintf(d->dfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
+-      d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir);
+-      if (IS_ERR(d->dfs_dir)) {
+-              err = PTR_ERR(d->dfs_dir);
+-              ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+-                        d->dfs_dir_name, err);
++      n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
++                   c->vi.ubi_num, c->vi.vol_id);
++      if (n == UBIFS_DFS_DIR_LEN) {
++              /* The array size is too small */
++              fname = UBIFS_DFS_DIR_NAME;
++              dent = ERR_PTR(-EINVAL);
+               goto out;
+       }
++      fname = d->dfs_dir_name;
++      dent = debugfs_create_dir(fname, dfs_rootdir);
++      if (IS_ERR_OR_NULL(dent))
++              goto out;
++      d->dfs_dir = dent;
++
+       fname = "dump_lprops";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_lprops = dent;
+       fname = "dump_budg";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_budg = dent;
+       fname = "dump_tnc";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_tnc = dent;
++      fname = "chk_general";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_gen = dent;
++
++      fname = "chk_index";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_index = dent;
++
++      fname = "chk_orphans";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_orph = dent;
++
++      fname = "chk_lprops";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_lprops = dent;
++
++      fname = "chk_fs";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_fs = dent;
++
++      fname = "tst_recovery";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_tst_rcvry = dent;
++
+       return 0;
+ out_remove:
+-      err = PTR_ERR(dent);
+-      ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+-                fname, err);
+       debugfs_remove_recursive(d->dfs_dir);
+ out:
++      err = dent ? PTR_ERR(dent) : -ENODEV;
++      ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
++                fname, err);
+       return err;
+ }
+@@ -2850,4 +3015,179 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c)
+       debugfs_remove_recursive(c->dbg->dfs_dir);
+ }
++struct ubifs_global_debug_info ubifs_dbg;
++
++static struct dentry *dfs_chk_gen;
++static struct dentry *dfs_chk_index;
++static struct dentry *dfs_chk_orph;
++static struct dentry *dfs_chk_lprops;
++static struct dentry *dfs_chk_fs;
++static struct dentry *dfs_tst_rcvry;
++
++static ssize_t dfs_global_file_read(struct file *file, char __user *u,
++                                  size_t count, loff_t *ppos)
++{
++      struct dentry *dent = file->f_path.dentry;
++      int val;
++
++      if (dent == dfs_chk_gen)
++              val = ubifs_dbg.chk_gen;
++      else if (dent == dfs_chk_index)
++              val = ubifs_dbg.chk_index;
++      else if (dent == dfs_chk_orph)
++              val = ubifs_dbg.chk_orph;
++      else if (dent == dfs_chk_lprops)
++              val = ubifs_dbg.chk_lprops;
++      else if (dent == dfs_chk_fs)
++              val = ubifs_dbg.chk_fs;
++      else if (dent == dfs_tst_rcvry)
++              val = ubifs_dbg.tst_rcvry;
++      else
++              return -EINVAL;
++
++      return provide_user_output(val, u, count, ppos);
++}
++
++static ssize_t dfs_global_file_write(struct file *file, const char __user *u,
++                                   size_t count, loff_t *ppos)
++{
++      struct dentry *dent = file->f_path.dentry;
++      int val;
++
++      val = interpret_user_input(u, count);
++      if (val < 0)
++              return val;
++
++      if (dent == dfs_chk_gen)
++              ubifs_dbg.chk_gen = val;
++      else if (dent == dfs_chk_index)
++              ubifs_dbg.chk_index = val;
++      else if (dent == dfs_chk_orph)
++              ubifs_dbg.chk_orph = val;
++      else if (dent == dfs_chk_lprops)
++              ubifs_dbg.chk_lprops = val;
++      else if (dent == dfs_chk_fs)
++              ubifs_dbg.chk_fs = val;
++      else if (dent == dfs_tst_rcvry)
++              ubifs_dbg.tst_rcvry = val;
++      else
++              return -EINVAL;
++
++      return count;
++}
++
++static const struct file_operations dfs_global_fops = {
++      .read = dfs_global_file_read,
++      .write = dfs_global_file_write,
++      .owner = THIS_MODULE,
++      .llseek = no_llseek,
++};
++
++/**
++ * dbg_debugfs_init - initialize debugfs file-system.
++ *
++ * UBIFS uses debugfs file-system to expose various debugging knobs to
++ * user-space. This function creates "ubifs" directory in the debugfs
++ * file-system. Returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++int dbg_debugfs_init(void)
++{
++      int err;
++      const char *fname;
++      struct dentry *dent;
++
++      fname = "ubifs";
++      dent = debugfs_create_dir(fname, NULL);
++      if (IS_ERR_OR_NULL(dent))
++              goto out;
++      dfs_rootdir = dent;
++
++      fname = "chk_general";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_gen = dent;
++
++      fname = "chk_index";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_index = dent;
++
++      fname = "chk_orphans";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_orph = dent;
++
++      fname = "chk_lprops";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_lprops = dent;
++
++      fname = "chk_fs";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_fs = dent;
++
++      fname = "tst_recovery";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_tst_rcvry = dent;
++
++      return 0;
++
++out_remove:
++      debugfs_remove_recursive(dfs_rootdir);
++out:
++      err = dent ? PTR_ERR(dent) : -ENODEV;
++      ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
++                fname, err);
++      return err;
++}
++
++/**
++ * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
++ */
++void dbg_debugfs_exit(void)
++{
++      debugfs_remove_recursive(dfs_rootdir);
++}
++
++/**
++ * ubifs_debugging_init - initialize UBIFS debugging.
++ * @c: UBIFS file-system description object
++ *
++ * This function initializes debugging-related data for the file system.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubifs_debugging_init(struct ubifs_info *c)
++{
++      c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
++      if (!c->dbg)
++              return -ENOMEM;
++
++      return 0;
++}
++
++/**
++ * ubifs_debugging_exit - free debugging data.
++ * @c: UBIFS file-system description object
++ */
++void ubifs_debugging_exit(struct ubifs_info *c)
++{
++      kfree(c->dbg);
++}
++
+ #endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
+index 555ba13..13917ce 100644
+--- a/fs/ubifs/debug.h
++++ b/fs/ubifs/debug.h
+@@ -31,17 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
+ #ifdef CONFIG_UBIFS_FS_DEBUG
++/*
++ * The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
++ * + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
++ */
++#define UBIFS_DFS_DIR_NAME "ubi%d_%d"
++#define UBIFS_DFS_DIR_LEN  (3 + 1 + 2*2 + 1)
++
+ /**
+  * ubifs_debug_info - per-FS debugging information.
+- * @buf: a buffer of LEB size, used for various purposes
+  * @old_zroot: old index root - used by 'dbg_check_old_index()'
+  * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
+  * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
+- * @failure_mode: failure mode for recovery testing
+- * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
+- * @fail_timeout: time in jiffies when delay of failure mode expires
+- * @fail_cnt: current number of calls to failure mode I/O functions
+- * @fail_cnt_max: number of calls by which to delay failure mode
++ *
++ * @pc_happened: non-zero if an emulated power cut happened
++ * @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
++ * @pc_timeout: time in jiffies when delay of failure mode expires
++ * @pc_cnt: current number of calls to failure mode I/O functions
++ * @pc_cnt_max: number of calls by which to delay failure mode
++ *
+  * @chk_lpt_sz: used by LPT tree size checker
+  * @chk_lpt_sz2: used by LPT tree size checker
+  * @chk_lpt_wastage: used by LPT tree size checker
+@@ -51,24 +59,40 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
+  * @new_ihead_offs: used by debugging to check @c->ihead_offs
+  *
+  * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
+- * @saved_free: saved free space (used by 'dbg_save_space_info()')
++ * @saved_bi: saved budgeting information
++ * @saved_free: saved amount of free space
++ * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
++ *
++ * @chk_gen: if general extra checks are enabled
++ * @chk_index: if index xtra checks are enabled
++ * @chk_orph: if orphans extra checks are enabled
++ * @chk_lprops: if lprops extra checks are enabled
++ * @chk_fs: if UBIFS contents extra checks are enabled
++ * @tst_rcvry: if UBIFS recovery testing mode enabled
+  *
+- * dfs_dir_name: name of debugfs directory containing this file-system's files
+- * dfs_dir: direntry object of the file-system debugfs directory
+- * dfs_dump_lprops: "dump lprops" debugfs knob
+- * dfs_dump_budg: "dump budgeting information" debugfs knob
+- * dfs_dump_tnc: "dump TNC" debugfs knob
++ * @dfs_dir_name: name of debugfs directory containing this file-system's files
++ * @dfs_dir: direntry object of the file-system debugfs directory
++ * @dfs_dump_lprops: "dump lprops" debugfs knob
++ * @dfs_dump_budg: "dump budgeting information" debugfs knob
++ * @dfs_dump_tnc: "dump TNC" debugfs knob
++ * @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks
++ * @dfs_chk_index: debugfs knob to enable UBIFS index extra checks
++ * @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks
++ * @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
++ * @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
++ * @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
+  */
+ struct ubifs_debug_info {
+-      void *buf;
+       struct ubifs_zbranch old_zroot;
+       int old_zroot_level;
+       unsigned long long old_zroot_sqnum;
+-      int failure_mode;
+-      int fail_delay;
+-      unsigned long fail_timeout;
+-      unsigned int fail_cnt;
+-      unsigned int fail_cnt_max;
++
++      int pc_happened;
++      int pc_delay;
++      unsigned long pc_timeout;
++      unsigned int pc_cnt;
++      unsigned int pc_cnt_max;
++
+       long long chk_lpt_sz;
+       long long chk_lpt_sz2;
+       long long chk_lpt_wastage;
+@@ -78,13 +102,47 @@ struct ubifs_debug_info {
+       int new_ihead_offs;
+       struct ubifs_lp_stats saved_lst;
++      struct ubifs_budg_info saved_bi;
+       long long saved_free;
++      int saved_idx_gc_cnt;
++
++      unsigned int chk_gen:1;
++      unsigned int chk_index:1;
++      unsigned int chk_orph:1;
++      unsigned int chk_lprops:1;
++      unsigned int chk_fs:1;
++      unsigned int tst_rcvry:1;
+-      char dfs_dir_name[100];
++      char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1];
+       struct dentry *dfs_dir;
+       struct dentry *dfs_dump_lprops;
+       struct dentry *dfs_dump_budg;
+       struct dentry *dfs_dump_tnc;
++      struct dentry *dfs_chk_gen;
++      struct dentry *dfs_chk_index;
++      struct dentry *dfs_chk_orph;
++      struct dentry *dfs_chk_lprops;
++      struct dentry *dfs_chk_fs;
++      struct dentry *dfs_tst_rcvry;
++};
++
++/**
++ * ubifs_global_debug_info - global (not per-FS) UBIFS debugging information.
++ *
++ * @chk_gen: if general extra checks are enabled
++ * @chk_index: if index xtra checks are enabled
++ * @chk_orph: if orphans extra checks are enabled
++ * @chk_lprops: if lprops extra checks are enabled
++ * @chk_fs: if UBIFS contents extra checks are enabled
++ * @tst_rcvry: if UBIFS recovery testing mode enabled
++ */
++struct ubifs_global_debug_info {
++      unsigned int chk_gen:1;
++      unsigned int chk_index:1;
++      unsigned int chk_orph:1;
++      unsigned int chk_lprops:1;
++      unsigned int chk_fs:1;
++      unsigned int tst_rcvry:1;
+ };
+ #define ubifs_assert(expr) do {                                                \
+@@ -103,173 +161,90 @@ struct ubifs_debug_info {
+       }                                                                      \
+ } while (0)
+-#define dbg_dump_stack() do {                                                  \
+-      if (!dbg_failure_mode)                                                 \
+-              dump_stack();                                                  \
+-} while (0)
+-
+-/* Generic debugging messages */
+-#define dbg_msg(fmt, ...) do {                                                 \
+-      spin_lock(&dbg_lock);                                                  \
+-      printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
+-             __func__, ##__VA_ARGS__);                                       \
+-      spin_unlock(&dbg_lock);                                                \
+-} while (0)
+-
+-#define dbg_do_msg(typ, fmt, ...) do {                                         \
+-      if (ubifs_msg_flags & typ)                                             \
+-              dbg_msg(fmt, ##__VA_ARGS__);                                   \
+-} while (0)
++#define dbg_dump_stack() dump_stack()
+ #define dbg_err(fmt, ...) do {                                                 \
+-      spin_lock(&dbg_lock);                                                  \
+       ubifs_err(fmt, ##__VA_ARGS__);                                         \
+-      spin_unlock(&dbg_lock);                                                \
+ } while (0)
+-const char *dbg_key_str0(const struct ubifs_info *c,
+-                       const union ubifs_key *key);
+-const char *dbg_key_str1(const struct ubifs_info *c,
+-                       const union ubifs_key *key);
++#define ubifs_dbg_msg(type, fmt, ...) \
++      pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
+-/*
+- * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
+- * macros.
+- */
+-#define DBGKEY(key) dbg_key_str0(c, (key))
+-#define DBGKEY1(key) dbg_key_str1(c, (key))
++#define DBG_KEY_BUF_LEN 32
++#define ubifs_dbg_msg_key(type, key, fmt, ...) do {                            \
++      char __tmp_key_buf[DBG_KEY_BUF_LEN];                                   \
++      pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__,             \
++               dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN));    \
++} while (0)
+-/* General messages */
+-#define dbg_gen(fmt, ...)   dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
++/* Just a debugging messages not related to any specific UBIFS subsystem */
++#define dbg_msg(fmt, ...)                                                      \
++      printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
++             __func__, ##__VA_ARGS__)
++/* General messages */
++#define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
+ /* Additional journal messages */
+-#define dbg_jnl(fmt, ...)   dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
+-
++#define dbg_jnl(fmt, ...)   ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__)
++#define dbg_jnlk(key, fmt, ...) \
++      ubifs_dbg_msg_key("jnl", key, fmt, ##__VA_ARGS__)
+ /* Additional TNC messages */
+-#define dbg_tnc(fmt, ...)   dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
+-
++#define dbg_tnc(fmt, ...)   ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__)
++#define dbg_tnck(key, fmt, ...) \
++      ubifs_dbg_msg_key("tnc", key, fmt, ##__VA_ARGS__)
+ /* Additional lprops messages */
+-#define dbg_lp(fmt, ...)    dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
+-
++#define dbg_lp(fmt, ...)    ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__)
+ /* Additional LEB find messages */
+-#define dbg_find(fmt, ...)  dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
+-
++#define dbg_find(fmt, ...)  ubifs_dbg_msg("find", fmt, ##__VA_ARGS__)
+ /* Additional mount messages */
+-#define dbg_mnt(fmt, ...)   dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
+-
++#define dbg_mnt(fmt, ...)   ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__)
++#define dbg_mntk(key, fmt, ...) \
++      ubifs_dbg_msg_key("mnt", key, fmt, ##__VA_ARGS__)
+ /* Additional I/O messages */
+-#define dbg_io(fmt, ...)    dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
+-
++#define dbg_io(fmt, ...)    ubifs_dbg_msg("io", fmt, ##__VA_ARGS__)
+ /* Additional commit messages */
+-#define dbg_cmt(fmt, ...)   dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
+-
++#define dbg_cmt(fmt, ...)   ubifs_dbg_msg("cmt", fmt, ##__VA_ARGS__)
+ /* Additional budgeting messages */
+-#define dbg_budg(fmt, ...)  dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
+-
++#define dbg_budg(fmt, ...)  ubifs_dbg_msg("budg", fmt, ##__VA_ARGS__)
+ /* Additional log messages */
+-#define dbg_log(fmt, ...)   dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
+-
++#define dbg_log(fmt, ...)   ubifs_dbg_msg("log", fmt, ##__VA_ARGS__)
+ /* Additional gc messages */
+-#define dbg_gc(fmt, ...)    dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
+-
++#define dbg_gc(fmt, ...)    ubifs_dbg_msg("gc", fmt, ##__VA_ARGS__)
+ /* Additional scan messages */
+-#define dbg_scan(fmt, ...)  dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
+-
++#define dbg_scan(fmt, ...)  ubifs_dbg_msg("scan", fmt, ##__VA_ARGS__)
+ /* Additional recovery messages */
+-#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
++#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
+-/*
+- * Debugging message type flags (must match msg_type_names in debug.c).
+- *
+- * UBIFS_MSG_GEN: general messages
+- * UBIFS_MSG_JNL: journal messages
+- * UBIFS_MSG_MNT: mount messages
+- * UBIFS_MSG_CMT: commit messages
+- * UBIFS_MSG_FIND: LEB find messages
+- * UBIFS_MSG_BUDG: budgeting messages
+- * UBIFS_MSG_GC: garbage collection messages
+- * UBIFS_MSG_TNC: TNC messages
+- * UBIFS_MSG_LP: lprops messages
+- * UBIFS_MSG_IO: I/O messages
+- * UBIFS_MSG_LOG: log messages
+- * UBIFS_MSG_SCAN: scan messages
+- * UBIFS_MSG_RCVRY: recovery messages
+- */
+-enum {
+-      UBIFS_MSG_GEN   = 0x1,
+-      UBIFS_MSG_JNL   = 0x2,
+-      UBIFS_MSG_MNT   = 0x4,
+-      UBIFS_MSG_CMT   = 0x8,
+-      UBIFS_MSG_FIND  = 0x10,
+-      UBIFS_MSG_BUDG  = 0x20,
+-      UBIFS_MSG_GC    = 0x40,
+-      UBIFS_MSG_TNC   = 0x80,
+-      UBIFS_MSG_LP    = 0x100,
+-      UBIFS_MSG_IO    = 0x200,
+-      UBIFS_MSG_LOG   = 0x400,
+-      UBIFS_MSG_SCAN  = 0x800,
+-      UBIFS_MSG_RCVRY = 0x1000,
+-};
+-
+-/* Debugging message type flags for each default debug message level */
+-#define UBIFS_MSG_LVL_0 0
+-#define UBIFS_MSG_LVL_1 0x1
+-#define UBIFS_MSG_LVL_2 0x7f
+-#define UBIFS_MSG_LVL_3 0xffff
+-
+-/*
+- * Debugging check flags (must match chk_names in debug.c).
+- *
+- * UBIFS_CHK_GEN: general checks
+- * UBIFS_CHK_TNC: check TNC
+- * UBIFS_CHK_IDX_SZ: check index size
+- * UBIFS_CHK_ORPH: check orphans
+- * UBIFS_CHK_OLD_IDX: check the old index
+- * UBIFS_CHK_LPROPS: check lprops
+- * UBIFS_CHK_FS: check the file-system
+- */
+-enum {
+-      UBIFS_CHK_GEN     = 0x1,
+-      UBIFS_CHK_TNC     = 0x2,
+-      UBIFS_CHK_IDX_SZ  = 0x4,
+-      UBIFS_CHK_ORPH    = 0x8,
+-      UBIFS_CHK_OLD_IDX = 0x10,
+-      UBIFS_CHK_LPROPS  = 0x20,
+-      UBIFS_CHK_FS      = 0x40,
+-};
++extern struct ubifs_global_debug_info ubifs_dbg;
+-/*
+- * Special testing flags (must match tst_names in debug.c).
+- *
+- * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
+- * UBIFS_TST_RCVRY: failure mode for recovery testing
+- */
+-enum {
+-      UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
+-      UBIFS_TST_RCVRY             = 0x4,
+-};
+-
+-#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1
+-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2
+-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3
+-#else
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0
+-#endif
+-
+-#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS
+-#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff
+-#else
+-#define UBIFS_CHK_FLAGS_DEFAULT 0
+-#endif
+-
+-extern spinlock_t dbg_lock;
+-
+-extern unsigned int ubifs_msg_flags;
+-extern unsigned int ubifs_chk_flags;
+-extern unsigned int ubifs_tst_flags;
++static inline int dbg_is_chk_gen(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen);
++}
++static inline int dbg_is_chk_index(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_index || c->dbg->chk_index);
++}
++static inline int dbg_is_chk_orph(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph);
++}
++static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops);
++}
++static inline int dbg_is_chk_fs(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs);
++}
++static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry);
++}
++static inline int dbg_is_power_cut(const struct ubifs_info *c)
++{
++      return !!c->dbg->pc_happened;
++}
+ int ubifs_debugging_init(struct ubifs_info *c);
+ void ubifs_debugging_exit(struct ubifs_info *c);
+@@ -280,17 +255,21 @@ const char *dbg_cstate(int cmt_state);
+ const char *dbg_jhead(int jhead);
+ const char *dbg_get_key_dump(const struct ubifs_info *c,
+                            const union ubifs_key *key);
+-void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
++const char *dbg_snprintf_key(const struct ubifs_info *c,
++                           const union ubifs_key *key, char *buffer, int len);
++void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
+ void dbg_dump_node(const struct ubifs_info *c, const void *node);
+ void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
+                      int offs);
+ void dbg_dump_budget_req(const struct ubifs_budget_req *req);
+ void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
+-void dbg_dump_budg(struct ubifs_info *c);
++void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
+ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
+ void dbg_dump_lprops(struct ubifs_info *c);
+ void dbg_dump_lpt_info(struct ubifs_info *c);
+ void dbg_dump_leb(const struct ubifs_info *c, int lnum);
++void dbg_dump_sleb(const struct ubifs_info *c,
++                 const struct ubifs_scan_leb *sleb, int offs);
+ void dbg_dump_znode(const struct ubifs_info *c,
+                   const struct ubifs_znode *znode);
+ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat);
+@@ -313,14 +292,13 @@ int dbg_check_cats(struct ubifs_info *c);
+ int dbg_check_ltab(struct ubifs_info *c);
+ int dbg_chk_lpt_free_spc(struct ubifs_info *c);
+ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len);
+-int dbg_check_synced_i_size(struct inode *inode);
+-int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
++int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode);
++int dbg_check_dir(struct ubifs_info *c, const struct inode *dir);
+ int dbg_check_tnc(struct ubifs_info *c, int extra);
+ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
+ int dbg_check_filesystem(struct ubifs_info *c);
+ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
+                   int add_pos);
+-int dbg_check_lprops(struct ubifs_info *c);
+ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
+                       int row, int col);
+ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+@@ -328,57 +306,12 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
+ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
+-/* Force the use of in-the-gaps method for testing */
+-
+-#define dbg_force_in_the_gaps_enabled \
+-      (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS)
+-
+-int dbg_force_in_the_gaps(void);
+-
+-/* Failure mode for recovery testing */
+-
+-#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
+-
+-#ifndef UBIFS_DBG_PRESERVE_UBI
+-
+-#define ubi_leb_read   dbg_leb_read
+-#define ubi_leb_write  dbg_leb_write
+-#define ubi_leb_change dbg_leb_change
+-#define ubi_leb_erase  dbg_leb_erase
+-#define ubi_leb_unmap  dbg_leb_unmap
+-#define ubi_is_mapped  dbg_is_mapped
+-#define ubi_leb_map    dbg_leb_map
+-
+-#endif
+-
+-int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+-               int len, int check);
+-int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                int offset, int len, int dtype);
+-int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                 int len, int dtype);
+-int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum);
+-int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum);
+-int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum);
+-int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
+-
+-static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf,
+-                         int offset, int len)
+-{
+-      return dbg_leb_read(desc, lnum, buf, offset, len, 0);
+-}
+-
+-static inline int dbg_write(struct ubi_volume_desc *desc, int lnum,
+-                          const void *buf, int offset, int len)
+-{
+-      return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
+-}
+-
+-static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
+-                                  const void *buf, int len)
+-{
+-      return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
+-}
++int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                int len, int dtype);
++int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                 int dtype);
++int dbg_leb_unmap(struct ubifs_info *c, int lnum);
++int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
+ /* Debugfs-related stuff */
+ int dbg_debugfs_init(void);
+@@ -390,116 +323,158 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
+ /* Use "if (0)" to make compiler check arguments even if debugging is off */
+ #define ubifs_assert(expr)  do {                                               \
+-      if (0 && (expr))                                                       \
++      if (0)                                                                 \
+               printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+                      __func__, __LINE__, current->pid);                      \
+ } while (0)
+-#define dbg_err(fmt, ...)   do {                                               \
+-      if (0)                                                                 \
+-              ubifs_err(fmt, ##__VA_ARGS__);                                 \
++#define dbg_err(fmt, ...)   do {                   \
++      if (0)                                     \
++              ubifs_err(fmt, ##__VA_ARGS__);     \
+ } while (0)
+-#define dbg_msg(fmt, ...) do {                                                 \
+-      if (0)                                                                 \
+-              printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n",         \
+-                     current->pid, __func__, ##__VA_ARGS__);                 \
++#define DBGKEY(key)  ((char *)(key))
++#define DBGKEY1(key) ((char *)(key))
++
++#define ubifs_dbg_msg(fmt, ...) do {               \
++      if (0)                                     \
++              pr_debug(fmt "\n", ##__VA_ARGS__); \
+ } while (0)
+ #define dbg_dump_stack()
+ #define ubifs_assert_cmt_locked(c)
+-#define dbg_gen(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_jnl(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_tnc(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_lp(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_find(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_mnt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_io(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_cmt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_budg(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_log(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_gc(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_scan(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-
+-#define DBGKEY(key)  ((char *)(key))
+-#define DBGKEY1(key) ((char *)(key))
+-
+-static inline int ubifs_debugging_init(struct ubifs_info *c)  { return 0; }
+-static inline void ubifs_debugging_exit(struct ubifs_info *c) {}
+-static inline const char *dbg_ntype(int type)                 { return ""; }
+-static inline const char *dbg_cstate(int cmt_state)           { return ""; }
+-static inline const char *dbg_jhead(int jhead)                        { return ""; }
+-static inline const char *dbg_get_key_dump(const struct ubifs_info *c,
+-                           const union ubifs_key *key)        { return ""; }
+-static inline void dbg_dump_inode(const struct ubifs_info *c,
+-      const struct inode *inode) {}
++#define dbg_msg(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_gen(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_jnl(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_jnlk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_tnc(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_tnck(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_lp(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_find(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_mnt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_mntk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_io(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_cmt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_budg(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_log(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_gc(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_scan(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_rcvry(fmt, ...)     ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++
++static inline int ubifs_debugging_init(struct ubifs_info *c)      { return 0; }
++static inline void ubifs_debugging_exit(struct ubifs_info *c)     { return; }
++static inline const char *dbg_ntype(int type)                     { return ""; }
++static inline const char *dbg_cstate(int cmt_state)               { return ""; }
++static inline const char *dbg_jhead(int jhead)                    { return ""; }
++static inline const char *
++dbg_get_key_dump(const struct ubifs_info *c,
++               const union ubifs_key *key)                      { return ""; }
++static inline const char *
++dbg_snprintf_key(const struct ubifs_info *c,
++               const union ubifs_key *key, char *buffer,
++               int len)                                         { return ""; }
++static inline void dbg_dump_inode(struct ubifs_info *c,
++                                const struct inode *inode)      { return; }
+ static inline void dbg_dump_node(const struct ubifs_info *c,
+-      const void *node)                                       {}
++                               const void *node)                { return; }
+ static inline void dbg_dump_lpt_node(const struct ubifs_info *c,
+-      void *node, int lnum, int offs)                         {}
+-static inline void dbg_dump_budget_req(const struct ubifs_budget_req *req) {}
+-static inline void dbg_dump_lstats(const struct ubifs_lp_stats *lst) {}
+-static inline void dbg_dump_budg(struct ubifs_info *c)                {}
++                                   void *node, int lnum,
++                                   int offs)                    { return; }
++static inline void
++dbg_dump_budget_req(const struct ubifs_budget_req *req)           { return; }
++static inline void
++dbg_dump_lstats(const struct ubifs_lp_stats *lst)                 { return; }
++static inline void
++dbg_dump_budg(struct ubifs_info *c,
++            const struct ubifs_budg_info *bi)                   { return; }
+ static inline void dbg_dump_lprop(const struct ubifs_info *c,
+-      const struct ubifs_lprops *lp)                          {}
+-static inline void dbg_dump_lprops(struct ubifs_info *c)      {}
+-static inline void dbg_dump_lpt_info(struct ubifs_info *c)    {}
+-static inline void dbg_dump_leb(const struct ubifs_info *c, int lnum) {}
+-static inline void dbg_dump_znode(const struct ubifs_info *c,
+-                  const struct ubifs_znode *znode)            {}
++                                const struct ubifs_lprops *lp)  { return; }
++static inline void dbg_dump_lprops(struct ubifs_info *c)          { return; }
++static inline void dbg_dump_lpt_info(struct ubifs_info *c)        { return; }
++static inline void dbg_dump_leb(const struct ubifs_info *c,
++                              int lnum)                         { return; }
++static inline void
++dbg_dump_sleb(const struct ubifs_info *c,
++            const struct ubifs_scan_leb *sleb, int offs)        { return; }
++static inline void
++dbg_dump_znode(const struct ubifs_info *c,
++             const struct ubifs_znode *znode)                   { return; }
+ static inline void dbg_dump_heap(struct ubifs_info *c,
+-      struct ubifs_lpt_heap *heap, int cat)                   {}
++                               struct ubifs_lpt_heap *heap,
++                               int cat)                         { return; }
+ static inline void dbg_dump_pnode(struct ubifs_info *c,
+-      struct ubifs_pnode *pnode, struct ubifs_nnode *parent, int iip) {}
+-static inline void dbg_dump_tnc(struct ubifs_info *c)         {}
+-static inline void dbg_dump_index(struct ubifs_info *c)               {}
+-static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c) {}
++                                struct ubifs_pnode *pnode,
++                                struct ubifs_nnode *parent,
++                                int iip)                        { return; }
++static inline void dbg_dump_tnc(struct ubifs_info *c)             { return; }
++static inline void dbg_dump_index(struct ubifs_info *c)           { return; }
++static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c)  { return; }
+ static inline int dbg_walk_index(struct ubifs_info *c,
+-      dbg_leaf_callback leaf_cb, dbg_znode_callback znode_cb, void *priv)
+-                                                              { return 0; }
+-
+-/* Checking functions */
+-static inline void dbg_save_space_info(struct ubifs_info *c)  {}
+-static inline int dbg_check_space_info(struct ubifs_info *c)  { return 0; }
+-static inline int dbg_check_lprops(struct ubifs_info *c)      { return 0; }
+-static inline int dbg_old_index_check_init(struct ubifs_info *c,
+-      struct ubifs_zbranch *zroot)                            { return 0; }
+-static inline int dbg_check_old_index(struct ubifs_info *c,
+-      struct ubifs_zbranch *zroot)                            { return 0; }
+-static inline int dbg_check_cats(struct ubifs_info *c)                { return 0; }
+-static inline int dbg_check_ltab(struct ubifs_info *c)                { return 0; }
+-static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)  { return 0; }
++                               dbg_leaf_callback leaf_cb,
++                               dbg_znode_callback znode_cb,
++                               void *priv)                      { return 0; }
++static inline void dbg_save_space_info(struct ubifs_info *c)      { return; }
++static inline int dbg_check_space_info(struct ubifs_info *c)      { return 0; }
++static inline int dbg_check_lprops(struct ubifs_info *c)          { return 0; }
++static inline int
++dbg_old_index_check_init(struct ubifs_info *c,
++                       struct ubifs_zbranch *zroot)             { return 0; }
++static inline int
++dbg_check_old_index(struct ubifs_info *c,
++                  struct ubifs_zbranch *zroot)                  { return 0; }
++static inline int dbg_check_cats(struct ubifs_info *c)            { return 0; }
++static inline int dbg_check_ltab(struct ubifs_info *c)            { return 0; }
++static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)      { return 0; }
+ static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
+-      int action, int len)                                    { return 0; }
+-static inline int dbg_check_synced_i_size(struct inode *inode)        { return 0; }
+-static inline int dbg_check_dir_size(struct ubifs_info *c,
+-      const struct inode *dir)                                { return 0; }
+-static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; }
++                               int action, int len)             { return 0; }
++static inline int
++dbg_check_synced_i_size(const struct ubifs_info *c,
++                      struct inode *inode)                      { return 0; }
++static inline int dbg_check_dir(struct ubifs_info *c,
++                              const struct inode *dir)          { return 0; }
++static inline int dbg_check_tnc(struct ubifs_info *c, int extra)  { return 0; }
+ static inline int dbg_check_idx_size(struct ubifs_info *c,
+-      long long idx_size)                                     { return 0; }
+-static inline int dbg_check_filesystem(struct ubifs_info *c)  { return 0; }
++                                   long long idx_size)          { return 0; }
++static inline int dbg_check_filesystem(struct ubifs_info *c)      { return 0; }
+ static inline void dbg_check_heap(struct ubifs_info *c,
+-      struct ubifs_lpt_heap *heap, int cat, int add_pos)      {}
++                                struct ubifs_lpt_heap *heap,
++                                int cat, int add_pos)           { return; }
+ static inline int dbg_check_lpt_nodes(struct ubifs_info *c,
+-      struct ubifs_cnode *cnode, int row, int col)            { return 0; }
++      struct ubifs_cnode *cnode, int row, int col)              { return 0; }
+ static inline int dbg_check_inode_size(struct ubifs_info *c,
+-      const struct inode *inode, loff_t size)                 { return 0; }
+-static inline int dbg_check_data_nodes_order(struct ubifs_info *c,
+-      struct list_head *head)                                 { return 0; }
+-static inline int dbg_check_nondata_nodes_order(struct ubifs_info *c,
+-      struct list_head *head)                                 { return 0; }
+-
+-#define dbg_force_in_the_gaps_enabled                         0
+-static inline int dbg_force_in_the_gaps(void)                 { return 0; }
+-#define dbg_failure_mode                                      0
+-
+-static inline int dbg_debugfs_init(void)                      { return 0; }
+-static inline void dbg_debugfs_exit(void)                     {}
+-static inline int dbg_debugfs_init_fs(struct ubifs_info *c)   { return 0; }
+-static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)   { return 0; }
++                                     const struct inode *inode,
++                                     loff_t size)               { return 0; }
++static inline int
++dbg_check_data_nodes_order(struct ubifs_info *c,
++                         struct list_head *head)                { return 0; }
++static inline int
++dbg_check_nondata_nodes_order(struct ubifs_info *c,
++                            struct list_head *head)             { return 0; }
++
++static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
++                              const void *buf, int offset,
++                              int len, int dtype)               { return 0; }
++static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
++                               const void *buf, int len,
++                               int dtype)                       { return 0; }
++static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum)   { return 0; }
++static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
++                            int dtype)                          { return 0; }
++
++static inline int dbg_is_chk_gen(const struct ubifs_info *c)      { return 0; }
++static inline int dbg_is_chk_index(const struct ubifs_info *c)    { return 0; }
++static inline int dbg_is_chk_orph(const struct ubifs_info *c)     { return 0; }
++static inline int dbg_is_chk_lprops(const struct ubifs_info *c)   { return 0; }
++static inline int dbg_is_chk_fs(const struct ubifs_info *c)       { return 0; }
++static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)    { return 0; }
++static inline int dbg_is_power_cut(const struct ubifs_info *c)    { return 0; }
++
++static inline int dbg_debugfs_init(void)                          { return 0; }
++static inline void dbg_debugfs_exit(void)                         { return; }
++static inline int dbg_debugfs_init_fs(struct ubifs_info *c)       { return 0; }
++static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)       { return 0; }
+ #endif /* !CONFIG_UBIFS_FS_DEBUG */
+ #endif /* !__UBIFS_DEBUG_H__ */
+diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
+index 14f64b6..9c5e3c5 100644
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -102,7 +102,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+        * UBIFS has to fully control "clean <-> dirty" transitions of inodes
+        * to make budgeting work.
+        */
+-      inode->i_flags |= (S_NOCMTIME);
++      inode->i_flags |= S_NOCMTIME;
+       inode_init_owner(inode, dir, mode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime =
+@@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+-static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
++static int dbg_check_name(const struct ubifs_info *c,
++                        const struct ubifs_dent_node *dent,
++                        const struct qstr *nm)
+ {
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (le16_to_cpu(dent->nlen) != nm->len)
+               return -EINVAL;
+@@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
+ #else
+-#define dbg_check_name(dent, nm) 0
++#define dbg_check_name(c, dent, nm) 0
+ #endif
+@@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
+               goto out;
+       }
+-      if (dbg_check_name(dent, &dentry->d_name)) {
++      if (dbg_check_name(c, dent, &dentry->d_name)) {
+               err = -EINVAL;
+               goto out;
+       }
+@@ -540,7 +542,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
+        if (inode->i_nlink == 0)
+                return -ENOENT;
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -595,7 +597,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
+               inode->i_nlink, dir->i_ino);
+       ubifs_assert(mutex_is_locked(&dir->i_mutex));
+       ubifs_assert(mutex_is_locked(&inode->i_mutex));
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -621,7 +623,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
+               ubifs_release_budget(c, &req);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return 0;
+@@ -711,7 +713,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
+               ubifs_release_budget(c, &req);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return 0;
+diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
+index d77db7e..7cf738a 100644
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -212,7 +212,7 @@ static void release_new_page_budget(struct ubifs_info *c)
+  */
+ static void release_existing_page_budget(struct ubifs_info *c)
+ {
+-      struct ubifs_budget_req req = { .dd_growth = c->page_budget};
++      struct ubifs_budget_req req = { .dd_growth = c->bi.page_budget};
+       ubifs_release_budget(c, &req);
+ }
+@@ -448,10 +448,12 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
+               if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) {
+                       /*
+                        * We change whole page so no need to load it. But we
+-                       * have to set the @PG_checked flag to make the further
+-                       * code know that the page is new. This might be not
+-                       * true, but it is better to budget more than to read
+-                       * the page from the media.
++                       * do not know whether this page exists on the media or
++                       * not, so we assume the latter because it requires
++                       * larger budget. The assumption is that it is better
++                       * to budget a bit more than to read the page from the
++                       * media. Thus, we are setting the @PG_checked flag
++                       * here.
+                        */
+                       SetPageChecked(page);
+                       skipped_read = 1;
+@@ -559,6 +561,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping,
+               dbg_gen("copied %d instead of %d, read page and repeat",
+                       copied, len);
+               cancel_budget(c, page, ui, appending);
++              ClearPageChecked(page);
+               /*
+                * Return 0 to force VFS to repeat the whole operation, or the
+@@ -968,11 +971,11 @@ static int do_writepage(struct page *page, int len)
+  * the page locked, and it locks @ui_mutex. However, write-back does take inode
+  * @i_mutex, which means other VFS operations may be run on this inode at the
+  * same time. And the problematic one is truncation to smaller size, from where
+- * we have to call 'truncate_setsize()', which first changes @inode->i_size, then
+- * drops the truncated pages. And while dropping the pages, it takes the page
+- * lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' with
+- * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
+- * means that @inode->i_size is changed while @ui_mutex is unlocked.
++ * we have to call 'truncate_setsize()', which first changes @inode->i_size,
++ * then drops the truncated pages. And while dropping the pages, it takes the
++ * page lock. This means that 'do_truncation()' cannot call 'truncate_setsize()'
++ * with @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'.
++ * This means that @inode->i_size is changed while @ui_mutex is unlocked.
+  *
+  * XXX(truncate): with the new truncate sequence this is not true anymore,
+  * and the calls to truncate_setsize can be move around freely.  They should
+@@ -1186,7 +1189,7 @@ out_budg:
+       if (budgeted)
+               ubifs_release_budget(c, &req);
+       else {
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return err;
+@@ -1260,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
+       if (err)
+               return err;
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -1309,6 +1312,13 @@ int ubifs_fsync(struct file *file, int datasync)
+       dbg_gen("syncing inode %lu", inode->i_ino);
++      if (c->ro_mount)
++              /*
++               * For some really strange reasons VFS does not filter out
++               * 'fsync()' for R/O mounted file-systems as per 2.6.39.
++               */
++              return 0;
++
+       /*
+        * VFS has already synchronized dirty pages for this inode. Synchronize
+        * the inode unless this is a 'datasync()' call.
+@@ -1426,10 +1436,11 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
+ }
+ /*
+- * mmap()d file has taken write protection fault and is being made
+- * writable. UBIFS must ensure page is budgeted for.
++ * mmap()d file has taken write protection fault and is being made writable.
++ * UBIFS must ensure page is budgeted for.
+  */
+-static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
++static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma,
++                               struct vm_fault *vmf)
+ {
+       struct page *page = vmf->page;
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+@@ -1530,7 +1541,6 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+       int err;
+-      /* 'generic_file_mmap()' takes care of NOMMU case */
+       err = generic_file_mmap(file, vma);
+       if (err)
+               return err;
+diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
+index 1d54383..2559d17 100644
+--- a/fs/ubifs/find.c
++++ b/fs/ubifs/find.c
+@@ -252,8 +252,8 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+                * But if the index takes fewer LEBs than it is reserved for it,
+                * this function must avoid picking those reserved LEBs.
+                */
+-              if (c->min_idx_lebs >= c->lst.idx_lebs) {
+-                      rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++              if (c->bi.min_idx_lebs >= c->lst.idx_lebs) {
++                      rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
+                       exclude_index = 1;
+               }
+               spin_unlock(&c->space_lock);
+@@ -276,7 +276,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+                       pick_free = 0;
+       } else {
+               spin_lock(&c->space_lock);
+-              exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs);
++              exclude_index = (c->bi.min_idx_lebs >= c->lst.idx_lebs);
+               spin_unlock(&c->space_lock);
+       }
+@@ -501,8 +501,8 @@ int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *offs,
+       /* Check if there are enough empty LEBs for commit */
+       spin_lock(&c->space_lock);
+-      if (c->min_idx_lebs > c->lst.idx_lebs)
+-              rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++      if (c->bi.min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
+       else
+               rsvd_idx_lebs = 0;
+       lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
+index 151f108..ded29f6 100644
+--- a/fs/ubifs/gc.c
++++ b/fs/ubifs/gc.c
+@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c)
+       if (err)
+               return err;
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (err)
++              return err;
++
+       err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
+       if (err)
+               return err;
+@@ -118,7 +122,7 @@ static int switch_gc_head(struct ubifs_info *c)
+  * This function compares data nodes @a and @b. Returns %1 if @a has greater
+  * inode or block number, and %-1 otherwise.
+  */
+-int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
++static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+ {
+       ino_t inuma, inumb;
+       struct ubifs_info *c = priv;
+@@ -161,7 +165,8 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+  * first and sorted by length in descending order. Directory entry nodes go
+  * after inode nodes and are sorted in ascending hash valuer order.
+  */
+-int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
++static int nondata_nodes_cmp(void *priv, struct list_head *a,
++                           struct list_head *b)
+ {
+       ino_t inuma, inumb;
+       struct ubifs_info *c = priv;
+@@ -473,6 +478,37 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
+       ubifs_assert(c->gc_lnum != lnum);
+       ubifs_assert(wbuf->lnum != lnum);
++      if (lp->free + lp->dirty == c->leb_size) {
++              /* Special case - a free LEB  */
++              dbg_gc("LEB %d is free, return it", lp->lnum);
++              ubifs_assert(!(lp->flags & LPROPS_INDEX));
++
++              if (lp->free != c->leb_size) {
++                      /*
++                       * Write buffers must be sync'd before unmapping
++                       * freeable LEBs, because one of them may contain data
++                       * which obsoletes something in 'lp->pnum'.
++                       */
++                      err = gc_sync_wbufs(c);
++                      if (err)
++                              return err;
++                      err = ubifs_change_one_lp(c, lp->lnum, c->leb_size,
++                                                0, 0, 0, 0);
++                      if (err)
++                              return err;
++              }
++              err = ubifs_leb_unmap(c, lp->lnum);
++              if (err)
++                      return err;
++
++              if (c->gc_lnum == -1) {
++                      c->gc_lnum = lnum;
++                      return LEB_RETAINED;
++              }
++
++              return LEB_FREED;
++      }
++
+       /*
+        * We scan the entire LEB even though we only really need to scan up to
+        * (c->leb_size - lp->free).
+@@ -682,37 +718,6 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
+                      "(min. space %d)", lp.lnum, lp.free, lp.dirty,
+                      lp.free + lp.dirty, min_space);
+-              if (lp.free + lp.dirty == c->leb_size) {
+-                      /* An empty LEB was returned */
+-                      dbg_gc("LEB %d is free, return it", lp.lnum);
+-                      /*
+-                       * ubifs_find_dirty_leb() doesn't return freeable index
+-                       * LEBs.
+-                       */
+-                      ubifs_assert(!(lp.flags & LPROPS_INDEX));
+-                      if (lp.free != c->leb_size) {
+-                              /*
+-                               * Write buffers must be sync'd before
+-                               * unmapping freeable LEBs, because one of them
+-                               * may contain data which obsoletes something
+-                               * in 'lp.pnum'.
+-                               */
+-                              ret = gc_sync_wbufs(c);
+-                              if (ret)
+-                                      goto out;
+-                              ret = ubifs_change_one_lp(c, lp.lnum,
+-                                                        c->leb_size, 0, 0, 0,
+-                                                        0);
+-                              if (ret)
+-                                      goto out;
+-                      }
+-                      ret = ubifs_leb_unmap(c, lp.lnum);
+-                      if (ret)
+-                              goto out;
+-                      ret = lp.lnum;
+-                      break;
+-              }
+-
+               space_before = c->leb_size - wbuf->offs - wbuf->used;
+               if (wbuf->lnum == -1)
+                       space_before = 0;
+diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
+index d821731..9228950 100644
+--- a/fs/ubifs/io.c
++++ b/fs/ubifs/io.c
+@@ -31,6 +31,26 @@
+  * buffer is full or when it is not used for some time (by timer). This is
+  * similar to the mechanism is used by JFFS2.
+  *
++ * UBIFS distinguishes between minimum write size (@c->min_io_size) and maximum
++ * write size (@c->max_write_size). The latter is the maximum amount of bytes
++ * the underlying flash is able to program at a time, and writing in
++ * @c->max_write_size units should presumably be faster. Obviously,
++ * @c->min_io_size <= @c->max_write_size. Write-buffers are of
++ * @c->max_write_size bytes in size for maximum performance. However, when a
++ * write-buffer is flushed, only the portion of it (aligned to @c->min_io_size
++ * boundary) which contains data is written, not the whole write-buffer,
++ * because this is more space-efficient.
++ *
++ * This optimization adds few complications to the code. Indeed, on the one
++ * hand, we want to write in optimal @c->max_write_size bytes chunks, which
++ * also means aligning writes at the @c->max_write_size bytes offsets. On the
++ * other hand, we do not want to waste space when synchronizing the write
++ * buffer, so during synchronization we writes in smaller chunks. And this makes
++ * the next write offset to be not aligned to @c->max_write_size bytes. So the
++ * have to make sure that the write-buffer offset (@wbuf->offs) becomes aligned
++ * to @c->max_write_size bytes again. We do this by temporarily shrinking
++ * write-buffer size (@wbuf->size).
++ *
+  * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
+  * mutexes defined inside these objects. Since sometimes upper-level code
+  * has to lock the write-buffer (e.g. journal space reservation code), many
+@@ -46,8 +66,8 @@
+  * UBIFS uses padding when it pads to the next min. I/O unit. In this case it
+  * uses padding nodes or padding bytes, if the padding node does not fit.
+  *
+- * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes
+- * every time they are read from the flash media.
++ * All UBIFS nodes are protected by CRC checksums and UBIFS checks CRC when
++ * they are read from the flash media.
+  */
+ #include <linux/crc32.h>
+@@ -66,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
+               c->no_chk_data_crc = 0;
+               c->vfs_sb->s_flags |= MS_RDONLY;
+               ubifs_warn("switched to read-only mode, error %d", err);
++              dump_stack();
++      }
++}
++
++/*
++ * Below are simple wrappers over UBI I/O functions which include some
++ * additional checks and UBIFS debugging stuff. See corresponding UBI function
++ * for more information.
++ */
++
++int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
++                 int len, int even_ebadmsg)
++{
++      int err;
++
++      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      /*
++       * In case of %-EBADMSG print the error message only if the
++       * @even_ebadmsg is true.
++       */
++      if (err && (err != -EBADMSG || even_ebadmsg)) {
++              ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
++                        len, lnum, offs, err);
+               dbg_dump_stack();
+       }
++      return err;
++}
++
++int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                  int len, int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
++      else
++              err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
++      if (err) {
++              ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
++                        len, lnum, offs, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                   int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
++      else
++              err = dbg_leb_change(c, lnum, buf, len, dtype);
++      if (err) {
++              ubifs_err("changing %d bytes in LEB %d failed, error %d",
++                        len, lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_unmap(c->ubi, lnum);
++      else
++              err = dbg_leb_unmap(c, lnum);
++      if (err) {
++              ubifs_err("unmap LEB %d failed, error %d", lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_map(c->ubi, lnum, dtype);
++      else
++              err = dbg_leb_map(c, lnum, dtype);
++      if (err) {
++              ubifs_err("mapping LEB %d failed, error %d", lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
++{
++      int err;
++
++      err = ubi_is_mapped(c->ubi, lnum);
++      if (err < 0) {
++              ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
++                        lnum, err);
++              dbg_dump_stack();
++      }
++      return err;
+ }
+ /**
+@@ -88,8 +225,12 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
+  * This function may skip data nodes CRC checking if @c->no_chk_data_crc is
+  * true, which is controlled by corresponding UBIFS mount option. However, if
+  * @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
+- * checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
+- * ignored and CRC is checked.
++ * checked. Similarly, if @c->mounting or @c->remounting_rw is true (we are
++ * mounting or re-mounting to R/W mode), @c->no_chk_data_crc is ignored and CRC
++ * is checked. This is because during mounting or re-mounting from R/O mode to
++ * R/W mode we may read journal nodes (when replying the journal or doing the
++ * recovery) and the journal nodes may potentially be corrupted, so checking is
++ * required.
+  *
+  * This function returns zero in case of success and %-EUCLEAN in case of bad
+  * CRC or magic.
+@@ -131,8 +272,8 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+                  node_len > c->ranges[type].max_len)
+               goto out_len;
+-      if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
+-           c->no_chk_data_crc)
++      if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->mounting &&
++          !c->remounting_rw && c->no_chk_data_crc)
+               return 0;
+       crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+@@ -343,11 +484,17 @@ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
+  *
+  * This function synchronizes write-buffer @buf and returns zero in case of
+  * success or a negative error code in case of failure.
++ *
++ * Note, although write-buffers are of @c->max_write_size, this function does
++ * not necessarily writes all @c->max_write_size bytes to the flash. Instead,
++ * if the write-buffer is only partially filled with data, only the used part
++ * of the write-buffer (aligned on @c->min_io_size boundary) is synchronized.
++ * This way we waste less space.
+  */
+ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+ {
+       struct ubifs_info *c = wbuf->c;
+-      int err, dirt;
++      int err, dirt, sync_len;
+       cancel_wbuf_timer_nolock(wbuf);
+       if (!wbuf->used || wbuf->lnum == -1)
+@@ -357,27 +504,49 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+       dbg_io("LEB %d:%d, %d bytes, jhead %s",
+              wbuf->lnum, wbuf->offs, wbuf->used, dbg_jhead(wbuf->jhead));
+       ubifs_assert(!(wbuf->avail & 7));
+-      ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
++      ubifs_assert(wbuf->offs + wbuf->size <= c->leb_size);
++      ubifs_assert(wbuf->size >= c->min_io_size);
++      ubifs_assert(wbuf->size <= c->max_write_size);
++      ubifs_assert(wbuf->size % c->min_io_size == 0);
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
+       if (c->ro_error)
+               return -EROFS;
+-      ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail);
+-      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
+-                          c->min_io_size, wbuf->dtype);
+-      if (err) {
+-              ubifs_err("cannot write %d bytes to LEB %d:%d",
+-                        c->min_io_size, wbuf->lnum, wbuf->offs);
+-              dbg_dump_stack();
++      /*
++       * Do not write whole write buffer but write only the minimum necessary
++       * amount of min. I/O units.
++       */
++      sync_len = ALIGN(wbuf->used, c->min_io_size);
++      dirt = sync_len - wbuf->used;
++      if (dirt)
++              ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
++      err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
++                            wbuf->dtype);
++      if (err)
+               return err;
+-      }
+-
+-      dirt = wbuf->avail;
+       spin_lock(&wbuf->lock);
+-      wbuf->offs += c->min_io_size;
+-      wbuf->avail = c->min_io_size;
++      wbuf->offs += sync_len;
++      /*
++       * Now @wbuf->offs is not necessarily aligned to @c->max_write_size.
++       * But our goal is to optimize writes and make sure we write in
++       * @c->max_write_size chunks and to @c->max_write_size-aligned offset.
++       * Thus, if @wbuf->offs is not aligned to @c->max_write_size now, make
++       * sure that @wbuf->offs + @wbuf->size is aligned to
++       * @c->max_write_size. This way we make sure that after next
++       * write-buffer flush we are again at the optimal offset (aligned to
++       * @c->max_write_size).
++       */
++      if (c->leb_size - wbuf->offs < c->max_write_size)
++              wbuf->size = c->leb_size - wbuf->offs;
++      else if (wbuf->offs & (c->max_write_size - 1))
++              wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
++      else
++              wbuf->size = c->max_write_size;
++      wbuf->avail = wbuf->size;
+       wbuf->used = 0;
+       wbuf->next_ino = 0;
+       spin_unlock(&wbuf->lock);
+@@ -396,8 +565,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+  * @dtype: data type
+  *
+  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
+- * The write-buffer is synchronized if it is not empty. Returns zero in case of
+- * success and a negative error code in case of failure.
++ * The write-buffer has to be empty. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+                          int dtype)
+@@ -409,18 +578,18 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+       ubifs_assert(offs >= 0 && offs <= c->leb_size);
+       ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
+       ubifs_assert(lnum != wbuf->lnum);
+-
+-      if (wbuf->used > 0) {
+-              int err = ubifs_wbuf_sync_nolock(wbuf);
+-
+-              if (err)
+-                      return err;
+-      }
++      ubifs_assert(wbuf->used == 0);
+       spin_lock(&wbuf->lock);
+       wbuf->lnum = lnum;
+       wbuf->offs = offs;
+-      wbuf->avail = c->min_io_size;
++      if (c->leb_size - wbuf->offs < c->max_write_size)
++              wbuf->size = c->leb_size - wbuf->offs;
++      else if (wbuf->offs & (c->max_write_size - 1))
++              wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
++      else
++              wbuf->size = c->max_write_size;
++      wbuf->avail = wbuf->size;
+       wbuf->used = 0;
+       spin_unlock(&wbuf->lock);
+       wbuf->dtype = dtype;
+@@ -500,8 +669,9 @@ out_timers:
+  *
+  * This function writes data to flash via write-buffer @wbuf. This means that
+  * the last piece of the node won't reach the flash media immediately if it
+- * does not take whole minimal I/O unit. Instead, the node will sit in RAM
+- * until the write-buffer is synchronized (e.g., by timer).
++ * does not take whole max. write unit (@c->max_write_size). Instead, the node
++ * will sit in RAM until the write-buffer is synchronized (e.g., by timer, or
++ * because more data are appended to the write-buffer).
+  *
+  * This function returns zero in case of success and a negative error code in
+  * case of failure. If the node cannot be written because there is no more
+@@ -510,7 +680,7 @@ out_timers:
+ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+ {
+       struct ubifs_info *c = wbuf->c;
+-      int err, written, n, aligned_len = ALIGN(len, 8), offs;
++      int err, written, n, aligned_len = ALIGN(len, 8);
+       dbg_io("%d bytes (%s) to jhead %s wbuf at LEB %d:%d", len,
+              dbg_ntype(((struct ubifs_ch *)buf)->node_type),
+@@ -518,9 +688,15 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+       ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
+       ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
+       ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
+-      ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size);
++      ubifs_assert(wbuf->avail > 0 && wbuf->avail <= wbuf->size);
++      ubifs_assert(wbuf->size >= c->min_io_size);
++      ubifs_assert(wbuf->size <= c->max_write_size);
++      ubifs_assert(wbuf->size % c->min_io_size == 0);
+       ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      ubifs_assert(!c->space_fixup);
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
+       if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
+               err = -ENOSPC;
+@@ -542,15 +718,19 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+               if (aligned_len == wbuf->avail) {
+                       dbg_io("flush jhead %s wbuf to LEB %d:%d",
+                              dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
+-                      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
+-                                          wbuf->offs, c->min_io_size,
+-                                          wbuf->dtype);
++                      err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
++                                            wbuf->offs, wbuf->size,
++                                            wbuf->dtype);
+                       if (err)
+                               goto out;
+                       spin_lock(&wbuf->lock);
+-                      wbuf->offs += c->min_io_size;
+-                      wbuf->avail = c->min_io_size;
++                      wbuf->offs += wbuf->size;
++                      if (c->leb_size - wbuf->offs >= c->max_write_size)
++                              wbuf->size = c->max_write_size;
++                      else
++                              wbuf->size = c->leb_size - wbuf->offs;
++                      wbuf->avail = wbuf->size;
+                       wbuf->used = 0;
+                       wbuf->next_ino = 0;
+                       spin_unlock(&wbuf->lock);
+@@ -564,39 +744,63 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+               goto exit;
+       }
+-      /*
+-       * The node is large enough and does not fit entirely within current
+-       * minimal I/O unit. We have to fill and flush write-buffer and switch
+-       * to the next min. I/O unit.
+-       */
+-      dbg_io("flush jhead %s wbuf to LEB %d:%d",
+-             dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
+-      memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
+-      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
+-                          c->min_io_size, wbuf->dtype);
+-      if (err)
+-              goto out;
++      written = 0;
++
++      if (wbuf->used) {
++              /*
++               * The node is large enough and does not fit entirely within
++               * current available space. We have to fill and flush
++               * write-buffer and switch to the next max. write unit.
++               */
++              dbg_io("flush jhead %s wbuf to LEB %d:%d",
++                     dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
++              memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
++              err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
++                                    wbuf->size, wbuf->dtype);
++              if (err)
++                      goto out;
++
++              wbuf->offs += wbuf->size;
++              len -= wbuf->avail;
++              aligned_len -= wbuf->avail;
++              written += wbuf->avail;
++      } else if (wbuf->offs & (c->max_write_size - 1)) {
++              /*
++               * The write-buffer offset is not aligned to
++               * @c->max_write_size and @wbuf->size is less than
++               * @c->max_write_size. Write @wbuf->size bytes to make sure the
++               * following writes are done in optimal @c->max_write_size
++               * chunks.
++               */
++              dbg_io("write %d bytes to LEB %d:%d",
++                     wbuf->size, wbuf->lnum, wbuf->offs);
++              err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
++                                    wbuf->size, wbuf->dtype);
++              if (err)
++                      goto out;
+-      offs = wbuf->offs + c->min_io_size;
+-      len -= wbuf->avail;
+-      aligned_len -= wbuf->avail;
+-      written = wbuf->avail;
++              wbuf->offs += wbuf->size;
++              len -= wbuf->size;
++              aligned_len -= wbuf->size;
++              written += wbuf->size;
++      }
+       /*
+-       * The remaining data may take more whole min. I/O units, so write the
+-       * remains multiple to min. I/O unit size directly to the flash media.
++       * The remaining data may take more whole max. write units, so write the
++       * remains multiple to max. write unit size directly to the flash media.
+        * We align node length to 8-byte boundary because we anyway flash wbuf
+        * if the remaining space is less than 8 bytes.
+        */
+-      n = aligned_len >> c->min_io_shift;
++      n = aligned_len >> c->max_write_shift;
+       if (n) {
+-              n <<= c->min_io_shift;
+-              dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
+-              err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
+-                                  wbuf->dtype);
++              n <<= c->max_write_shift;
++              dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
++                     wbuf->offs);
++              err = ubifs_leb_write(c, wbuf->lnum, buf + written,
++                                    wbuf->offs, n, wbuf->dtype);
+               if (err)
+                       goto out;
+-              offs += n;
++              wbuf->offs += n;
+               aligned_len -= n;
+               len -= n;
+               written += n;
+@@ -606,14 +810,17 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+       if (aligned_len)
+               /*
+                * And now we have what's left and what does not take whole
+-               * min. I/O unit, so write it to the write-buffer and we are
++               * max. write unit, so write it to the write-buffer and we are
+                * done.
+                */
+               memcpy(wbuf->buf, buf + written, len);
+-      wbuf->offs = offs;
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              wbuf->size = c->max_write_size;
++      else
++              wbuf->size = c->leb_size - wbuf->offs;
++      wbuf->avail = wbuf->size - aligned_len;
+       wbuf->used = aligned_len;
+-      wbuf->avail = c->min_io_size - aligned_len;
+       wbuf->next_ino = 0;
+       spin_unlock(&wbuf->lock);
+@@ -666,18 +873,15 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
+       ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+       ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      ubifs_assert(!c->space_fixup);
+       if (c->ro_error)
+               return -EROFS;
+       ubifs_prepare_node(c, buf, len, 1);
+-      err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype);
+-      if (err) {
+-              ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
+-                        buf_len, lnum, offs, err);
++      err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
++      if (err)
+               dbg_dump_node(c, buf);
+-              dbg_dump_stack();
+-      }
+       return err;
+ }
+@@ -729,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+       if (rlen > 0) {
+               /* Read everything that goes before write-buffer */
+-              err = ubi_read(c->ubi, lnum, buf, offs, rlen);
+-              if (err && err != -EBADMSG) {
+-                      ubifs_err("failed to read node %d from LEB %d:%d, "
+-                                "error %d", type, lnum, offs, err);
+-                      dbg_dump_stack();
++              err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
++              if (err && err != -EBADMSG)
+                       return err;
+-              }
+       }
+       if (type != ch->node_type) {
+@@ -790,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+       ubifs_assert(!(offs & 7) && offs < c->leb_size);
+       ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
+-      if (err && err != -EBADMSG) {
+-              ubifs_err("cannot read node %d from LEB %d:%d, error %d",
+-                        type, lnum, offs, err);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
++      if (err && err != -EBADMSG)
+               return err;
+-      }
+       if (type != ch->node_type) {
+               ubifs_err("bad node type (%d but expected %d)",
+@@ -837,11 +1034,11 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
+ {
+       size_t size;
+-      wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
++      wbuf->buf = kmalloc(c->max_write_size, GFP_KERNEL);
+       if (!wbuf->buf)
+               return -ENOMEM;
+-      size = (c->min_io_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
++      size = (c->max_write_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
+       wbuf->inodes = kmalloc(size, GFP_KERNEL);
+       if (!wbuf->inodes) {
+               kfree(wbuf->buf);
+@@ -851,7 +1048,14 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
+       wbuf->used = 0;
+       wbuf->lnum = wbuf->offs = -1;
+-      wbuf->avail = c->min_io_size;
++      /*
++       * If the LEB starts at the max. write size aligned address, then
++       * write-buffer size has to be set to @c->max_write_size. Otherwise,
++       * set it to something smaller so that it ends at the closest max.
++       * write size boundary.
++       */
++      size = c->max_write_size - (c->leb_start % c->max_write_size);
++      wbuf->avail = wbuf->size = size;
+       wbuf->dtype = UBI_UNKNOWN;
+       wbuf->sync_callback = NULL;
+       mutex_init(&wbuf->io_mutex);
+diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
+index 914f1bd..2f438ab 100644
+--- a/fs/ubifs/journal.c
++++ b/fs/ubifs/journal.c
+@@ -141,14 +141,8 @@ again:
+        * LEB with some empty space.
+        */
+       lnum = ubifs_find_free_space(c, len, &offs, squeeze);
+-      if (lnum >= 0) {
+-              /* Found an LEB, add it to the journal head */
+-              err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
+-              if (err)
+-                      goto out_return;
+-              /* A new bud was successfully allocated and added to the log */
++      if (lnum >= 0)
+               goto out;
+-      }
+       err = lnum;
+       if (err != -ENOSPC)
+@@ -203,12 +197,23 @@ again:
+               return 0;
+       }
+-      err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
+-      if (err)
+-              goto out_return;
+       offs = 0;
+ out:
++      /*
++       * Make sure we synchronize the write-buffer before we add the new bud
++       * to the log. Otherwise we may have a power cut after the log
++       * reference node for the last bud (@lnum) is written but before the
++       * write-buffer data are written to the next-to-last bud
++       * (@wbuf->lnum). And the effect would be that the recovery would see
++       * that there is corruption in the next-to-last bud.
++       */
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (err)
++              goto out_return;
++      err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
++      if (err)
++              goto out_return;
+       err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
+       if (err)
+               goto out_unlock;
+@@ -380,10 +385,8 @@ out:
+       if (err == -ENOSPC) {
+               /* This are some budgeting problems, print useful information */
+               down_write(&c->commit_sem);
+-              spin_lock(&c->space_lock);
+               dbg_dump_stack();
+-              dbg_dump_budg(c);
+-              spin_unlock(&c->space_lock);
++              dbg_dump_budg(c, &c->bi);
+               dbg_dump_lprops(c);
+               cmt_retries = dbg_check_lprops(c);
+               up_write(&c->commit_sem);
+@@ -666,6 +669,7 @@ out_free:
+ out_release:
+       release_head(c, BASEHD);
++      kfree(dent);
+ out_ro:
+       ubifs_ro_mode(c, err);
+       if (last_reference)
+@@ -690,17 +694,26 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+ {
+       struct ubifs_data_node *data;
+       int err, lnum, offs, compr_type, out_len;
+-      int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR;
++      int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
+       struct ubifs_inode *ui = ubifs_inode(inode);
+-      dbg_jnl("ino %lu, blk %u, len %d, key %s",
+-              (unsigned long)key_inum(c, key), key_block(c, key), len,
+-              DBGKEY(key));
++      dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
++              (unsigned long)key_inum(c, key), key_block(c, key), len);
+       ubifs_assert(len <= UBIFS_BLOCK_SIZE);
+-      data = kmalloc(dlen, GFP_NOFS);
+-      if (!data)
+-              return -ENOMEM;
++      data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
++      if (!data) {
++              /*
++               * Fall-back to the write reserve buffer. Note, we might be
++               * currently on the memory reclaim path, when the kernel is
++               * trying to free some memory by writing out dirty pages. The
++               * write reserve buffer helps us to guarantee that we are
++               * always able to write the data.
++               */
++              allocated = 0;
++              mutex_lock(&c->write_reserve_mutex);
++              data = c->write_reserve_buf;
++      }
+       data->ch.node_type = UBIFS_DATA_NODE;
+       key_write(c, key, &data->key);
+@@ -736,7 +749,10 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+               goto out_ro;
+       finish_reservation(c);
+-      kfree(data);
++      if (!allocated)
++              mutex_unlock(&c->write_reserve_mutex);
++      else
++              kfree(data);
+       return 0;
+ out_release:
+@@ -745,7 +761,10 @@ out_ro:
+       ubifs_ro_mode(c, err);
+       finish_reservation(c);
+ out_free:
+-      kfree(data);
++      if (!allocated)
++              mutex_unlock(&c->write_reserve_mutex);
++      else
++              kfree(data);
+       return err;
+ }
+@@ -1157,7 +1176,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
+               dn = (void *)trun + UBIFS_TRUN_NODE_SZ;
+               blk = new_size >> UBIFS_BLOCK_SHIFT;
+               data_key_init(c, &key, inum, blk);
+-              dbg_jnl("last block key %s", DBGKEY(&key));
++              dbg_jnlk(&key, "last block key ");
+               err = ubifs_tnc_lookup(c, &key, dn);
+               if (err == -ENOENT)
+                       dlen = 0; /* Not found (so it is a hole) */
+diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
+index 4d0cb12..f9fd068 100644
+--- a/fs/ubifs/log.c
++++ b/fs/ubifs/log.c
+@@ -100,20 +100,6 @@ struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
+ }
+ /**
+- * next_log_lnum - switch to the next log LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: current log LEB
+- */
+-static inline int next_log_lnum(const struct ubifs_info *c, int lnum)
+-{
+-      lnum += 1;
+-      if (lnum > c->log_last)
+-              lnum = UBIFS_LOG_LNUM;
+-
+-      return lnum;
+-}
+-
+-/**
+  * empty_log_bytes - calculate amount of empty space in the log.
+  * @c: UBIFS file-system description object
+  */
+@@ -175,26 +161,6 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
+ }
+ /**
+- * ubifs_create_buds_lists - create journal head buds lists for remount rw.
+- * @c: UBIFS file-system description object
+- */
+-void ubifs_create_buds_lists(struct ubifs_info *c)
+-{
+-      struct rb_node *p;
+-
+-      spin_lock(&c->buds_lock);
+-      p = rb_first(&c->buds);
+-      while (p) {
+-              struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb);
+-              struct ubifs_jhead *jhead = &c->jheads[bud->jhead];
+-
+-              list_add_tail(&bud->list, &jhead->buds_list);
+-              p = rb_next(p);
+-      }
+-      spin_unlock(&c->buds_lock);
+-}
+-
+-/**
+  * ubifs_add_bud_to_log - add a new bud to the log.
+  * @c: UBIFS file-system description object
+  * @jhead: journal head the bud belongs to
+@@ -277,7 +243,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+       ref->jhead = cpu_to_le32(jhead);
+       if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -296,7 +262,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+                * an unclean reboot, because the target LEB might have been
+                * unmapped, but not yet physically erased.
+                */
+-              err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM);
++              err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
+               if (err)
+                       goto out_unlock;
+       }
+@@ -317,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+       return 0;
+ out_unlock:
+-      if (err != -EAGAIN)
+-              ubifs_ro_mode(c, err);
+       mutex_unlock(&c->log_mutex);
+       kfree(ref);
+       kfree(bud);
+@@ -445,7 +409,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
+       /* Switch to the next log LEB */
+       if (c->lhead_offs) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -466,7 +430,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
+       c->lhead_offs += len;
+       if (c->lhead_offs == c->leb_size) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -553,7 +517,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
+       }
+       mutex_lock(&c->log_mutex);
+       for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
+-           lnum = next_log_lnum(c, lnum)) {
++           lnum = ubifs_next_log_lnum(c, lnum)) {
+               dbg_log("unmap log LEB %d", lnum);
+               err = ubifs_leb_unmap(c, lnum);
+               if (err)
+@@ -662,7 +626,7 @@ static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
+               err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
+               if (err)
+                       return err;
+-              *lnum = next_log_lnum(c, *lnum);
++              *lnum = ubifs_next_log_lnum(c, *lnum);
+               *offs = 0;
+       }
+       memcpy(buf + *offs, node, len);
+@@ -732,7 +696,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
+               ubifs_scan_destroy(sleb);
+               if (lnum == c->lhead_lnum)
+                       break;
+-              lnum = next_log_lnum(c, lnum);
++              lnum = ubifs_next_log_lnum(c, lnum);
+       }
+       if (offs) {
+               int sz = ALIGN(offs, c->min_io_size);
+@@ -752,7 +716,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
+       /* Unmap remaining LEBs */
+       lnum = write_lnum;
+       do {
+-              lnum = next_log_lnum(c, lnum);
++              lnum = ubifs_next_log_lnum(c, lnum);
+               err = ubifs_leb_unmap(c, lnum);
+               if (err)
+                       return err;
+@@ -786,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
+       struct ubifs_bud *bud;
+       long long bud_bytes = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       spin_lock(&c->buds_lock);
+diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
+index 4d4ca38..f8a181e 100644
+--- a/fs/ubifs/lprops.c
++++ b/fs/ubifs/lprops.c
+@@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
+       pnode = (struct ubifs_pnode *)container_of(lprops - pos,
+                                                  struct ubifs_pnode,
+                                                  lprops[0]);
+-      return !test_bit(COW_ZNODE, &pnode->flags) &&
++      return !test_bit(COW_CNODE, &pnode->flags) &&
+              test_bit(DIRTY_CNODE, &pnode->flags);
+ }
+@@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
+       struct list_head *pos;
+       int i, cat;
+-      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++      if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
+               return 0;
+       list_for_each_entry(lprops, &c->empty_list, list) {
+@@ -958,7 +958,7 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
+ {
+       int i = 0, j, err = 0;
+-      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++      if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
+               return;
+       for (i = 0; i < heap->cnt; i++) {
+@@ -1007,21 +1007,11 @@ out:
+ }
+ /**
+- * struct scan_check_data - data provided to scan callback function.
+- * @lst: LEB properties statistics
+- * @err: error code
+- */
+-struct scan_check_data {
+-      struct ubifs_lp_stats lst;
+-      int err;
+-};
+-
+-/**
+  * scan_check_cb - scan callback.
+  * @c: the UBIFS file-system description object
+  * @lp: LEB properties to scan
+  * @in_tree: whether the LEB properties are in main memory
+- * @data: information passed to and from the caller of the scan
++ * @lst: lprops statistics to update
+  *
+  * This function returns a code that indicates whether the scan should continue
+  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
+@@ -1030,12 +1020,12 @@ struct scan_check_data {
+  */
+ static int scan_check_cb(struct ubifs_info *c,
+                        const struct ubifs_lprops *lp, int in_tree,
+-                       struct scan_check_data *data)
++                       struct ubifs_lp_stats *lst)
+ {
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
+-      struct ubifs_lp_stats *lst = &data->lst;
+-      int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty;
++      int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
++      void *buf = NULL;
+       cat = lp->flags & LPROPS_CAT_MASK;
+       if (cat != LPROPS_UNCAT) {
+@@ -1043,7 +1033,7 @@ static int scan_check_cb(struct ubifs_info *c,
+               if (cat != (lp->flags & LPROPS_CAT_MASK)) {
+                       ubifs_err("bad LEB category %d expected %d",
+                                 (lp->flags & LPROPS_CAT_MASK), cat);
+-                      goto out;
++                      return -EINVAL;
+               }
+       }
+@@ -1077,7 +1067,7 @@ static int scan_check_cb(struct ubifs_info *c,
+                       }
+                       if (!found) {
+                               ubifs_err("bad LPT list (category %d)", cat);
+-                              goto out;
++                              return -EINVAL;
+                       }
+               }
+       }
+@@ -1089,36 +1079,40 @@ static int scan_check_cb(struct ubifs_info *c,
+               if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
+                   lp != heap->arr[lp->hpos]) {
+                       ubifs_err("bad LPT heap (category %d)", cat);
+-                      goto out;
++                      return -EINVAL;
+               }
+       }
+-      sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
+-      if (IS_ERR(sleb)) {
+-              /*
+-               * After an unclean unmount, empty and freeable LEBs
+-               * may contain garbage.
+-               */
+-              if (lp->free == c->leb_size) {
+-                      ubifs_err("scan errors were in empty LEB "
+-                                "- continuing checking");
+-                      lst->empty_lebs += 1;
+-                      lst->total_free += c->leb_size;
+-                      lst->total_dark += ubifs_calc_dark(c, c->leb_size);
+-                      return LPT_SCAN_CONTINUE;
+-              }
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf)
++              return -ENOMEM;
+-              if (lp->free + lp->dirty == c->leb_size &&
+-                  !(lp->flags & LPROPS_INDEX)) {
+-                      ubifs_err("scan errors were in freeable LEB "
+-                                "- continuing checking");
+-                      lst->total_free  += lp->free;
+-                      lst->total_dirty += lp->dirty;
+-                      lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
+-                      return LPT_SCAN_CONTINUE;
++      /*
++       * After an unclean unmount, empty and freeable LEBs
++       * may contain garbage - do not scan them.
++       */
++      if (lp->free == c->leb_size) {
++              lst->empty_lebs += 1;
++              lst->total_free += c->leb_size;
++              lst->total_dark += ubifs_calc_dark(c, c->leb_size);
++              return LPT_SCAN_CONTINUE;
++      }
++      if (lp->free + lp->dirty == c->leb_size &&
++          !(lp->flags & LPROPS_INDEX)) {
++              lst->total_free  += lp->free;
++              lst->total_dirty += lp->dirty;
++              lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
++              return LPT_SCAN_CONTINUE;
++      }
++
++      sleb = ubifs_scan(c, lnum, 0, buf, 0);
++      if (IS_ERR(sleb)) {
++              ret = PTR_ERR(sleb);
++              if (ret == -EUCLEAN) {
++                      dbg_dump_lprops(c);
++                      dbg_dump_budg(c, &c->bi);
+               }
+-              data->err = PTR_ERR(sleb);
+-              return LPT_SCAN_STOP;
++              goto out;
+       }
+       is_idx = -1;
+@@ -1236,6 +1230,7 @@ static int scan_check_cb(struct ubifs_info *c,
+       }
+       ubifs_scan_destroy(sleb);
++      vfree(buf);
+       return LPT_SCAN_CONTINUE;
+ out_print:
+@@ -1245,9 +1240,10 @@ out_print:
+       dbg_dump_leb(c, lnum);
+ out_destroy:
+       ubifs_scan_destroy(sleb);
++      ret = -EINVAL;
+ out:
+-      data->err = -EINVAL;
+-      return LPT_SCAN_STOP;
++      vfree(buf);
++      return ret;
+ }
+ /**
+@@ -1264,10 +1260,9 @@ out:
+ int dbg_check_lprops(struct ubifs_info *c)
+ {
+       int i, err;
+-      struct scan_check_data data;
+-      struct ubifs_lp_stats *lst = &data.lst;
++      struct ubifs_lp_stats lst;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       /*
+@@ -1280,29 +1275,23 @@ int dbg_check_lprops(struct ubifs_info *c)
+                       return err;
+       }
+-      memset(lst, 0, sizeof(struct ubifs_lp_stats));
+-
+-      data.err = 0;
++      memset(&lst, 0, sizeof(struct ubifs_lp_stats));
+       err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
+                                   (ubifs_lpt_scan_callback)scan_check_cb,
+-                                  &data);
++                                  &lst);
+       if (err && err != -ENOSPC)
+               goto out;
+-      if (data.err) {
+-              err = data.err;
+-              goto out;
+-      }
+-      if (lst->empty_lebs != c->lst.empty_lebs ||
+-          lst->idx_lebs != c->lst.idx_lebs ||
+-          lst->total_free != c->lst.total_free ||
+-          lst->total_dirty != c->lst.total_dirty ||
+-          lst->total_used != c->lst.total_used) {
++      if (lst.empty_lebs != c->lst.empty_lebs ||
++          lst.idx_lebs != c->lst.idx_lebs ||
++          lst.total_free != c->lst.total_free ||
++          lst.total_dirty != c->lst.total_dirty ||
++          lst.total_used != c->lst.total_used) {
+               ubifs_err("bad overall accounting");
+               ubifs_err("calculated: empty_lebs %d, idx_lebs %d, "
+                         "total_free %lld, total_dirty %lld, total_used %lld",
+-                        lst->empty_lebs, lst->idx_lebs, lst->total_free,
+-                        lst->total_dirty, lst->total_used);
++                        lst.empty_lebs, lst.idx_lebs, lst.total_free,
++                        lst.total_dirty, lst.total_used);
+               ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, "
+                         "total_free %lld, total_dirty %lld, total_used %lld",
+                         c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
+@@ -1311,11 +1300,11 @@ int dbg_check_lprops(struct ubifs_info *c)
+               goto out;
+       }
+-      if (lst->total_dead != c->lst.total_dead ||
+-          lst->total_dark != c->lst.total_dark) {
++      if (lst.total_dead != c->lst.total_dead ||
++          lst.total_dark != c->lst.total_dark) {
+               ubifs_err("bad dead/dark space accounting");
+               ubifs_err("calculated: total_dead %lld, total_dark %lld",
+-                        lst->total_dead, lst->total_dark);
++                        lst.total_dead, lst.total_dark);
+               ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
+                         c->lst.total_dead, c->lst.total_dark);
+               err = -EINVAL;
+diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
+index 72775d3..66d59d0 100644
+--- a/fs/ubifs/lpt.c
++++ b/fs/ubifs/lpt.c
+@@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+-                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                           UBI_SHORTTERM);
++                      err = ubifs_leb_change(c, lnum++, buf, alen,
++                                             UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+@@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                               set_ltab(c, lnum, c->leb_size - alen,
+                                           alen - len);
+                               memset(p, 0xff, alen - len);
+-                              err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                                   UBI_SHORTTERM);
++                              err = ubifs_leb_change(c, lnum++, buf, alen,
++                                                     UBI_SHORTTERM);
+                               if (err)
+                                       goto out;
+                               p = buf;
+@@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+-                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                           UBI_SHORTTERM);
++                      err = ubifs_leb_change(c, lnum++, buf, alen,
++                                             UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+@@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+               alen = ALIGN(len, c->min_io_size);
+               set_ltab(c, lnum, c->leb_size - alen, alen - len);
+               memset(p, 0xff, alen - len);
+-              err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM);
++              err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
+               if (err)
+                       goto out;
+               p = buf;
+@@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+       /* Write remaining buffer */
+       memset(p, 0xff, alen - len);
+-      err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
+       if (err)
+               goto out;
+@@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+               if (c->big_lpt)
+                       nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+       } else {
+-              err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
++              err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
+               if (err)
+                       goto out;
+               err = ubifs_unpack_nnode(c, buf, nnode);
+@@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+ out:
+       ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
++      dbg_dump_stack();
+       kfree(nnode);
+       return err;
+ }
+@@ -1270,10 +1271,9 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+       lnum = branch->lnum;
+       offs = branch->offs;
+       pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+-      if (!pnode) {
+-              err = -ENOMEM;
+-              goto out;
+-      }
++      if (!pnode)
++              return -ENOMEM;
++
+       if (lnum == 0) {
+               /*
+                * This pnode was not written which just means that the LEB
+@@ -1291,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+                       lprops->flags = ubifs_categorize_lprops(c, lprops);
+               }
+       } else {
+-              err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
++              err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
+               if (err)
+                       goto out;
+               err = unpack_pnode(c, buf, pnode);
+@@ -1313,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+ out:
+       ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
+       dbg_dump_pnode(c, pnode, parent, iip);
++      dbg_dump_stack();
+       dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
+       kfree(pnode);
+       return err;
+@@ -1332,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
+       buf = vmalloc(c->ltab_sz);
+       if (!buf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
++      err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
+       if (err)
+               goto out;
+       err = unpack_ltab(c, buf);
+@@ -1355,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
+       buf = vmalloc(c->lsave_sz);
+       if (!buf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
++      err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
++                           c->lsave_sz, 1);
+       if (err)
+               goto out;
+       err = unpack_lsave(c, buf);
+@@ -1815,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
+               if (c->big_lpt)
+                       nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+       } else {
+-              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
+-                             c->nnode_sz);
++              err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
++                                   c->nnode_sz, 1);
+               if (err)
+                       return ERR_PTR(err);
+               err = ubifs_unpack_nnode(c, buf, nnode);
+@@ -1884,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
+               ubifs_assert(branch->lnum >= c->lpt_first &&
+                            branch->lnum <= c->lpt_last);
+               ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
+-              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
+-                             c->pnode_sz);
++              err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
++                                   c->pnode_sz, 1);
+               if (err)
+                       return ERR_PTR(err);
+               err = unpack_pnode(c, buf, pnode);
+@@ -1984,12 +1986,11 @@ again:
+                               if (path[h].in_tree)
+                                       continue;
+-                              nnode = kmalloc(sz, GFP_NOFS);
++                              nnode = kmemdup(&path[h].nnode, sz, GFP_NOFS);
+                               if (!nnode) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
+-                              memcpy(nnode, &path[h].nnode, sz);
+                               parent = nnode->parent;
+                               parent->nbranch[nnode->iip].nnode = nnode;
+                               path[h].ptr.nnode = nnode;
+@@ -2002,12 +2003,11 @@ again:
+                               const size_t sz = sizeof(struct ubifs_pnode);
+                               struct ubifs_nnode *parent;
+-                              pnode = kmalloc(sz, GFP_NOFS);
++                              pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS);
+                               if (!pnode) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
+-                              memcpy(pnode, &path[h].pnode, sz);
+                               parent = pnode->parent;
+                               parent->nbranch[pnode->iip].pnode = pnode;
+                               path[h].ptr.pnode = pnode;
+@@ -2225,7 +2225,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
+       struct ubifs_cnode *cn;
+       int num, iip = 0, err;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       while (cnode) {
+diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
+index 5c90dec..cddd6bd 100644
+--- a/fs/ubifs/lpt_commit.c
++++ b/fs/ubifs/lpt_commit.c
+@@ -27,8 +27,15 @@
+ #include <linux/crc16.h>
+ #include <linux/slab.h>
++#include <linux/random.h>
+ #include "ubifs.h"
++#ifdef CONFIG_UBIFS_FS_DEBUG
++static int dbg_populate_lsave(struct ubifs_info *c);
++#else
++#define dbg_populate_lsave(c) 0
++#endif
++
+ /**
+  * first_dirty_cnode - find first dirty cnode.
+  * @c: UBIFS file-system description object
+@@ -110,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
+               return 0;
+       cnt += 1;
+       while (1) {
+-              ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags));
+-              __set_bit(COW_ZNODE, &cnode->flags);
++              ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
++              __set_bit(COW_CNODE, &cnode->flags);
+               cnext = next_dirty_cnode(cnode);
+               if (!cnext) {
+                       cnode->cnext = c->lpt_cnext;
+@@ -459,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
+                */
+               clear_bit(DIRTY_CNODE, &cnode->flags);
+               smp_mb__before_clear_bit();
+-              clear_bit(COW_ZNODE, &cnode->flags);
++              clear_bit(COW_CNODE, &cnode->flags);
+               smp_mb__after_clear_bit();
+               offs += len;
+               dbg_chk_lpt_sz(c, 1, len);
+@@ -586,7 +593,7 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
+                       if (nnode->nbranch[iip].lnum)
+                               break;
+               }
+-       } while (iip >= UBIFS_LPT_FANOUT);
++      } while (iip >= UBIFS_LPT_FANOUT);
+       /* Go right */
+       nnode = ubifs_get_nnode(c, nnode, iip);
+@@ -815,6 +822,10 @@ static void populate_lsave(struct ubifs_info *c)
+               c->lpt_drty_flgs |= LSAVE_DIRTY;
+               ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
+       }
++
++      if (dbg_populate_lsave(c))
++              return;
++
+       list_for_each_entry(lprops, &c->empty_list, list) {
+               c->lsave[cnt++] = lprops->lnum;
+               if (cnt >= c->lsave_cnt)
+@@ -1150,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
+       void *buf = c->lpt_buf;
+       dbg_lp("LEB %d", lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              ubifs_err("cannot read LEB %d, error %d", lnum, err);
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
+               return err;
+-      }
++
+       while (1) {
+               if (!is_a_node(c, buf, len)) {
+                       int pad_len;
+@@ -1628,29 +1639,35 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
+ {
+       int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
+       int ret;
+-      void *buf = c->dbg->buf;
++      void *buf, *p;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+-      dbg_lp("LEB %d", lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
+-              return err;
++      buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory for ltab checking");
++              return 0;
+       }
++
++      dbg_lp("LEB %d", lnum);
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
++              goto out;
++
+       while (1) {
+-              if (!is_a_node(c, buf, len)) {
++              if (!is_a_node(c, p, len)) {
+                       int i, pad_len;
+-                      pad_len = get_pad_len(c, buf, len);
++                      pad_len = get_pad_len(c, p, len);
+                       if (pad_len) {
+-                              buf += pad_len;
++                              p += pad_len;
+                               len -= pad_len;
+                               dirty += pad_len;
+                               continue;
+                       }
+-                      if (!dbg_is_all_ff(buf, len)) {
++                      if (!dbg_is_all_ff(p, len)) {
+                               dbg_msg("invalid empty space in LEB %d at %d",
+                                       lnum, c->leb_size - len);
+                               err = -EINVAL;
+@@ -1668,16 +1685,21 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
+                                       lnum, dirty, c->ltab[i].dirty);
+                               err = -EINVAL;
+                       }
+-                      return err;
++                      goto out;
+               }
+-              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_type = get_lpt_node_type(c, p, &node_num);
+               node_len = get_lpt_node_len(c, node_type);
+               ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len);
+               if (ret == 1)
+                       dirty += node_len;
+-              buf += node_len;
++              p += node_len;
+               len -= node_len;
+       }
++
++      err = 0;
++out:
++      vfree(buf);
++      return err;
+ }
+ /**
+@@ -1690,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
+ {
+       int lnum, err, i, cnt;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       /* Bring the entire tree into memory */
+@@ -1733,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
+       long long free = 0;
+       int i;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       for (i = 0; i < c->lpt_lebs; i++) {
+@@ -1775,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+       long long chk_lpt_sz, lpt_sz;
+       int err = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       switch (action) {
+@@ -1870,25 +1892,30 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+ {
+       int err, len = c->leb_size, node_type, node_num, node_len, offs;
+-      void *buf = c->dbg->buf;
++      void *buf, *p;
+       printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              ubifs_err("cannot read LEB %d, error %d", lnum, err);
++      buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory to dump LPT");
+               return;
+       }
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
++              goto out;
++
+       while (1) {
+               offs = c->leb_size - len;
+-              if (!is_a_node(c, buf, len)) {
++              if (!is_a_node(c, p, len)) {
+                       int pad_len;
+-                      pad_len = get_pad_len(c, buf, len);
++                      pad_len = get_pad_len(c, p, len);
+                       if (pad_len) {
+                               printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n",
+                                      lnum, offs, pad_len);
+-                              buf += pad_len;
++                              p += pad_len;
+                               len -= pad_len;
+                               continue;
+                       }
+@@ -1898,7 +1925,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       break;
+               }
+-              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_type = get_lpt_node_type(c, p, &node_num);
+               switch (node_type) {
+               case UBIFS_LPT_PNODE:
+               {
+@@ -1923,7 +1950,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       else
+                               printk(KERN_DEBUG "LEB %d:%d, nnode, ",
+                                      lnum, offs);
+-                      err = ubifs_unpack_nnode(c, buf, &nnode);
++                      err = ubifs_unpack_nnode(c, p, &nnode);
+                       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+                               printk(KERN_CONT "%d:%d", nnode.nbranch[i].lnum,
+                                      nnode.nbranch[i].offs);
+@@ -1944,15 +1971,18 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       break;
+               default:
+                       ubifs_err("LPT node type %d not recognized", node_type);
+-                      return;
++                      goto out;
+               }
+-              buf += node_len;
++              p += node_len;
+               len -= node_len;
+       }
+       printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
++out:
++      vfree(buf);
++      return;
+ }
+ /**
+@@ -1974,4 +2004,47 @@ void dbg_dump_lpt_lebs(const struct ubifs_info *c)
+              current->pid);
+ }
++/**
++ * dbg_populate_lsave - debugging version of 'populate_lsave()'
++ * @c: UBIFS file-system description object
++ *
++ * This is a debugging version for 'populate_lsave()' which populates lsave
++ * with random LEBs instead of useful LEBs, which is good for test coverage.
++ * Returns zero if lsave has not been populated (this debugging feature is
++ * disabled) an non-zero if lsave has been populated.
++ */
++static int dbg_populate_lsave(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++      int i;
++
++      if (!dbg_is_chk_gen(c))
++              return 0;
++      if (random32() & 3)
++              return 0;
++
++      for (i = 0; i < c->lsave_cnt; i++)
++              c->lsave[i] = c->main_first;
++
++      list_for_each_entry(lprops, &c->empty_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++      list_for_each_entry(lprops, &c->freeable_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++      list_for_each_entry(lprops, &c->frdi_idx_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++
++      heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++      heap = &c->lpt_heap[LPROPS_DIRTY - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++      heap = &c->lpt_heap[LPROPS_FREE - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++
++      return 1;
++}
++
+ #endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
+index 21f47af..278c238 100644
+--- a/fs/ubifs/master.c
++++ b/fs/ubifs/master.c
+@@ -148,7 +148,7 @@ static int validate_master(const struct ubifs_info *c)
+       }
+       main_sz = (long long)c->main_lebs * c->leb_size;
+-      if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
++      if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
+               err = 9;
+               goto out;
+       }
+@@ -218,7 +218,7 @@ static int validate_master(const struct ubifs_info *c)
+       }
+       if (c->lst.total_dead + c->lst.total_dark +
+-          c->lst.total_used + c->old_idx_sz > main_sz) {
++          c->lst.total_used + c->bi.old_idx_sz > main_sz) {
+               err = 21;
+               goto out;
+       }
+@@ -286,7 +286,7 @@ int ubifs_read_master(struct ubifs_info *c)
+       c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
+       c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
+       c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
+-      c->old_idx_sz      = le64_to_cpu(c->mst_node->index_size);
++      c->bi.old_idx_sz   = le64_to_cpu(c->mst_node->index_size);
+       c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
+       c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
+       c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
+@@ -305,7 +305,7 @@ int ubifs_read_master(struct ubifs_info *c)
+       c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
+       c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
+-      c->calc_idx_sz = c->old_idx_sz;
++      c->calc_idx_sz = c->bi.old_idx_sz;
+       if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
+               c->no_orphs = 1;
+diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
+index c3de04d..ee7cb5e 100644
+--- a/fs/ubifs/misc.h
++++ b/fs/ubifs/misc.h
+@@ -39,6 +39,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
+ }
+ /**
++ * ubifs_zn_obsolete - check if znode is obsolete.
++ * @znode: znode to check
++ *
++ * This helper function returns %1 if @znode is obsolete and %0 otherwise.
++ */
++static inline int ubifs_zn_obsolete(const struct ubifs_znode *znode)
++{
++      return !!test_bit(OBSOLETE_ZNODE, &znode->flags);
++}
++
++/**
++ * ubifs_zn_cow - check if znode has to be copied on write.
++ * @znode: znode to check
++ *
++ * This helper function returns %1 if @znode is has COW flag set and %0
++ * otherwise.
++ */
++static inline int ubifs_zn_cow(const struct ubifs_znode *znode)
++{
++      return !!test_bit(COW_ZNODE, &znode->flags);
++}
++
++/**
+  * ubifs_wake_up_bgt - wake up background thread.
+  * @c: UBIFS file-system description object
+  */
+@@ -122,86 +145,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
+ }
+ /**
+- * ubifs_leb_unmap - unmap an LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to unmap
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_unmap(c->ubi, lnum);
+-      if (err) {
+-              ubifs_err("unmap LEB %d failed, error %d", lnum, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+- * ubifs_leb_write - write to a LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to write
+- * @buf: buffer to write from
+- * @offs: offset within LEB to write to
+- * @len: length to write
+- * @dtype: data type
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
+-                                const void *buf, int offs, int len, int dtype)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+-      if (err) {
+-              ubifs_err("writing %d bytes at %d:%d, error %d",
+-                        len, lnum, offs, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+- * ubifs_leb_change - atomic LEB change.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to write
+- * @buf: buffer to write from
+- * @len: length to write
+- * @dtype: data type
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
+-                                 const void *buf, int len, int dtype)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+-      if (err) {
+-              ubifs_err("changing %d bytes in LEB %d, error %d",
+-                        len, lnum, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+  * ubifs_encode_dev - encode device node IDs.
+  * @dev: UBIFS device node information
+  * @rdev: device IDs to encode
+@@ -340,4 +283,21 @@ static inline void ubifs_release_lprops(struct ubifs_info *c)
+       mutex_unlock(&c->lp_mutex);
+ }
++/**
++ * ubifs_next_log_lnum - switch to the next log LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: current log LEB
++ *
++ * This helper function returns the log LEB number which goes next after LEB
++ * 'lnum'.
++ */
++static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
++{
++      lnum += 1;
++      if (lnum > c->log_last)
++              lnum = UBIFS_LOG_LNUM;
++
++      return lnum;
++}
++
+ #endif /* __UBIFS_MISC_H__ */
+diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
+index 82009c7..c542c73 100644
+--- a/fs/ubifs/orphan.c
++++ b/fs/ubifs/orphan.c
+@@ -673,7 +673,8 @@ static int kill_orphans(struct ubifs_info *c)
+               sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
+               if (IS_ERR(sleb)) {
+                       if (PTR_ERR(sleb) == -EUCLEAN)
+-                              sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
++                              sleb = ubifs_recover_leb(c, lnum, 0,
++                                                       c->sbuf, -1);
+                       if (IS_ERR(sleb)) {
+                               err = PTR_ERR(sleb);
+                               break;
+@@ -892,15 +893,22 @@ static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb)
+ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
+ {
+       int lnum, err = 0;
++      void *buf;
+       /* Check no-orphans flag and skip this if no orphans */
+       if (c->no_orphs)
+               return 0;
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory to check orphans");
++              return 0;
++      }
++
+       for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+               struct ubifs_scan_leb *sleb;
+-              sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
++              sleb = ubifs_scan(c, lnum, 0, buf, 0);
+               if (IS_ERR(sleb)) {
+                       err = PTR_ERR(sleb);
+                       break;
+@@ -912,6 +920,7 @@ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
+                       break;
+       }
++      vfree(buf);
+       return err;
+ }
+@@ -920,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
+       struct check_info ci;
+       int err;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_ORPH))
++      if (!dbg_is_chk_orph(c))
+               return 0;
+       ci.last_ino = 0;
+diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
+index 77e9b87..2a935b3 100644
+--- a/fs/ubifs/recovery.c
++++ b/fs/ubifs/recovery.c
+@@ -28,6 +28,23 @@
+  * UBIFS always cleans away all remnants of an unclean un-mount, so that
+  * errors do not accumulate. However UBIFS defers recovery if it is mounted
+  * read-only, and the flash is not modified in that case.
++ *
++ * The general UBIFS approach to the recovery is that it recovers from
++ * corruptions which could be caused by power cuts, but it refuses to recover
++ * from corruption caused by other reasons. And UBIFS tries to distinguish
++ * between these 2 reasons of corruptions and silently recover in the former
++ * case and loudly complain in the latter case.
++ *
++ * UBIFS writes only to erased LEBs, so it writes only to the flash space
++ * containing only 0xFFs. UBIFS also always writes strictly from the beginning
++ * of the LEB to the end. And UBIFS assumes that the underlying flash media
++ * writes in @c->max_write_size bytes at a time.
++ *
++ * Hence, if UBIFS finds a corrupted node at offset X, it expects only the min.
++ * I/O unit corresponding to offset X to contain corrupted data, all the
++ * following min. I/O units have to contain empty space (all 0xFFs). If this is
++ * not true, the corruption cannot be the result of a power cut, and UBIFS
++ * refuses to mount.
+  */
+ #include <linux/crc32.h>
+@@ -100,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
+       if (!sbuf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
++      err = ubifs_leb_read(c, lnum, sbuf, 0, c->leb_size, 0);
+       if (err && err != -EBADMSG)
+               goto out_free;
+@@ -196,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
+       mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
+       ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
+-      err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
+       if (err)
+               goto out;
+-      err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
+       if (err)
+               goto out;
+ out:
+@@ -257,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
+                               if (cor1)
+                                       goto out_err;
+                               mst = mst1;
+-                      } else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
++                      } else if (offs1 == 0 &&
++                                 c->leb_size - offs2 - sz < sz) {
+                               /* 1st LEB was unmapped and written, 2nd not */
+                               if (cor1)
+                                       goto out_err;
+@@ -300,6 +318,32 @@ int ubifs_recover_master_node(struct ubifs_info *c)
+                       goto out_free;
+               }
+               memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
++
++              /*
++               * We had to recover the master node, which means there was an
++               * unclean reboot. However, it is possible that the master node
++               * is clean at this point, i.e., %UBIFS_MST_DIRTY is not set.
++               * E.g., consider the following chain of events:
++               *
++               * 1. UBIFS was cleanly unmounted, so the master node is clean
++               * 2. UBIFS is being mounted R/W and starts changing the master
++               *    node in the first (%UBIFS_MST_LNUM). A power cut happens,
++               *    so this LEB ends up with some amount of garbage at the
++               *    end.
++               * 3. UBIFS is being mounted R/O. We reach this place and
++               *    recover the master node from the second LEB
++               *    (%UBIFS_MST_LNUM + 1). But we cannot update the media
++               *    because we are being mounted R/O. We have to defer the
++               *    operation.
++               * 4. However, this master node (@c->mst_node) is marked as
++               *    clean (since the step 1). And if we just return, the
++               *    mount code will be confused and won't recover the master
++               *    node when it is re-mounter R/W later.
++               *
++               *    Thus, to force the recovery by marking the master node as
++               *    dirty.
++               */
++              c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+       } else {
+               /* Write the recovered master node */
+               c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;
+@@ -362,8 +406,9 @@ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
+  * @offs: offset to check
+  *
+  * This function returns %1 if @offs was in the last write to the LEB whose data
+- * is in @buf, otherwise %0 is returned.  The determination is made by checking
+- * for subsequent empty space starting from the next @c->min_io_size boundary.
++ * is in @buf, otherwise %0 is returned. The determination is made by checking
++ * for subsequent empty space starting from the next @c->max_write_size
++ * boundary.
+  */
+ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+ {
+@@ -371,10 +416,10 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+       uint8_t *p;
+       /*
+-       * Round up to the next @c->min_io_size boundary i.e. @offs is in the
+-       * last wbuf written. After that should be empty space.
++       * Round up to the next @c->max_write_size boundary i.e. @offs is in
++       * the last wbuf written. After that should be empty space.
+        */
+-      empty_offs = ALIGN(offs + 1, c->min_io_size);
++      empty_offs = ALIGN(offs + 1, c->max_write_size);
+       check_len = c->leb_size - empty_offs;
+       p = buf + empty_offs - offs;
+       return is_empty(p, check_len);
+@@ -429,7 +474,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+       int skip, dlen = le32_to_cpu(ch->len);
+       /* Check for empty space after the corrupt node's common header */
+-      skip = ALIGN(offs + UBIFS_CH_SZ, c->min_io_size) - offs;
++      skip = ALIGN(offs + UBIFS_CH_SZ, c->max_write_size) - offs;
+       if (is_empty(buf + skip, len - skip))
+               return 1;
+       /*
+@@ -441,7 +486,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+               return 0;
+       }
+       /* Now we know the corrupt node's length we can skip over it */
+-      skip = ALIGN(offs + dlen, c->min_io_size) - offs;
++      skip = ALIGN(offs + dlen, c->max_write_size) - offs;
+       /* After which there should be empty space */
+       if (is_empty(buf + skip, len - skip))
+               return 1;
+@@ -495,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+                       int len = ALIGN(endpt, c->min_io_size);
+                       if (start) {
+-                              err = ubi_read(c->ubi, lnum, sleb->buf, 0,
+-                                             start);
++                              err = ubifs_leb_read(c, lnum, sleb->buf, 0,
++                                                   start, 1);
+                               if (err)
+                                       return err;
+                       }
+@@ -510,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+                                       ubifs_pad(c, buf, pad_len);
+                               }
+                       }
+-                      err = ubi_leb_change(c->ubi, lnum, sleb->buf, len,
+-                                           UBI_UNKNOWN);
++                      err = ubifs_leb_change(c, lnum, sleb->buf, len,
++                                             UBI_UNKNOWN);
+                       if (err)
+                               return err;
+               }
+@@ -520,16 +565,15 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ }
+ /**
+- * drop_incomplete_group - drop nodes from an incomplete group.
++ * drop_last_group - drop the last group of nodes.
+  * @sleb: scanned LEB information
+  * @offs: offset of dropped nodes is returned here
+  *
+- * This function returns %1 if nodes are dropped and %0 otherwise.
++ * This is a helper function for 'ubifs_recover_leb()' which drops the last
++ * group of nodes of the scanned LEB.
+  */
+-static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
++static void drop_last_group(struct ubifs_scan_leb *sleb, int *offs)
+ {
+-      int dropped = 0;
+-
+       while (!list_empty(&sleb->nodes)) {
+               struct ubifs_scan_node *snod;
+               struct ubifs_ch *ch;
+@@ -538,15 +582,40 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+                                 list);
+               ch = snod->node;
+               if (ch->group_type != UBIFS_IN_NODE_GROUP)
+-                      return dropped;
+-              dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
++                      break;
++
++              dbg_rcvry("dropping grouped node at %d:%d",
++                        sleb->lnum, snod->offs);
++              *offs = snod->offs;
++              list_del(&snod->list);
++              kfree(snod);
++              sleb->nodes_cnt -= 1;
++      }
++}
++
++/**
++ * drop_last_node - drop the last node.
++ * @sleb: scanned LEB information
++ * @offs: offset of dropped nodes is returned here
++ * @grouped: non-zero if whole group of nodes have to be dropped
++ *
++ * This is a helper function for 'ubifs_recover_leb()' which drops the last
++ * node of the scanned LEB.
++ */
++static void drop_last_node(struct ubifs_scan_leb *sleb, int *offs)
++{
++      struct ubifs_scan_node *snod;
++
++      if (!list_empty(&sleb->nodes)) {
++              snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
++                                list);
++
++              dbg_rcvry("dropping last node at %d:%d", sleb->lnum, snod->offs);
+               *offs = snod->offs;
+               list_del(&snod->list);
+               kfree(snod);
+               sleb->nodes_cnt -= 1;
+-              dropped = 1;
+       }
+-      return dropped;
+ }
+ /**
+@@ -555,7 +624,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+  * @lnum: LEB number
+  * @offs: offset
+  * @sbuf: LEB-sized buffer to use
+- * @grouped: nodes may be grouped for recovery
++ * @jhead: journal head number this LEB belongs to (%-1 if the LEB does not
++ *         belong to any journal head)
+  *
+  * This function does a scan of a LEB, but caters for errors that might have
+  * been caused by the unclean unmount from which we are attempting to recover.
+@@ -563,25 +633,21 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+  * found, and a negative error code in case of failure.
+  */
+ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+-                                       int offs, void *sbuf, int grouped)
++                                       int offs, void *sbuf, int jhead)
+ {
+-      int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
+-      int empty_chkd = 0, start = offs;
++      int ret = 0, err, len = c->leb_size - offs, start = offs, min_io_unit;
++      int grouped = jhead == -1 ? 0 : c->jheads[jhead].grouped;
+       struct ubifs_scan_leb *sleb;
+       void *buf = sbuf + offs;
+-      dbg_rcvry("%d:%d", lnum, offs);
++      dbg_rcvry("%d:%d, jhead %d, grouped %d", lnum, offs, jhead, grouped);
+       sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+       if (IS_ERR(sleb))
+               return sleb;
+-      if (sleb->ecc)
+-              need_clean = 1;
+-
++      ubifs_assert(len >= 8);
+       while (len >= 8) {
+-              int ret;
+-
+               dbg_scan("look at LEB %d:%d (%d bytes left)",
+                        lnum, offs, len);
+@@ -591,8 +657,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+                * Scan quietly until there is an error from which we cannot
+                * recover
+                */
+-              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+-
++              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+               if (ret == SCANNED_A_NODE) {
+                       /* A valid node, and not a padding node */
+                       struct ubifs_ch *ch = buf;
+@@ -605,104 +670,127 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+                       offs += node_len;
+                       buf += node_len;
+                       len -= node_len;
+-                      continue;
+-              }
+-
+-              if (ret > 0) {
++              } else if (ret > 0) {
+                       /* Padding bytes or a valid padding node */
+                       offs += ret;
+                       buf += ret;
+                       len -= ret;
+-                      continue;
+-              }
+-
+-              if (ret == SCANNED_EMPTY_SPACE) {
+-                      if (!is_empty(buf, len)) {
+-                              if (!is_last_write(c, buf, offs))
+-                                      break;
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                      }
+-                      empty_chkd = 1;
++              } else if (ret == SCANNED_EMPTY_SPACE ||
++                         ret == SCANNED_GARBAGE     ||
++                         ret == SCANNED_A_BAD_PAD_NODE ||
++                         ret == SCANNED_A_CORRUPT_NODE) {
++                      dbg_rcvry("found corruption (%d) at %d:%d",
++                                ret, lnum, offs);
+                       break;
+-              }
+-
+-              if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
+-                      if (is_last_write(c, buf, offs)) {
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                              empty_chkd = 1;
+-                              break;
+-                      }
+-
+-              if (ret == SCANNED_A_CORRUPT_NODE)
+-                      if (no_more_nodes(c, buf, len, lnum, offs)) {
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                              empty_chkd = 1;
+-                              break;
+-                      }
+-
+-              if (quiet) {
+-                      /* Redo the last scan but noisily */
+-                      quiet = 0;
+-                      continue;
+-              }
+-
+-              switch (ret) {
+-              case SCANNED_GARBAGE:
+-                      dbg_err("garbage");
+-                      goto corrupted;
+-              case SCANNED_A_CORRUPT_NODE:
+-              case SCANNED_A_BAD_PAD_NODE:
+-                      dbg_err("bad node");
+-                      goto corrupted;
+-              default:
+-                      dbg_err("unknown");
++              } else {
++                      dbg_err("unexpected return value %d", ret);
+                       err = -EINVAL;
+                       goto error;
+               }
+       }
+-      if (!empty_chkd && !is_empty(buf, len)) {
+-              if (is_last_write(c, buf, offs)) {
+-                      clean_buf(c, &buf, lnum, &offs, &len);
+-                      need_clean = 1;
+-              } else {
++      if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE) {
++              if (!is_last_write(c, buf, offs))
++                      goto corrupted_rescan;
++      } else if (ret == SCANNED_A_CORRUPT_NODE) {
++              if (!no_more_nodes(c, buf, len, lnum, offs))
++                      goto corrupted_rescan;
++      } else if (!is_empty(buf, len)) {
++              if (!is_last_write(c, buf, offs)) {
+                       int corruption = first_non_ff(buf, len);
++                      /*
++                       * See header comment for this file for more
++                       * explanations about the reasons we have this check.
++                       */
+                       ubifs_err("corrupt empty space LEB %d:%d, corruption "
+                                 "starts at %d", lnum, offs, corruption);
+                       /* Make sure we dump interesting non-0xFF data */
+-                      offs = corruption;
++                      offs += corruption;
+                       buf += corruption;
+                       goto corrupted;
+               }
+       }
+-      /* Drop nodes from incomplete group */
+-      if (grouped && drop_incomplete_group(sleb, &offs)) {
+-              buf = sbuf + offs;
+-              len = c->leb_size - offs;
+-              clean_buf(c, &buf, lnum, &offs, &len);
+-              need_clean = 1;
+-      }
++      min_io_unit = round_down(offs, c->min_io_size);
++      if (grouped)
++              /*
++               * If nodes are grouped, always drop the incomplete group at
++               * the end.
++               */
++              drop_last_group(sleb, &offs);
+-      if (offs % c->min_io_size) {
+-              clean_buf(c, &buf, lnum, &offs, &len);
+-              need_clean = 1;
++      if (jhead == GCHD) {
++              /*
++               * If this LEB belongs to the GC head then while we are in the
++               * middle of the same min. I/O unit keep dropping nodes. So
++               * basically, what we want is to make sure that the last min.
++               * I/O unit where we saw the corruption is dropped completely
++               * with all the uncorrupted nodes which may possibly sit there.
++               *
++               * In other words, let's name the min. I/O unit where the
++               * corruption starts B, and the previous min. I/O unit A. The
++               * below code tries to deal with a situation when half of B
++               * contains valid nodes or the end of a valid node, and the
++               * second half of B contains corrupted data or garbage. This
++               * means that UBIFS had been writing to B just before the power
++               * cut happened. I do not know how realistic is this scenario
++               * that half of the min. I/O unit had been written successfully
++               * and the other half not, but this is possible in our 'failure
++               * mode emulation' infrastructure at least.
++               *
++               * So what is the problem, why we need to drop those nodes? Why
++               * can't we just clean-up the second half of B by putting a
++               * padding node there? We can, and this works fine with one
++               * exception which was reproduced with power cut emulation
++               * testing and happens extremely rarely.
++               *
++               * Imagine the file-system is full, we run GC which starts
++               * moving valid nodes from LEB X to LEB Y (obviously, LEB Y is
++               * the current GC head LEB). The @c->gc_lnum is -1, which means
++               * that GC will retain LEB X and will try to continue. Imagine
++               * that LEB X is currently the dirtiest LEB, and the amount of
++               * used space in LEB Y is exactly the same as amount of free
++               * space in LEB X.
++               *
++               * And a power cut happens when nodes are moved from LEB X to
++               * LEB Y. We are here trying to recover LEB Y which is the GC
++               * head LEB. We find the min. I/O unit B as described above.
++               * Then we clean-up LEB Y by padding min. I/O unit. And later
++               * 'ubifs_rcvry_gc_commit()' function fails, because it cannot
++               * find a dirty LEB which could be GC'd into LEB Y! Even LEB X
++               * does not match because the amount of valid nodes there does
++               * not fit the free space in LEB Y any more! And this is
++               * because of the padding node which we added to LEB Y. The
++               * user-visible effect of this which I once observed and
++               * analysed is that we cannot mount the file-system with
++               * -ENOSPC error.
++               *
++               * So obviously, to make sure that situation does not happen we
++               * should free min. I/O unit B in LEB Y completely and the last
++               * used min. I/O unit in LEB Y should be A. This is basically
++               * what the below code tries to do.
++               */
++              while (offs > min_io_unit)
++                      drop_last_node(sleb, &offs);
+       }
++      buf = sbuf + offs;
++      len = c->leb_size - offs;
++
++      clean_buf(c, &buf, lnum, &offs, &len);
+       ubifs_end_scan(c, sleb, lnum, offs);
+-      if (need_clean) {
+-              err = fix_unclean_leb(c, sleb, start);
+-              if (err)
+-                      goto error;
+-      }
++      err = fix_unclean_leb(c, sleb, start);
++      if (err)
++              goto error;
+       return sleb;
++corrupted_rescan:
++      /* Re-scan the corrupted data with verbose messages */
++      dbg_err("corruptio %d", ret);
++      ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ corrupted:
+       ubifs_scanned_corruption(c, lnum, offs, buf);
+       err = -EUCLEAN;
+@@ -733,7 +821,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
+               return -ENOMEM;
+       if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
+               goto out_err;
+-      err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
++      err = ubifs_leb_read(c, lnum, (void *)cs_node, offs,
++                           UBIFS_CS_NODE_SZ, 0);
+       if (err && err != -EBADMSG)
+               goto out_free;
+       ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
+@@ -819,7 +908,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+               }
+               ubifs_scan_destroy(sleb);
+       }
+-      return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
++      return ubifs_recover_leb(c, lnum, offs, sbuf, -1);
+ }
+ /**
+@@ -833,15 +922,10 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+-                      void *sbuf)
++static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
+ {
+-      int len, err;
++      int len = c->max_write_size, err;
+-      if (c->min_io_size > 1)
+-              len = c->min_io_size;
+-      else
+-              len = 512;
+       if (offs + len > c->leb_size)
+               len = c->leb_size - offs;
+@@ -849,15 +933,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+               return 0;
+       /* Read at the head location and check it is empty flash */
+-      err = ubi_read(c->ubi, lnum, sbuf, offs, len);
++      err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
+       if (err || !is_empty(sbuf, len)) {
+               dbg_rcvry("cleaning head at %d:%d", lnum, offs);
+               if (offs == 0)
+                       return ubifs_leb_unmap(c, lnum);
+-              err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
++              err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
+               if (err)
+                       return err;
+-              return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
++              return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
+       }
+       return 0;
+@@ -880,7 +964,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
++int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
+ {
+       int err;
+@@ -900,7 +984,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+ }
+ /**
+- *  clean_an_unclean_leb - read and write a LEB to remove corruption.
++ * clean_an_unclean_leb - read and write a LEB to remove corruption.
+  * @c: UBIFS file-system description object
+  * @ucleb: unclean LEB information
+  * @sbuf: LEB-sized buffer to use
+@@ -911,7 +995,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-static int clean_an_unclean_leb(const struct ubifs_info *c,
++static int clean_an_unclean_leb(struct ubifs_info *c,
+                               struct ubifs_unclean_leb *ucleb, void *sbuf)
+ {
+       int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
+@@ -927,7 +1011,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+               return 0;
+       }
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
+       if (err && err != -EBADMSG)
+               return err;
+@@ -987,7 +1071,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+       }
+       /* Write back the LEB atomically */
+-      err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
++      err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
+       if (err)
+               return err;
+@@ -1007,7 +1091,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
++int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
+ {
+       dbg_rcvry("recovery");
+       while (!list_empty(&c->unclean_leb_list)) {
+@@ -1026,6 +1110,53 @@ int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
+ }
+ /**
++ * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty
++ * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns
++ * zero in case of success and a negative error code in case of failure.
++ */
++static int grab_empty_leb(struct ubifs_info *c)
++{
++      int lnum, err;
++
++      /*
++       * Note, it is very important to first search for an empty LEB and then
++       * run the commit, not vice-versa. The reason is that there might be
++       * only one empty LEB at the moment, the one which has been the
++       * @c->gc_lnum just before the power cut happened. During the regular
++       * UBIFS operation (not now) @c->gc_lnum is marked as "taken", so no
++       * one but GC can grab it. But at this moment this single empty LEB is
++       * not marked as taken, so if we run commit - what happens? Right, the
++       * commit will grab it and write the index there. Remember that the
++       * index always expands as long as there is free space, and it only
++       * starts consolidating when we run out of space.
++       *
++       * IOW, if we run commit now, we might not be able to find a free LEB
++       * after this.
++       */
++      lnum = ubifs_find_free_leb_for_idx(c);
++      if (lnum < 0) {
++              dbg_err("could not find an empty LEB");
++              dbg_dump_lprops(c);
++              dbg_dump_budg(c, &c->bi);
++              return lnum;
++      }
++
++      /* Reset the index flag */
++      err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
++                                LPROPS_INDEX, 0);
++      if (err)
++              return err;
++
++      c->gc_lnum = lnum;
++      dbg_rcvry("found empty LEB %d, run commit", lnum);
++
++      return ubifs_run_commit(c);
++}
++
++/**
+  * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit.
+  * @c: UBIFS file-system description object
+  *
+@@ -1047,71 +1178,26 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+ {
+       struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
+       struct ubifs_lprops lp;
+-      int lnum, err;
++      int err;
++
++      dbg_rcvry("GC head LEB %d, offs %d", wbuf->lnum, wbuf->offs);
+       c->gc_lnum = -1;
+-      if (wbuf->lnum == -1) {
+-              dbg_rcvry("no GC head LEB");
+-              goto find_free;
+-      }
+-      /*
+-       * See whether the used space in the dirtiest LEB fits in the GC head
+-       * LEB.
+-       */
+-      if (wbuf->offs == c->leb_size) {
+-              dbg_rcvry("no room in GC head LEB");
+-              goto find_free;
+-      }
++      if (wbuf->lnum == -1 || wbuf->offs == c->leb_size)
++              return grab_empty_leb(c);
++
+       err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
+       if (err) {
+-              /*
+-               * There are no dirty or empty LEBs subject to here being
+-               * enough for the index. Try to use
+-               * 'ubifs_find_free_leb_for_idx()', which will return any empty
+-               * LEBs (ignoring index requirements). If the index then
+-               * doesn't have enough LEBs the recovery commit will fail -
+-               * which is the  same result anyway i.e. recovery fails. So
+-               * there is no problem ignoring index  requirements and just
+-               * grabbing a free LEB since we have already established there
+-               * is not a dirty LEB we could have used instead.
+-               */
+-              if (err == -ENOSPC) {
+-                      dbg_rcvry("could not find a dirty LEB");
+-                      goto find_free;
+-              }
+-              return err;
+-      }
+-      ubifs_assert(!(lp.flags & LPROPS_INDEX));
+-      lnum = lp.lnum;
+-      if (lp.free + lp.dirty == c->leb_size) {
+-              /* An empty LEB was returned */
+-              if (lp.free != c->leb_size) {
+-                      err = ubifs_change_one_lp(c, lnum, c->leb_size,
+-                                                0, 0, 0, 0);
+-                      if (err)
+-                              return err;
+-              }
+-              err = ubifs_leb_unmap(c, lnum);
+-              if (err)
+-                      return err;
+-              c->gc_lnum = lnum;
+-              dbg_rcvry("allocated LEB %d for GC", lnum);
+-              /* Run the commit */
+-              dbg_rcvry("committing");
+-              return ubifs_run_commit(c);
+-      }
+-      /*
+-       * There was no empty LEB so the used space in the dirtiest LEB must fit
+-       * in the GC head LEB.
+-       */
+-      if (lp.free + lp.dirty < wbuf->offs) {
+-              dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d",
+-                        lnum, wbuf->lnum, wbuf->offs);
+-              err = ubifs_return_leb(c, lnum);
+-              if (err)
++              if (err != -ENOSPC)
+                       return err;
+-              goto find_free;
++
++              dbg_rcvry("could not find a dirty LEB");
++              return grab_empty_leb(c);
+       }
++
++      ubifs_assert(!(lp.flags & LPROPS_INDEX));
++      ubifs_assert(lp.free + lp.dirty >= wbuf->offs);
++
+       /*
+        * We run the commit before garbage collection otherwise subsequent
+        * mounts will see the GC and orphan deletion in a different order.
+@@ -1120,11 +1206,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+       err = ubifs_run_commit(c);
+       if (err)
+               return err;
+-      /*
+-       * The data in the dirtiest LEB fits in the GC head LEB, so do the GC
+-       * - use locking to keep 'ubifs_assert()' happy.
+-       */
+-      dbg_rcvry("GC'ing LEB %d", lnum);
++
++      dbg_rcvry("GC'ing LEB %d", lp.lnum);
+       mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
+       err = ubifs_garbage_collect_leb(c, &lp);
+       if (err >= 0) {
+@@ -1140,37 +1223,17 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+                       err = -EINVAL;
+               return err;
+       }
+-      if (err != LEB_RETAINED) {
+-              dbg_err("GC returned %d", err);
++
++      ubifs_assert(err == LEB_RETAINED);
++      if (err != LEB_RETAINED)
+               return -EINVAL;
+-      }
++
+       err = ubifs_leb_unmap(c, c->gc_lnum);
+       if (err)
+               return err;
+-      dbg_rcvry("allocated LEB %d for GC", lnum);
+-      return 0;
+-find_free:
+-      /*
+-       * There is no GC head LEB or the free space in the GC head LEB is too
+-       * small, or there are not dirty LEBs. Allocate gc_lnum by calling
+-       * 'ubifs_find_free_leb_for_idx()' so GC is not run.
+-       */
+-      lnum = ubifs_find_free_leb_for_idx(c);
+-      if (lnum < 0) {
+-              dbg_err("could not find an empty LEB");
+-              return lnum;
+-      }
+-      /* And reset the index flag */
+-      err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+-                                LPROPS_INDEX, 0);
+-      if (err)
+-              return err;
+-      c->gc_lnum = lnum;
+-      dbg_rcvry("allocated LEB %d for GC", lnum);
+-      /* Run the commit */
+-      dbg_rcvry("committing");
+-      return ubifs_run_commit(c);
++      dbg_rcvry("allocated LEB %d for GC", lp.lnum);
++      return 0;
+ }
+ /**
+@@ -1393,7 +1456,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
+       if (i_size >= e->d_size)
+               return 0;
+       /* Read the LEB */
+-      err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size);
++      err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
+       if (err)
+               goto out;
+       /* Change the size field and recalculate the CRC */
+@@ -1409,10 +1472,10 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
+               len -= 1;
+       len = ALIGN(len + 1, c->min_io_size);
+       /* Atomically write the fixed LEB back again */
+-      err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
++      err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
+       if (err)
+               goto out;
+-      dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ",
++      dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
+                 (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
+       return 0;
+@@ -1461,20 +1524,27 @@ int ubifs_recover_size(struct ubifs_info *c)
+                               e->i_size = le64_to_cpu(ino->size);
+                       }
+               }
++
+               if (e->exists && e->i_size < e->d_size) {
+-                      if (!e->inode && c->ro_mount) {
++                      if (c->ro_mount) {
+                               /* Fix the inode size and pin it in memory */
+                               struct inode *inode;
++                              struct ubifs_inode *ui;
++
++                              ubifs_assert(!e->inode);
+                               inode = ubifs_iget(c->vfs_sb, e->inum);
+                               if (IS_ERR(inode))
+                                       return PTR_ERR(inode);
++
++                              ui = ubifs_inode(inode);
+                               if (inode->i_size < e->d_size) {
+                                       dbg_rcvry("ino %lu size %lld -> %lld",
+                                                 (unsigned long)e->inum,
+-                                                e->d_size, inode->i_size);
++                                                inode->i_size, e->d_size);
+                                       inode->i_size = e->d_size;
+-                                      ubifs_inode(inode)->ui_size = e->d_size;
++                                      ui->ui_size = e->d_size;
++                                      ui->synced_i_size = e->d_size;
+                                       e->inode = inode;
+                                       this = rb_next(this);
+                                       continue;
+@@ -1489,9 +1559,11 @@ int ubifs_recover_size(struct ubifs_info *c)
+                                       iput(e->inode);
+                       }
+               }
++
+               this = rb_next(this);
+               rb_erase(&e->rb, &c->size_tree);
+               kfree(e);
+       }
++
+       return 0;
+ }
+diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
+index eed0fcf..b007637 100644
+--- a/fs/ubifs/replay.c
++++ b/fs/ubifs/replay.c
+@@ -33,43 +33,32 @@
+  */
+ #include "ubifs.h"
+-
+-/*
+- * Replay flags.
+- *
+- * REPLAY_DELETION: node was deleted
+- * REPLAY_REF: node is a reference node
+- */
+-enum {
+-      REPLAY_DELETION = 1,
+-      REPLAY_REF = 2,
+-};
++#include <linux/list_sort.h>
+ /**
+- * struct replay_entry - replay tree entry.
++ * struct replay_entry - replay list entry.
+  * @lnum: logical eraseblock number of the node
+  * @offs: node offset
+  * @len: node length
++ * @deletion: non-zero if this entry corresponds to a node deletion
+  * @sqnum: node sequence number
+- * @flags: replay flags
+- * @rb: links the replay tree
++ * @list: links the replay list
+  * @key: node key
+  * @nm: directory entry name
+  * @old_size: truncation old size
+  * @new_size: truncation new size
+- * @free: amount of free space in a bud
+- * @dirty: amount of dirty space in a bud from padding and deletion nodes
+  *
+- * UBIFS journal replay must compare node sequence numbers, which means it must
+- * build a tree of node information to insert into the TNC.
++ * The replay process first scans all buds and builds the replay list, then
++ * sorts the replay list in nodes sequence number order, and then inserts all
++ * the replay entries to the TNC.
+  */
+ struct replay_entry {
+       int lnum;
+       int offs;
+       int len;
++      unsigned int deletion:1;
+       unsigned long long sqnum;
+-      int flags;
+-      struct rb_node rb;
++      struct list_head list;
+       union ubifs_key key;
+       union {
+               struct qstr nm;
+@@ -77,10 +66,6 @@ struct replay_entry {
+                       loff_t old_size;
+                       loff_t new_size;
+               };
+-              struct {
+-                      int free;
+-                      int dirty;
+-              };
+       };
+ };
+@@ -88,57 +73,64 @@ struct replay_entry {
+  * struct bud_entry - entry in the list of buds to replay.
+  * @list: next bud in the list
+  * @bud: bud description object
+- * @free: free bytes in the bud
+  * @sqnum: reference node sequence number
++ * @free: free bytes in the bud
++ * @dirty: dirty bytes in the bud
+  */
+ struct bud_entry {
+       struct list_head list;
+       struct ubifs_bud *bud;
+-      int free;
+       unsigned long long sqnum;
++      int free;
++      int dirty;
+ };
+ /**
+  * set_bud_lprops - set free and dirty space used by a bud.
+  * @c: UBIFS file-system description object
+- * @r: replay entry of bud
++ * @b: bud entry which describes the bud
++ *
++ * This function makes sure the LEB properties of bud @b are set correctly
++ * after the replay. Returns zero in case of success and a negative error code
++ * in case of failure.
+  */
+-static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
++static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
+ {
+       const struct ubifs_lprops *lp;
+       int err = 0, dirty;
+       ubifs_get_lprops(c);
+-      lp = ubifs_lpt_lookup_dirty(c, r->lnum);
++      lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
+       if (IS_ERR(lp)) {
+               err = PTR_ERR(lp);
+               goto out;
+       }
+       dirty = lp->dirty;
+-      if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
++      if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+               /*
+                * The LEB was added to the journal with a starting offset of
+                * zero which means the LEB must have been empty. The LEB
+-               * property values should be lp->free == c->leb_size and
+-               * lp->dirty == 0, but that is not the case. The reason is that
+-               * the LEB was garbage collected. The garbage collector resets
+-               * the free and dirty space without recording it anywhere except
+-               * lprops, so if there is not a commit then lprops does not have
+-               * that information next time the file system is mounted.
++               * property values should be @lp->free == @c->leb_size and
++               * @lp->dirty == 0, but that is not the case. The reason is that
++               * the LEB had been garbage collected before it became the bud,
++               * and there was not commit inbetween. The garbage collector
++               * resets the free and dirty space without recording it
++               * anywhere except lprops, so if there was no commit then
++               * lprops does not have that information.
+                *
+                * We do not need to adjust free space because the scan has told
+                * us the exact value which is recorded in the replay entry as
+-               * r->free.
++               * @b->free.
+                *
+                * However we do need to subtract from the dirty space the
+                * amount of space that the garbage collector reclaimed, which
+                * is the whole LEB minus the amount of space that was free.
+                */
+-              dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++              dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
+                       lp->free, lp->dirty);
+-              dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++              dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
+                       lp->free, lp->dirty);
+               dirty -= c->leb_size - lp->free;
+               /*
+@@ -150,21 +142,48 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+                */
+               if (dirty != 0)
+                       dbg_msg("LEB %d lp: %d free %d dirty "
+-                              "replay: %d free %d dirty", r->lnum, lp->free,
+-                              lp->dirty, r->free, r->dirty);
++                              "replay: %d free %d dirty", b->bud->lnum,
++                              lp->free, lp->dirty, b->free, b->dirty);
+       }
+-      lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
++      lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
+                            lp->flags | LPROPS_TAKEN, 0);
+       if (IS_ERR(lp)) {
+               err = PTR_ERR(lp);
+               goto out;
+       }
++
++      /* Make sure the journal head points to the latest bud */
++      err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
++                                   b->bud->lnum, c->leb_size - b->free,
++                                   UBI_SHORTTERM);
++
+ out:
+       ubifs_release_lprops(c);
+       return err;
+ }
+ /**
++ * set_buds_lprops - set free and dirty space for all replayed buds.
++ * @c: UBIFS file-system description object
++ *
++ * This function sets LEB properties for all replayed buds. Returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++static int set_buds_lprops(struct ubifs_info *c)
++{
++      struct bud_entry *b;
++      int err;
++
++      list_for_each_entry(b, &c->replay_buds, list) {
++              err = set_bud_lprops(c, b);
++              if (err)
++                      return err;
++      }
++
++      return 0;
++}
++
++/**
+  * trun_remove_range - apply a replay entry for a truncation to the TNC.
+  * @c: UBIFS file-system description object
+  * @r: replay entry of truncation
+@@ -200,24 +219,22 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
+  */
+ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+ {
+-      int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
++      int err;
+-      dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
+-              r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
++      dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ",
++               r->lnum, r->offs, r->len, r->deletion, r->sqnum);
+       /* Set c->replay_sqnum to help deal with dangling branches. */
+       c->replay_sqnum = r->sqnum;
+-      if (r->flags & REPLAY_REF)
+-              err = set_bud_lprops(c, r);
+-      else if (is_hash_key(c, &r->key)) {
+-              if (deletion)
++      if (is_hash_key(c, &r->key)) {
++              if (r->deletion)
+                       err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
+               else
+                       err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
+                                              r->len, &r->nm);
+       } else {
+-              if (deletion)
++              if (r->deletion)
+                       switch (key_type(c, &r->key)) {
+                       case UBIFS_INO_KEY:
+                       {
+@@ -240,7 +257,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+                       return err;
+               if (c->need_recovery)
+-                      err = ubifs_recover_size_accum(c, &r->key, deletion,
++                      err = ubifs_recover_size_accum(c, &r->key, r->deletion,
+                                                      r->new_size);
+       }
+@@ -248,68 +265,77 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+ }
+ /**
+- * destroy_replay_tree - destroy the replay.
+- * @c: UBIFS file-system description object
++ * replay_entries_cmp - compare 2 replay entries.
++ * @priv: UBIFS file-system description object
++ * @a: first replay entry
++ * @a: second replay entry
+  *
+- * Destroy the replay tree.
++ * This is a comparios function for 'list_sort()' which compares 2 replay
++ * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has
++ * greater sequence number and %-1 otherwise.
+  */
+-static void destroy_replay_tree(struct ubifs_info *c)
++static int replay_entries_cmp(void *priv, struct list_head *a,
++                            struct list_head *b)
+ {
+-      struct rb_node *this = c->replay_tree.rb_node;
+-      struct replay_entry *r;
+-
+-      while (this) {
+-              if (this->rb_left) {
+-                      this = this->rb_left;
+-                      continue;
+-              } else if (this->rb_right) {
+-                      this = this->rb_right;
+-                      continue;
+-              }
+-              r = rb_entry(this, struct replay_entry, rb);
+-              this = rb_parent(this);
+-              if (this) {
+-                      if (this->rb_left == &r->rb)
+-                              this->rb_left = NULL;
+-                      else
+-                              this->rb_right = NULL;
+-              }
+-              if (is_hash_key(c, &r->key))
+-                      kfree(r->nm.name);
+-              kfree(r);
+-      }
+-      c->replay_tree = RB_ROOT;
++      struct replay_entry *ra, *rb;
++
++      cond_resched();
++      if (a == b)
++              return 0;
++
++      ra = list_entry(a, struct replay_entry, list);
++      rb = list_entry(b, struct replay_entry, list);
++      ubifs_assert(ra->sqnum != rb->sqnum);
++      if (ra->sqnum > rb->sqnum)
++              return 1;
++      return -1;
+ }
+ /**
+- * apply_replay_tree - apply the replay tree to the TNC.
++ * apply_replay_list - apply the replay list to the TNC.
+  * @c: UBIFS file-system description object
+  *
+- * Apply the replay tree.
+- * Returns zero in case of success and a negative error code in case of
+- * failure.
++ * Apply all entries in the replay list to the TNC. Returns zero in case of
++ * success and a negative error code in case of failure.
+  */
+-static int apply_replay_tree(struct ubifs_info *c)
++static int apply_replay_list(struct ubifs_info *c)
+ {
+-      struct rb_node *this = rb_first(&c->replay_tree);
++      struct replay_entry *r;
++      int err;
+-      while (this) {
+-              struct replay_entry *r;
+-              int err;
++      list_sort(c, &c->replay_list, &replay_entries_cmp);
++      list_for_each_entry(r, &c->replay_list, list) {
+               cond_resched();
+-              r = rb_entry(this, struct replay_entry, rb);
+               err = apply_replay_entry(c, r);
+               if (err)
+                       return err;
+-              this = rb_next(this);
+       }
++
+       return 0;
+ }
+ /**
+- * insert_node - insert a node to the replay tree.
++ * destroy_replay_list - destroy the replay.
++ * @c: UBIFS file-system description object
++ *
++ * Destroy the replay list.
++ */
++static void destroy_replay_list(struct ubifs_info *c)
++{
++      struct replay_entry *r, *tmp;
++
++      list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
++              if (is_hash_key(c, &r->key))
++                      kfree(r->nm.name);
++              list_del(&r->list);
++              kfree(r);
++      }
++}
++
++/**
++ * insert_node - insert a node to the replay list
+  * @c: UBIFS file-system description object
+  * @lnum: node logical eraseblock number
+  * @offs: node offset
+@@ -321,39 +347,25 @@ static int apply_replay_tree(struct ubifs_info *c)
+  * @old_size: truncation old size
+  * @new_size: truncation new size
+  *
+- * This function inserts a scanned non-direntry node to the replay tree. The
+- * replay tree is an RB-tree containing @struct replay_entry elements which are
+- * indexed by the sequence number. The replay tree is applied at the very end
+- * of the replay process. Since the tree is sorted in sequence number order,
+- * the older modifications are applied first. This function returns zero in
+- * case of success and a negative error code in case of failure.
++ * This function inserts a scanned non-direntry node to the replay list. The
++ * replay list contains @struct replay_entry elements, and we sort this list in
++ * sequence number order before applying it. The replay list is applied at the
++ * very end of the replay process. Since the list is sorted in sequence number
++ * order, the older modifications are applied first. This function returns zero
++ * in case of success and a negative error code in case of failure.
+  */
+ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+                      union ubifs_key *key, unsigned long long sqnum,
+                      int deletion, int *used, loff_t old_size,
+                      loff_t new_size)
+ {
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+       struct replay_entry *r;
++      dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
++
+       if (key_inum(c, key) >= c->highest_inum)
+               c->highest_inum = key_inum(c, key);
+-      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              } else if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay");
+-              return -EINVAL;
+-      }
+-
+       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+       if (!r)
+               return -ENOMEM;
+@@ -363,19 +375,18 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+       r->lnum = lnum;
+       r->offs = offs;
+       r->len = len;
++      r->deletion = !!deletion;
+       r->sqnum = sqnum;
+-      r->flags = (deletion ? REPLAY_DELETION : 0);
++      key_copy(c, key, &r->key);
+       r->old_size = old_size;
+       r->new_size = new_size;
+-      key_copy(c, key, &r->key);
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
++      list_add_tail(&r->list, &c->replay_list);
+       return 0;
+ }
+ /**
+- * insert_dent - insert a directory entry node into the replay tree.
++ * insert_dent - insert a directory entry node into the replay list.
+  * @c: UBIFS file-system description object
+  * @lnum: node logical eraseblock number
+  * @offs: node offset
+@@ -387,43 +398,25 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+  * @deletion: non-zero if this is a deletion
+  * @used: number of bytes in use in a LEB
+  *
+- * This function inserts a scanned directory entry node to the replay tree.
+- * Returns zero in case of success and a negative error code in case of
+- * failure.
+- *
+- * This function is also used for extended attribute entries because they are
+- * implemented as directory entry nodes.
++ * This function inserts a scanned directory entry node or an extended
++ * attribute entry to the replay list. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+                      union ubifs_key *key, const char *name, int nlen,
+                      unsigned long long sqnum, int deletion, int *used)
+ {
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+       struct replay_entry *r;
+       char *nbuf;
++      dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
+       if (key_inum(c, key) >= c->highest_inum)
+               c->highest_inum = key_inum(c, key);
+-      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              }
+-              if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay");
+-              return -EINVAL;
+-      }
+-
+       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+       if (!r)
+               return -ENOMEM;
++
+       nbuf = kmalloc(nlen + 1, GFP_KERNEL);
+       if (!nbuf) {
+               kfree(r);
+@@ -435,17 +428,15 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+       r->lnum = lnum;
+       r->offs = offs;
+       r->len = len;
++      r->deletion = !!deletion;
+       r->sqnum = sqnum;
++      key_copy(c, key, &r->key);
+       r->nm.len = nlen;
+       memcpy(nbuf, name, nlen);
+       nbuf[nlen] = '\0';
+       r->nm.name = nbuf;
+-      r->flags = (deletion ? REPLAY_DELETION : 0);
+-      key_copy(c, key, &r->key);
+-      ubifs_assert(!*p);
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
++      list_add_tail(&r->list, &c->replay_list);
+       return 0;
+ }
+@@ -482,29 +473,90 @@ int ubifs_validate_entry(struct ubifs_info *c,
+ }
+ /**
++ * is_last_bud - check if the bud is the last in the journal head.
++ * @c: UBIFS file-system description object
++ * @bud: bud description object
++ *
++ * This function checks if bud @bud is the last bud in its journal head. This
++ * information is then used by 'replay_bud()' to decide whether the bud can
++ * have corruptions or not. Indeed, only last buds can be corrupted by power
++ * cuts. Returns %1 if this is the last bud, and %0 if not.
++ */
++static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
++{
++      struct ubifs_jhead *jh = &c->jheads[bud->jhead];
++      struct ubifs_bud *next;
++      uint32_t data;
++      int err;
++
++      if (list_is_last(&bud->list, &jh->buds_list))
++              return 1;
++
++      /*
++       * The following is a quirk to make sure we work correctly with UBIFS
++       * images used with older UBIFS.
++       *
++       * Normally, the last bud will be the last in the journal head's list
++       * of bud. However, there is one exception if the UBIFS image belongs
++       * to older UBIFS. This is fairly unlikely: one would need to use old
++       * UBIFS, then have a power cut exactly at the right point, and then
++       * try to mount this image with new UBIFS.
++       *
++       * The exception is: it is possible to have 2 buds A and B, A goes
++       * before B, and B is the last, bud B is contains no data, and bud A is
++       * corrupted at the end. The reason is that in older versions when the
++       * journal code switched the next bud (from A to B), it first added a
++       * log reference node for the new bud (B), and only after this it
++       * synchronized the write-buffer of current bud (A). But later this was
++       * changed and UBIFS started to always synchronize the write-buffer of
++       * the bud (A) before writing the log reference for the new bud (B).
++       *
++       * But because older UBIFS always synchronized A's write-buffer before
++       * writing to B, we can recognize this exceptional situation but
++       * checking the contents of bud B - if it is empty, then A can be
++       * treated as the last and we can recover it.
++       *
++       * TODO: remove this piece of code in a couple of years (today it is
++       * 16.05.2011).
++       */
++      next = list_entry(bud->list.next, struct ubifs_bud, list);
++      if (!list_is_last(&next->list, &jh->buds_list))
++              return 0;
++
++      err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
++      if (err)
++              return 0;
++
++      return data == 0xFFFFFFFF;
++}
++
++/**
+  * replay_bud - replay a bud logical eraseblock.
+  * @c: UBIFS file-system description object
+- * @lnum: bud logical eraseblock number to replay
+- * @offs: bud start offset
+- * @jhead: journal head to which this bud belongs
+- * @free: amount of free space in the bud is returned here
+- * @dirty: amount of dirty space from padding and deletion nodes is returned
+- * here
++ * @b: bud entry which describes the bud
+  *
+- * This function returns zero in case of success and a negative error code in
+- * case of failure.
++ * This function replays bud @bud, recovers it if needed, and adds all nodes
++ * from this bud to the replay list. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+-static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+-                    int *free, int *dirty)
++static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
+ {
+-      int err = 0, used = 0;
++      int is_last = is_last_bud(c, b->bud);
++      int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
+-      struct ubifs_bud *bud;
+-      dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
+-      if (c->need_recovery)
+-              sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
++      dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d",
++              lnum, b->bud->jhead, offs, is_last);
++
++      if (c->need_recovery && is_last)
++              /*
++               * Recover only last LEBs in the journal heads, because power
++               * cuts may cause corruptions only in these LEBs, because only
++               * these LEBs could possibly be written to at the power cut
++               * time.
++               */
++              sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead);
+       else
+               sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
+       if (IS_ERR(sleb))
+@@ -620,19 +672,13 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+                       goto out;
+       }
+-      bud = ubifs_search_bud(c, lnum);
+-      if (!bud)
+-              BUG();
+-
++      ubifs_assert(ubifs_search_bud(c, lnum));
+       ubifs_assert(sleb->endpt - offs >= used);
+       ubifs_assert(sleb->endpt % c->min_io_size == 0);
+-      if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount)
+-              err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum,
+-                                           sleb->endpt, UBI_SHORTTERM);
+-
+-      *dirty = sleb->endpt - offs - used;
+-      *free = c->leb_size - sleb->endpt;
++      b->dirty = sleb->endpt - offs - used;
++      b->free = c->leb_size - sleb->endpt;
++      dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, b->dirty, b->free);
+ out:
+       ubifs_scan_destroy(sleb);
+@@ -646,55 +692,6 @@ out_dump:
+ }
+ /**
+- * insert_ref_node - insert a reference node to the replay tree.
+- * @c: UBIFS file-system description object
+- * @lnum: node logical eraseblock number
+- * @offs: node offset
+- * @sqnum: sequence number
+- * @free: amount of free space in bud
+- * @dirty: amount of dirty space from padding and deletion nodes
+- *
+- * This function inserts a reference node to the replay tree and returns zero
+- * in case of success or a negative error code in case of failure.
+- */
+-static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+-                         unsigned long long sqnum, int free, int dirty)
+-{
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+-      struct replay_entry *r;
+-
+-      dbg_mnt("add ref LEB %d:%d", lnum, offs);
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              } else if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay tree");
+-              return -EINVAL;
+-      }
+-
+-      r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+-      if (!r)
+-              return -ENOMEM;
+-
+-      r->lnum = lnum;
+-      r->offs = offs;
+-      r->sqnum = sqnum;
+-      r->flags = REPLAY_REF;
+-      r->free = free;
+-      r->dirty = dirty;
+-
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
+-      return 0;
+-}
+-
+-/**
+  * replay_buds - replay all buds.
+  * @c: UBIFS file-system description object
+  *
+@@ -704,17 +701,16 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+ static int replay_buds(struct ubifs_info *c)
+ {
+       struct bud_entry *b;
+-      int err, uninitialized_var(free), uninitialized_var(dirty);
++      int err;
++      unsigned long long prev_sqnum = 0;
+       list_for_each_entry(b, &c->replay_buds, list) {
+-              err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
+-                               &free, &dirty);
+-              if (err)
+-                      return err;
+-              err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
+-                                    free, dirty);
++              err = replay_bud(c, b);
+               if (err)
+                       return err;
++
++              ubifs_assert(b->sqnum > prev_sqnum);
++              prev_sqnum = b->sqnum;
+       }
+       return 0;
+@@ -1054,25 +1050,29 @@ int ubifs_replay_journal(struct ubifs_info *c)
+       if (err)
+               goto out;
+-      err = apply_replay_tree(c);
++      err = apply_replay_list(c);
++      if (err)
++              goto out;
++
++      err = set_buds_lprops(c);
+       if (err)
+               goto out;
+       /*
+-       * UBIFS budgeting calculations use @c->budg_uncommitted_idx variable
+-       * to roughly estimate index growth. Things like @c->min_idx_lebs
++       * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
++       * to roughly estimate index growth. Things like @c->bi.min_idx_lebs
+        * depend on it. This means we have to initialize it to make sure
+        * budgeting works properly.
+        */
+-      c->budg_uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
+-      c->budg_uncommitted_idx *= c->max_idx_node_sz;
++      c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
++      c->bi.uncommitted_idx *= c->max_idx_node_sz;
+       ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
+       dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
+               "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
+               (unsigned long)c->highest_inum);
+ out:
+-      destroy_replay_tree(c);
++      destroy_replay_list(c);
+       destroy_bud_list(c);
+       c->replaying = 0;
+       return err;
+diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
+index bf31b47..771f7fb 100644
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -247,7 +247,7 @@ static int create_default_filesystem(struct ubifs_info *c)
+       mst->total_dirty = cpu_to_le64(tmp64);
+       /*  The indexing LEB does not contribute to dark space */
+-      tmp64 = (c->main_lebs - 1) * c->dark_wm;
++      tmp64 = ((long long)(c->main_lebs - 1) * c->dark_wm);
+       mst->total_dark = cpu_to_le64(tmp64);
+       mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
+@@ -410,13 +410,23 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+       }
+       if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
+-              err = 7;
++              ubifs_err("too few main LEBs count %d, must be at least %d",
++                        c->main_lebs, UBIFS_MIN_MAIN_LEBS);
+               goto failed;
+       }
+-      if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
+-          c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
+-              err = 8;
++      max_bytes = (long long)c->leb_size * UBIFS_MIN_BUD_LEBS;
++      if (c->max_bud_bytes < max_bytes) {
++              ubifs_err("too small journal (%lld bytes), must be at least "
++                        "%lld bytes",  c->max_bud_bytes, max_bytes);
++              goto failed;
++      }
++
++      max_bytes = (long long)c->leb_size * c->main_lebs;
++      if (c->max_bud_bytes > max_bytes) {
++              ubifs_err("too large journal size (%lld bytes), only %lld bytes"
++                        "available in the main area",
++                        c->max_bud_bytes, max_bytes);
+               goto failed;
+       }
+@@ -450,7 +460,6 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+               goto failed;
+       }
+-      max_bytes = c->main_lebs * (long long)c->leb_size;
+       if (c->rp_size < 0 || max_bytes < c->rp_size) {
+               err = 14;
+               goto failed;
+@@ -475,7 +484,8 @@ failed:
+  * @c: UBIFS file-system description object
+  *
+  * This function returns a pointer to the superblock node or a negative error
+- * code.
++ * code. Note, the user of this function is responsible of kfree()'ing the
++ * returned superblock buffer.
+  */
+ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
+ {
+@@ -616,6 +626,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
+       c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
+       memcpy(&c->uuid, &sup->uuid, 16);
+       c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
++      c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+       /* Automatically increase file system size to the maximum size */
+       c->old_leb_cnt = c->leb_cnt;
+@@ -650,3 +661,152 @@ out:
+       kfree(sup);
+       return err;
+ }
++
++/**
++ * fixup_leb - fixup/unmap an LEB containing free space.
++ * @c: UBIFS file-system description object
++ * @lnum: the LEB number to fix up
++ * @len: number of used bytes in LEB (starting at offset 0)
++ *
++ * This function reads the contents of the given LEB number @lnum, then fixes
++ * it up, so that empty min. I/O units in the end of LEB are actually erased on
++ * flash (rather than being just all-0xff real data). If the LEB is completely
++ * empty, it is simply unmapped.
++ */
++static int fixup_leb(struct ubifs_info *c, int lnum, int len)
++{
++      int err;
++
++      ubifs_assert(len >= 0);
++      ubifs_assert(len % c->min_io_size == 0);
++      ubifs_assert(len < c->leb_size);
++
++      if (len == 0) {
++              dbg_mnt("unmap empty LEB %d", lnum);
++              return ubifs_leb_unmap(c, lnum);
++      }
++
++      dbg_mnt("fixup LEB %d, data len %d", lnum, len);
++      err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
++      if (err)
++              return err;
++
++      return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
++}
++
++/**
++ * fixup_free_space - find & remap all LEBs containing free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function walks through all LEBs in the filesystem and fiexes up those
++ * containing free/empty space.
++ */
++static int fixup_free_space(struct ubifs_info *c)
++{
++      int lnum, err = 0;
++      struct ubifs_lprops *lprops;
++
++      ubifs_get_lprops(c);
++
++      /* Fixup LEBs in the master area */
++      for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) {
++              err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz);
++              if (err)
++                      goto out;
++      }
++
++      /* Unmap unused log LEBs */
++      lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
++      while (lnum != c->ltail_lnum) {
++              err = fixup_leb(c, lnum, 0);
++              if (err)
++                      goto out;
++              lnum = ubifs_next_log_lnum(c, lnum);
++      }
++
++      /* Fixup the current log head */
++      err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
++      if (err)
++              goto out;
++
++      /* Fixup LEBs in the LPT area */
++      for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
++              int free = c->ltab[lnum - c->lpt_first].free;
++
++              if (free > 0) {
++                      err = fixup_leb(c, lnum, c->leb_size - free);
++                      if (err)
++                              goto out;
++              }
++      }
++
++      /* Unmap LEBs in the orphans area */
++      for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
++              err = fixup_leb(c, lnum, 0);
++              if (err)
++                      goto out;
++      }
++
++      /* Fixup LEBs in the main area */
++      for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
++              lprops = ubifs_lpt_lookup(c, lnum);
++              if (IS_ERR(lprops)) {
++                      err = PTR_ERR(lprops);
++                      goto out;
++              }
++
++              if (lprops->free > 0) {
++                      err = fixup_leb(c, lnum, c->leb_size - lprops->free);
++                      if (err)
++                              goto out;
++              }
++      }
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * ubifs_fixup_free_space - find & fix all LEBs with free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function fixes up LEBs containing free space on first mount, if the
++ * appropriate flag was set when the FS was created. Each LEB with one or more
++ * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure
++ * the free space is actually erased. E.g., this is necessary for some NAND
++ * chips, since the free space may have been programmed like real "0xff" data
++ * (generating a non-0xff ECC), causing future writes to the not-really-erased
++ * NAND pages to behave badly. After the space is fixed up, the superblock flag
++ * is cleared, so that this is skipped for all future mounts.
++ */
++int ubifs_fixup_free_space(struct ubifs_info *c)
++{
++      int err;
++      struct ubifs_sb_node *sup;
++
++      ubifs_assert(c->space_fixup);
++      ubifs_assert(!c->ro_mount);
++
++      ubifs_msg("start fixing up free space");
++
++      err = fixup_free_space(c);
++      if (err)
++              return err;
++
++      sup = ubifs_read_sb_node(c);
++      if (IS_ERR(sup))
++              return PTR_ERR(sup);
++
++      /* Free-space fixup is no longer required */
++      c->space_fixup = 0;
++      sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
++
++      err = ubifs_write_sb_node(c, sup);
++      kfree(sup);
++      if (err)
++              return err;
++
++      ubifs_msg("free space fixup complete");
++      return err;
++}
+diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
+index 3e1ee57..37383e8 100644
+--- a/fs/ubifs/scan.c
++++ b/fs/ubifs/scan.c
+@@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+       INIT_LIST_HEAD(&sleb->nodes);
+       sleb->buf = sbuf;
+-      err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
++      err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
+       if (err && err != -EBADMSG) {
+               ubifs_err("cannot read %d bytes from LEB %d:%d,"
+                         " error %d", c->leb_size - offs, lnum, offs, err);
+@@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
+       int len;
+       ubifs_err("corruption at LEB %d:%d", lnum, offs);
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+       len = c->leb_size - offs;
+       if (len > 8192)
+@@ -328,7 +328,7 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+               if (!quiet)
+                       ubifs_err("empty space starts at non-aligned offset %d",
+                                 offs);
+-              goto corrupted;;
++              goto corrupted;
+       }
+       ubifs_end_scan(c, sleb, lnum, offs);
+diff --git a/fs/ubifs/shrinker.c b/fs/ubifs/shrinker.c
+index 46961c0..d8f5d0f 100644
+--- a/fs/ubifs/shrinker.c
++++ b/fs/ubifs/shrinker.c
+@@ -283,7 +283,11 @@ int ubifs_shrinker(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+       long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
+       if (nr == 0)
+-              return clean_zn_cnt;
++              /*
++               * Due to the way UBIFS updates the clean znode counter it may
++               * temporarily be negative.
++               */
++              return clean_zn_cnt >= 0 ? clean_zn_cnt : 1;
+       if (!clean_zn_cnt) {
+               /*
+diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
+index 91fac54..83651cd 100644
+--- a/fs/ubifs/super.c
++++ b/fs/ubifs/super.c
+@@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+       if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
+               return 4;
+-      if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG)
++      if (ui->xattr && !S_ISREG(inode->i_mode))
+               return 5;
+       if (!ubifs_compr_present(ui->compr_type)) {
+@@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+                          ubifs_compr_name(ui->compr_type));
+       }
+-      err = dbg_check_dir_size(c, inode);
++      err = dbg_check_dir(c, inode);
+       return err;
+ }
+@@ -367,7 +367,7 @@ out:
+               ubifs_release_dirty_inode_budget(c, ui);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+ done:
+@@ -504,9 +504,12 @@ static int init_constants_early(struct ubifs_info *c)
+       c->leb_cnt = c->vi.size;
+       c->leb_size = c->vi.usable_leb_size;
++      c->leb_start = c->di.leb_start;
+       c->half_leb_size = c->leb_size / 2;
+       c->min_io_size = c->di.min_io_size;
+       c->min_io_shift = fls(c->min_io_size) - 1;
++      c->max_write_size = c->di.max_write_size;
++      c->max_write_shift = fls(c->max_write_size) - 1;
+       if (c->leb_size < UBIFS_MIN_LEB_SZ) {
+               ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
+@@ -526,6 +529,18 @@ static int init_constants_early(struct ubifs_info *c)
+       }
+       /*
++       * Maximum write size has to be greater or equivalent to min. I/O
++       * size, and be multiple of min. I/O size.
++       */
++      if (c->max_write_size < c->min_io_size ||
++          c->max_write_size % c->min_io_size ||
++          !is_power_of_2(c->max_write_size)) {
++              ubifs_err("bad write buffer size %d for %d min. I/O unit",
++                        c->max_write_size, c->min_io_size);
++              return -EINVAL;
++      }
++
++      /*
+        * UBIFS aligns all node to 8-byte boundary, so to make function in
+        * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is
+        * less than 8.
+@@ -533,6 +548,10 @@ static int init_constants_early(struct ubifs_info *c)
+       if (c->min_io_size < 8) {
+               c->min_io_size = 8;
+               c->min_io_shift = 3;
++              if (c->max_write_size < c->min_io_size) {
++                      c->max_write_size = c->min_io_size;
++                      c->max_write_shift = c->min_io_shift;
++              }
+       }
+       c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+@@ -667,11 +686,11 @@ static int init_constants_sb(struct ubifs_info *c)
+        * be compressed and direntries are of the maximum size.
+        *
+        * Note, data, which may be stored in inodes is budgeted separately, so
+-       * it is not included into 'c->inode_budget'.
++       * it is not included into 'c->bi.inode_budget'.
+        */
+-      c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
+-      c->inode_budget = UBIFS_INO_NODE_SZ;
+-      c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
++      c->bi.page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
++      c->bi.inode_budget = UBIFS_INO_NODE_SZ;
++      c->bi.dent_budget = UBIFS_MAX_DENT_NODE_SZ;
+       /*
+        * When the amount of flash space used by buds becomes
+@@ -715,7 +734,7 @@ static void init_constants_master(struct ubifs_info *c)
+ {
+       long long tmp64;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->report_rp_size = ubifs_reported_space(c, c->rp_size);
+       /*
+@@ -784,15 +803,18 @@ static int alloc_wbufs(struct ubifs_info *c)
+               c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
+               c->jheads[i].wbuf.jhead = i;
++              c->jheads[i].grouped = 1;
+       }
+       c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
+       /*
+        * Garbage Collector head likely contains long-term data and
+-       * does not need to be synchronized by timer.
++       * does not need to be synchronized by timer. Also GC head nodes are
++       * not grouped.
+        */
+       c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
+       c->jheads[GCHD].wbuf.no_timer = 1;
++      c->jheads[GCHD].grouped = 0;
+       return 0;
+ }
+@@ -884,7 +906,7 @@ static int check_volume_empty(struct ubifs_info *c)
+       c->empty = 1;
+       for (lnum = 0; lnum < c->leb_cnt; lnum++) {
+-              err = ubi_is_mapped(c->ubi, lnum);
++              err = ubifs_is_mapped(c, lnum);
+               if (unlikely(err < 0))
+                       return err;
+               if (err == 1) {
+@@ -1117,8 +1139,8 @@ static int check_free_space(struct ubifs_info *c)
+ {
+       ubifs_assert(c->dark_wm > 0);
+       if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
+-              ubifs_err("insufficient free space to mount in read/write mode");
+-              dbg_dump_budg(c);
++              ubifs_err("insufficient free space to mount in R/W mode");
++              dbg_dump_budg(c, &c->bi);
+               dbg_dump_lprops(c);
+               return -ENOSPC;
+       }
+@@ -1194,11 +1216,14 @@ static int mount_ubifs(struct ubifs_info *c)
+       if (c->bulk_read == 1)
+               bu_init(c);
+-      /*
+-       * We have to check all CRCs, even for data nodes, when we mount the FS
+-       * (specifically, when we are replaying).
+-       */
+-      c->always_chk_crc = 1;
++      if (!c->ro_mount) {
++              c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
++                                             GFP_KERNEL);
++              if (!c->write_reserve_buf)
++                      goto out_free;
++      }
++
++      c->mounting = 1;
+       err = ubifs_read_superblock(c);
+       if (err)
+@@ -1227,12 +1252,12 @@ static int mount_ubifs(struct ubifs_info *c)
+               goto out_free;
+       }
++      err = alloc_wbufs(c);
++      if (err)
++              goto out_cbuf;
++
+       sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
+       if (!c->ro_mount) {
+-              err = alloc_wbufs(c);
+-              if (err)
+-                      goto out_cbuf;
+-
+               /* Create background thread */
+               c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
+               if (IS_ERR(c->bgt)) {
+@@ -1254,12 +1279,25 @@ static int mount_ubifs(struct ubifs_info *c)
+       if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
+               ubifs_msg("recovery needed");
+               c->need_recovery = 1;
+-              if (!c->ro_mount) {
+-                      err = ubifs_recover_inl_heads(c, c->sbuf);
+-                      if (err)
+-                              goto out_master;
+-              }
+-      } else if (!c->ro_mount) {
++      }
++
++      if (c->need_recovery && !c->ro_mount) {
++              err = ubifs_recover_inl_heads(c, c->sbuf);
++              if (err)
++                      goto out_master;
++      }
++
++      err = ubifs_lpt_init(c, 1, !c->ro_mount);
++      if (err)
++              goto out_master;
++
++      if (!c->ro_mount && c->space_fixup) {
++              err = ubifs_fixup_free_space(c);
++              if (err)
++                      goto out_master;
++      }
++
++      if (!c->ro_mount) {
+               /*
+                * Set the "dirty" flag so that if we reboot uncleanly we
+                * will notice this immediately on the next mount.
+@@ -1267,14 +1305,10 @@ static int mount_ubifs(struct ubifs_info *c)
+               c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+               err = ubifs_write_master(c);
+               if (err)
+-                      goto out_master;
++                      goto out_lpt;
+       }
+-      err = ubifs_lpt_init(c, 1, !c->ro_mount);
+-      if (err)
+-              goto out_lpt;
+-
+-      err = dbg_check_idx_size(c, c->old_idx_sz);
++      err = dbg_check_idx_size(c, c->bi.old_idx_sz);
+       if (err)
+               goto out_lpt;
+@@ -1283,7 +1317,7 @@ static int mount_ubifs(struct ubifs_info *c)
+               goto out_journal;
+       /* Calculate 'min_idx_lebs' after journal replay */
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
+       if (err)
+@@ -1374,7 +1408,7 @@ static int mount_ubifs(struct ubifs_info *c)
+       if (err)
+               goto out_infos;
+-      c->always_chk_crc = 0;
++      c->mounting = 0;
+       ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
+                 c->vi.ubi_num, c->vi.vol_id, c->vi.name);
+@@ -1395,6 +1429,7 @@ static int mount_ubifs(struct ubifs_info *c)
+       dbg_msg("compiled on:         " __DATE__ " at " __TIME__);
+       dbg_msg("min. I/O unit size:  %d bytes", c->min_io_size);
++      dbg_msg("max. write size:     %d bytes", c->max_write_size);
+       dbg_msg("LEB size:            %d bytes (%d KiB)",
+               c->leb_size, c->leb_size >> 10);
+       dbg_msg("data journal heads:  %d",
+@@ -1411,7 +1446,8 @@ static int mount_ubifs(struct ubifs_info *c)
+               c->main_lebs, c->main_first, c->leb_cnt - 1);
+       dbg_msg("index LEBs:          %d", c->lst.idx_lebs);
+       dbg_msg("total index bytes:   %lld (%lld KiB, %lld MiB)",
+-              c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
++              c->bi.old_idx_sz, c->bi.old_idx_sz >> 10,
++              c->bi.old_idx_sz >> 20);
+       dbg_msg("key hash type:       %d", c->key_hash_type);
+       dbg_msg("tree fanout:         %d", c->fanout);
+       dbg_msg("reserved GC LEB:     %d", c->gc_lnum);
+@@ -1424,9 +1460,9 @@ static int mount_ubifs(struct ubifs_info *c)
+               UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
+       dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
+               UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
+-      dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu",
+-              UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+-              UBIFS_MAX_DENT_NODE_SZ);
++      dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu, idx %d",
++              UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
++              UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout));
+       dbg_msg("dead watermark:      %d", c->dead_wm);
+       dbg_msg("dark watermark:      %d", c->dark_wm);
+       dbg_msg("LEB overhead:        %d", c->leb_overhead);
+@@ -1466,6 +1502,7 @@ out_wbufs:
+ out_cbuf:
+       kfree(c->cbuf);
+ out_free:
++      kfree(c->write_reserve_buf);
+       kfree(c->bu.buf);
+       vfree(c->ileb_buf);
+       vfree(c->sbuf);
+@@ -1504,6 +1541,7 @@ static void ubifs_umount(struct ubifs_info *c)
+       kfree(c->cbuf);
+       kfree(c->rcvrd_mst_node);
+       kfree(c->mst_node);
++      kfree(c->write_reserve_buf);
+       kfree(c->bu.buf);
+       vfree(c->ileb_buf);
+       vfree(c->sbuf);
+@@ -1535,7 +1573,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+       mutex_lock(&c->umount_mutex);
+       dbg_save_space_info(c);
+       c->remounting_rw = 1;
+-      c->always_chk_crc = 1;
++      c->ro_mount = 0;
+       err = check_free_space(c);
+       if (err)
+@@ -1551,6 +1589,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+               }
+               sup->leb_cnt = cpu_to_le32(c->leb_cnt);
+               err = ubifs_write_sb_node(c, sup);
++              kfree(sup);
+               if (err)
+                       goto out;
+       }
+@@ -1590,16 +1629,14 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+               goto out;
+       }
+-      err = ubifs_lpt_init(c, 0, 1);
+-      if (err)
++      c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
++      if (!c->write_reserve_buf)
+               goto out;
+-      err = alloc_wbufs(c);
++      err = ubifs_lpt_init(c, 0, 1);
+       if (err)
+               goto out;
+-      ubifs_create_buds_lists(c);
+-
+       /* Create background thread */
+       c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
+       if (IS_ERR(c->bgt)) {
+@@ -1634,20 +1671,37 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+       if (err)
+               goto out;
++      dbg_gen("re-mounted read-write");
++      c->remounting_rw = 0;
++
+       if (c->need_recovery) {
+               c->need_recovery = 0;
+               ubifs_msg("deferred recovery completed");
++      } else {
++              /*
++               * Do not run the debugging space check if the were doing
++               * recovery, because when we saved the information we had the
++               * file-system in a state where the TNC and lprops has been
++               * modified in memory, but all the I/O operations (including a
++               * commit) were deferred. So the file-system was in
++               * "non-committed" state. Now the file-system is in committed
++               * state, and of course the amount of free space will change
++               * because, for example, the old index size was imprecise.
++               */
++              err = dbg_check_space_info(c);
++      }
++
++      if (c->space_fixup) {
++              err = ubifs_fixup_free_space(c);
++              if (err)
++                      goto out;
+       }
+-      dbg_gen("re-mounted read-write");
+-      c->ro_mount = 0;
+-      c->remounting_rw = 0;
+-      c->always_chk_crc = 0;
+-      err = dbg_check_space_info(c);
+       mutex_unlock(&c->umount_mutex);
+       return err;
+ out:
++      c->ro_mount = 1;
+       vfree(c->orph_buf);
+       c->orph_buf = NULL;
+       if (c->bgt) {
+@@ -1655,11 +1709,12 @@ out:
+               c->bgt = NULL;
+       }
+       free_wbufs(c);
++      kfree(c->write_reserve_buf);
++      c->write_reserve_buf = NULL;
+       vfree(c->ileb_buf);
+       c->ileb_buf = NULL;
+       ubifs_lpt_free(c, 1);
+       c->remounting_rw = 0;
+-      c->always_chk_crc = 0;
+       mutex_unlock(&c->umount_mutex);
+       return err;
+ }
+@@ -1696,9 +1751,10 @@ static void ubifs_remount_ro(struct ubifs_info *c)
+       if (err)
+               ubifs_ro_mode(c, err);
+-      free_wbufs(c);
+       vfree(c->orph_buf);
+       c->orph_buf = NULL;
++      kfree(c->write_reserve_buf);
++      c->write_reserve_buf = NULL;
+       vfree(c->ileb_buf);
+       c->ileb_buf = NULL;
+       ubifs_lpt_free(c, 1);
+@@ -1722,10 +1778,11 @@ static void ubifs_put_super(struct super_block *sb)
+        * of the media. For example, there will be dirty inodes if we failed
+        * to write them back because of I/O errors.
+        */
+-      ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
+-      ubifs_assert(c->budg_idx_growth == 0);
+-      ubifs_assert(c->budg_dd_growth == 0);
+-      ubifs_assert(c->budg_data_growth == 0);
++      if (!c->ro_error) {
++              ubifs_assert(c->bi.idx_growth == 0);
++              ubifs_assert(c->bi.dd_growth == 0);
++              ubifs_assert(c->bi.data_growth == 0);
++      }
+       /*
+        * The 'c->umount_lock' prevents races between UBIFS memory shrinker
+@@ -1929,6 +1986,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+       mutex_init(&c->mst_mutex);
+       mutex_init(&c->umount_mutex);
+       mutex_init(&c->bu_mutex);
++      mutex_init(&c->write_reserve_mutex);
+       init_waitqueue_head(&c->cmt_wq);
+       c->buds = RB_ROOT;
+       c->old_idx = RB_ROOT;
+@@ -1946,6 +2004,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+       INIT_LIST_HEAD(&c->old_buds);
+       INIT_LIST_HEAD(&c->orph_list);
+       INIT_LIST_HEAD(&c->orph_new);
++      c->no_chk_data_crc = 1;
+       c->vfs_sb = sb;
+       c->highest_inum = UBIFS_FIRST_INO;
+diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
+index ad9cf01..16ad84d 100644
+--- a/fs/ubifs/tnc.c
++++ b/fs/ubifs/tnc.c
+@@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
+       __set_bit(DIRTY_ZNODE, &zn->flags);
+       __clear_bit(COW_ZNODE, &zn->flags);
+-      ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++      ubifs_assert(!ubifs_zn_obsolete(znode));
+       __set_bit(OBSOLETE_ZNODE, &znode->flags);
+       if (znode->level != 0) {
+@@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
+       struct ubifs_znode *zn;
+       int err;
+-      if (!test_bit(COW_ZNODE, &znode->flags)) {
++      if (!ubifs_zn_cow(znode)) {
+               /* znode is not being committed */
+               if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
+                       atomic_long_inc(&c->dirty_zn_cnt);
+@@ -344,12 +344,11 @@ static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+               return err;
+       }
+-      lnc_node = kmalloc(zbr->len, GFP_NOFS);
++      lnc_node = kmemdup(node, zbr->len, GFP_NOFS);
+       if (!lnc_node)
+               /* We don't have to have the cache, so no error */
+               return 0;
+-      memcpy(lnc_node, node, zbr->len);
+       zbr->leaf = lnc_node;
+       return 0;
+ }
+@@ -447,8 +446,11 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+  *
+  * Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
+  * is true (it is controlled by corresponding mount option). However, if
+- * @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
+- * checked.
++ * @c->mounting or @c->remounting_rw is true (we are mounting or re-mounting to
++ * R/W mode), @c->no_chk_data_crc is ignored and CRC is checked. This is
++ * because during mounting or re-mounting from R/O mode to R/W mode we may read
++ * journal nodes (when replying the journal or doing the recovery) and the
++ * journal nodes may potentially be corrupted, so checking is required.
+  */
+ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+                        int len, int lnum, int offs)
+@@ -459,7 +461,7 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+       dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
+       if (err) {
+               ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
+                         type, lnum, offs, err);
+@@ -476,7 +478,8 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+       if (node_len != len)
+               return 0;
+-      if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
++      if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting &&
++          !c->remounting_rw)
+               return 1;
+       crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+@@ -502,7 +505,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+ {
+       int ret;
+-      dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
++      dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
+       ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
+                           zbr->offs);
+@@ -516,8 +519,8 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+                       ret = 0;
+       }
+       if (ret == 0 && c->replaying)
+-              dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
+-                      zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
++              dbg_mntk(key, "dangling branch LEB %d:%d len %d, key ",
++                      zbr->lnum, zbr->offs, zbr->len);
+       return ret;
+ }
+@@ -992,9 +995,9 @@ static int fallible_resolve_collision(struct ubifs_info *c,
+       if (adding || !o_znode)
+               return 0;
+-      dbg_mnt("dangling match LEB %d:%d len %d %s",
++      dbg_mntk(key, "dangling match LEB %d:%d len %d key ",
+               o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
+-              o_znode->zbranch[o_n].len, DBGKEY(key));
++              o_znode->zbranch[o_n].len);
+       *zn = o_znode;
+       *n = o_n;
+       return 1;
+@@ -1176,7 +1179,7 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       unsigned long time = get_seconds();
+-      dbg_tnc("search key %s", DBGKEY(key));
++      dbg_tnck(key, "search key ");
+       ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
+       znode = c->zroot.znode;
+@@ -1312,7 +1315,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       unsigned long time = get_seconds();
+-      dbg_tnc("search and dirty key %s", DBGKEY(key));
++      dbg_tnck(key, "search and dirty key ");
+       znode = c->zroot.znode;
+       if (unlikely(!znode)) {
+@@ -1662,7 +1665,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
+       if (!overlap) {
+               /* We may safely unlock the write-buffer and read the data */
+               spin_unlock(&wbuf->lock);
+-              return ubi_read(c->ubi, lnum, buf, offs, len);
++              return ubifs_leb_read(c, lnum, buf, offs, len, 0);
+       }
+       /* Don't read under wbuf */
+@@ -1676,7 +1679,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
+       if (rlen > 0)
+               /* Read everything that goes before write-buffer */
+-              return ubi_read(c->ubi, lnum, buf, offs, rlen);
++              return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
+       return 0;
+ }
+@@ -1719,8 +1722,8 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
+       if (!keys_eq(c, &zbr->key, &key1)) {
+               ubifs_err("bad key in node at LEB %d:%d",
+                         zbr->lnum, zbr->offs);
+-              dbg_tnc("looked for key %s found node's key %s",
+-                      DBGKEY(&zbr->key), DBGKEY1(&key1));
++              dbg_tnck(&zbr->key, "looked for key ");
++              dbg_tnck(&key1, "found node's key ");
+               goto out_err;
+       }
+@@ -1763,7 +1766,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+       if (wbuf)
+               err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
+       else
+-              err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
++              err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
+       /* Check for a race with GC */
+       if (maybe_leb_gced(c, lnum, bu->gc_seq))
+@@ -1773,7 +1776,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+               ubifs_err("failed to read from LEB %d:%d, error %d",
+                         lnum, offs, err);
+               dbg_dump_stack();
+-              dbg_tnc("key %s", DBGKEY(&bu->key));
++              dbg_tnck(&bu->key, "key ");
+               return err;
+       }
+@@ -1808,7 +1811,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+       int found, n, err;
+       struct ubifs_znode *znode;
+-      dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
++      dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
+       mutex_lock(&c->tnc_mutex);
+       found = ubifs_lookup_level0(c, key, &znode, &n);
+       if (!found) {
+@@ -1982,8 +1985,7 @@ again:
+       zp = znode->parent;
+       if (znode->child_cnt < c->fanout) {
+               ubifs_assert(n != c->fanout);
+-              dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
+-                      DBGKEY(key));
++              dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level);
+               insert_zbranch(znode, zbr, n);
+@@ -1998,7 +2000,7 @@ again:
+        * Unfortunately, @znode does not have more empty slots and we have to
+        * split it.
+        */
+-      dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
++      dbg_tnck(key, "splitting level %d, key ", znode->level);
+       if (znode->alt)
+               /*
+@@ -2092,7 +2094,7 @@ do_split:
+       }
+       /* Insert new key and branch */
+-      dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
++      dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level);
+       insert_zbranch(zi, zbr, n);
+@@ -2168,7 +2170,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
++      dbg_tnck(key, "%d:%d, len %d, key ", lnum, offs, len);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (!found) {
+               struct ubifs_zbranch zbr;
+@@ -2217,8 +2219,8 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
+-              old_offs, lnum, offs, len, DBGKEY(key));
++      dbg_tnck(key, "old LEB %d:%d, new LEB %d:%d, len %d, key ", old_lnum,
++               old_offs, lnum, offs, len);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2300,8 +2302,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
+-              DBGKEY(key));
++      dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
++               lnum, offs, nm->len, nm->name);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2394,7 +2396,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+       /* Delete without merge for now */
+       ubifs_assert(znode->level == 0);
+       ubifs_assert(n >= 0 && n < c->fanout);
+-      dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
++      dbg_tnck(&znode->zbranch[n].key, "deleting key ");
+       zbr = &znode->zbranch[n];
+       lnc_free(zbr);
+@@ -2419,7 +2421,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+        */
+       do {
+-              ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++              ubifs_assert(!ubifs_zn_obsolete(znode));
+               ubifs_assert(ubifs_zn_dirty(znode));
+               zp = znode->parent;
+@@ -2475,9 +2477,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+                       c->zroot.offs = zbr->offs;
+                       c->zroot.len = zbr->len;
+                       c->zroot.znode = znode;
+-                      ubifs_assert(!test_bit(OBSOLETE_ZNODE,
+-                                   &zp->flags));
+-                      ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
++                      ubifs_assert(!ubifs_zn_obsolete(zp));
++                      ubifs_assert(ubifs_zn_dirty(zp));
+                       atomic_long_dec(&c->dirty_zn_cnt);
+                       if (zp->cnext) {
+@@ -2505,7 +2506,7 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("key %s", DBGKEY(key));
++      dbg_tnck(key, "key ");
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2536,7 +2537,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
++      dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
+       err = lookup_level0_dirty(c, key, &znode, &n);
+       if (err < 0)
+               goto out_unlock;
+@@ -2553,11 +2554,11 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+               if (err) {
+                       /* Ensure the znode is dirtied */
+                       if (znode->cnext || !ubifs_zn_dirty(znode)) {
+-                                  znode = dirty_cow_bottom_up(c, znode);
+-                                  if (IS_ERR(znode)) {
+-                                          err = PTR_ERR(znode);
+-                                          goto out_unlock;
+-                                  }
++                              znode = dirty_cow_bottom_up(c, znode);
++                              if (IS_ERR(znode)) {
++                                      err = PTR_ERR(znode);
++                                      goto out_unlock;
++                              }
+                       }
+                       err = tnc_delete(c, znode, n);
+               }
+@@ -2651,7 +2652,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
+                               dbg_dump_znode(c, znode);
+                               goto out_unlock;
+                       }
+-                      dbg_tnc("removing %s", DBGKEY(key));
++                      dbg_tnck(key, "removing key ");
+               }
+               if (k) {
+                       for (i = n + 1 + k; i < znode->child_cnt; i++)
+@@ -2771,7 +2772,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
+       struct ubifs_zbranch *zbr;
+       union ubifs_key *dkey;
+-      dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
++      dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
+       ubifs_assert(is_hash_key(c, key));
+       mutex_lock(&c->tnc_mutex);
+@@ -2861,7 +2862,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
+               struct ubifs_znode *znode = cnext;
+               cnext = cnext->cnext;
+-              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++              if (ubifs_zn_obsolete(znode))
+                       kfree(znode);
+       } while (cnext && cnext != c->cnext);
+ }
+@@ -2872,12 +2873,13 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
+  */
+ void ubifs_tnc_close(struct ubifs_info *c)
+ {
+-      long clean_freed;
+-
+       tnc_destroy_cnext(c);
+       if (c->zroot.znode) {
+-              clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
+-              atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt);
++              long n;
++
++              ubifs_destroy_tnc_subtree(c->zroot.znode);
++              n = atomic_long_read(&c->clean_zn_cnt);
++              atomic_long_sub(n, &ubifs_clean_zn_cnt);
+       }
+       kfree(c->gap_lebs);
+       kfree(c->ilebs);
+@@ -3296,7 +3298,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+       if (!S_ISREG(inode->i_mode))
+               return 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+@@ -3329,12 +3331,13 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+ out_dump:
+       block = key_block(c, key);
+-      ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
+-                "(data key %s)", (unsigned long)inode->i_ino, size,
+-                ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
++      ubifs_err("inode %lu has size %lld, but there are data at offset %lld",
++                (unsigned long)inode->i_ino, size,
++                ((loff_t)block) << UBIFS_BLOCK_SHIFT);
++      mutex_unlock(&c->tnc_mutex);
+       dbg_dump_inode(c, inode);
+       dbg_dump_stack();
+-      err = -EINVAL;
++      return -EINVAL;
+ out_unlock:
+       mutex_unlock(&c->tnc_mutex);
+diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
+index 53288e5..4c15f07 100644
+--- a/fs/ubifs/tnc_commit.c
++++ b/fs/ubifs/tnc_commit.c
+@@ -22,6 +22,7 @@
+ /* This file implements TNC functions for committing */
++#include <linux/random.h>
+ #include "ubifs.h"
+ /**
+@@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
+       atomic_long_dec(&c->dirty_zn_cnt);
+       ubifs_assert(ubifs_zn_dirty(znode));
+-      ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
++      ubifs_assert(ubifs_zn_cow(znode));
++      /*
++       * Note, unlike 'write_index()' we do not add memory barriers here
++       * because this function is called with @c->tnc_mutex locked.
++       */
+       __clear_bit(DIRTY_ZNODE, &znode->flags);
+       __clear_bit(COW_ZNODE, &znode->flags);
+@@ -377,15 +382,13 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
+                               c->gap_lebs = NULL;
+                               return err;
+                       }
+-                      if (!dbg_force_in_the_gaps_enabled) {
++                      if (!dbg_is_chk_index(c)) {
+                               /*
+                                * Do not print scary warnings if the debugging
+                                * option which forces in-the-gaps is enabled.
+                                */
+-                              ubifs_err("out of space");
+-                              spin_lock(&c->space_lock);
+-                              dbg_dump_budg(c);
+-                              spin_unlock(&c->space_lock);
++                              ubifs_warn("out of space");
++                              dbg_dump_budg(c, &c->bi);
+                               dbg_dump_lprops(c);
+                       }
+                       /* Try to commit anyway */
+@@ -493,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
+               else
+                       next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+-              if (c->min_io_size == 1) {
+-                      buf_offs += ALIGN(len, 8);
+-                      if (next_len) {
+-                              if (buf_offs + next_len <= c->leb_size)
+-                                      continue;
+-                              err = ubifs_update_one_lp(c, lnum, 0,
+-                                              c->leb_size - buf_offs, 0, 0);
+-                              if (err)
+-                                      return err;
+-                              lnum = -1;
+-                              continue;
+-                      }
+-                      err = ubifs_update_one_lp(c, lnum,
+-                                      c->leb_size - buf_offs, 0, 0, 0);
+-                      if (err)
+-                              return err;
+-                      break;
+-              }
+-
+               /* Update buffer positions */
+               wlen = used + len;
+               used += ALIGN(len, 8);
+@@ -660,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
+       }
+       cnt += 1;
+       while (1) {
+-              ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
++              ubifs_assert(!ubifs_zn_cow(znode));
+               __set_bit(COW_ZNODE, &znode->flags);
+               znode->alt = 0;
+               cnext = find_next_dirty(znode);
+@@ -706,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
+               c->ilebs[c->ileb_cnt++] = lnum;
+               dbg_cmt("LEB %d", lnum);
+       }
+-      if (dbg_force_in_the_gaps())
++      if (dbg_is_chk_index(c) && !(random32() & 7))
+               return -ENOSPC;
+       return 0;
+ }
+@@ -796,16 +780,16 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+       spin_lock(&c->space_lock);
+       /*
+        * Although we have not finished committing yet, update size of the
+-       * committed index ('c->old_idx_sz') and zero out the index growth
++       * committed index ('c->bi.old_idx_sz') and zero out the index growth
+        * budget. It is OK to do this now, because we've reserved all the
+        * space which is needed to commit the index, and it is save for the
+        * budgeting subsystem to assume the index is already committed,
+        * even though it is not.
+        */
+-      ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+-      c->old_idx_sz = c->calc_idx_sz;
+-      c->budg_uncommitted_idx = 0;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
++      c->bi.old_idx_sz = c->calc_idx_sz;
++      c->bi.uncommitted_idx = 0;
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       spin_unlock(&c->space_lock);
+       mutex_unlock(&c->tnc_mutex);
+@@ -832,7 +816,7 @@ static int write_index(struct ubifs_info *c)
+       struct ubifs_idx_node *idx;
+       struct ubifs_znode *znode, *cnext;
+       int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
+-      int avail, wlen, err, lnum_pos = 0;
++      int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
+       cnext = c->enext;
+       if (!cnext)
+@@ -909,7 +893,7 @@ static int write_index(struct ubifs_info *c)
+               cnext = znode->cnext;
+               ubifs_assert(ubifs_zn_dirty(znode));
+-              ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
++              ubifs_assert(ubifs_zn_cow(znode));
+               /*
+                * It is important that other threads should see %DIRTY_ZNODE
+@@ -924,6 +908,28 @@ static int write_index(struct ubifs_info *c)
+               clear_bit(COW_ZNODE, &znode->flags);
+               smp_mb__after_clear_bit();
++              /*
++               * We have marked the znode as clean but have not updated the
++               * @c->clean_zn_cnt counter. If this znode becomes dirty again
++               * before 'free_obsolete_znodes()' is called, then
++               * @c->clean_zn_cnt will be decremented before it gets
++               * incremented (resulting in 2 decrements for the same znode).
++               * This means that @c->clean_zn_cnt may become negative for a
++               * while.
++               *
++               * Q: why we cannot increment @c->clean_zn_cnt?
++               * A: because we do not have the @c->tnc_mutex locked, and the
++               *    following code would be racy and buggy:
++               *
++               *    if (!ubifs_zn_obsolete(znode)) {
++               *            atomic_long_inc(&c->clean_zn_cnt);
++               *            atomic_long_inc(&ubifs_clean_zn_cnt);
++               *    }
++               *
++               *    Thus, we just delay the @c->clean_zn_cnt update until we
++               *    have the mutex locked.
++               */
++
+               /* Do not access znode from this point on */
+               /* Update buffer positions */
+@@ -940,65 +946,38 @@ static int write_index(struct ubifs_info *c)
+               else
+                       next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+-              if (c->min_io_size == 1) {
+-                      /*
+-                       * Write the prepared index node immediately if there is
+-                       * no minimum IO size
+-                       */
+-                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+-                                            wlen, UBI_SHORTTERM);
+-                      if (err)
+-                              return err;
+-                      buf_offs += ALIGN(wlen, 8);
+-                      if (next_len) {
+-                              used = 0;
+-                              avail = buf_len;
+-                              if (buf_offs + next_len > c->leb_size) {
+-                                      err = ubifs_update_one_lp(c, lnum,
+-                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
+-                                      if (err)
+-                                              return err;
+-                                      lnum = -1;
+-                              }
++              nxt_offs = buf_offs + used + next_len;
++              if (next_len && nxt_offs <= c->leb_size) {
++                      if (avail > 0)
+                               continue;
+-                      }
++                      else
++                              blen = buf_len;
+               } else {
+-                      int blen, nxt_offs = buf_offs + used + next_len;
+-
+-                      if (next_len && nxt_offs <= c->leb_size) {
+-                              if (avail > 0)
+-                                      continue;
+-                              else
+-                                      blen = buf_len;
+-                      } else {
+-                              wlen = ALIGN(wlen, 8);
+-                              blen = ALIGN(wlen, c->min_io_size);
+-                              ubifs_pad(c, c->cbuf + wlen, blen - wlen);
+-                      }
+-                      /*
+-                       * The buffer is full or there are no more znodes
+-                       * to do
+-                       */
+-                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+-                                            blen, UBI_SHORTTERM);
+-                      if (err)
+-                              return err;
+-                      buf_offs += blen;
+-                      if (next_len) {
+-                              if (nxt_offs > c->leb_size) {
+-                                      err = ubifs_update_one_lp(c, lnum,
+-                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
+-                                      if (err)
+-                                              return err;
+-                                      lnum = -1;
+-                              }
+-                              used -= blen;
+-                              if (used < 0)
+-                                      used = 0;
+-                              avail = buf_len - used;
+-                              memmove(c->cbuf, c->cbuf + blen, used);
+-                              continue;
++                      wlen = ALIGN(wlen, 8);
++                      blen = ALIGN(wlen, c->min_io_size);
++                      ubifs_pad(c, c->cbuf + wlen, blen - wlen);
++              }
++
++              /* The buffer is full or there are no more znodes to do */
++              err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
++                                    UBI_SHORTTERM);
++              if (err)
++                      return err;
++              buf_offs += blen;
++              if (next_len) {
++                      if (nxt_offs > c->leb_size) {
++                              err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
++                                                        0, LPROPS_TAKEN);
++                              if (err)
++                                      return err;
++                              lnum = -1;
+                       }
++                      used -= blen;
++                      if (used < 0)
++                              used = 0;
++                      avail = buf_len - used;
++                      memmove(c->cbuf, c->cbuf + blen, used);
++                      continue;
+               }
+               break;
+       }
+@@ -1031,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
+       do {
+               znode = cnext;
+               cnext = znode->cnext;
+-              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++              if (ubifs_zn_obsolete(znode))
+                       kfree(znode);
+               else {
+                       znode->cnext = NULL;
+diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
+index b48db99..dc28fe6 100644
+--- a/fs/ubifs/tnc_misc.c
++++ b/fs/ubifs/tnc_misc.c
+@@ -328,8 +328,8 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
+               case UBIFS_XENT_KEY:
+                       break;
+               default:
+-                      dbg_msg("bad key type at slot %d: %s", i,
+-                              DBGKEY(&zbr->key));
++                      dbg_msg("bad key type at slot %d: %d",
++                              i, key_type(c, &zbr->key));
+                       err = 3;
+                       goto out_dump;
+               }
+@@ -475,7 +475,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+                                     zbr->offs);
+       if (err) {
+-              dbg_tnc("key %s", DBGKEY(key));
++              dbg_tnck(key, "key ");
+               return err;
+       }
+@@ -484,8 +484,8 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+       if (!keys_eq(c, key, &key1)) {
+               ubifs_err("bad key in node at LEB %d:%d",
+                         zbr->lnum, zbr->offs);
+-              dbg_tnc("looked for key %s found node's key %s",
+-                      DBGKEY(key), DBGKEY1(&key1));
++              dbg_tnck(key, "looked for key ");
++              dbg_tnck(&key1, "but found node's key ");
+               dbg_dump_node(c, node);
+               return -EINVAL;
+       }
+diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
+index 191ca78..e24380c 100644
+--- a/fs/ubifs/ubifs-media.h
++++ b/fs/ubifs/ubifs-media.h
+@@ -408,9 +408,11 @@ enum {
+  * Superblock flags.
+  *
+  * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
++ * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
+  */
+ enum {
+       UBIFS_FLG_BIGLPT = 0x02,
++      UBIFS_FLG_SPACE_FIXUP = 0x04,
+ };
+ /**
+@@ -434,7 +436,7 @@ struct ubifs_ch {
+       __u8 node_type;
+       __u8 group_type;
+       __u8 padding[2];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * union ubifs_dev_desc - device node descriptor.
+@@ -448,7 +450,7 @@ struct ubifs_ch {
+ union ubifs_dev_desc {
+       __le32 new;
+       __le64 huge;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_ino_node - inode node.
+@@ -509,7 +511,7 @@ struct ubifs_ino_node {
+       __le16 compr_type;
+       __u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
+       __u8 data[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_dent_node - directory entry node.
+@@ -534,7 +536,7 @@ struct ubifs_dent_node {
+       __le16 nlen;
+       __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
+       __u8 name[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_data_node - data node.
+@@ -555,7 +557,7 @@ struct ubifs_data_node {
+       __le16 compr_type;
+       __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
+       __u8 data[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_trun_node - truncation node.
+@@ -575,7 +577,7 @@ struct ubifs_trun_node {
+       __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
+       __le64 old_size;
+       __le64 new_size;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_pad_node - padding node.
+@@ -586,7 +588,7 @@ struct ubifs_trun_node {
+ struct ubifs_pad_node {
+       struct ubifs_ch ch;
+       __le32 pad_len;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_sb_node - superblock node.
+@@ -644,7 +646,7 @@ struct ubifs_sb_node {
+       __u8 uuid[16];
+       __le32 ro_compat_version;
+       __u8 padding2[3968];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_mst_node - master node.
+@@ -711,7 +713,7 @@ struct ubifs_mst_node {
+       __le32 idx_lebs;
+       __le32 leb_cnt;
+       __u8 padding[344];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_ref_node - logical eraseblock reference node.
+@@ -727,7 +729,7 @@ struct ubifs_ref_node {
+       __le32 offs;
+       __le32 jhead;
+       __u8 padding[28];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_branch - key/reference/length branch
+@@ -741,7 +743,7 @@ struct ubifs_branch {
+       __le32 offs;
+       __le32 len;
+       __u8 key[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_idx_node - indexing node.
+@@ -755,7 +757,7 @@ struct ubifs_idx_node {
+       __le16 child_cnt;
+       __le16 level;
+       __u8 branches[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_cs_node - commit start node.
+@@ -765,7 +767,7 @@ struct ubifs_idx_node {
+ struct ubifs_cs_node {
+       struct ubifs_ch ch;
+       __le64 cmt_no;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_orph_node - orphan node.
+@@ -777,6 +779,6 @@ struct ubifs_orph_node {
+       struct ubifs_ch ch;
+       __le64 cmt_no;
+       __le64 inos[];
+-} __attribute__ ((packed));
++} __packed;
+ #endif /* __UBIFS_MEDIA_H__ */
+diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
+index 381d6b2..caf9e4b 100644
+--- a/fs/ubifs/ubifs.h
++++ b/fs/ubifs/ubifs.h
+@@ -84,9 +84,6 @@
+ #define INUM_WARN_WATERMARK 0xFFF00000
+ #define INUM_WATERMARK      0xFFFFFF00
+-/* Largest key size supported in this implementation */
+-#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
+-
+ /* Maximum number of entries in each LPT (LEB category) heap */
+ #define LPT_HEAP_SZ 256
+@@ -151,6 +148,12 @@
+  */
+ #define WORST_COMPR_FACTOR 2
++/*
++ * How much memory is needed for a buffer where we comress a data node.
++ */
++#define COMPRESSED_DATA_NODE_BUF_SZ \
++      (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
++
+ /* Maximum expected tree height for use by bottom_up_buf */
+ #define BOTTOM_UP_HEIGHT 64
+@@ -224,14 +227,14 @@ enum {
+  * LPT cnode flag bits.
+  *
+  * DIRTY_CNODE: cnode is dirty
+- * COW_CNODE: cnode is being committed and must be copied before writing
+  * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
+- * so it can (and must) be freed when the commit is finished
++ *                 so it can (and must) be freed when the commit is finished
++ * COW_CNODE: cnode is being committed and must be copied before writing
+  */
+ enum {
+       DIRTY_CNODE    = 0,
+-      COW_CNODE      = 1,
+-      OBSOLETE_CNODE = 2,
++      OBSOLETE_CNODE = 1,
++      COW_CNODE      = 2,
+ };
+ /*
+@@ -271,10 +274,10 @@ struct ubifs_old_idx {
+ /* The below union makes it easier to deal with keys */
+ union ubifs_key {
+-      uint8_t u8[CUR_MAX_KEY_LEN];
+-      uint32_t u32[CUR_MAX_KEY_LEN/4];
+-      uint64_t u64[CUR_MAX_KEY_LEN/8];
+-      __le32 j32[CUR_MAX_KEY_LEN/4];
++      uint8_t u8[UBIFS_SK_LEN];
++      uint32_t u32[UBIFS_SK_LEN/4];
++      uint64_t u64[UBIFS_SK_LEN/8];
++      __le32 j32[UBIFS_SK_LEN/4];
+ };
+ /**
+@@ -383,9 +386,9 @@ struct ubifs_gced_idx_leb {
+  * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
+  * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
+  * make sure @inode->i_size is always changed under @ui_mutex, because it
+- * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would deadlock
+- * with 'ubifs_writepage()' (see file.c). All the other inode fields are
+- * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
++ * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would
++ * deadlock with 'ubifs_writepage()' (see file.c). All the other inode fields
++ * are changed under @ui_mutex, so they do not need "shadow" fields. Note, one
+  * could consider to rework locking and base it on "shadow" fields.
+  */
+ struct ubifs_inode {
+@@ -646,6 +649,7 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
+  * @offs: write-buffer offset in this logical eraseblock
+  * @avail: number of bytes available in the write-buffer
+  * @used:  number of used bytes in the write-buffer
++ * @size: write-buffer size (in [@c->min_io_size, @c->max_write_size] range)
+  * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
+  * %UBI_UNKNOWN)
+  * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
+@@ -680,6 +684,7 @@ struct ubifs_wbuf {
+       int offs;
+       int avail;
+       int used;
++      int size;
+       int dtype;
+       int jhead;
+       int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
+@@ -714,12 +719,14 @@ struct ubifs_bud {
+  * struct ubifs_jhead - journal head.
+  * @wbuf: head's write-buffer
+  * @buds_list: list of bud LEBs belonging to this journal head
++ * @grouped: non-zero if UBIFS groups nodes when writing to this journal head
+  *
+  * Note, the @buds list is protected by the @c->buds_lock.
+  */
+ struct ubifs_jhead {
+       struct ubifs_wbuf wbuf;
+       struct list_head buds_list;
++      unsigned int grouped:1;
+ };
+ /**
+@@ -929,6 +936,40 @@ struct ubifs_mount_opts {
+       unsigned int compr_type:2;
+ };
++/**
++ * struct ubifs_budg_info - UBIFS budgeting information.
++ * @idx_growth: amount of bytes budgeted for index growth
++ * @data_growth: amount of bytes budgeted for cached data
++ * @dd_growth: amount of bytes budgeted for cached data that will make
++ *             other data dirty
++ * @uncommitted_idx: amount of bytes were budgeted for growth of the index, but
++ *                   which still have to be taken into account because the index
++ *                   has not been committed so far
++ * @old_idx_sz: size of index on flash
++ * @min_idx_lebs: minimum number of LEBs required for the index
++ * @nospace: non-zero if the file-system does not have flash space (used as
++ *           optimization)
++ * @nospace_rp: the same as @nospace, but additionally means that even reserved
++ *              pool is full
++ * @page_budget: budget for a page (constant, nenver changed after mount)
++ * @inode_budget: budget for an inode (constant, nenver changed after mount)
++ * @dent_budget: budget for a directory entry (constant, nenver changed after
++ *               mount)
++ */
++struct ubifs_budg_info {
++      long long idx_growth;
++      long long data_growth;
++      long long dd_growth;
++      long long uncommitted_idx;
++      unsigned long long old_idx_sz;
++      int min_idx_lebs;
++      unsigned int nospace:1;
++      unsigned int nospace_rp:1;
++      int page_budget;
++      int inode_budget;
++      int dent_budget;
++};
++
+ struct ubifs_debug_info;
+ /**
+@@ -972,6 +1013,7 @@ struct ubifs_debug_info;
+  * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
+  *
+  * @big_lpt: flag that LPT is too big to write whole during commit
++ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
+  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
+  *                   recovery)
+  * @bulk_read: enable bulk-reads
+@@ -1003,6 +1045,11 @@ struct ubifs_debug_info;
+  * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu
+  * @bu: pre-allocated bulk-read information
+  *
++ * @write_reserve_mutex: protects @write_reserve_buf
++ * @write_reserve_buf: on the write path we allocate memory, which might
++ *                     sometimes be unavailable, in which case we use this
++ *                     write reserve buffer
++ *
+  * @log_lebs: number of logical eraseblocks in the log
+  * @log_bytes: log size in bytes
+  * @log_last: last LEB of the log
+@@ -1024,7 +1071,12 @@ struct ubifs_debug_info;
+  *
+  * @min_io_size: minimal input/output unit size
+  * @min_io_shift: number of bits in @min_io_size minus one
++ * @max_write_size: maximum amount of bytes the underlying flash can write at a
++ *                  time (MTD write buffer size)
++ * @max_write_shift: number of bits in @max_write_size minus one
+  * @leb_size: logical eraseblock size in bytes
++ * @leb_start: starting offset of logical eraseblocks within physical
++ *             eraseblocks
+  * @half_leb_size: half LEB size
+  * @idx_leb_size: how many bytes of an LEB are effectively available when it is
+  *                used to store indexing nodes (@leb_size - @max_idx_node_sz)
+@@ -1039,32 +1091,14 @@ struct ubifs_debug_info;
+  * @dirty_zn_cnt: number of dirty znodes
+  * @clean_zn_cnt: number of clean znodes
+  *
+- * @budg_idx_growth: amount of bytes budgeted for index growth
+- * @budg_data_growth: amount of bytes budgeted for cached data
+- * @budg_dd_growth: amount of bytes budgeted for cached data that will make
+- *                  other data dirty
+- * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
+- *                        but which still have to be taken into account because
+- *                        the index has not been committed so far
+- * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
+- *              @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
+- *              @nospace, and @nospace_rp;
+- * @min_idx_lebs: minimum number of LEBs required for the index
+- * @old_idx_sz: size of index on flash
++ * @space_lock: protects @bi and @lst
++ * @lst: lprops statistics
++ * @bi: budgeting information
+  * @calc_idx_sz: temporary variable which is used to calculate new index size
+  *               (contains accurate new index size at end of TNC commit start)
+- * @lst: lprops statistics
+- * @nospace: non-zero if the file-system does not have flash space (used as
+- *           optimization)
+- * @nospace_rp: the same as @nospace, but additionally means that even reserved
+- *              pool is full
+- *
+- * @page_budget: budget for a page
+- * @inode_budget: budget for an inode
+- * @dent_budget: budget for a directory entry
+  *
+  * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
+- * I/O unit
++ *                 I/O unit
+  * @mst_node_alsz: master node aligned size
+  * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
+  * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
+@@ -1166,22 +1200,20 @@ struct ubifs_debug_info;
+  * @rp_uid: reserved pool user ID
+  * @rp_gid: reserved pool group ID
+  *
+- * @empty: if the UBI device is empty
+- * @replay_tree: temporary tree used during journal replay
++ * @empty: %1 if the UBI device is empty
++ * @need_recovery: %1 if the file-system needs recovery
++ * @replaying: %1 during journal replay
++ * @mounting: %1 while mounting
++ * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
+  * @replay_list: temporary list used during journal replay
+  * @replay_buds: list of buds to replay
+  * @cs_sqnum: sequence number of first node in the log (commit start node)
+  * @replay_sqnum: sequence number of node currently being replayed
+- * @need_recovery: file-system needs recovery
+- * @replaying: set to %1 during journal replay
+  * @unclean_leb_list: LEBs to recover when re-mounting R/O mounted FS to R/W
+  *                    mode
+  * @rcvrd_mst_node: recovered master node to write when re-mounting R/O mounted
+  *                  FS to R/W mode
+  * @size_tree: inode size information for recovery
+- * @remounting_rw: set while re-mounting from R/O mode to R/W mode
+- * @always_chk_crc: always check CRCs (while mounting and remounting to R/W
+- *                  mode)
+  * @mount_opts: UBIFS-specific mount options
+  *
+  * @dbg: debugging-related information
+@@ -1221,6 +1253,7 @@ struct ubifs_info {
+       wait_queue_head_t cmt_wq;
+       unsigned int big_lpt:1;
++      unsigned int space_fixup:1;
+       unsigned int no_chk_data_crc:1;
+       unsigned int bulk_read:1;
+       unsigned int default_compr:2;
+@@ -1250,6 +1283,9 @@ struct ubifs_info {
+       struct mutex bu_mutex;
+       struct bu_info bu;
++      struct mutex write_reserve_mutex;
++      void *write_reserve_buf;
++
+       int log_lebs;
+       long long log_bytes;
+       int log_last;
+@@ -1271,7 +1307,10 @@ struct ubifs_info {
+       int min_io_size;
+       int min_io_shift;
++      int max_write_size;
++      int max_write_shift;
+       int leb_size;
++      int leb_start;
+       int half_leb_size;
+       int idx_leb_size;
+       int leb_cnt;
+@@ -1285,21 +1324,10 @@ struct ubifs_info {
+       atomic_long_t dirty_zn_cnt;
+       atomic_long_t clean_zn_cnt;
+-      long long budg_idx_growth;
+-      long long budg_data_growth;
+-      long long budg_dd_growth;
+-      long long budg_uncommitted_idx;
+       spinlock_t space_lock;
+-      int min_idx_lebs;
+-      unsigned long long old_idx_sz;
+-      unsigned long long calc_idx_sz;
+       struct ubifs_lp_stats lst;
+-      unsigned int nospace:1;
+-      unsigned int nospace_rp:1;
+-
+-      int page_budget;
+-      int inode_budget;
+-      int dent_budget;
++      struct ubifs_budg_info bi;
++      unsigned long long calc_idx_sz;
+       int ref_node_alsz;
+       int mst_node_alsz;
+@@ -1402,19 +1430,18 @@ struct ubifs_info {
+       gid_t rp_gid;
+       /* The below fields are used only during mounting and re-mounting */
+-      int empty;
+-      struct rb_root replay_tree;
++      unsigned int empty:1;
++      unsigned int need_recovery:1;
++      unsigned int replaying:1;
++      unsigned int mounting:1;
++      unsigned int remounting_rw:1;
+       struct list_head replay_list;
+       struct list_head replay_buds;
+       unsigned long long cs_sqnum;
+       unsigned long long replay_sqnum;
+-      int need_recovery;
+-      int replaying;
+       struct list_head unclean_leb_list;
+       struct ubifs_mst_node *rcvrd_mst_node;
+       struct rb_root size_tree;
+-      int remounting_rw;
+-      int always_chk_crc;
+       struct ubifs_mount_opts mount_opts;
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+@@ -1438,6 +1465,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+ /* io.c */
+ void ubifs_ro_mode(struct ubifs_info *c, int err);
++int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
++                 int len, int even_ebadmsg);
++int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                  int len, int dtype);
++int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                   int dtype);
++int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
++int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
++int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
+ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
+ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+                          int dtype);
+@@ -1605,6 +1641,7 @@ int ubifs_write_master(struct ubifs_info *c);
+ int ubifs_read_superblock(struct ubifs_info *c);
+ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
+ int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
++int ubifs_fixup_free_space(struct ubifs_info *c);
+ /* replay.c */
+ int ubifs_validate_entry(struct ubifs_info *c,
+@@ -1713,11 +1750,11 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
+ int ubifs_recover_master_node(struct ubifs_info *c);
+ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
+ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+-                                       int offs, void *sbuf, int grouped);
++                                       int offs, void *sbuf, int jhead);
+ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+                                            int offs, void *sbuf);
+-int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
+-int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
++int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
++int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
+ int ubifs_rcvry_gc_commit(struct ubifs_info *c);
+ int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
+                            int deletion, loff_t new_size);
+diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
+index c74400f..2fdc4fa 100644
+--- a/fs/ubifs/xattr.c
++++ b/fs/ubifs/xattr.c
+@@ -79,9 +79,9 @@ enum {
+       SECURITY_XATTR,
+ };
+-static const struct inode_operations none_inode_operations;
+-static const struct address_space_operations none_address_operations;
+-static const struct file_operations none_file_operations;
++static const struct inode_operations empty_iops;
++static const struct file_operations empty_fops;
++static struct address_space_operations empty_aops;
+ /**
+  * create_xattr - create an extended attribute.
+@@ -130,20 +130,19 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
+       }
+       /* Re-define all operations to be "nothing" */
+-      inode->i_mapping->a_ops = &none_address_operations;
+-      inode->i_op = &none_inode_operations;
+-      inode->i_fop = &none_file_operations;
++      inode->i_mapping->a_ops = &empty_aops;
++      inode->i_op = &empty_iops;
++      inode->i_fop = &empty_fops;
+       inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA;
+       ui = ubifs_inode(inode);
+       ui->xattr = 1;
+       ui->flags |= UBIFS_XATTR_FL;
+-      ui->data = kmalloc(size, GFP_NOFS);
++      ui->data = kmemdup(value, size, GFP_NOFS);
+       if (!ui->data) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+-      memcpy(ui->data, value, size);
+       inode->i_size = ui->ui_size = size;
+       ui->data_len = size;
+@@ -204,12 +203,11 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
+               return err;
+       kfree(ui->data);
+-      ui->data = kmalloc(size, GFP_NOFS);
++      ui->data = kmemdup(value, size, GFP_NOFS);
+       if (!ui->data) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+-      memcpy(ui->data, value, size);
+       inode->i_size = ui->ui_size = size;
+       ui->data_len = size;
+diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
+index b31bd9e..db4836b 100644
+--- a/include/linux/mtd/ubi.h
++++ b/include/linux/mtd/ubi.h
+@@ -21,7 +21,7 @@
+ #ifndef __LINUX_UBI_H__
+ #define __LINUX_UBI_H__
+-#include <asm/ioctl.h>
++#include <linux/ioctl.h>
+ #include <linux/types.h>
+ #include <mtd/ubi-user.h>
+@@ -87,7 +87,7 @@ enum {
+  * physical eraseblock size and on how much bytes UBI headers consume. But
+  * because of the volume alignment (@alignment), the usable size of logical
+  * eraseblocks if a volume may be less. The following equation is true:
+- *    @usable_leb_size = LEB size - (LEB size mod @alignment),
++ *    @usable_leb_size = LEB size - (LEB size mod @alignment),
+  * where LEB size is the logical eraseblock size defined by the UBI device.
+  *
+  * The alignment is multiple to the minimal flash input/output unit size or %1
+@@ -116,29 +116,53 @@ struct ubi_volume_info {
+  * struct ubi_device_info - UBI device description data structure.
+  * @ubi_num: ubi device number
+  * @leb_size: logical eraseblock size on this UBI device
++ * @leb_start: starting offset of logical eraseblocks within physical
++ *             eraseblocks
+  * @min_io_size: minimal I/O unit size
++ * @max_write_size: maximum amount of bytes the underlying flash can write at a
++ *                  time (MTD write buffer size)
+  * @ro_mode: if this device is in read-only mode
+  * @cdev: UBI character device major and minor numbers
+  *
+  * Note, @leb_size is the logical eraseblock size offered by the UBI device.
+  * Volumes of this UBI device may have smaller logical eraseblock size if their
+  * alignment is not equivalent to %1.
++ *
++ * The @max_write_size field describes flash write maximum write unit. For
++ * example, NOR flash allows for changing individual bytes, so @min_io_size is
++ * %1. However, it does not mean than NOR flash has to write data byte-by-byte.
++ * Instead, CFI NOR flashes have a write-buffer of, e.g., 64 bytes, and when
++ * writing large chunks of data, they write 64-bytes at a time. Obviously, this
++ * improves write throughput.
++ *
++ * Also, the MTD device may have N interleaved (striped) flash chips
++ * underneath, in which case @min_io_size can be physical min. I/O size of
++ * single flash chip, while @max_write_size can be N * @min_io_size.
++ *
++ * The @max_write_size field is always greater or equivalent to @min_io_size.
++ * E.g., some NOR flashes may have (@min_io_size = 1, @max_write_size = 64). In
++ * contrast, NAND flashes usually have @min_io_size = @max_write_size = NAND
++ * page size.
+  */
+ struct ubi_device_info {
+       int ubi_num;
+       int leb_size;
++      int leb_start;
+       int min_io_size;
++      int max_write_size;
+       int ro_mode;
+       dev_t cdev;
+ };
+ /*
+- * enum - volume notification types.
+- * @UBI_VOLUME_ADDED: volume has been added
+- * @UBI_VOLUME_REMOVED: start volume volume
+- * @UBI_VOLUME_RESIZED: volume size has been re-sized
+- * @UBI_VOLUME_RENAMED: volume name has been re-named
+- * @UBI_VOLUME_UPDATED: volume name has been updated
++ * Volume notification types.
++ * @UBI_VOLUME_ADDED: a volume has been added (an UBI device was attached or a
++ *                    volume was created)
++ * @UBI_VOLUME_REMOVED: a volume has been removed (an UBI device was detached
++ *                    or a volume was removed)
++ * @UBI_VOLUME_RESIZED: a volume has been re-sized
++ * @UBI_VOLUME_RENAMED: a volume has been re-named
++ * @UBI_VOLUME_UPDATED: data has been written to a volume
+  *
+  * These constants define which type of event has happened when a volume
+  * notification function is invoked.
diff --git a/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig b/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig
new file mode 100644 (file)
index 0000000..6b76af3
--- /dev/null
@@ -0,0 +1,2234 @@
+#
+# Automatically generated make config: don't edit
+# Linux/mips 2.6.37-2.8 Kernel Configuration
+# Fri Aug 31 17:36:37 2012
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+CONFIG_BRCMSTB=y
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_CAVIUM_OCTEON_HELPER=y
+
+#
+# Broadcom STB options
+#
+# CONFIG_BRCM_LEGACY is not set
+# CONFIG_BCM7125C0 is not set
+# CONFIG_BCM7231B0 is not set
+# CONFIG_BCM7340B0 is not set
+# CONFIG_BCM7344B0 is not set
+# CONFIG_BCM7346B0 is not set
+# CONFIG_BCM7358A0 is not set
+# CONFIG_BCM7405B0 is not set
+# CONFIG_BCM7405D0 is not set
+# CONFIG_BCM7408B0 is not set
+# CONFIG_BCM7420C0 is not set
+CONFIG_BCM7425B0=y
+# CONFIG_BCM7429A0 is not set
+# CONFIG_BCM7435A0 is not set
+# CONFIG_BCM7468B0 is not set
+# CONFIG_BCM7550A0 is not set
+# CONFIG_BCM7550B0 is not set
+# CONFIG_BCM7552B0 is not set
+
+#
+# Memory map
+#
+CONFIG_BRCM_UPPER_MEMORY=y
+# CONFIG_BRCM_OVERRIDE_RAM_SIZE is not set
+
+#
+# Onchip peripherals
+#
+CONFIG_BRCM_CONSOLE_DEVICE=0
+CONFIG_BRCM_FLASH=y
+# CONFIG_BRCM_FIXED_MTD_PARTITIONS is not set
+CONFIG_MTD_BRCMNAND=y
+CONFIG_SPI_BRCMSTB=y
+CONFIG_BCMGENET=y
+
+#
+# BCMGENET options
+#
+# CONFIG_BCMGENET_0_GPHY is not set
+# CONFIG_BCMGENET_RX_DESC_THROTTLE is not set
+CONFIG_BCMGENET_NAPI=y
+# CONFIG_BCMGENET_RX_CSUM is not set
+# CONFIG_BCMGENET_TX_CSUM is not set
+# CONFIG_BCMGENET_DUMP_DATA is not set
+# CONFIG_BCMGENET_DUMP_TRACE is not set
+CONFIG_BRCM_USB=y
+# CONFIG_BRCM_OVERRIDE_USB is not set
+CONFIG_BRCM_SDIO=y
+CONFIG_BRCM_PM=y
+CONFIG_CSRC_WKTMR=y
+# CONFIG_CSRC_UPG is not set
+
+#
+# Miscellaneous options
+#
+# CONFIG_BRCM_FORCE_DOCSIS is not set
+CONFIG_BRCM_LIBGCC=y
+# CONFIG_BRCM_SCSI_NO_RW10_RETRIES is not set
+CONFIG_BRCM_WLAN_MODULES=y
+# CONFIG_BRCM_DEBUG_OPTIONS is not set
+CONFIG_BMIPS5000=y
+CONFIG_BRCM_HAS_16550=y
+CONFIG_BRCM_HAS_UARTA=y
+CONFIG_BRCM_HAS_UARTB=y
+CONFIG_BRCM_HAS_UARTC=y
+CONFIG_BRCM_UARTA_IS_16550=y
+CONFIG_BRCM_UARTB_IS_16550=y
+CONFIG_BRCM_UARTC_IS_16550=y
+CONFIG_BRCM_HAS_PCIE=y
+CONFIG_BRCM_GENET_V3=y
+CONFIG_BRCM_GENET_VERSION=3
+CONFIG_BRCM_HAS_GENET=y
+CONFIG_BRCM_HAS_GENET_0=y
+CONFIG_BRCM_MOCA_ON_GENET_1=y
+CONFIG_BRCM_HAS_SATA=y
+CONFIG_BRCM_HAS_SATA3=y
+# CONFIG_BRCM_SATA_75MHZ_PLL is not set
+# CONFIG_BRCM_SATA_SINGLE_PORT is not set
+CONFIG_BRCM_HAS_NOR=y
+CONFIG_BRCM_HAS_NAND_MINOR_0=y
+CONFIG_BRCM_HAS_NAND_MAJOR_5=y
+CONFIG_BRCMNAND_MAJOR_VERS=5
+CONFIG_BRCMNAND_MINOR_VERS=0
+CONFIG_BRCM_HAS_NAND=y
+CONFIG_BRCM_HAS_EDU=y
+CONFIG_BRCM_HAS_SPI=y
+CONFIG_BRCM_HAS_BSPI_V4=y
+CONFIG_BRCM_BSPI_MAJOR_VERS=4
+CONFIG_BRCM_HAS_WKTMR=y
+CONFIG_BRCM_HAS_SDIO=y
+CONFIG_BRCM_HAS_SDIO_V1=y
+CONFIG_BRCM_HAS_EMMC=y
+CONFIG_BRCM_ZSCM_L2=y
+CONFIG_BRCM_CPU_DIV=y
+CONFIG_BRCM_HAS_XKS01=y
+CONFIG_BRCM_HAS_XI=y
+CONFIG_BRCM_HAS_UPPER_MEMORY=y
+CONFIG_BRCM_UPPER_768MB=y
+CONFIG_BRCM_HAS_2GB_MEMC0=y
+CONFIG_BRCM_HAS_1GB_MEMC1=y
+CONFIG_BRCM_HAS_DIGITAL_DDR_PHY=y
+CONFIG_BRCM_HAS_STANDBY=y
+CONFIG_BRCM_HAS_AON=y
+CONFIG_BRCM_PWR_HANDSHAKE=y
+CONFIG_BRCM_PWR_HANDSHAKE_V1=y
+CONFIG_BRCM_PLATFORM_DEFAULTS=y
+CONFIG_BCM7425=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_BOOT_RAW=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CFE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_BOARD_SCACHE=y
+CONFIG_MIPS_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SMP=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_USE_OF is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
+# CONFIG_HAVE_SPARSE_IRQ is not set
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_PENDING_IRQ is not set
+# CONFIG_AUTO_IRQ_AFFINITY is not set
+CONFIG_IRQ_PER_CPU=y
+# CONFIG_HARDIRQS_SW_RESEND is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+CONFIG_MTD_ABSENT=y
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_DENALI is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_IWMC3200TOP is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_AHCI_PLATFORM=y
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_MII=y
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=m
+# CONFIG_RT2400PCI is not set
+# CONFIG_RT2500PCI is not set
+# CONFIG_RT61PCI is not set
+CONFIG_RT2800PCI_PCI=y
+# CONFIG_RT2800PCI is not set
+# CONFIG_RT2500USB is not set
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_DEBUG is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=y
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DVB_CORE=y
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_LIRC=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+CONFIG_IR_RC5_SZ_DECODER=y
+CONFIG_IR_LIRC_CODEC=y
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=y
+CONFIG_MEDIA_TUNER_CUSTOMISE=y
+
+#
+# Customize TV tuners
+#
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_MT2131=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_MEDIA_TUNER_MXL5007T=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MAX2165=m
+CONFIG_MEDIA_TUNER_TDA18218=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_DVB_DYNAMIC_MINORS=y
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+# CONFIG_TTPCI_EEPROM is not set
+# CONFIG_DVB_BUDGET_CORE is not set
+
+#
+# Supported USB Adapters
+#
+# CONFIG_DVB_USB is not set
+# CONFIG_DVB_TTUSB_BUDGET is not set
+# CONFIG_DVB_TTUSB_DEC is not set
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported SDMC DM1105 Adapters
+#
+# CONFIG_DVB_DM1105 is not set
+
+#
+# Supported Earthsoft PT1 Adapters
+#
+# CONFIG_DVB_PT1 is not set
+
+#
+# Supported Mantis Adapters
+#
+# CONFIG_MANTIS_CORE is not set
+
+#
+# Supported nGene Adapters
+#
+# CONFIG_DVB_NGENE is not set
+
+#
+# Supported DVB Frontends
+#
+CONFIG_DVB_FE_CUSTOMISE=y
+
+#
+# Customise DVB Frontends
+#
+
+#
+# Multistandard (satellite) frontends
+#
+CONFIG_DVB_STB0899=m
+CONFIG_DVB_STB6100=m
+CONFIG_DVB_STV090x=m
+CONFIG_DVB_STV6110x=m
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_ZL10036=m
+CONFIG_DVB_ZL10039=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0288=m
+CONFIG_DVB_STB6000=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_STV6110=m
+CONFIG_DVB_STV0900=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_TDA8261=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TUA6100=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+CONFIG_DVB_MB86A16=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_S5H1432=m
+CONFIG_DVB_DRX397XD=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+CONFIG_DVB_AF9013=m
+CONFIG_DVB_EC100=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_LGDT3305=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_S5H1411=m
+
+#
+# ISDB-T (terrestrial) frontends
+#
+CONFIG_DVB_S921=m
+CONFIG_DVB_DIB8000=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+CONFIG_DVB_ISL6405=m
+CONFIG_DVB_ISL6421=m
+CONFIG_DVB_ISL6423=m
+CONFIG_DVB_LGS8GL5=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_TDA665x=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_MIPS=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_WDM=m
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_BKL=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.0307 b/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.0307
new file mode 100644 (file)
index 0000000..a4b2d51
--- /dev/null
@@ -0,0 +1,2212 @@
+#
+# Automatically generated make config: don't edit
+# Linux/mips 2.6.37-2.4 Kernel Configuration
+# Tue Mar  6 19:12:02 2012
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+CONFIG_BRCMSTB=y
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_CAVIUM_OCTEON_HELPER=y
+
+#
+# Broadcom STB options
+#
+# CONFIG_BRCM_LEGACY is not set
+# CONFIG_BCM35125C0 is not set
+# CONFIG_BCM35126B0 is not set
+# CONFIG_BCM35230C0 is not set
+# CONFIG_BCM35330A0 is not set
+# CONFIG_BCM7125C0 is not set
+# CONFIG_BCM7231A0 is not set
+# CONFIG_BCM7231B0 is not set
+# CONFIG_BCM7340B0 is not set
+# CONFIG_BCM7342B0 is not set
+# CONFIG_BCM7344A0 is not set
+# CONFIG_BCM7344B0 is not set
+# CONFIG_BCM7346A0 is not set
+# CONFIG_BCM7346B0 is not set
+# CONFIG_BCM7358A0 is not set
+# CONFIG_BCM7405B0 is not set
+# CONFIG_BCM7405D0 is not set
+# CONFIG_BCM7408B0 is not set
+# CONFIG_BCM7420C0 is not set
+CONFIG_BCM7425A0=y
+# CONFIG_BCM7425B0 is not set
+# CONFIG_BCM7429A0 is not set
+# CONFIG_BCM7435A0 is not set
+# CONFIG_BCM7468B0 is not set
+# CONFIG_BCM7550A0 is not set
+# CONFIG_BCM7550B0 is not set
+# CONFIG_BCM7552A0 is not set
+# CONFIG_BCM7552B0 is not set
+# CONFIG_BCM7631B0 is not set
+# CONFIG_BCM7640A0 is not set
+# CONFIG_BCM7640B0 is not set
+
+#
+# Memory map
+#
+CONFIG_BRCM_UPPER_MEMORY=y
+# CONFIG_BRCM_OVERRIDE_RAM_SIZE is not set
+
+#
+# Onchip peripherals
+#
+CONFIG_BRCM_CONSOLE_DEVICE=0
+CONFIG_BRCM_FLASH=y
+# CONFIG_BRCM_FIXED_MTD_PARTITIONS is not set
+CONFIG_MTD_BRCMNAND=y
+CONFIG_SPI_BRCMSTB=y
+CONFIG_BCMGENET=y
+
+#
+# BCMGENET options
+#
+# CONFIG_BCMGENET_0_GPHY is not set
+# CONFIG_BCMGENET_1_GPHY is not set
+# CONFIG_BCMGENET_RX_DESC_THROTTLE is not set
+CONFIG_BCMGENET_NAPI=y
+# CONFIG_BCMGENET_RX_CSUM is not set
+# CONFIG_BCMGENET_TX_CSUM is not set
+# CONFIG_BCMGENET_DUMP_DATA is not set
+# CONFIG_BCMGENET_DUMP_TRACE is not set
+CONFIG_BRCM_MOCA=y
+CONFIG_BRCM_USB=y
+# CONFIG_BRCM_OVERRIDE_USB is not set
+CONFIG_BRCM_SDIO=y
+CONFIG_BRCM_PM=y
+CONFIG_CSRC_WKTMR=y
+# CONFIG_CSRC_UPG is not set
+
+#
+# Miscellaneous options
+#
+# CONFIG_BRCM_FORCE_DOCSIS is not set
+CONFIG_BRCM_LIBGCC=y
+# CONFIG_BRCM_SCSI_NO_RW10_RETRIES is not set
+CONFIG_BRCM_WLAN_MODULES=y
+# CONFIG_BRCM_DEBUG_OPTIONS is not set
+CONFIG_BMIPS5000=y
+CONFIG_BRCM_HAS_16550=y
+CONFIG_BRCM_HAS_UARTA=y
+CONFIG_BRCM_HAS_UARTB=y
+CONFIG_BRCM_HAS_UARTC=y
+CONFIG_BRCM_UARTA_IS_16550=y
+CONFIG_BRCM_UARTB_IS_16550=y
+CONFIG_BRCM_UARTC_IS_16550=y
+CONFIG_BRCM_HAS_PCIE=y
+CONFIG_BRCM_GENET_V2=y
+CONFIG_BRCM_GENET_VERSION=2
+CONFIG_BRCM_HAS_GENET=y
+CONFIG_BRCM_HAS_GENET_0=y
+CONFIG_BRCM_HAS_GENET_1=y
+CONFIG_BRCM_HAS_MOCA=y
+CONFIG_BRCM_HAS_MOCA_11_PLUS=y
+CONFIG_BRCM_MOCA_VERS=0x1102
+CONFIG_BRCM_MOCA_ON_GENET_1=y
+CONFIG_BRCM_HAS_SATA=y
+CONFIG_BRCM_HAS_SATA3=y
+# CONFIG_BRCM_SATA_75MHZ_PLL is not set
+# CONFIG_BRCM_SATA_SINGLE_PORT is not set
+CONFIG_BRCM_HAS_NOR=y
+CONFIG_BRCM_HAS_NAND_MINOR_0=y
+CONFIG_BRCM_HAS_NAND_MAJOR_5=y
+CONFIG_BRCMNAND_MAJOR_VERS=5
+CONFIG_BRCMNAND_MINOR_VERS=0
+CONFIG_BRCM_HAS_NAND=y
+CONFIG_BRCM_HAS_EDU=y
+CONFIG_BRCM_HAS_SPI=y
+CONFIG_BRCM_HAS_BSPI_V4=y
+CONFIG_BRCM_BSPI_MAJOR_VERS=4
+CONFIG_BRCM_HAS_WKTMR=y
+CONFIG_BRCM_HAS_SDIO=y
+CONFIG_BRCM_HAS_SDIO_V1=y
+CONFIG_BRCM_HAS_EMMC=y
+CONFIG_BRCM_ZSCM_L2=y
+CONFIG_BRCM_CPU_DIV=y
+CONFIG_BRCM_HAS_XKS01=y
+CONFIG_BRCM_HAS_UPPER_MEMORY=y
+CONFIG_BRCM_UPPER_768MB=y
+CONFIG_BRCM_HAS_2GB_MEMC0=y
+CONFIG_BRCM_HAS_1GB_MEMC1=y
+CONFIG_BRCM_HAS_DIGITAL_DDR_PHY=y
+CONFIG_BRCM_HAS_STANDBY=y
+CONFIG_BRCM_HAS_AON=y
+CONFIG_BRCM_PWR_HANDSHAKE=y
+CONFIG_BRCM_PWR_HANDSHAKE_V0=y
+CONFIG_BRCM_PLATFORM_DEFAULTS=y
+CONFIG_BCM7425=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_BOOT_RAW=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CFE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_BOARD_SCACHE=y
+CONFIG_MIPS_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SMP=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_USE_OF is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
+# CONFIG_HAVE_SPARSE_IRQ is not set
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_PENDING_IRQ is not set
+# CONFIG_AUTO_IRQ_AFFINITY is not set
+CONFIG_IRQ_PER_CPU=y
+# CONFIG_HARDIRQS_SW_RESEND is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+CONFIG_MTD_ABSENT=y
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_DENALI is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_IWMC3200TOP is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI=y
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_MII=y
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=m
+# CONFIG_RT2400PCI is not set
+# CONFIG_RT2500PCI is not set
+# CONFIG_RT61PCI is not set
+CONFIG_RT2800PCI_PCI=y
+# CONFIG_RT2800PCI is not set
+# CONFIG_RT2500USB is not set
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_DEBUG is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=y
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_VT_CONSOLE is not set
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DVB_CORE=y
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_LIRC=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+CONFIG_IR_RC5_SZ_DECODER=y
+CONFIG_IR_LIRC_CODEC=y
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=y
+CONFIG_MEDIA_TUNER_CUSTOMISE=y
+
+#
+# Customize TV tuners
+#
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_MT2131=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_MEDIA_TUNER_MXL5007T=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MAX2165=m
+CONFIG_MEDIA_TUNER_TDA18218=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_DVB_DYNAMIC_MINORS=y
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+# CONFIG_TTPCI_EEPROM is not set
+# CONFIG_DVB_BUDGET_CORE is not set
+
+#
+# Supported USB Adapters
+#
+# CONFIG_DVB_USB is not set
+# CONFIG_DVB_TTUSB_BUDGET is not set
+# CONFIG_DVB_TTUSB_DEC is not set
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported SDMC DM1105 Adapters
+#
+# CONFIG_DVB_DM1105 is not set
+
+#
+# Supported Earthsoft PT1 Adapters
+#
+# CONFIG_DVB_PT1 is not set
+
+#
+# Supported Mantis Adapters
+#
+# CONFIG_MANTIS_CORE is not set
+
+#
+# Supported nGene Adapters
+#
+# CONFIG_DVB_NGENE is not set
+
+#
+# Supported DVB Frontends
+#
+CONFIG_DVB_FE_CUSTOMISE=y
+
+#
+# Customise DVB Frontends
+#
+
+#
+# Multistandard (satellite) frontends
+#
+CONFIG_DVB_STB0899=m
+CONFIG_DVB_STB6100=m
+CONFIG_DVB_STV090x=m
+CONFIG_DVB_STV6110x=m
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_ZL10036=m
+CONFIG_DVB_ZL10039=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0288=m
+CONFIG_DVB_STB6000=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_STV6110=m
+CONFIG_DVB_STV0900=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_TDA8261=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TUA6100=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+CONFIG_DVB_MB86A16=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_S5H1432=m
+CONFIG_DVB_DRX397XD=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+CONFIG_DVB_AF9013=m
+CONFIG_DVB_EC100=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_LGDT3305=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_S5H1411=m
+
+#
+# ISDB-T (terrestrial) frontends
+#
+CONFIG_DVB_S921=m
+CONFIG_DVB_DIB8000=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+CONFIG_DVB_ISL6405=m
+CONFIG_DVB_ISL6421=m
+CONFIG_DVB_ISL6423=m
+CONFIG_DVB_LGS8GL5=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_TDA665x=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_MIPS=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_WDM=m
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_BKL=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.0308 b/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.0308
new file mode 100644 (file)
index 0000000..55b418b
--- /dev/null
@@ -0,0 +1,2263 @@
+#
+# Automatically generated make config: don't edit
+# Linux/mips 2.6.37-2.4 Kernel Configuration
+# Wed Mar  7 15:29:18 2012
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+CONFIG_BRCMSTB=y
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_CAVIUM_OCTEON_HELPER=y
+
+#
+# Broadcom STB options
+#
+# CONFIG_BRCM_LEGACY is not set
+# CONFIG_BCM35125C0 is not set
+# CONFIG_BCM35126B0 is not set
+# CONFIG_BCM35230C0 is not set
+# CONFIG_BCM35330A0 is not set
+# CONFIG_BCM7125C0 is not set
+# CONFIG_BCM7231A0 is not set
+# CONFIG_BCM7231B0 is not set
+# CONFIG_BCM7340B0 is not set
+# CONFIG_BCM7342B0 is not set
+# CONFIG_BCM7344A0 is not set
+# CONFIG_BCM7344B0 is not set
+# CONFIG_BCM7346A0 is not set
+# CONFIG_BCM7346B0 is not set
+# CONFIG_BCM7358A0 is not set
+# CONFIG_BCM7405B0 is not set
+# CONFIG_BCM7405D0 is not set
+# CONFIG_BCM7408B0 is not set
+# CONFIG_BCM7420C0 is not set
+CONFIG_BCM7425A0=y
+# CONFIG_BCM7425B0 is not set
+# CONFIG_BCM7429A0 is not set
+# CONFIG_BCM7435A0 is not set
+# CONFIG_BCM7468B0 is not set
+# CONFIG_BCM7550A0 is not set
+# CONFIG_BCM7550B0 is not set
+# CONFIG_BCM7552A0 is not set
+# CONFIG_BCM7552B0 is not set
+# CONFIG_BCM7631B0 is not set
+# CONFIG_BCM7640A0 is not set
+# CONFIG_BCM7640B0 is not set
+
+#
+# Memory map
+#
+CONFIG_BRCM_UPPER_MEMORY=y
+# CONFIG_BRCM_OVERRIDE_RAM_SIZE is not set
+
+#
+# Onchip peripherals
+#
+CONFIG_BRCM_CONSOLE_DEVICE=0
+CONFIG_BRCM_FLASH=y
+# CONFIG_BRCM_FIXED_MTD_PARTITIONS is not set
+CONFIG_MTD_BRCMNAND=y
+CONFIG_SPI_BRCMSTB=y
+CONFIG_BCMGENET=y
+
+#
+# BCMGENET options
+#
+# CONFIG_BCMGENET_0_GPHY is not set
+# CONFIG_BCMGENET_1_GPHY is not set
+# CONFIG_BCMGENET_RX_DESC_THROTTLE is not set
+CONFIG_BCMGENET_NAPI=y
+# CONFIG_BCMGENET_RX_CSUM is not set
+# CONFIG_BCMGENET_TX_CSUM is not set
+# CONFIG_BCMGENET_DUMP_DATA is not set
+# CONFIG_BCMGENET_DUMP_TRACE is not set
+CONFIG_BRCM_MOCA=y
+CONFIG_BRCM_USB=y
+# CONFIG_BRCM_OVERRIDE_USB is not set
+CONFIG_BRCM_SDIO=y
+CONFIG_BRCM_PM=y
+CONFIG_CSRC_WKTMR=y
+# CONFIG_CSRC_UPG is not set
+
+#
+# Miscellaneous options
+#
+# CONFIG_BRCM_FORCE_DOCSIS is not set
+CONFIG_BRCM_LIBGCC=y
+# CONFIG_BRCM_SCSI_NO_RW10_RETRIES is not set
+CONFIG_BRCM_WLAN_MODULES=y
+# CONFIG_BRCM_DEBUG_OPTIONS is not set
+CONFIG_BMIPS5000=y
+CONFIG_BRCM_HAS_16550=y
+CONFIG_BRCM_HAS_UARTA=y
+CONFIG_BRCM_HAS_UARTB=y
+CONFIG_BRCM_HAS_UARTC=y
+CONFIG_BRCM_UARTA_IS_16550=y
+CONFIG_BRCM_UARTB_IS_16550=y
+CONFIG_BRCM_UARTC_IS_16550=y
+CONFIG_BRCM_HAS_PCIE=y
+CONFIG_BRCM_GENET_V2=y
+CONFIG_BRCM_GENET_VERSION=2
+CONFIG_BRCM_HAS_GENET=y
+CONFIG_BRCM_HAS_GENET_0=y
+CONFIG_BRCM_HAS_GENET_1=y
+CONFIG_BRCM_HAS_MOCA=y
+CONFIG_BRCM_HAS_MOCA_11_PLUS=y
+CONFIG_BRCM_MOCA_VERS=0x1102
+CONFIG_BRCM_MOCA_ON_GENET_1=y
+CONFIG_BRCM_HAS_SATA=y
+CONFIG_BRCM_HAS_SATA3=y
+# CONFIG_BRCM_SATA_75MHZ_PLL is not set
+# CONFIG_BRCM_SATA_SINGLE_PORT is not set
+CONFIG_BRCM_HAS_NOR=y
+CONFIG_BRCM_HAS_NAND_MINOR_0=y
+CONFIG_BRCM_HAS_NAND_MAJOR_5=y
+CONFIG_BRCMNAND_MAJOR_VERS=5
+CONFIG_BRCMNAND_MINOR_VERS=0
+CONFIG_BRCM_HAS_NAND=y
+CONFIG_BRCM_HAS_EDU=y
+CONFIG_BRCM_HAS_SPI=y
+CONFIG_BRCM_HAS_BSPI_V4=y
+CONFIG_BRCM_BSPI_MAJOR_VERS=4
+CONFIG_BRCM_HAS_WKTMR=y
+CONFIG_BRCM_HAS_SDIO=y
+CONFIG_BRCM_HAS_SDIO_V1=y
+CONFIG_BRCM_HAS_EMMC=y
+CONFIG_BRCM_ZSCM_L2=y
+CONFIG_BRCM_CPU_DIV=y
+CONFIG_BRCM_HAS_XKS01=y
+CONFIG_BRCM_HAS_UPPER_MEMORY=y
+CONFIG_BRCM_UPPER_768MB=y
+CONFIG_BRCM_HAS_2GB_MEMC0=y
+CONFIG_BRCM_HAS_1GB_MEMC1=y
+CONFIG_BRCM_HAS_DIGITAL_DDR_PHY=y
+CONFIG_BRCM_HAS_STANDBY=y
+CONFIG_BRCM_HAS_AON=y
+CONFIG_BRCM_PWR_HANDSHAKE=y
+CONFIG_BRCM_PWR_HANDSHAKE_V0=y
+CONFIG_BRCM_PLATFORM_DEFAULTS=y
+CONFIG_BCM7425=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_BOOT_RAW=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CFE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_BOARD_SCACHE=y
+CONFIG_MIPS_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SMP=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_USE_OF is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
+# CONFIG_HAVE_SPARSE_IRQ is not set
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_PENDING_IRQ is not set
+# CONFIG_AUTO_IRQ_AFFINITY is not set
+CONFIG_IRQ_PER_CPU=y
+# CONFIG_HARDIRQS_SW_RESEND is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+CONFIG_MTD_ABSENT=y
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_DENALI is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_IWMC3200TOP is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI=y
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_MII=y
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_IWLWIFI is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=m
+# CONFIG_RT2400PCI is not set
+# CONFIG_RT2500PCI is not set
+# CONFIG_RT61PCI is not set
+CONFIG_RT2800PCI_PCI=y
+# CONFIG_RT2800PCI is not set
+# CONFIG_RT2500USB is not set
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_DEBUG is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=y
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_VT_CONSOLE is not set
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DVB_CORE=y
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_LIRC=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+CONFIG_IR_RC5_SZ_DECODER=y
+CONFIG_IR_LIRC_CODEC=y
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=y
+CONFIG_MEDIA_TUNER_CUSTOMISE=y
+
+#
+# Customize TV tuners
+#
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_MT2131=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_MEDIA_TUNER_MXL5007T=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MAX2165=m
+CONFIG_MEDIA_TUNER_TDA18218=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_DVB_DYNAMIC_MINORS=y
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+# CONFIG_TTPCI_EEPROM is not set
+# CONFIG_DVB_BUDGET_CORE is not set
+
+#
+# Supported USB Adapters
+#
+# CONFIG_DVB_USB is not set
+# CONFIG_DVB_TTUSB_BUDGET is not set
+# CONFIG_DVB_TTUSB_DEC is not set
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported SDMC DM1105 Adapters
+#
+# CONFIG_DVB_DM1105 is not set
+
+#
+# Supported Earthsoft PT1 Adapters
+#
+# CONFIG_DVB_PT1 is not set
+
+#
+# Supported Mantis Adapters
+#
+# CONFIG_MANTIS_CORE is not set
+
+#
+# Supported nGene Adapters
+#
+# CONFIG_DVB_NGENE is not set
+
+#
+# Supported DVB Frontends
+#
+CONFIG_DVB_FE_CUSTOMISE=y
+
+#
+# Customise DVB Frontends
+#
+
+#
+# Multistandard (satellite) frontends
+#
+CONFIG_DVB_STB0899=m
+CONFIG_DVB_STB6100=m
+CONFIG_DVB_STV090x=m
+CONFIG_DVB_STV6110x=m
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_ZL10036=m
+CONFIG_DVB_ZL10039=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0288=m
+CONFIG_DVB_STB6000=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_STV6110=m
+CONFIG_DVB_STV0900=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_TDA8261=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TUA6100=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+CONFIG_DVB_MB86A16=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_S5H1432=m
+CONFIG_DVB_DRX397XD=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+CONFIG_DVB_AF9013=m
+CONFIG_DVB_EC100=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_LGDT3305=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_S5H1411=m
+
+#
+# ISDB-T (terrestrial) frontends
+#
+CONFIG_DVB_S921=m
+CONFIG_DVB_DIB8000=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+CONFIG_DVB_ISL6405=m
+CONFIG_DVB_ISL6421=m
+CONFIG_DVB_ISL6423=m
+CONFIG_DVB_LGS8GL5=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_TDA665x=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_MIPS=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+CONFIG_USB_WDM=m
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_BKL=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.org b/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig.org
new file mode 100644 (file)
index 0000000..1debb96
--- /dev/null
@@ -0,0 +1,1755 @@
+#
+# Automatically generated make config: don't edit
+# Linux/mips 2.6.37-2.4 Kernel Configuration
+# Wed Dec 14 14:40:53 2011
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+CONFIG_BRCMSTB=y
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_CAVIUM_OCTEON_HELPER=y
+
+#
+# Broadcom STB options
+#
+# CONFIG_BRCM_LEGACY is not set
+# CONFIG_BCM35125C0 is not set
+# CONFIG_BCM35126B0 is not set
+# CONFIG_BCM35230C0 is not set
+# CONFIG_BCM35330A0 is not set
+# CONFIG_BCM7125C0 is not set
+# CONFIG_BCM7231A0 is not set
+# CONFIG_BCM7231B0 is not set
+# CONFIG_BCM7340B0 is not set
+# CONFIG_BCM7342B0 is not set
+# CONFIG_BCM7344A0 is not set
+# CONFIG_BCM7344B0 is not set
+# CONFIG_BCM7346A0 is not set
+# CONFIG_BCM7346B0 is not set
+# CONFIG_BCM7358A0 is not set
+# CONFIG_BCM7405B0 is not set
+# CONFIG_BCM7405D0 is not set
+# CONFIG_BCM7408B0 is not set
+# CONFIG_BCM7420C0 is not set
+CONFIG_BCM7425A0=y
+# CONFIG_BCM7425B0 is not set
+# CONFIG_BCM7429A0 is not set
+# CONFIG_BCM7435A0 is not set
+# CONFIG_BCM7468B0 is not set
+# CONFIG_BCM7550A0 is not set
+# CONFIG_BCM7550B0 is not set
+# CONFIG_BCM7552A0 is not set
+# CONFIG_BCM7552B0 is not set
+# CONFIG_BCM7631B0 is not set
+# CONFIG_BCM7640A0 is not set
+# CONFIG_BCM7640B0 is not set
+
+#
+# Memory map
+#
+CONFIG_BRCM_UPPER_MEMORY=y
+# CONFIG_BRCM_OVERRIDE_RAM_SIZE is not set
+
+#
+# Onchip peripherals
+#
+CONFIG_BRCM_CONSOLE_DEVICE=0
+CONFIG_BRCM_FLASH=y
+# CONFIG_BRCM_FIXED_MTD_PARTITIONS is not set
+CONFIG_MTD_BRCMNAND=y
+CONFIG_SPI_BRCMSTB=y
+CONFIG_BCMGENET=y
+
+#
+# BCMGENET options
+#
+# CONFIG_BCMGENET_0_GPHY is not set
+# CONFIG_BCMGENET_1_GPHY is not set
+# CONFIG_BCMGENET_RX_DESC_THROTTLE is not set
+CONFIG_BCMGENET_NAPI=y
+# CONFIG_BCMGENET_RX_CSUM is not set
+# CONFIG_BCMGENET_TX_CSUM is not set
+# CONFIG_BCMGENET_DUMP_DATA is not set
+# CONFIG_BCMGENET_DUMP_TRACE is not set
+CONFIG_BRCM_MOCA=y
+CONFIG_BRCM_USB=y
+# CONFIG_BRCM_OVERRIDE_USB is not set
+CONFIG_BRCM_SDIO=y
+CONFIG_BRCM_PM=y
+CONFIG_CSRC_WKTMR=y
+# CONFIG_CSRC_UPG is not set
+
+#
+# Miscellaneous options
+#
+# CONFIG_BRCM_FORCE_DOCSIS is not set
+CONFIG_BRCM_LIBGCC=y
+# CONFIG_BRCM_SCSI_NO_RW10_RETRIES is not set
+CONFIG_BRCM_WLAN_MODULES=y
+# CONFIG_BRCM_DEBUG_OPTIONS is not set
+CONFIG_BMIPS5000=y
+CONFIG_BRCM_HAS_16550=y
+CONFIG_BRCM_HAS_UARTA=y
+CONFIG_BRCM_HAS_UARTB=y
+CONFIG_BRCM_HAS_UARTC=y
+CONFIG_BRCM_UARTA_IS_16550=y
+CONFIG_BRCM_UARTB_IS_16550=y
+CONFIG_BRCM_UARTC_IS_16550=y
+CONFIG_BRCM_HAS_PCIE=y
+CONFIG_BRCM_GENET_V2=y
+CONFIG_BRCM_GENET_VERSION=2
+CONFIG_BRCM_HAS_GENET=y
+CONFIG_BRCM_HAS_GENET_0=y
+CONFIG_BRCM_HAS_GENET_1=y
+CONFIG_BRCM_HAS_MOCA=y
+CONFIG_BRCM_HAS_MOCA_11_PLUS=y
+CONFIG_BRCM_MOCA_VERS=0x1102
+CONFIG_BRCM_MOCA_ON_GENET_1=y
+CONFIG_BRCM_HAS_SATA=y
+CONFIG_BRCM_HAS_SATA3=y
+# CONFIG_BRCM_SATA_75MHZ_PLL is not set
+# CONFIG_BRCM_SATA_SINGLE_PORT is not set
+CONFIG_BRCM_HAS_NOR=y
+CONFIG_BRCM_HAS_NAND_MINOR_0=y
+CONFIG_BRCM_HAS_NAND_MAJOR_5=y
+CONFIG_BRCMNAND_MAJOR_VERS=5
+CONFIG_BRCMNAND_MINOR_VERS=0
+CONFIG_BRCM_HAS_NAND=y
+CONFIG_BRCM_HAS_EDU=y
+CONFIG_BRCM_HAS_SPI=y
+CONFIG_BRCM_HAS_BSPI_V4=y
+CONFIG_BRCM_BSPI_MAJOR_VERS=4
+CONFIG_BRCM_HAS_WKTMR=y
+CONFIG_BRCM_HAS_SDIO=y
+CONFIG_BRCM_HAS_SDIO_V1=y
+CONFIG_BRCM_HAS_EMMC=y
+CONFIG_BRCM_ZSCM_L2=y
+CONFIG_BRCM_CPU_DIV=y
+CONFIG_BRCM_HAS_XKS01=y
+CONFIG_BRCM_HAS_UPPER_MEMORY=y
+CONFIG_BRCM_UPPER_768MB=y
+CONFIG_BRCM_HAS_2GB_MEMC0=y
+CONFIG_BRCM_HAS_1GB_MEMC1=y
+CONFIG_BRCM_HAS_DIGITAL_DDR_PHY=y
+CONFIG_BRCM_HAS_STANDBY=y
+CONFIG_BRCM_HAS_AON=y
+CONFIG_BRCM_PWR_HANDSHAKE=y
+CONFIG_BRCM_PWR_HANDSHAKE_V0=y
+CONFIG_BRCM_PLATFORM_DEFAULTS=y
+CONFIG_BCM7425=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_BOOT_RAW=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CFE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_BOARD_SCACHE=y
+CONFIG_MIPS_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_HIGHMEM=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SMP=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_USE_OF is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
+# CONFIG_HAVE_SPARSE_IRQ is not set
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_PENDING_IRQ is not set
+# CONFIG_AUTO_IRQ_AFFINITY is not set
+CONFIG_IRQ_PER_CPU=y
+# CONFIG_HARDIRQS_SW_RESEND is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+
+#
+# Some wireless drivers require a rate control algorithm
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+CONFIG_MTD_ABSENT=y
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_DENALI is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_RICOH is not set
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+# CONFIG_IWMC3200TOP is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI=y
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_SIL24 is not set
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_MII=y
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+CONFIG_WLAN=y
+# CONFIG_ATMEL is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=y
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+# CONFIG_VT_CONSOLE is not set
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+# CONFIG_I2C is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_BKL=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/recipes/linux/linux-vuduo2_3.1.1.bb b/recipes/linux/linux-vuduo2_3.1.1.bb
new file mode 100644 (file)
index 0000000..d190b05
--- /dev/null
@@ -0,0 +1,51 @@
+DESCRIPTION = "Linux kernel for vuplus duo2"
+LICENSE = "GPL"
+KV = "3.1.1"
+
+SRCREV = "r0"
+
+MODULE = "linux-3.1.1"
+
+#      file://brcm_nand_timing.patch;patch=1;pnum=1 \
+
+SRC_URI += "file://stblinux-2.6.37-2.8.tar.bz2 \
+       file://dvb-core.patch;patch=1;pnum=1 \
+       file://pinmux.patch;patch=1;pnum=1 \
+       file://debug.patch;patch=1;pnum=1 \
+       file://fix_cpu_proc.patch;patch=1;pnum=1 \
+       file://brcm_disable_enet1.patch;patch=1;pnum=1 \
+       file://${MACHINE}_defconfig \
+        "
+
+S = "${WORKDIR}/stblinux-2.6.37"
+
+inherit kernel
+
+FILES_kernel-image = "/boot/vmlinux.gz /boot/autoexec.bat"
+
+export OS = "Linux"
+KERNEL_IMAGETYPE = "vmlinux"
+KERNEL_OUTPUT = "vmlinux"
+KERNEL_OBJECT_SUFFIX = "ko"
+
+
+do_configure_prepend() {
+        oe_machinstall -m 0644 ${WORKDIR}/${MACHINE}_defconfig ${S}/.config
+        oe_runmake oldconfig
+}
+
+kernel_do_install_append() {
+        install -d ${D}/${KERNEL_IMAGEDEST}
+        install -m 0755 ${KERNEL_OUTPUT} ${D}/${KERNEL_IMAGEDEST}
+        gzip ${D}/${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}
+}
+
+pkg_postinst_kernel-image () {
+        if [ -d /proc/stb ] ; then
+                flash_eraseall -j /dev/mtd1
+                nandwrite -p /dev/mtd1 /${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}.gz
+        fi
+        rm -f /${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}.gz
+        true
+}
+
diff --git a/recipes/linux/linux-vusolo2-2.6.37/bcmgenet_oobctrl.patch b/recipes/linux/linux-vusolo2-2.6.37/bcmgenet_oobctrl.patch
new file mode 100644 (file)
index 0000000..80183f9
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/drivers/net/bcmgenet/bcmmii.c b/drivers/net/bcmgenet/bcmmii.c
+index 7e2027a..127d2d0 100755
+--- a/drivers/net/bcmgenet/bcmmii.c
++++ b/drivers/net/bcmgenet/bcmmii.c
+@@ -229,7 +229,7 @@ int mii_init(struct net_device *dev)
+       case BRCM_PHY_TYPE_EXT_RGMII:
+               GENET_RGMII_OOB_CTRL(pDevCtrl) |= RGMII_MODE_EN;
+               /* Don't shift tx clock by 90 degree, does it still needed? */
+-              GENET_RGMII_OOB_CTRL(pDevCtrl) |= (1 << 16);
++              //csh GENET_RGMII_OOB_CTRL(pDevCtrl) |= (1 << 16);
+               pDevCtrl->mii.supports_gmii = 1;
+               pDevCtrl->sys->sys_port_ctrl = PORT_MODE_EXT_GPHY;
+               mii_write(dev, pDevCtrl->phyAddr, MII_BMCR, bmcr|MII_BMCR);
diff --git a/recipes/linux/linux-vusolo2-2.6.37/brcm_disable_enet1.patch b/recipes/linux/linux-vusolo2-2.6.37/brcm_disable_enet1.patch
new file mode 100644 (file)
index 0000000..698443d
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/arch/mips/brcmstb/bchip.c b/arch/mips/brcmstb/bchip.c
+index fc7883f..1fe5d4d 100644
+--- a/arch/mips/brcmstb/bchip.c
++++ b/arch/mips/brcmstb/bchip.c
+@@ -552,7 +552,7 @@ void __init bchip_set_features(void)
+       brcm_smp_enabled = 1;
+ #endif
+ #if defined(CONFIG_BRCM_HAS_EMAC_1) || defined(CONFIG_BRCM_HAS_GENET_1)
+-      brcm_enet1_enabled = 1;
++      brcm_enet1_enabled = 0;
+ #endif
+ #if defined(CONFIG_BRCM_HAS_MOCA)
+       brcm_moca_enabled = 1;
diff --git a/recipes/linux/linux-vusolo2-2.6.37/brcm_nand_timing.patch b/recipes/linux/linux-vusolo2-2.6.37/brcm_nand_timing.patch
new file mode 100644 (file)
index 0000000..aa06633
--- /dev/null
@@ -0,0 +1,16 @@
+diff --git a/drivers/mtd/nand/brcmstb_nand.c b/drivers/mtd/nand/brcmstb_nand.c
+index 97bd867..c28e090 100644
+--- a/drivers/mtd/nand/brcmstb_nand.c
++++ b/drivers/mtd/nand/brcmstb_nand.c
+@@ -1268,6 +1268,11 @@ static int __devinit brcmstb_nand_probe(struct platform_device *pdev)
+               goto out;
+       }
++      //Timing Adjust
++        BDEV_WR_RB(REG_TIMING_1(host->cs), 0x4232222D);
++        BDEV_WR_RB(REG_TIMING_2(host->cs), 0x1a84);
++
++
+ #ifdef CONFIG_MTD_PARTITIONS
+       nr_parts = parse_mtd_partitions(mtd, part_probe_types, &parts, 0);
+       if (nr_parts <= 0) {
diff --git a/recipes/linux/linux-vusolo2-2.6.37/debug.patch b/recipes/linux/linux-vusolo2-2.6.37/debug.patch
new file mode 100644 (file)
index 0000000..5576999
--- /dev/null
@@ -0,0 +1,44 @@
+diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
+index da606e6..d75f8c7 100644
+--- a/drivers/serial/8250.c
++++ b/drivers/serial/8250.c
+@@ -1319,6 +1319,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
+       if (up->port.flags & UPF_FOURPORT)
+               outb_p(save_ICP, ICP);
++      printk("irq %d\n", irq);
+       up->port.irq = (irq > 0) ? irq : 0;
+ }
+@@ -2774,6 +2775,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+       }
+       serial8250_isa_init_ports();
++      printk("serial8250_register_ports %d\n", nr_uarts);
+       for (i = 0; i < nr_uarts; i++) {
+               struct uart_8250_port *up = &serial8250_ports[i];
+@@ -2783,6 +2785,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+               if (up->port.flags & UPF_FIXED_TYPE)
+                       serial8250_init_fixed_type_port(up, up->port.type);
++              printk("serial8250_register_ports --> uart_add_one_port %d\n", up->port.irq);
+               uart_add_one_port(drv, &up->port);
+       }
+ }
+@@ -3045,6 +3048,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
+               port.pm                 = p->pm;
+               port.dev                = &dev->dev;
+               port.irqflags           |= irqflag;
++              printk("serial8250_probe %d\n", port.irq);
+               ret = serial8250_register_port(&port);
+               if (ret < 0) {
+                       dev_err(&dev->dev, "unable to register port at index %d "
+@@ -3216,6 +3220,7 @@ int serial8250_register_port(struct uart_port *port)
+                       serial8250_isa_config(0, &uart->port,
+                                       &uart->capabilities);
++              printk("serial8250_register_port %d --> uart_add_one_port\n", uart->port.irq);
+               ret = uart_add_one_port(&serial8250_reg, &uart->port);
+               if (ret == 0)
+                       ret = uart->port.line;
diff --git a/recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch b/recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch
new file mode 100644 (file)
index 0000000..87b1738
--- /dev/null
@@ -0,0 +1,1330 @@
+diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
+index 0b51828..8f22bcd 100644
+--- a/drivers/media/dvb/dvb-core/Makefile
++++ b/drivers/media/dvb/dvb-core/Makefile
+@@ -2,8 +2,10 @@
+ # Makefile for the kernel DVB device drivers.
+ #
++dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
++
+ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o   \
+                dvb_ca_en50221.o dvb_frontend.o                \
+-               dvb_net.o dvb_ringbuffer.o dvb_math.o
++               $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
+ obj-$(CONFIG_DVB_CORE) += dvb-core.o
+diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
+index ad1f61d..cb59681 100644
+--- a/drivers/media/dvb/dvb-core/dmxdev.c
++++ b/drivers/media/dvb/dvb-core/dmxdev.c
+@@ -83,7 +83,11 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+               ret = wait_event_interruptible(src->queue,
+                                              !dvb_ringbuffer_empty(src) ||
+-                                             (src->error != 0));
++                                             (src->error != 0) ||
++                                             (src->do_wait != 1));
++              if (src->do_wait != 1)
++                      ret = -EINTR;
++
+               if (ret < 0)
+                       break;
+@@ -572,13 +576,13 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+       dmx_output_t otype;
+       int ret;
+       int ts_type;
+-      enum dmx_ts_pes ts_pes;
++      dmx_pes_type_t ts_pes;
+       struct dmx_ts_feed *tsfeed;
+       feed->ts = NULL;
+       otype = para->output;
+-      ts_pes = (enum dmx_ts_pes)para->pes_type;
++      ts_pes = para->pes_type;
+       if (ts_pes < DMX_PES_OTHER)
+               ts_type = TS_DECODER;
+@@ -963,6 +967,22 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count,
+       return ret;
+ }
++static int dvb_demux_lock_filter(struct dmxdev_filter *dmxdevfilter)
++{
++      int ret;
++
++      dmxdevfilter->buffer.do_wait = 0;
++
++      if (waitqueue_active(&dmxdevfilter->buffer.queue))
++              wake_up(&dmxdevfilter->buffer.queue);
++
++      ret = mutex_lock_interruptible(&dmxdevfilter->mutex);
++
++      dmxdevfilter->buffer.do_wait = 1;
++
++      return ret;
++}
++
+ static int dvb_demux_do_ioctl(struct file *file,
+                             unsigned int cmd, void *parg)
+ {
+@@ -976,7 +996,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+       switch (cmd) {
+       case DMX_START:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -988,7 +1008,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_STOP:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -997,7 +1017,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_SET_FILTER:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -1006,7 +1026,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_SET_PES_FILTER:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -1015,7 +1035,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_SET_BUFFER_SIZE:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+@@ -1059,7 +1079,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_ADD_PID:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+@@ -1068,7 +1088,7 @@ static int dvb_demux_do_ioctl(struct file *file,
+               break;
+       case DMX_REMOVE_PID:
+-              if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
++              if (dvb_demux_lock_filter(dmxdevfilter)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
+index 4a88a3e..faa3671 100644
+--- a/drivers/media/dvb/dvb-core/dvb_demux.c
++++ b/drivers/media/dvb/dvb-core/dvb_demux.c
+@@ -478,97 +478,94 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
+ EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
+-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
++static inline int find_next_packet(const u8 *buf, int pos, size_t count,
++                                 const int pktsize)
+ {
+-      int p = 0, i, j;
++      int start = pos, lost;
+-      spin_lock(&demux->lock);
+-
+-      if (demux->tsbufp) {
+-              i = demux->tsbufp;
+-              j = 188 - i;
+-              if (count < j) {
+-                      memcpy(&demux->tsbuf[i], buf, count);
+-                      demux->tsbufp += count;
+-                      goto bailout;
+-              }
+-              memcpy(&demux->tsbuf[i], buf, j);
+-              if (demux->tsbuf[0] == 0x47)
+-                      dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+-              demux->tsbufp = 0;
+-              p += j;
++      while (pos < count) {
++              if (buf[pos] == 0x47 ||
++                  (pktsize == 204 && buf[pos] == 0xB8))
++                      break;
++              pos++;
+       }
+-      while (p < count) {
+-              if (buf[p] == 0x47) {
+-                      if (count - p >= 188) {
+-                              dvb_dmx_swfilter_packet(demux, &buf[p]);
+-                              p += 188;
+-                      } else {
+-                              i = count - p;
+-                              memcpy(demux->tsbuf, &buf[p], i);
+-                              demux->tsbufp = i;
+-                              goto bailout;
+-                      }
+-              } else
+-                      p++;
++      lost = pos - start;
++      if (lost) {
++              /* This garbage is part of a valid packet? */
++              int backtrack = pos - pktsize;
++              if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
++                  (pktsize == 204 && buf[backtrack] == 0xB8)))
++                      return backtrack;
+       }
+-bailout:
+-      spin_unlock(&demux->lock);
++      return pos;
+ }
+-EXPORT_SYMBOL(dvb_dmx_swfilter);
+-
+-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
++/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
++static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
++              size_t count, const int pktsize)
+ {
+       int p = 0, i, j;
+-      u8 tmppack[188];
++      const u8 *q;
+       spin_lock(&demux->lock);
+-      if (demux->tsbufp) {
++      if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
+               i = demux->tsbufp;
+-              j = 204 - i;
++              j = pktsize - i;
+               if (count < j) {
+                       memcpy(&demux->tsbuf[i], buf, count);
+                       demux->tsbufp += count;
+                       goto bailout;
+               }
+               memcpy(&demux->tsbuf[i], buf, j);
+-              if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
+-                      memcpy(tmppack, demux->tsbuf, 188);
+-                      if (tmppack[0] == 0xB8)
+-                              tmppack[0] = 0x47;
+-                      dvb_dmx_swfilter_packet(demux, tmppack);
+-              }
++              if (demux->tsbuf[0] == 0x47) /* double check */
++                      dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+               demux->tsbufp = 0;
+               p += j;
+       }
+-      while (p < count) {
+-              if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
+-                      if (count - p >= 204) {
+-                              memcpy(tmppack, &buf[p], 188);
+-                              if (tmppack[0] == 0xB8)
+-                                      tmppack[0] = 0x47;
+-                              dvb_dmx_swfilter_packet(demux, tmppack);
+-                              p += 204;
+-                      } else {
+-                              i = count - p;
+-                              memcpy(demux->tsbuf, &buf[p], i);
+-                              demux->tsbufp = i;
+-                              goto bailout;
+-                      }
+-              } else {
+-                      p++;
++      while (1) {
++              p = find_next_packet(buf, p, count, pktsize);
++              if (p >= count)
++                      break;
++              if (count - p < pktsize)
++                      break;
++
++              q = &buf[p];
++
++              if (pktsize == 204 && (*q == 0xB8)) {
++                      memcpy(demux->tsbuf, q, 188);
++                      demux->tsbuf[0] = 0x47;
++                      q = demux->tsbuf;
+               }
++              dvb_dmx_swfilter_packet(demux, q);
++              p += pktsize;
++      }
++
++      i = count - p;
++      if (i) {
++              memcpy(demux->tsbuf, &buf[p], i);
++              demux->tsbufp = i;
++              if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
++                      demux->tsbuf[0] = 0x47;
+       }
+ bailout:
+       spin_unlock(&demux->lock);
+ }
++void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
++{
++      _dvb_dmx_swfilter(demux, buf, count, 188);
++}
++EXPORT_SYMBOL(dvb_dmx_swfilter);
++
++void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
++{
++      _dvb_dmx_swfilter(demux, buf, count, 204);
++}
+ EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+ static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
+index cad6634..efe9c30 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
+@@ -105,7 +105,8 @@ struct dvb_frontend_private {
+       /* thread/frontend values */
+       struct dvb_device *dvbdev;
+-      struct dvb_frontend_parameters parameters;
++      struct dvb_frontend_parameters parameters_in;
++      struct dvb_frontend_parameters parameters_out;
+       struct dvb_fe_events events;
+       struct semaphore sem;
+       struct list_head list_head;
+@@ -160,12 +161,11 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
+       e = &events->events[events->eventw];
+-      memcpy (&e->parameters, &fepriv->parameters,
+-              sizeof (struct dvb_frontend_parameters));
+-
+       if (status & FE_HAS_LOCK)
+               if (fe->ops.get_frontend)
+-                      fe->ops.get_frontend(fe, &e->parameters);
++                      fe->ops.get_frontend(fe, &fepriv->parameters_out);
++
++      e->parameters = fepriv->parameters_out;
+       events->eventw = wp;
+@@ -277,12 +277,12 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
+       int ready = 0;
+       int fe_set_err = 0;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+-      int original_inversion = fepriv->parameters.inversion;
+-      u32 original_frequency = fepriv->parameters.frequency;
++      int original_inversion = fepriv->parameters_in.inversion;
++      u32 original_frequency = fepriv->parameters_in.frequency;
+       /* are we using autoinversion? */
+       autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+-                       (fepriv->parameters.inversion == INVERSION_AUTO));
++                       (fepriv->parameters_in.inversion == INVERSION_AUTO));
+       /* setup parameters correctly */
+       while(!ready) {
+@@ -348,18 +348,19 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
+               fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
+       /* set the frontend itself */
+-      fepriv->parameters.frequency += fepriv->lnb_drift;
++      fepriv->parameters_in.frequency += fepriv->lnb_drift;
+       if (autoinversion)
+-              fepriv->parameters.inversion = fepriv->inversion;
++              fepriv->parameters_in.inversion = fepriv->inversion;
+       if (fe->ops.set_frontend)
+-              fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
++              fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
++      fepriv->parameters_out = fepriv->parameters_in;
+       if (fe_set_err < 0) {
+               fepriv->state = FESTATE_ERROR;
+               return fe_set_err;
+       }
+-      fepriv->parameters.frequency = original_frequency;
+-      fepriv->parameters.inversion = original_inversion;
++      fepriv->parameters_in.frequency = original_frequency;
++      fepriv->parameters_in.inversion = original_inversion;
+       fepriv->auto_sub_step++;
+       return 0;
+@@ -383,7 +384,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+               if (fepriv->state & FESTATE_RETUNE) {
+                       if (fe->ops.set_frontend)
+                               retval = fe->ops.set_frontend(fe,
+-                                                      &fepriv->parameters);
++                                                      &fepriv->parameters_in);
++                      fepriv->parameters_out = fepriv->parameters_in;
+                       if (retval < 0)
+                               fepriv->state = FESTATE_ERROR;
+                       else
+@@ -413,8 +415,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+               /* if we're tuned, then we have determined the correct inversion */
+               if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+-                  (fepriv->parameters.inversion == INVERSION_AUTO)) {
+-                      fepriv->parameters.inversion = fepriv->inversion;
++                  (fepriv->parameters_in.inversion == INVERSION_AUTO)) {
++                      fepriv->parameters_in.inversion = fepriv->inversion;
+               }
+               return;
+       }
+@@ -594,12 +596,14 @@ restart:
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
+-                                      params = &fepriv->parameters;
++                                      params = &fepriv->parameters_in;
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               if (fe->ops.tune)
+                                       fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
++                              if (params)
++                                      fepriv->parameters_out = *params;
+                               if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+                                       dprintk("%s: state changed, adding current state\n", __func__);
+@@ -612,11 +616,9 @@ restart:
+                               dvb_frontend_swzigzag(fe);
+                               break;
+                       case DVBFE_ALGO_CUSTOM:
+-                              params = NULL; /* have we been asked to RETUNE ?        */
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+-                                      params = &fepriv->parameters;
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               /* Case where we are going to search for a carrier
+@@ -625,7 +627,7 @@ restart:
+                                */
+                               if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+                                       if (fe->ops.search) {
+-                                              fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
++                                              fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
+                                               /* We did do a search as was requested, the flags are
+                                                * now unset as well and has the flags wrt to search.
+                                                */
+@@ -636,11 +638,12 @@ restart:
+                               /* Track the carrier if the search was successful */
+                               if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
+                                       if (fe->ops.track)
+-                                              fe->ops.track(fe, &fepriv->parameters);
++                                              fe->ops.track(fe, &fepriv->parameters_in);
+                               } else {
+                                       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       fepriv->delay = HZ / 2;
+                               }
++                              fepriv->parameters_out = fepriv->parameters_in;
+                               fe->ops.read_status(fe, &s);
+                               if (s != fepriv->status) {
+                                       dvb_frontend_add_event(fe, s); /* update event list */
+@@ -860,34 +863,34 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+ {
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int i;
+-      memset(&(fe->dtv_property_cache), 0,
+-                      sizeof(struct dtv_frontend_properties));
+-
+-      fe->dtv_property_cache.state = DTV_CLEAR;
+-      fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
+-      fe->dtv_property_cache.inversion = INVERSION_AUTO;
+-      fe->dtv_property_cache.fec_inner = FEC_AUTO;
+-      fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+-      fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO;
+-      fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+-      fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
+-      fe->dtv_property_cache.symbol_rate = QAM_AUTO;
+-      fe->dtv_property_cache.code_rate_HP = FEC_AUTO;
+-      fe->dtv_property_cache.code_rate_LP = FEC_AUTO;
+-
+-      fe->dtv_property_cache.isdbt_partial_reception = -1;
+-      fe->dtv_property_cache.isdbt_sb_mode = -1;
+-      fe->dtv_property_cache.isdbt_sb_subchannel = -1;
+-      fe->dtv_property_cache.isdbt_sb_segment_idx = -1;
+-      fe->dtv_property_cache.isdbt_sb_segment_count = -1;
+-      fe->dtv_property_cache.isdbt_layer_enabled = 0x7;
++      memset(c, 0, sizeof(struct dtv_frontend_properties));
++
++      c->state = DTV_CLEAR;
++      c->delivery_system = SYS_UNDEFINED;
++      c->inversion = INVERSION_AUTO;
++      c->fec_inner = FEC_AUTO;
++      c->transmission_mode = TRANSMISSION_MODE_AUTO;
++      c->bandwidth_hz = BANDWIDTH_AUTO;
++      c->guard_interval = GUARD_INTERVAL_AUTO;
++      c->hierarchy = HIERARCHY_AUTO;
++      c->symbol_rate = QAM_AUTO;
++      c->code_rate_HP = FEC_AUTO;
++      c->code_rate_LP = FEC_AUTO;
++
++      c->isdbt_partial_reception = -1;
++      c->isdbt_sb_mode = -1;
++      c->isdbt_sb_subchannel = -1;
++      c->isdbt_sb_segment_idx = -1;
++      c->isdbt_sb_segment_count = -1;
++      c->isdbt_layer_enabled = 0x7;
+       for (i = 0; i < 3; i++) {
+-              fe->dtv_property_cache.layer[i].fec = FEC_AUTO;
+-              fe->dtv_property_cache.layer[i].modulation = QAM_AUTO;
+-              fe->dtv_property_cache.layer[i].interleaving = -1;
+-              fe->dtv_property_cache.layer[i].segment_count = -1;
++              c->layer[i].fec = FEC_AUTO;
++              c->layer[i].modulation = QAM_AUTO;
++              c->layer[i].interleaving = -1;
++              c->layer[i].segment_count = -1;
+       }
+       return 0;
+@@ -901,7 +904,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+       .buffer = b \
+ }
+-static struct dtv_cmds_h dtv_cmds[] = {
++static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
+       _DTV_CMD(DTV_TUNE, 1, 0),
+       _DTV_CMD(DTV_CLEAR, 1, 0),
+@@ -963,6 +966,7 @@ static struct dtv_cmds_h dtv_cmds[] = {
+       _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
+       _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
++      _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
+       /* Get */
+       _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
+@@ -1020,10 +1024,9 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
+  * it's being used for the legacy or new API, reducing code and complexity.
+  */
+ static void dtv_property_cache_sync(struct dvb_frontend *fe,
+-                                  struct dvb_frontend_parameters *p)
++                                  struct dtv_frontend_properties *c,
++                                  const struct dvb_frontend_parameters *p)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+-
+       c->frequency = p->frequency;
+       c->inversion = p->inversion;
+@@ -1074,9 +1077,9 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
+  */
+ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+-      struct dvb_frontend_parameters *p = &fepriv->parameters;
++      struct dvb_frontend_parameters *p = &fepriv->parameters_in;
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+@@ -1086,14 +1089,12 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+               dprintk("%s() Preparing QPSK req\n", __func__);
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+-              c->delivery_system = SYS_DVBS;
+               break;
+       case FE_QAM:
+               dprintk("%s() Preparing QAM req\n", __func__);
+               p->u.qam.symbol_rate = c->symbol_rate;
+               p->u.qam.fec_inner = c->fec_inner;
+               p->u.qam.modulation = c->modulation;
+-              c->delivery_system = SYS_DVBC_ANNEX_AC;
+               break;
+       case FE_OFDM:
+               dprintk("%s() Preparing OFDM req\n", __func__);
+@@ -1111,15 +1112,10 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+               p->u.ofdm.transmission_mode = c->transmission_mode;
+               p->u.ofdm.guard_interval = c->guard_interval;
+               p->u.ofdm.hierarchy_information = c->hierarchy;
+-              c->delivery_system = SYS_DVBT;
+               break;
+       case FE_ATSC:
+               dprintk("%s() Preparing VSB req\n", __func__);
+               p->u.vsb.modulation = c->modulation;
+-              if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+-                      c->delivery_system = SYS_ATSC;
+-              else
+-                      c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       }
+ }
+@@ -1129,9 +1125,9 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+  */
+ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+-      struct dvb_frontend_parameters *p = &fepriv->parameters;
++      struct dvb_frontend_parameters *p = &fepriv->parameters_in;
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+@@ -1148,10 +1144,9 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+               break;
+       }
+-      if(c->delivery_system == SYS_ISDBT) {
+-              /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+-              p->frequency = c->frequency;
+-              p->inversion = c->inversion;
++      /* Fake out a generic DVB-T request so we pass validation in the ioctl */
++      if ((c->delivery_system == SYS_ISDBT) ||
++          (c->delivery_system == SYS_DVBT2)) {
+               p->u.ofdm.constellation = QAM_AUTO;
+               p->u.ofdm.code_rate_HP = FEC_AUTO;
+               p->u.ofdm.code_rate_LP = FEC_AUTO;
+@@ -1171,7 +1166,7 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+ static void dtv_property_cache_submit(struct dvb_frontend *fe)
+ {
+-      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       /* For legacy delivery systems we don't need the delivery_system to
+        * be specified, but we populate the older structures from the cache
+@@ -1204,133 +1199,149 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
+                                   struct dtv_property *tvp,
+                                   struct file *file)
+ {
+-      int r = 0;
+-
+-      /* Allow the frontend to validate incoming properties */
+-      if (fe->ops.get_property)
+-              r = fe->ops.get_property(fe, tvp);
++      const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++      struct dvb_frontend_private *fepriv = fe->frontend_priv;
++      struct dtv_frontend_properties cdetected;
++      int r;
+-      if (r < 0)
+-              return r;
++      /*
++       * If the driver implements a get_frontend function, then convert
++       * detected parameters to S2API properties.
++       */
++      if (fe->ops.get_frontend) {
++              cdetected = *c;
++              dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
++              c = &cdetected;
++      }
+       switch(tvp->cmd) {
+       case DTV_FREQUENCY:
+-              tvp->u.data = fe->dtv_property_cache.frequency;
++              tvp->u.data = c->frequency;
+               break;
+       case DTV_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.modulation;
++              tvp->u.data = c->modulation;
+               break;
+       case DTV_BANDWIDTH_HZ:
+-              tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
++              tvp->u.data = c->bandwidth_hz;
+               break;
+       case DTV_INVERSION:
+-              tvp->u.data = fe->dtv_property_cache.inversion;
++              tvp->u.data = c->inversion;
+               break;
+       case DTV_SYMBOL_RATE:
+-              tvp->u.data = fe->dtv_property_cache.symbol_rate;
++              tvp->u.data = c->symbol_rate;
+               break;
+       case DTV_INNER_FEC:
+-              tvp->u.data = fe->dtv_property_cache.fec_inner;
++              tvp->u.data = c->fec_inner;
+               break;
+       case DTV_PILOT:
+-              tvp->u.data = fe->dtv_property_cache.pilot;
++              tvp->u.data = c->pilot;
+               break;
+       case DTV_ROLLOFF:
+-              tvp->u.data = fe->dtv_property_cache.rolloff;
++              tvp->u.data = c->rolloff;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+-              tvp->u.data = fe->dtv_property_cache.delivery_system;
++              tvp->u.data = c->delivery_system;
+               break;
+       case DTV_VOLTAGE:
+-              tvp->u.data = fe->dtv_property_cache.voltage;
++              tvp->u.data = c->voltage;
+               break;
+       case DTV_TONE:
+-              tvp->u.data = fe->dtv_property_cache.sectone;
++              tvp->u.data = c->sectone;
+               break;
+       case DTV_API_VERSION:
+               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+               break;
+       case DTV_CODE_RATE_HP:
+-              tvp->u.data = fe->dtv_property_cache.code_rate_HP;
++              tvp->u.data = c->code_rate_HP;
+               break;
+       case DTV_CODE_RATE_LP:
+-              tvp->u.data = fe->dtv_property_cache.code_rate_LP;
++              tvp->u.data = c->code_rate_LP;
+               break;
+       case DTV_GUARD_INTERVAL:
+-              tvp->u.data = fe->dtv_property_cache.guard_interval;
++              tvp->u.data = c->guard_interval;
+               break;
+       case DTV_TRANSMISSION_MODE:
+-              tvp->u.data = fe->dtv_property_cache.transmission_mode;
++              tvp->u.data = c->transmission_mode;
+               break;
+       case DTV_HIERARCHY:
+-              tvp->u.data = fe->dtv_property_cache.hierarchy;
++              tvp->u.data = c->hierarchy;
+               break;
+       /* ISDB-T Support here */
+       case DTV_ISDBT_PARTIAL_RECEPTION:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception;
++              tvp->u.data = c->isdbt_partial_reception;
+               break;
+       case DTV_ISDBT_SOUND_BROADCASTING:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode;
++              tvp->u.data = c->isdbt_sb_mode;
+               break;
+       case DTV_ISDBT_SB_SUBCHANNEL_ID:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel;
++              tvp->u.data = c->isdbt_sb_subchannel;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_IDX:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx;
++              tvp->u.data = c->isdbt_sb_segment_idx;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count;
++              tvp->u.data = c->isdbt_sb_segment_count;
+               break;
+       case DTV_ISDBT_LAYER_ENABLED:
+-              tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled;
++              tvp->u.data = c->isdbt_layer_enabled;
+               break;
+       case DTV_ISDBT_LAYERA_FEC:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].fec;
++              tvp->u.data = c->layer[0].fec;
+               break;
+       case DTV_ISDBT_LAYERA_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].modulation;
++              tvp->u.data = c->layer[0].modulation;
+               break;
+       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].segment_count;
++              tvp->u.data = c->layer[0].segment_count;
+               break;
+       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+-              tvp->u.data = fe->dtv_property_cache.layer[0].interleaving;
++              tvp->u.data = c->layer[0].interleaving;
+               break;
+       case DTV_ISDBT_LAYERB_FEC:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].fec;
++              tvp->u.data = c->layer[1].fec;
+               break;
+       case DTV_ISDBT_LAYERB_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].modulation;
++              tvp->u.data = c->layer[1].modulation;
+               break;
+       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].segment_count;
++              tvp->u.data = c->layer[1].segment_count;
+               break;
+       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+-              tvp->u.data = fe->dtv_property_cache.layer[1].interleaving;
++              tvp->u.data = c->layer[1].interleaving;
+               break;
+       case DTV_ISDBT_LAYERC_FEC:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].fec;
++              tvp->u.data = c->layer[2].fec;
+               break;
+       case DTV_ISDBT_LAYERC_MODULATION:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].modulation;
++              tvp->u.data = c->layer[2].modulation;
+               break;
+       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].segment_count;
++              tvp->u.data = c->layer[2].segment_count;
+               break;
+       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+-              tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
++              tvp->u.data = c->layer[2].interleaving;
+               break;
+       case DTV_ISDBS_TS_ID:
+-              tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
++              tvp->u.data = c->isdbs_ts_id;
++              break;
++      case DTV_DVBT2_PLP_ID:
++              tvp->u.data = c->dvbt2_plp_id;
+               break;
+       default:
+-              r = -1;
++              return -EINVAL;
++      }
++
++      /* Allow the frontend to override outgoing properties */
++      if (fe->ops.get_property) {
++              r = fe->ops.get_property(fe, tvp);
++              if (r < 0)
++                      return r;
+       }
+       dtv_property_dump(tvp);
+-      return r;
++      return 0;
+ }
+ static int dtv_property_process_set(struct dvb_frontend *fe,
+@@ -1338,15 +1349,16 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
+                                   struct file *file)
+ {
+       int r = 0;
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       dtv_property_dump(tvp);
+       /* Allow the frontend to validate incoming properties */
+-      if (fe->ops.set_property)
++      if (fe->ops.set_property) {
+               r = fe->ops.set_property(fe, tvp);
+-
+-      if (r < 0)
+-              return r;
++              if (r < 0)
++                      return r;
++      }
+       switch(tvp->cmd) {
+       case DTV_CLEAR:
+@@ -1361,126 +1373,129 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
+                * tunerequest so we can pass validation in the FE_SET_FRONTEND
+                * ioctl.
+                */
+-              fe->dtv_property_cache.state = tvp->cmd;
++              c->state = tvp->cmd;
+               dprintk("%s() Finalised property cache\n", __func__);
+               dtv_property_cache_submit(fe);
+-              r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
+-                      &fepriv->parameters);
++              r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
++                      &fepriv->parameters_in);
+               break;
+       case DTV_FREQUENCY:
+-              fe->dtv_property_cache.frequency = tvp->u.data;
++              c->frequency = tvp->u.data;
+               break;
+       case DTV_MODULATION:
+-              fe->dtv_property_cache.modulation = tvp->u.data;
++              c->modulation = tvp->u.data;
+               break;
+       case DTV_BANDWIDTH_HZ:
+-              fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
++              c->bandwidth_hz = tvp->u.data;
+               break;
+       case DTV_INVERSION:
+-              fe->dtv_property_cache.inversion = tvp->u.data;
++              c->inversion = tvp->u.data;
+               break;
+       case DTV_SYMBOL_RATE:
+-              fe->dtv_property_cache.symbol_rate = tvp->u.data;
++              c->symbol_rate = tvp->u.data;
+               break;
+       case DTV_INNER_FEC:
+-              fe->dtv_property_cache.fec_inner = tvp->u.data;
++              c->fec_inner = tvp->u.data;
+               break;
+       case DTV_PILOT:
+-              fe->dtv_property_cache.pilot = tvp->u.data;
++              c->pilot = tvp->u.data;
+               break;
+       case DTV_ROLLOFF:
+-              fe->dtv_property_cache.rolloff = tvp->u.data;
++              c->rolloff = tvp->u.data;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+-              fe->dtv_property_cache.delivery_system = tvp->u.data;
++              c->delivery_system = tvp->u.data;
+               break;
+       case DTV_VOLTAGE:
+-              fe->dtv_property_cache.voltage = tvp->u.data;
++              c->voltage = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
+-                      (void *)fe->dtv_property_cache.voltage);
++                      (void *)c->voltage);
+               break;
+       case DTV_TONE:
+-              fe->dtv_property_cache.sectone = tvp->u.data;
++              c->sectone = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
+-                      (void *)fe->dtv_property_cache.sectone);
++                      (void *)c->sectone);
+               break;
+       case DTV_CODE_RATE_HP:
+-              fe->dtv_property_cache.code_rate_HP = tvp->u.data;
++              c->code_rate_HP = tvp->u.data;
+               break;
+       case DTV_CODE_RATE_LP:
+-              fe->dtv_property_cache.code_rate_LP = tvp->u.data;
++              c->code_rate_LP = tvp->u.data;
+               break;
+       case DTV_GUARD_INTERVAL:
+-              fe->dtv_property_cache.guard_interval = tvp->u.data;
++              c->guard_interval = tvp->u.data;
+               break;
+       case DTV_TRANSMISSION_MODE:
+-              fe->dtv_property_cache.transmission_mode = tvp->u.data;
++              c->transmission_mode = tvp->u.data;
+               break;
+       case DTV_HIERARCHY:
+-              fe->dtv_property_cache.hierarchy = tvp->u.data;
++              c->hierarchy = tvp->u.data;
+               break;
+       /* ISDB-T Support here */
+       case DTV_ISDBT_PARTIAL_RECEPTION:
+-              fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data;
++              c->isdbt_partial_reception = tvp->u.data;
+               break;
+       case DTV_ISDBT_SOUND_BROADCASTING:
+-              fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data;
++              c->isdbt_sb_mode = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SUBCHANNEL_ID:
+-              fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data;
++              c->isdbt_sb_subchannel = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_IDX:
+-              fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data;
++              c->isdbt_sb_segment_idx = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_COUNT:
+-              fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data;
++              c->isdbt_sb_segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYER_ENABLED:
+-              fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data;
++              c->isdbt_layer_enabled = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_FEC:
+-              fe->dtv_property_cache.layer[0].fec = tvp->u.data;
++              c->layer[0].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_MODULATION:
+-              fe->dtv_property_cache.layer[0].modulation = tvp->u.data;
++              c->layer[0].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+-              fe->dtv_property_cache.layer[0].segment_count = tvp->u.data;
++              c->layer[0].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+-              fe->dtv_property_cache.layer[0].interleaving = tvp->u.data;
++              c->layer[0].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_FEC:
+-              fe->dtv_property_cache.layer[1].fec = tvp->u.data;
++              c->layer[1].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_MODULATION:
+-              fe->dtv_property_cache.layer[1].modulation = tvp->u.data;
++              c->layer[1].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+-              fe->dtv_property_cache.layer[1].segment_count = tvp->u.data;
++              c->layer[1].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+-              fe->dtv_property_cache.layer[1].interleaving = tvp->u.data;
++              c->layer[1].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_FEC:
+-              fe->dtv_property_cache.layer[2].fec = tvp->u.data;
++              c->layer[2].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_MODULATION:
+-              fe->dtv_property_cache.layer[2].modulation = tvp->u.data;
++              c->layer[2].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+-              fe->dtv_property_cache.layer[2].segment_count = tvp->u.data;
++              c->layer[2].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+-              fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
++              c->layer[2].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBS_TS_ID:
+-              fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
++              c->isdbs_ts_id = tvp->u.data;
++              break;
++      case DTV_DVBT2_PLP_ID:
++              c->dvbt2_plp_id = tvp->u.data;
+               break;
+       default:
+-              r = -1;
++              return -EINVAL;
+       }
+       return r;
+@@ -1491,6 +1506,7 @@ static int dvb_frontend_ioctl(struct file *file,
+ {
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int err = -EOPNOTSUPP;
+@@ -1510,7 +1526,7 @@ static int dvb_frontend_ioctl(struct file *file,
+       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+               err = dvb_frontend_ioctl_properties(file, cmd, parg);
+       else {
+-              fe->dtv_property_cache.state = DTV_UNDEFINED;
++              c->state = DTV_UNDEFINED;
+               err = dvb_frontend_ioctl_legacy(file, cmd, parg);
+       }
+@@ -1523,6 +1539,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+ {
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
++      struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int err = 0;
+       struct dtv_properties *tvps = NULL;
+@@ -1554,11 +1571,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+               }
+               for (i = 0; i < tvps->num; i++) {
+-                      (tvp + i)->result = dtv_property_process_set(fe, tvp + i, file);
+-                      err |= (tvp + i)->result;
++                      err = dtv_property_process_set(fe, tvp + i, file);
++                      if (err < 0)
++                              goto out;
++                      (tvp + i)->result = err;
+               }
+-              if(fe->dtv_property_cache.state == DTV_TUNE)
++              if (c->state == DTV_TUNE)
+                       dprintk("%s() Property cache is full, tuning\n", __func__);
+       } else
+@@ -1586,8 +1605,10 @@ static int dvb_frontend_ioctl_properties(struct file *file,
+               }
+               for (i = 0; i < tvps->num; i++) {
+-                      (tvp + i)->result = dtv_property_process_get(fe, tvp + i, file);
+-                      err |= (tvp + i)->result;
++                      err = dtv_property_process_get(fe, tvp + i, file);
++                      if (err < 0)
++                              goto out;
++                      (tvp + i)->result = err;
+               }
+               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+@@ -1638,7 +1659,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+       case FE_READ_STATUS: {
+               fe_status_t* status = parg;
+-              /* if retune was requested but hasn't occured yet, prevent
++              /* if retune was requested but hasn't occurred yet, prevent
+                * that user get signal state from previous tuning */
+               if (fepriv->state == FESTATE_RETUNE ||
+                   fepriv->state == FESTATE_ERROR) {
+@@ -1729,7 +1750,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+                        * Dish network legacy switches (as used by Dish500)
+                        * are controlled by sending 9-bit command words
+                        * spaced 8msec apart.
+-                       * the actual command word is switch/port dependant
++                       * the actual command word is switch/port dependent
+                        * so it is up to the userspace application to send
+                        * the right command.
+                        * The command must always start with a '0' after
+@@ -1787,10 +1808,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+               break;
+       case FE_SET_FRONTEND: {
++              struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+               struct dvb_frontend_tune_settings fetunesettings;
+-              if(fe->dtv_property_cache.state == DTV_TUNE) {
+-                      if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
++              if (c->state == DTV_TUNE) {
++                      if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
+                               err = -EINVAL;
+                               break;
+                       }
+@@ -1800,9 +1822,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+                               break;
+                       }
+-                      memcpy (&fepriv->parameters, parg,
++                      memcpy (&fepriv->parameters_in, parg,
+                               sizeof (struct dvb_frontend_parameters));
+-                      dtv_property_cache_sync(fe, &fepriv->parameters);
++                      dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
+               }
+               memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
+@@ -1811,15 +1833,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+               /* force auto frequency inversion if requested */
+               if (dvb_force_auto_inversion) {
+-                      fepriv->parameters.inversion = INVERSION_AUTO;
++                      fepriv->parameters_in.inversion = INVERSION_AUTO;
+                       fetunesettings.parameters.inversion = INVERSION_AUTO;
+               }
+               if (fe->ops.info.type == FE_OFDM) {
+                       /* without hierarchical coding code_rate_LP is irrelevant,
+                        * so we tolerate the otherwise invalid FEC_NONE setting */
+-                      if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+-                          fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
+-                              fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
++                      if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
++                          fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
++                              fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
+               }
+               /* get frontend-specific tuning settings */
+@@ -1832,8 +1854,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+                       switch(fe->ops.info.type) {
+                       case FE_QPSK:
+                               fepriv->min_delay = HZ/20;
+-                              fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
+-                              fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
++                              fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
++                              fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
+                               break;
+                       case FE_QAM:
+@@ -1875,8 +1897,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
+       case FE_GET_FRONTEND:
+               if (fe->ops.get_frontend) {
+-                      memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
+-                      err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
++                      err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
++                      memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
+               }
+               break;
+@@ -1967,6 +1989,14 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
+       if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+               if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
+                       goto err0;
++
++              /* If we took control of the bus, we need to force
++                 reinitialization.  This is because many ts_bus_ctrl()
++                 functions strobe the RESET pin on the demod, and if the
++                 frontend thread already exists then the dvb_init() routine
++                 won't get called (which is what usually does initial
++                 register configuration). */
++              fepriv->reinitialise = 1;
+       }
+       if ((ret = dvb_generic_open (inode, file)) < 0)
+diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
+index f9f19be..5590eb6 100644
+--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
++++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
+@@ -239,7 +239,6 @@ struct analog_demod_ops {
+       void (*set_params)(struct dvb_frontend *fe,
+                          struct analog_parameters *params);
+       int  (*has_signal)(struct dvb_frontend *fe);
+-      int  (*is_stereo)(struct dvb_frontend *fe);
+       int  (*get_afc)(struct dvb_frontend *fe);
+       void (*tuner_status)(struct dvb_frontend *fe);
+       void (*standby)(struct dvb_frontend *fe);
+@@ -359,6 +358,9 @@ struct dtv_frontend_properties {
+       /* ISDB-T specifics */
+       u32                     isdbs_ts_id;
++
++      /* DVB-T2 specifics */
++      u32                     dvbt2_plp_id;
+ };
+ struct dvb_frontend {
+diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
+index 4df42aa..51752a9 100644
+--- a/drivers/media/dvb/dvb-core/dvb_net.c
++++ b/drivers/media/dvb/dvb-core/dvb_net.c
+@@ -1329,7 +1329,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
+               return -EBUSY;
+       dvb_net_stop(net);
+-      flush_scheduled_work();
++      flush_work_sync(&priv->set_multicast_list_wq);
++      flush_work_sync(&priv->restart_net_feed_wq);
+       printk("dvb_net: removed network interface %s\n", net->name);
+       unregister_netdev(net);
+       dvbnet->state[num]=0;
+diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
+index 3a3126c..1e53acd 100644
+--- a/drivers/media/dvb/dvb-core/dvb_net.h
++++ b/drivers/media/dvb/dvb-core/dvb_net.h
+@@ -32,6 +32,8 @@
+ #define DVB_NET_DEVICES_MAX 10
++#ifdef CONFIG_DVB_NET
++
+ struct dvb_net {
+       struct dvb_device *dvbdev;
+       struct net_device *device[DVB_NET_DEVICES_MAX];
+@@ -40,8 +42,25 @@ struct dvb_net {
+       struct dmx_demux *demux;
+ };
+-
+ void dvb_net_release(struct dvb_net *);
+ int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
++#else
++
++struct dvb_net {
++      struct dvb_device *dvbdev;
++};
++
++static inline void dvb_net_release(struct dvb_net *dvbnet)
++{
++}
++
++static inline int dvb_net_init(struct dvb_adapter *adap,
++                             struct dvb_net *dvbnet, struct dmx_demux *dmx)
++{
++      return 0;
++}
++
++#endif /* ifdef CONFIG_DVB_NET */
++
+ #endif
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+index a5712cd..d5333f3 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+@@ -45,6 +45,7 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
+       rbuf->data=data;
+       rbuf->size=len;
+       rbuf->error=0;
++      rbuf->do_wait=1;
+       init_waitqueue_head(&rbuf->queue);
+diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+index 41f04da..6951dd3 100644
+--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
++++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+@@ -39,6 +39,7 @@ struct dvb_ringbuffer {
+       wait_queue_head_t queue;
+       spinlock_t        lock;
++      int               do_wait;
+ };
+ #define DVB_RINGBUFFER_PKTHDRSIZE 3
+diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h
+index fec66bd..d47bccd 100644
+--- a/include/linux/dvb/audio.h
++++ b/include/linux/dvb/audio.h
+@@ -67,7 +67,7 @@ typedef struct audio_status {
+ typedef
+-struct audio_karaoke{  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
++struct audio_karaoke {  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
+       int vocal1;    /* into left and right t at 70% each */
+       int vocal2;    /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
+       int melody;    /* mixed into the left channel and */
+diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
+index 493a2bf..36a3ed6 100644
+--- a/include/linux/dvb/frontend.h
++++ b/include/linux/dvb/frontend.h
+@@ -175,14 +175,20 @@ typedef enum fe_transmit_mode {
+       TRANSMISSION_MODE_2K,
+       TRANSMISSION_MODE_8K,
+       TRANSMISSION_MODE_AUTO,
+-      TRANSMISSION_MODE_4K
++      TRANSMISSION_MODE_4K,
++      TRANSMISSION_MODE_1K,
++      TRANSMISSION_MODE_16K,
++      TRANSMISSION_MODE_32K,
+ } fe_transmit_mode_t;
+ typedef enum fe_bandwidth {
+       BANDWIDTH_8_MHZ,
+       BANDWIDTH_7_MHZ,
+       BANDWIDTH_6_MHZ,
+-      BANDWIDTH_AUTO
++      BANDWIDTH_AUTO,
++      BANDWIDTH_5_MHZ,
++      BANDWIDTH_10_MHZ,
++      BANDWIDTH_1_712_MHZ,
+ } fe_bandwidth_t;
+@@ -191,7 +197,10 @@ typedef enum fe_guard_interval {
+       GUARD_INTERVAL_1_16,
+       GUARD_INTERVAL_1_8,
+       GUARD_INTERVAL_1_4,
+-      GUARD_INTERVAL_AUTO
++      GUARD_INTERVAL_AUTO,
++      GUARD_INTERVAL_1_128,
++      GUARD_INTERVAL_19_128,
++      GUARD_INTERVAL_19_256,
+ } fe_guard_interval_t;
+@@ -305,7 +314,9 @@ struct dvb_frontend_event {
+ #define DTV_ISDBS_TS_ID               42
+-#define DTV_MAX_COMMAND                               DTV_ISDBS_TS_ID
++#define DTV_DVBT2_PLP_ID      43
++
++#define DTV_MAX_COMMAND                               DTV_DVBT2_PLP_ID
+ typedef enum fe_pilot {
+       PILOT_ON,
+@@ -337,6 +348,7 @@ typedef enum fe_delivery_system {
+       SYS_DMBTH,
+       SYS_CMMB,
+       SYS_DAB,
++      SYS_DVBT2,
+ } fe_delivery_system_t;
+ struct dtv_cmds_h {
+diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
+index 5a7546c..1421cc8 100644
+--- a/include/linux/dvb/version.h
++++ b/include/linux/dvb/version.h
+@@ -24,6 +24,6 @@
+ #define _DVBVERSION_H_
+ #define DVB_API_VERSION 5
+-#define DVB_API_VERSION_MINOR 2
++#define DVB_API_VERSION_MINOR 3
+ #endif /*_DVBVERSION_H_*/
diff --git a/recipes/linux/linux-vusolo2-2.6.37/fix_cpu_proc.patch b/recipes/linux/linux-vusolo2-2.6.37/fix_cpu_proc.patch
new file mode 100644 (file)
index 0000000..2074d6a
--- /dev/null
@@ -0,0 +1,13 @@
+diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
+index e56931e..b740915 100644
+--- a/arch/mips/kernel/cpu-probe.c
++++ b/arch/mips/kernel/cpu-probe.c
+@@ -936,7 +936,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
+       case PRID_IMP_BMIPS5000:
+       case PRID_IMP_BMIPS5200:
+               c->cputype = CPU_BMIPS5000;
+-              __cpu_name[cpu] = "Broadcom BMIPS5000";
++              __cpu_name[cpu] = "Brcm4380";
+               set_elf_platform(cpu, "bmips5000");
+               c->options |= MIPS_CPU_ULRI;
+               break;
diff --git a/recipes/linux/linux-vusolo2-2.6.37/pinmux.patch b/recipes/linux/linux-vusolo2-2.6.37/pinmux.patch
new file mode 100644 (file)
index 0000000..ac9cfbb
--- /dev/null
@@ -0,0 +1,15 @@
+diff --git a/arch/mips/brcmstb/board.c b/arch/mips/brcmstb/board.c
+index 706c3c4..4cc0a4c 100644
+--- a/arch/mips/brcmstb/board.c
++++ b/arch/mips/brcmstb/board.c
+@@ -604,6 +604,10 @@ void board_pinmux_setup(void)
+       PINMUX(18, sgpio_00, 1);        /* MoCA I2C */
+       PINMUX(19, sgpio_01, 1);
++
++      PINMUX(6, gpio_006, 2);
++      PINMUX(6, gpio_007, 2);
++
+ #if defined(CONFIG_BCM7425B0)
+       brcm_moca_i2c_base = BPHYSADDR(BCHP_BSCC_REG_START);
+ #else
diff --git a/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.4.tar.bz2 b/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.4.tar.bz2
new file mode 100644 (file)
index 0000000..dbb8ab2
Binary files /dev/null and b/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.4.tar.bz2 differ
diff --git a/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.8.tar.bz2 b/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.8.tar.bz2
new file mode 100644 (file)
index 0000000..0a75327
Binary files /dev/null and b/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.8.tar.bz2 differ
diff --git a/recipes/linux/linux-vusolo2-2.6.37/ubifs_packport.patch b/recipes/linux/linux-vusolo2-2.6.37/ubifs_packport.patch
new file mode 100644 (file)
index 0000000..193c5e6
--- /dev/null
@@ -0,0 +1,9138 @@
+diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
+index 830e3f7..f8b0160 100644
+--- a/fs/ubifs/Kconfig
++++ b/fs/ubifs/Kconfig
+@@ -44,29 +44,17 @@ config UBIFS_FS_ZLIB
+ # Debugging-related stuff
+ config UBIFS_FS_DEBUG
+-      bool "Enable debugging"
++      bool "Enable debugging support"
+       depends on UBIFS_FS
+       select DEBUG_FS
+-      select KALLSYMS_ALL
+-      help
+-        This option enables UBIFS debugging.
+-
+-config UBIFS_FS_DEBUG_MSG_LVL
+-      int "Default message level (0 = no extra messages, 3 = lots)"
+-      depends on UBIFS_FS_DEBUG
+-      default "0"
+-      help
+-        This controls the amount of debugging messages produced by UBIFS.
+-        If reporting bugs, please try to have available a full dump of the
+-        messages at level 1 while the misbehaviour was occurring. Level 2
+-        may become necessary if level 1 messages were not enough to find the
+-        bug. Generally Level 3 should be avoided.
+-
+-config UBIFS_FS_DEBUG_CHKS
+-      bool "Enable extra checks"
+-      depends on UBIFS_FS_DEBUG
+-      help
+-        If extra checks are enabled UBIFS will check the consistency of its
+-        internal data structures during operation. However, UBIFS performance
+-        is dramatically slower when this option is selected especially if the
+-        file system is large.
++      select KALLSYMS
++      help
++        This option enables UBIFS debugging support. It makes sure various
++        assertions, self-checks, debugging messages and test modes are compiled
++        in (this all is compiled out otherwise). Assertions are light-weight
++        and this option also enables them. Self-checks, debugging messages and
++        test modes are switched off by default. Thus, it is safe and actually
++        recommended to have debugging support enabled, and it should not slow
++        down UBIFS. You can then further enable / disable individual  debugging
++        features using UBIFS module parameters and the corresponding sysfs
++        interfaces.
+diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
+index c8ff0d1..02c73e7 100644
+--- a/fs/ubifs/budget.c
++++ b/fs/ubifs/budget.c
+@@ -106,7 +106,7 @@ static long long get_liability(struct ubifs_info *c)
+       long long liab;
+       spin_lock(&c->space_lock);
+-      liab = c->budg_idx_growth + c->budg_data_growth + c->budg_dd_growth;
++      liab = c->bi.idx_growth + c->bi.data_growth + c->bi.dd_growth;
+       spin_unlock(&c->space_lock);
+       return liab;
+ }
+@@ -180,7 +180,7 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
+       int idx_lebs;
+       long long idx_size;
+-      idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
++      idx_size = c->bi.old_idx_sz + c->bi.idx_growth + c->bi.uncommitted_idx;
+       /* And make sure we have thrice the index size of space reserved */
+       idx_size += idx_size << 1;
+       /*
+@@ -292,13 +292,13 @@ static int can_use_rp(struct ubifs_info *c)
+  * budgeted index space to the size of the current index, multiplies this by 3,
+  * and makes sure this does not exceed the amount of free LEBs.
+  *
+- * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables:
++ * Notes about @c->bi.min_idx_lebs and @c->lst.idx_lebs variables:
+  * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might
+  *    be large, because UBIFS does not do any index consolidation as long as
+  *    there is free space. IOW, the index may take a lot of LEBs, but the LEBs
+  *    will contain a lot of dirt.
+- * o @c->min_idx_lebs is the number of LEBS the index presumably takes. IOW,
+- *    the index may be consolidated to take up to @c->min_idx_lebs LEBs.
++ * o @c->bi.min_idx_lebs is the number of LEBS the index presumably takes. IOW,
++ *    the index may be consolidated to take up to @c->bi.min_idx_lebs LEBs.
+  *
+  * This function returns zero in case of success, and %-ENOSPC in case of
+  * failure.
+@@ -343,13 +343,13 @@ static int do_budget_space(struct ubifs_info *c)
+              c->lst.taken_empty_lebs;
+       if (unlikely(rsvd_idx_lebs > lebs)) {
+               dbg_budg("out of indexing space: min_idx_lebs %d (old %d), "
+-                       "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs,
++                       "rsvd_idx_lebs %d", min_idx_lebs, c->bi.min_idx_lebs,
+                        rsvd_idx_lebs);
+               return -ENOSPC;
+       }
+       available = ubifs_calc_available(c, min_idx_lebs);
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
+       if (unlikely(available < outstanding)) {
+               dbg_budg("out of data space: available %lld, outstanding %lld",
+@@ -360,7 +360,7 @@ static int do_budget_space(struct ubifs_info *c)
+       if (available - outstanding <= c->rp_size && !can_use_rp(c))
+               return -ENOSPC;
+-      c->min_idx_lebs = min_idx_lebs;
++      c->bi.min_idx_lebs = min_idx_lebs;
+       return 0;
+ }
+@@ -393,11 +393,11 @@ static int calc_data_growth(const struct ubifs_info *c,
+ {
+       int data_growth;
+-      data_growth = req->new_ino  ? c->inode_budget : 0;
++      data_growth = req->new_ino  ? c->bi.inode_budget : 0;
+       if (req->new_page)
+-              data_growth += c->page_budget;
++              data_growth += c->bi.page_budget;
+       if (req->new_dent)
+-              data_growth += c->dent_budget;
++              data_growth += c->bi.dent_budget;
+       data_growth += req->new_ino_d;
+       return data_growth;
+ }
+@@ -413,12 +413,12 @@ static int calc_dd_growth(const struct ubifs_info *c,
+ {
+       int dd_growth;
+-      dd_growth = req->dirtied_page ? c->page_budget : 0;
++      dd_growth = req->dirtied_page ? c->bi.page_budget : 0;
+       if (req->dirtied_ino)
+-              dd_growth += c->inode_budget << (req->dirtied_ino - 1);
++              dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1);
+       if (req->mod_dent)
+-              dd_growth += c->dent_budget;
++              dd_growth += c->bi.dent_budget;
+       dd_growth += req->dirtied_ino_d;
+       return dd_growth;
+ }
+@@ -460,19 +460,19 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
+ again:
+       spin_lock(&c->space_lock);
+-      ubifs_assert(c->budg_idx_growth >= 0);
+-      ubifs_assert(c->budg_data_growth >= 0);
+-      ubifs_assert(c->budg_dd_growth >= 0);
++      ubifs_assert(c->bi.idx_growth >= 0);
++      ubifs_assert(c->bi.data_growth >= 0);
++      ubifs_assert(c->bi.dd_growth >= 0);
+-      if (unlikely(c->nospace) && (c->nospace_rp || !can_use_rp(c))) {
++      if (unlikely(c->bi.nospace) && (c->bi.nospace_rp || !can_use_rp(c))) {
+               dbg_budg("no space");
+               spin_unlock(&c->space_lock);
+               return -ENOSPC;
+       }
+-      c->budg_idx_growth += idx_growth;
+-      c->budg_data_growth += data_growth;
+-      c->budg_dd_growth += dd_growth;
++      c->bi.idx_growth += idx_growth;
++      c->bi.data_growth += data_growth;
++      c->bi.dd_growth += dd_growth;
+       err = do_budget_space(c);
+       if (likely(!err)) {
+@@ -484,9 +484,9 @@ again:
+       }
+       /* Restore the old values */
+-      c->budg_idx_growth -= idx_growth;
+-      c->budg_data_growth -= data_growth;
+-      c->budg_dd_growth -= dd_growth;
++      c->bi.idx_growth -= idx_growth;
++      c->bi.data_growth -= data_growth;
++      c->bi.dd_growth -= dd_growth;
+       spin_unlock(&c->space_lock);
+       if (req->fast) {
+@@ -506,9 +506,9 @@ again:
+                       goto again;
+               }
+               dbg_budg("FS is full, -ENOSPC");
+-              c->nospace = 1;
++              c->bi.nospace = 1;
+               if (can_use_rp(c) || c->rp_size == 0)
+-                      c->nospace_rp = 1;
++                      c->bi.nospace_rp = 1;
+               smp_wmb();
+       } else
+               ubifs_err("cannot budget space, error %d", err);
+@@ -523,8 +523,8 @@ again:
+  * This function releases the space budgeted by 'ubifs_budget_space()'. Note,
+  * since the index changes (which were budgeted for in @req->idx_growth) will
+  * only be written to the media on commit, this function moves the index budget
+- * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be
+- * zeroed by the commit operation.
++ * from @c->bi.idx_growth to @c->bi.uncommitted_idx. The latter will be zeroed
++ * by the commit operation.
+  */
+ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
+ {
+@@ -553,23 +553,23 @@ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
+       if (!req->data_growth && !req->dd_growth)
+               return;
+-      c->nospace = c->nospace_rp = 0;
++      c->bi.nospace = c->bi.nospace_rp = 0;
+       smp_wmb();
+       spin_lock(&c->space_lock);
+-      c->budg_idx_growth -= req->idx_growth;
+-      c->budg_uncommitted_idx += req->idx_growth;
+-      c->budg_data_growth -= req->data_growth;
+-      c->budg_dd_growth -= req->dd_growth;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+-
+-      ubifs_assert(c->budg_idx_growth >= 0);
+-      ubifs_assert(c->budg_data_growth >= 0);
+-      ubifs_assert(c->budg_dd_growth >= 0);
+-      ubifs_assert(c->min_idx_lebs < c->main_lebs);
+-      ubifs_assert(!(c->budg_idx_growth & 7));
+-      ubifs_assert(!(c->budg_data_growth & 7));
+-      ubifs_assert(!(c->budg_dd_growth & 7));
++      c->bi.idx_growth -= req->idx_growth;
++      c->bi.uncommitted_idx += req->idx_growth;
++      c->bi.data_growth -= req->data_growth;
++      c->bi.dd_growth -= req->dd_growth;
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++
++      ubifs_assert(c->bi.idx_growth >= 0);
++      ubifs_assert(c->bi.data_growth >= 0);
++      ubifs_assert(c->bi.dd_growth >= 0);
++      ubifs_assert(c->bi.min_idx_lebs < c->main_lebs);
++      ubifs_assert(!(c->bi.idx_growth & 7));
++      ubifs_assert(!(c->bi.data_growth & 7));
++      ubifs_assert(!(c->bi.dd_growth & 7));
+       spin_unlock(&c->space_lock);
+ }
+@@ -586,13 +586,13 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
+ {
+       spin_lock(&c->space_lock);
+       /* Release the index growth reservation */
+-      c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
++      c->bi.idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       /* Release the data growth reservation */
+-      c->budg_data_growth -= c->page_budget;
++      c->bi.data_growth -= c->bi.page_budget;
+       /* Increase the dirty data growth reservation instead */
+-      c->budg_dd_growth += c->page_budget;
++      c->bi.dd_growth += c->bi.page_budget;
+       /* And re-calculate the indexing space reservation */
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       spin_unlock(&c->space_lock);
+ }
+@@ -612,7 +612,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
+       memset(&req, 0, sizeof(struct ubifs_budget_req));
+       /* The "no space" flags will be cleared because dd_growth is > 0 */
+-      req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
++      req.dd_growth = c->bi.inode_budget + ALIGN(ui->data_len, 8);
+       ubifs_release_budget(c, &req);
+ }
+@@ -682,9 +682,9 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
+       int rsvd_idx_lebs, lebs;
+       long long available, outstanding, free;
+-      ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
+-      available = ubifs_calc_available(c, c->min_idx_lebs);
++      ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
++      available = ubifs_calc_available(c, c->bi.min_idx_lebs);
+       /*
+        * When reporting free space to user-space, UBIFS guarantees that it is
+@@ -697,8 +697,8 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
+        * Note, the calculations below are similar to what we have in
+        * 'do_budget_space()', so refer there for comments.
+        */
+-      if (c->min_idx_lebs > c->lst.idx_lebs)
+-              rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs;
++      if (c->bi.min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
+       else
+               rsvd_idx_lebs = 0;
+       lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
+index 02429d8..fb3b5c8 100644
+--- a/fs/ubifs/commit.c
++++ b/fs/ubifs/commit.c
+@@ -48,6 +48,56 @@
+ #include <linux/slab.h>
+ #include "ubifs.h"
++/*
++ * nothing_to_commit - check if there is nothing to commit.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function which checks if there is anything to commit. It is
++ * used as an optimization to avoid starting the commit if it is not really
++ * necessary. Indeed, the commit operation always assumes flash I/O (e.g.,
++ * writing the commit start node to the log), and it is better to avoid doing
++ * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is
++ * nothing to commit, it is more optimal to avoid any flash I/O.
++ *
++ * This function has to be called with @c->commit_sem locked for writing -
++ * this function does not take LPT/TNC locks because the @c->commit_sem
++ * guarantees that we have exclusive access to the TNC and LPT data structures.
++ *
++ * This function returns %1 if there is nothing to commit and %0 otherwise.
++ */
++static int nothing_to_commit(struct ubifs_info *c)
++{
++      /*
++       * During mounting or remounting from R/O mode to R/W mode we may
++       * commit for various recovery-related reasons.
++       */
++      if (c->mounting || c->remounting_rw)
++              return 0;
++
++      /*
++       * If the root TNC node is dirty, we definitely have something to
++       * commit.
++       */
++      if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
++              return 0;
++
++      /*
++       * Even though the TNC is clean, the LPT tree may have dirty nodes. For
++       * example, this may happen if the budgeting subsystem invoked GC to
++       * make some free space, and the GC found an LEB with only dirty and
++       * free space. In this case GC would just change the lprops of this
++       * LEB (by turning all space into free space) and unmap it.
++       */
++      if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags))
++              return 0;
++
++      ubifs_assert(atomic_long_read(&c->dirty_zn_cnt) == 0);
++      ubifs_assert(c->dirty_pn_cnt == 0);
++      ubifs_assert(c->dirty_nn_cnt == 0);
++
++      return 1;
++}
++
+ /**
+  * do_commit - commit the journal.
+  * @c: UBIFS file-system description object
+@@ -70,6 +120,12 @@ static int do_commit(struct ubifs_info *c)
+               goto out_up;
+       }
++      if (nothing_to_commit(c)) {
++              up_write(&c->commit_sem);
++              err = 0;
++              goto out_cancel;
++      }
++
+       /* Sync all write buffers (necessary for recovery) */
+       for (i = 0; i < c->jhead_cnt; i++) {
+               err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+@@ -126,7 +182,7 @@ static int do_commit(struct ubifs_info *c)
+       c->mst_node->root_len    = cpu_to_le32(zroot.len);
+       c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
+       c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
+-      c->mst_node->index_size  = cpu_to_le64(c->old_idx_sz);
++      c->mst_node->index_size  = cpu_to_le64(c->bi.old_idx_sz);
+       c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
+       c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
+       c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
+@@ -162,12 +218,12 @@ static int do_commit(struct ubifs_info *c)
+       if (err)
+               goto out;
++out_cancel:
+       spin_lock(&c->cs_lock);
+       c->cmt_state = COMMIT_RESTING;
+       wake_up(&c->cmt_wq);
+       dbg_cmt("commit end");
+       spin_unlock(&c->cs_lock);
+-
+       return 0;
+ out_up:
+@@ -362,7 +418,7 @@ int ubifs_run_commit(struct ubifs_info *c)
+       spin_lock(&c->cs_lock);
+       if (c->cmt_state == COMMIT_BROKEN) {
+-              err = -EINVAL;
++              err = -EROFS;
+               goto out;
+       }
+@@ -388,7 +444,7 @@ int ubifs_run_commit(struct ubifs_info *c)
+        * re-check it.
+        */
+       if (c->cmt_state == COMMIT_BROKEN) {
+-              err = -EINVAL;
++              err = -EROFS;
+               goto out_cmt_unlock;
+       }
+@@ -520,8 +576,8 @@ int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+       struct idx_node *i;
+       size_t sz;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_OLD_IDX))
+-              goto out;
++      if (!dbg_is_chk_index(c))
++              return 0;
+       INIT_LIST_HEAD(&list);
+diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
+index 0bee4db..1934084 100644
+--- a/fs/ubifs/debug.c
++++ b/fs/ubifs/debug.c
+@@ -27,33 +27,16 @@
+  * various local functions of those subsystems.
+  */
+-#define UBIFS_DBG_PRESERVE_UBI
+-
+-#include "ubifs.h"
+ #include <linux/module.h>
+-#include <linux/moduleparam.h>
+ #include <linux/debugfs.h>
+ #include <linux/math64.h>
+-#include <linux/slab.h>
++#include <linux/uaccess.h>
++#include <linux/random.h>
++#include "ubifs.h"
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+-DEFINE_SPINLOCK(dbg_lock);
+-
+-static char dbg_key_buf0[128];
+-static char dbg_key_buf1[128];
+-
+-unsigned int ubifs_msg_flags = UBIFS_MSG_FLAGS_DEFAULT;
+-unsigned int ubifs_chk_flags = UBIFS_CHK_FLAGS_DEFAULT;
+-unsigned int ubifs_tst_flags;
+-
+-module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
+-module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
+-module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
+-
+-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
+-MODULE_PARM_DESC(debug_chks, "Debug check flags");
+-MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
++static DEFINE_SPINLOCK(dbg_lock);
+ static const char *get_key_fmt(int fmt)
+ {
+@@ -95,8 +78,30 @@ static const char *get_key_type(int type)
+       }
+ }
+-static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+-                      char *buffer)
++static const char *get_dent_type(int type)
++{
++      switch (type) {
++      case UBIFS_ITYPE_REG:
++              return "file";
++      case UBIFS_ITYPE_DIR:
++              return "dir";
++      case UBIFS_ITYPE_LNK:
++              return "symlink";
++      case UBIFS_ITYPE_BLK:
++              return "blkdev";
++      case UBIFS_ITYPE_CHR:
++              return "char dev";
++      case UBIFS_ITYPE_FIFO:
++              return "fifo";
++      case UBIFS_ITYPE_SOCK:
++              return "socket";
++      default:
++              return "unknown/invalid type";
++      }
++}
++
++const char *dbg_snprintf_key(const struct ubifs_info *c,
++                           const union ubifs_key *key, char *buffer, int len)
+ {
+       char *p = buffer;
+       int type = key_type(c, key);
+@@ -104,45 +109,34 @@ static void sprintf_key(const struct ubifs_info *c, const union ubifs_key *key,
+       if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
+               switch (type) {
+               case UBIFS_INO_KEY:
+-                      sprintf(p, "(%lu, %s)", (unsigned long)key_inum(c, key),
+-                             get_key_type(type));
++                      len -= snprintf(p, len, "(%lu, %s)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type));
+                       break;
+               case UBIFS_DENT_KEY:
+               case UBIFS_XENT_KEY:
+-                      sprintf(p, "(%lu, %s, %#08x)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type), key_hash(c, key));
++                      len -= snprintf(p, len, "(%lu, %s, %#08x)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type), key_hash(c, key));
+                       break;
+               case UBIFS_DATA_KEY:
+-                      sprintf(p, "(%lu, %s, %u)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type), key_block(c, key));
++                      len -= snprintf(p, len, "(%lu, %s, %u)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type), key_block(c, key));
+                       break;
+               case UBIFS_TRUN_KEY:
+-                      sprintf(p, "(%lu, %s)",
+-                              (unsigned long)key_inum(c, key),
+-                              get_key_type(type));
++                      len -= snprintf(p, len, "(%lu, %s)",
++                                      (unsigned long)key_inum(c, key),
++                                      get_key_type(type));
+                       break;
+               default:
+-                      sprintf(p, "(bad key type: %#08x, %#08x)",
+-                              key->u32[0], key->u32[1]);
++                      len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
++                                      key->u32[0], key->u32[1]);
+               }
+       } else
+-              sprintf(p, "bad key format %d", c->key_fmt);
+-}
+-
+-const char *dbg_key_str0(const struct ubifs_info *c, const union ubifs_key *key)
+-{
+-      /* dbg_lock must be held */
+-      sprintf_key(c, key, dbg_key_buf0);
+-      return dbg_key_buf0;
+-}
+-
+-const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key)
+-{
+-      /* dbg_lock must be held */
+-      sprintf_key(c, key, dbg_key_buf1);
+-      return dbg_key_buf1;
++              len -= snprintf(p, len, "bad key format %d", c->key_fmt);
++      ubifs_assert(len > 0);
++      return p;
+ }
+ const char *dbg_ntype(int type)
+@@ -227,53 +221,83 @@ const char *dbg_jhead(int jhead)
+ static void dump_ch(const struct ubifs_ch *ch)
+ {
+-      printk(KERN_DEBUG "\tmagic          %#x\n", le32_to_cpu(ch->magic));
+-      printk(KERN_DEBUG "\tcrc            %#x\n", le32_to_cpu(ch->crc));
+-      printk(KERN_DEBUG "\tnode_type      %d (%s)\n", ch->node_type,
++      printk(KERN_ERR "\tmagic          %#x\n", le32_to_cpu(ch->magic));
++      printk(KERN_ERR "\tcrc            %#x\n", le32_to_cpu(ch->crc));
++      printk(KERN_ERR "\tnode_type      %d (%s)\n", ch->node_type,
+              dbg_ntype(ch->node_type));
+-      printk(KERN_DEBUG "\tgroup_type     %d (%s)\n", ch->group_type,
++      printk(KERN_ERR "\tgroup_type     %d (%s)\n", ch->group_type,
+              dbg_gtype(ch->group_type));
+-      printk(KERN_DEBUG "\tsqnum          %llu\n",
++      printk(KERN_ERR "\tsqnum          %llu\n",
+              (unsigned long long)le64_to_cpu(ch->sqnum));
+-      printk(KERN_DEBUG "\tlen            %u\n", le32_to_cpu(ch->len));
++      printk(KERN_ERR "\tlen            %u\n", le32_to_cpu(ch->len));
+ }
+-void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode)
++void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
+ {
+       const struct ubifs_inode *ui = ubifs_inode(inode);
++      struct qstr nm = { .name = NULL };
++      union ubifs_key key;
++      struct ubifs_dent_node *dent, *pdent = NULL;
++      int count = 2;
+-      printk(KERN_DEBUG "Dump in-memory inode:");
+-      printk(KERN_DEBUG "\tinode          %lu\n", inode->i_ino);
+-      printk(KERN_DEBUG "\tsize           %llu\n",
++      printk(KERN_ERR "Dump in-memory inode:");
++      printk(KERN_ERR "\tinode          %lu\n", inode->i_ino);
++      printk(KERN_ERR "\tsize           %llu\n",
+              (unsigned long long)i_size_read(inode));
+-      printk(KERN_DEBUG "\tnlink          %u\n", inode->i_nlink);
+-      printk(KERN_DEBUG "\tuid            %u\n", (unsigned int)inode->i_uid);
+-      printk(KERN_DEBUG "\tgid            %u\n", (unsigned int)inode->i_gid);
+-      printk(KERN_DEBUG "\tatime          %u.%u\n",
++      printk(KERN_ERR "\tnlink          %u\n", inode->i_nlink);
++      printk(KERN_ERR "\tuid            %u\n", (unsigned int)inode->i_uid);
++      printk(KERN_ERR "\tgid            %u\n", (unsigned int)inode->i_gid);
++      printk(KERN_ERR "\tatime          %u.%u\n",
+              (unsigned int)inode->i_atime.tv_sec,
+              (unsigned int)inode->i_atime.tv_nsec);
+-      printk(KERN_DEBUG "\tmtime          %u.%u\n",
++      printk(KERN_ERR "\tmtime          %u.%u\n",
+              (unsigned int)inode->i_mtime.tv_sec,
+              (unsigned int)inode->i_mtime.tv_nsec);
+-      printk(KERN_DEBUG "\tctime          %u.%u\n",
++      printk(KERN_ERR "\tctime          %u.%u\n",
+              (unsigned int)inode->i_ctime.tv_sec,
+              (unsigned int)inode->i_ctime.tv_nsec);
+-      printk(KERN_DEBUG "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
+-      printk(KERN_DEBUG "\txattr_size     %u\n", ui->xattr_size);
+-      printk(KERN_DEBUG "\txattr_cnt      %u\n", ui->xattr_cnt);
+-      printk(KERN_DEBUG "\txattr_names    %u\n", ui->xattr_names);
+-      printk(KERN_DEBUG "\tdirty          %u\n", ui->dirty);
+-      printk(KERN_DEBUG "\txattr          %u\n", ui->xattr);
+-      printk(KERN_DEBUG "\tbulk_read      %u\n", ui->xattr);
+-      printk(KERN_DEBUG "\tsynced_i_size  %llu\n",
++      printk(KERN_ERR "\tcreat_sqnum    %llu\n", ui->creat_sqnum);
++      printk(KERN_ERR "\txattr_size     %u\n", ui->xattr_size);
++      printk(KERN_ERR "\txattr_cnt      %u\n", ui->xattr_cnt);
++      printk(KERN_ERR "\txattr_names    %u\n", ui->xattr_names);
++      printk(KERN_ERR "\tdirty          %u\n", ui->dirty);
++      printk(KERN_ERR "\txattr          %u\n", ui->xattr);
++      printk(KERN_ERR "\tbulk_read      %u\n", ui->xattr);
++      printk(KERN_ERR "\tsynced_i_size  %llu\n",
+              (unsigned long long)ui->synced_i_size);
+-      printk(KERN_DEBUG "\tui_size        %llu\n",
++      printk(KERN_ERR "\tui_size        %llu\n",
+              (unsigned long long)ui->ui_size);
+-      printk(KERN_DEBUG "\tflags          %d\n", ui->flags);
+-      printk(KERN_DEBUG "\tcompr_type     %d\n", ui->compr_type);
+-      printk(KERN_DEBUG "\tlast_page_read %lu\n", ui->last_page_read);
+-      printk(KERN_DEBUG "\tread_in_a_row  %lu\n", ui->read_in_a_row);
+-      printk(KERN_DEBUG "\tdata_len       %d\n", ui->data_len);
++      printk(KERN_ERR "\tflags          %d\n", ui->flags);
++      printk(KERN_ERR "\tcompr_type     %d\n", ui->compr_type);
++      printk(KERN_ERR "\tlast_page_read %lu\n", ui->last_page_read);
++      printk(KERN_ERR "\tread_in_a_row  %lu\n", ui->read_in_a_row);
++      printk(KERN_ERR "\tdata_len       %d\n", ui->data_len);
++
++      if (!S_ISDIR(inode->i_mode))
++              return;
++
++      printk(KERN_ERR "List of directory entries:\n");
++      ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
++
++      lowest_dent_key(c, &key, inode->i_ino);
++      while (1) {
++              dent = ubifs_tnc_next_ent(c, &key, &nm);
++              if (IS_ERR(dent)) {
++                      if (PTR_ERR(dent) != -ENOENT)
++                              printk(KERN_ERR "error %ld\n", PTR_ERR(dent));
++                      break;
++              }
++
++              printk(KERN_ERR "\t%d: %s (%s)\n",
++                     count++, dent->name, get_dent_type(dent->type));
++
++              nm.name = dent->name;
++              nm.len = le16_to_cpu(dent->nlen);
++              kfree(pdent);
++              pdent = dent;
++              key_read(c, &dent->key, &key);
++      }
++      kfree(pdent);
+ }
+ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+@@ -281,14 +305,15 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       int i, n;
+       union ubifs_key key;
+       const struct ubifs_ch *ch = node;
++      char key_buf[DBG_KEY_BUF_LEN];
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+       /* If the magic is incorrect, just hexdump the first bytes */
+       if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) {
+-              printk(KERN_DEBUG "Not a node, first %zu bytes:", UBIFS_CH_SZ);
+-              print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
++              printk(KERN_ERR "Not a node, first %zu bytes:", UBIFS_CH_SZ);
++              print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1,
+                              (void *)node, UBIFS_CH_SZ, 1);
+               return;
+       }
+@@ -301,7 +326,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_pad_node *pad = node;
+-              printk(KERN_DEBUG "\tpad_len        %u\n",
++              printk(KERN_ERR "\tpad_len        %u\n",
+                      le32_to_cpu(pad->pad_len));
+               break;
+       }
+@@ -310,48 +335,50 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_sb_node *sup = node;
+               unsigned int sup_flags = le32_to_cpu(sup->flags);
+-              printk(KERN_DEBUG "\tkey_hash       %d (%s)\n",
++              printk(KERN_ERR "\tkey_hash       %d (%s)\n",
+                      (int)sup->key_hash, get_key_hash(sup->key_hash));
+-              printk(KERN_DEBUG "\tkey_fmt        %d (%s)\n",
++              printk(KERN_ERR "\tkey_fmt        %d (%s)\n",
+                      (int)sup->key_fmt, get_key_fmt(sup->key_fmt));
+-              printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
+-              printk(KERN_DEBUG "\t  big_lpt      %u\n",
++              printk(KERN_ERR "\tflags          %#x\n", sup_flags);
++              printk(KERN_ERR "\t  big_lpt      %u\n",
+                      !!(sup_flags & UBIFS_FLG_BIGLPT));
+-              printk(KERN_DEBUG "\tmin_io_size    %u\n",
++              printk(KERN_ERR "\t  space_fixup  %u\n",
++                     !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
++              printk(KERN_ERR "\tmin_io_size    %u\n",
+                      le32_to_cpu(sup->min_io_size));
+-              printk(KERN_DEBUG "\tleb_size       %u\n",
++              printk(KERN_ERR "\tleb_size       %u\n",
+                      le32_to_cpu(sup->leb_size));
+-              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++              printk(KERN_ERR "\tleb_cnt        %u\n",
+                      le32_to_cpu(sup->leb_cnt));
+-              printk(KERN_DEBUG "\tmax_leb_cnt    %u\n",
++              printk(KERN_ERR "\tmax_leb_cnt    %u\n",
+                      le32_to_cpu(sup->max_leb_cnt));
+-              printk(KERN_DEBUG "\tmax_bud_bytes  %llu\n",
++              printk(KERN_ERR "\tmax_bud_bytes  %llu\n",
+                      (unsigned long long)le64_to_cpu(sup->max_bud_bytes));
+-              printk(KERN_DEBUG "\tlog_lebs       %u\n",
++              printk(KERN_ERR "\tlog_lebs       %u\n",
+                      le32_to_cpu(sup->log_lebs));
+-              printk(KERN_DEBUG "\tlpt_lebs       %u\n",
++              printk(KERN_ERR "\tlpt_lebs       %u\n",
+                      le32_to_cpu(sup->lpt_lebs));
+-              printk(KERN_DEBUG "\torph_lebs      %u\n",
++              printk(KERN_ERR "\torph_lebs      %u\n",
+                      le32_to_cpu(sup->orph_lebs));
+-              printk(KERN_DEBUG "\tjhead_cnt      %u\n",
++              printk(KERN_ERR "\tjhead_cnt      %u\n",
+                      le32_to_cpu(sup->jhead_cnt));
+-              printk(KERN_DEBUG "\tfanout         %u\n",
++              printk(KERN_ERR "\tfanout         %u\n",
+                      le32_to_cpu(sup->fanout));
+-              printk(KERN_DEBUG "\tlsave_cnt      %u\n",
++              printk(KERN_ERR "\tlsave_cnt      %u\n",
+                      le32_to_cpu(sup->lsave_cnt));
+-              printk(KERN_DEBUG "\tdefault_compr  %u\n",
++              printk(KERN_ERR "\tdefault_compr  %u\n",
+                      (int)le16_to_cpu(sup->default_compr));
+-              printk(KERN_DEBUG "\trp_size        %llu\n",
++              printk(KERN_ERR "\trp_size        %llu\n",
+                      (unsigned long long)le64_to_cpu(sup->rp_size));
+-              printk(KERN_DEBUG "\trp_uid         %u\n",
++              printk(KERN_ERR "\trp_uid         %u\n",
+                      le32_to_cpu(sup->rp_uid));
+-              printk(KERN_DEBUG "\trp_gid         %u\n",
++              printk(KERN_ERR "\trp_gid         %u\n",
+                      le32_to_cpu(sup->rp_gid));
+-              printk(KERN_DEBUG "\tfmt_version    %u\n",
++              printk(KERN_ERR "\tfmt_version    %u\n",
+                      le32_to_cpu(sup->fmt_version));
+-              printk(KERN_DEBUG "\ttime_gran      %u\n",
++              printk(KERN_ERR "\ttime_gran      %u\n",
+                      le32_to_cpu(sup->time_gran));
+-              printk(KERN_DEBUG "\tUUID           %pUB\n",
++              printk(KERN_ERR "\tUUID           %pUB\n",
+                      sup->uuid);
+               break;
+       }
+@@ -359,61 +386,61 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_mst_node *mst = node;
+-              printk(KERN_DEBUG "\thighest_inum   %llu\n",
++              printk(KERN_ERR "\thighest_inum   %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->highest_inum));
+-              printk(KERN_DEBUG "\tcommit number  %llu\n",
++              printk(KERN_ERR "\tcommit number  %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->cmt_no));
+-              printk(KERN_DEBUG "\tflags          %#x\n",
++              printk(KERN_ERR "\tflags          %#x\n",
+                      le32_to_cpu(mst->flags));
+-              printk(KERN_DEBUG "\tlog_lnum       %u\n",
++              printk(KERN_ERR "\tlog_lnum       %u\n",
+                      le32_to_cpu(mst->log_lnum));
+-              printk(KERN_DEBUG "\troot_lnum      %u\n",
++              printk(KERN_ERR "\troot_lnum      %u\n",
+                      le32_to_cpu(mst->root_lnum));
+-              printk(KERN_DEBUG "\troot_offs      %u\n",
++              printk(KERN_ERR "\troot_offs      %u\n",
+                      le32_to_cpu(mst->root_offs));
+-              printk(KERN_DEBUG "\troot_len       %u\n",
++              printk(KERN_ERR "\troot_len       %u\n",
+                      le32_to_cpu(mst->root_len));
+-              printk(KERN_DEBUG "\tgc_lnum        %u\n",
++              printk(KERN_ERR "\tgc_lnum        %u\n",
+                      le32_to_cpu(mst->gc_lnum));
+-              printk(KERN_DEBUG "\tihead_lnum     %u\n",
++              printk(KERN_ERR "\tihead_lnum     %u\n",
+                      le32_to_cpu(mst->ihead_lnum));
+-              printk(KERN_DEBUG "\tihead_offs     %u\n",
++              printk(KERN_ERR "\tihead_offs     %u\n",
+                      le32_to_cpu(mst->ihead_offs));
+-              printk(KERN_DEBUG "\tindex_size     %llu\n",
++              printk(KERN_ERR "\tindex_size     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->index_size));
+-              printk(KERN_DEBUG "\tlpt_lnum       %u\n",
++              printk(KERN_ERR "\tlpt_lnum       %u\n",
+                      le32_to_cpu(mst->lpt_lnum));
+-              printk(KERN_DEBUG "\tlpt_offs       %u\n",
++              printk(KERN_ERR "\tlpt_offs       %u\n",
+                      le32_to_cpu(mst->lpt_offs));
+-              printk(KERN_DEBUG "\tnhead_lnum     %u\n",
++              printk(KERN_ERR "\tnhead_lnum     %u\n",
+                      le32_to_cpu(mst->nhead_lnum));
+-              printk(KERN_DEBUG "\tnhead_offs     %u\n",
++              printk(KERN_ERR "\tnhead_offs     %u\n",
+                      le32_to_cpu(mst->nhead_offs));
+-              printk(KERN_DEBUG "\tltab_lnum      %u\n",
++              printk(KERN_ERR "\tltab_lnum      %u\n",
+                      le32_to_cpu(mst->ltab_lnum));
+-              printk(KERN_DEBUG "\tltab_offs      %u\n",
++              printk(KERN_ERR "\tltab_offs      %u\n",
+                      le32_to_cpu(mst->ltab_offs));
+-              printk(KERN_DEBUG "\tlsave_lnum     %u\n",
++              printk(KERN_ERR "\tlsave_lnum     %u\n",
+                      le32_to_cpu(mst->lsave_lnum));
+-              printk(KERN_DEBUG "\tlsave_offs     %u\n",
++              printk(KERN_ERR "\tlsave_offs     %u\n",
+                      le32_to_cpu(mst->lsave_offs));
+-              printk(KERN_DEBUG "\tlscan_lnum     %u\n",
++              printk(KERN_ERR "\tlscan_lnum     %u\n",
+                      le32_to_cpu(mst->lscan_lnum));
+-              printk(KERN_DEBUG "\tleb_cnt        %u\n",
++              printk(KERN_ERR "\tleb_cnt        %u\n",
+                      le32_to_cpu(mst->leb_cnt));
+-              printk(KERN_DEBUG "\tempty_lebs     %u\n",
++              printk(KERN_ERR "\tempty_lebs     %u\n",
+                      le32_to_cpu(mst->empty_lebs));
+-              printk(KERN_DEBUG "\tidx_lebs       %u\n",
++              printk(KERN_ERR "\tidx_lebs       %u\n",
+                      le32_to_cpu(mst->idx_lebs));
+-              printk(KERN_DEBUG "\ttotal_free     %llu\n",
++              printk(KERN_ERR "\ttotal_free     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_free));
+-              printk(KERN_DEBUG "\ttotal_dirty    %llu\n",
++              printk(KERN_ERR "\ttotal_dirty    %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dirty));
+-              printk(KERN_DEBUG "\ttotal_used     %llu\n",
++              printk(KERN_ERR "\ttotal_used     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_used));
+-              printk(KERN_DEBUG "\ttotal_dead     %llu\n",
++              printk(KERN_ERR "\ttotal_dead     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dead));
+-              printk(KERN_DEBUG "\ttotal_dark     %llu\n",
++              printk(KERN_ERR "\ttotal_dark     %llu\n",
+                      (unsigned long long)le64_to_cpu(mst->total_dark));
+               break;
+       }
+@@ -421,11 +448,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_ref_node *ref = node;
+-              printk(KERN_DEBUG "\tlnum           %u\n",
++              printk(KERN_ERR "\tlnum           %u\n",
+                      le32_to_cpu(ref->lnum));
+-              printk(KERN_DEBUG "\toffs           %u\n",
++              printk(KERN_ERR "\toffs           %u\n",
+                      le32_to_cpu(ref->offs));
+-              printk(KERN_DEBUG "\tjhead          %u\n",
++              printk(KERN_ERR "\tjhead          %u\n",
+                      le32_to_cpu(ref->jhead));
+               break;
+       }
+@@ -434,39 +461,40 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_ino_node *ino = node;
+               key_read(c, &ino->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tcreat_sqnum    %llu\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tcreat_sqnum    %llu\n",
+                      (unsigned long long)le64_to_cpu(ino->creat_sqnum));
+-              printk(KERN_DEBUG "\tsize           %llu\n",
++              printk(KERN_ERR "\tsize           %llu\n",
+                      (unsigned long long)le64_to_cpu(ino->size));
+-              printk(KERN_DEBUG "\tnlink          %u\n",
++              printk(KERN_ERR "\tnlink          %u\n",
+                      le32_to_cpu(ino->nlink));
+-              printk(KERN_DEBUG "\tatime          %lld.%u\n",
++              printk(KERN_ERR "\tatime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->atime_sec),
+                      le32_to_cpu(ino->atime_nsec));
+-              printk(KERN_DEBUG "\tmtime          %lld.%u\n",
++              printk(KERN_ERR "\tmtime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->mtime_sec),
+                      le32_to_cpu(ino->mtime_nsec));
+-              printk(KERN_DEBUG "\tctime          %lld.%u\n",
++              printk(KERN_ERR "\tctime          %lld.%u\n",
+                      (long long)le64_to_cpu(ino->ctime_sec),
+                      le32_to_cpu(ino->ctime_nsec));
+-              printk(KERN_DEBUG "\tuid            %u\n",
++              printk(KERN_ERR "\tuid            %u\n",
+                      le32_to_cpu(ino->uid));
+-              printk(KERN_DEBUG "\tgid            %u\n",
++              printk(KERN_ERR "\tgid            %u\n",
+                      le32_to_cpu(ino->gid));
+-              printk(KERN_DEBUG "\tmode           %u\n",
++              printk(KERN_ERR "\tmode           %u\n",
+                      le32_to_cpu(ino->mode));
+-              printk(KERN_DEBUG "\tflags          %#x\n",
++              printk(KERN_ERR "\tflags          %#x\n",
+                      le32_to_cpu(ino->flags));
+-              printk(KERN_DEBUG "\txattr_cnt      %u\n",
++              printk(KERN_ERR "\txattr_cnt      %u\n",
+                      le32_to_cpu(ino->xattr_cnt));
+-              printk(KERN_DEBUG "\txattr_size     %u\n",
++              printk(KERN_ERR "\txattr_size     %u\n",
+                      le32_to_cpu(ino->xattr_size));
+-              printk(KERN_DEBUG "\txattr_names    %u\n",
++              printk(KERN_ERR "\txattr_names    %u\n",
+                      le32_to_cpu(ino->xattr_names));
+-              printk(KERN_DEBUG "\tcompr_type     %#x\n",
++              printk(KERN_ERR "\tcompr_type     %#x\n",
+                      (int)le16_to_cpu(ino->compr_type));
+-              printk(KERN_DEBUG "\tdata len       %u\n",
++              printk(KERN_ERR "\tdata len       %u\n",
+                      le32_to_cpu(ino->data_len));
+               break;
+       }
+@@ -477,15 +505,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               int nlen = le16_to_cpu(dent->nlen);
+               key_read(c, &dent->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tinum           %llu\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tinum           %llu\n",
+                      (unsigned long long)le64_to_cpu(dent->inum));
+-              printk(KERN_DEBUG "\ttype           %d\n", (int)dent->type);
+-              printk(KERN_DEBUG "\tnlen           %d\n", nlen);
+-              printk(KERN_DEBUG "\tname           ");
++              printk(KERN_ERR "\ttype           %d\n", (int)dent->type);
++              printk(KERN_ERR "\tnlen           %d\n", nlen);
++              printk(KERN_ERR "\tname           ");
+               if (nlen > UBIFS_MAX_NLEN)
+-                      printk(KERN_DEBUG "(bad name length, not printing, "
++                      printk(KERN_ERR "(bad name length, not printing, "
+                                         "bad or corrupted node)");
+               else {
+                       for (i = 0; i < nlen && dent->name[i]; i++)
+@@ -501,15 +530,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
+               key_read(c, &dn->key, &key);
+-              printk(KERN_DEBUG "\tkey            %s\n", DBGKEY(&key));
+-              printk(KERN_DEBUG "\tsize           %u\n",
++              printk(KERN_ERR "\tkey            %s\n",
++                     dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
++              printk(KERN_ERR "\tsize           %u\n",
+                      le32_to_cpu(dn->size));
+-              printk(KERN_DEBUG "\tcompr_typ      %d\n",
++              printk(KERN_ERR "\tcompr_typ      %d\n",
+                      (int)le16_to_cpu(dn->compr_type));
+-              printk(KERN_DEBUG "\tdata size      %d\n",
++              printk(KERN_ERR "\tdata size      %d\n",
+                      dlen);
+-              printk(KERN_DEBUG "\tdata:\n");
+-              print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET, 32, 1,
++              printk(KERN_ERR "\tdata:\n");
++              print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
+                              (void *)&dn->data, dlen, 0);
+               break;
+       }
+@@ -517,11 +547,11 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_trun_node *trun = node;
+-              printk(KERN_DEBUG "\tinum           %u\n",
++              printk(KERN_ERR "\tinum           %u\n",
+                      le32_to_cpu(trun->inum));
+-              printk(KERN_DEBUG "\told_size       %llu\n",
++              printk(KERN_ERR "\told_size       %llu\n",
+                      (unsigned long long)le64_to_cpu(trun->old_size));
+-              printk(KERN_DEBUG "\tnew_size       %llu\n",
++              printk(KERN_ERR "\tnew_size       %llu\n",
+                      (unsigned long long)le64_to_cpu(trun->new_size));
+               break;
+       }
+@@ -530,19 +560,21 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+               const struct ubifs_idx_node *idx = node;
+               n = le16_to_cpu(idx->child_cnt);
+-              printk(KERN_DEBUG "\tchild_cnt      %d\n", n);
+-              printk(KERN_DEBUG "\tlevel          %d\n",
++              printk(KERN_ERR "\tchild_cnt      %d\n", n);
++              printk(KERN_ERR "\tlevel          %d\n",
+                      (int)le16_to_cpu(idx->level));
+-              printk(KERN_DEBUG "\tBranches:\n");
++              printk(KERN_ERR "\tBranches:\n");
+               for (i = 0; i < n && i < c->fanout - 1; i++) {
+                       const struct ubifs_branch *br;
+                       br = ubifs_idx_branch(c, idx, i);
+                       key_read(c, &br->key, &key);
+-                      printk(KERN_DEBUG "\t%d: LEB %d:%d len %d key %s\n",
++                      printk(KERN_ERR "\t%d: LEB %d:%d len %d key %s\n",
+                              i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
+-                             le32_to_cpu(br->len), DBGKEY(&key));
++                             le32_to_cpu(br->len),
++                             dbg_snprintf_key(c, &key, key_buf,
++                                              DBG_KEY_BUF_LEN));
+               }
+               break;
+       }
+@@ -552,20 +584,20 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+       {
+               const struct ubifs_orph_node *orph = node;
+-              printk(KERN_DEBUG "\tcommit number  %llu\n",
++              printk(KERN_ERR "\tcommit number  %llu\n",
+                      (unsigned long long)
+                               le64_to_cpu(orph->cmt_no) & LLONG_MAX);
+-              printk(KERN_DEBUG "\tlast node flag %llu\n",
++              printk(KERN_ERR "\tlast node flag %llu\n",
+                      (unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
+               n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
+-              printk(KERN_DEBUG "\t%d orphan inode numbers:\n", n);
++              printk(KERN_ERR "\t%d orphan inode numbers:\n", n);
+               for (i = 0; i < n; i++)
+-                      printk(KERN_DEBUG "\t  ino %llu\n",
++                      printk(KERN_ERR "\t  ino %llu\n",
+                              (unsigned long long)le64_to_cpu(orph->inos[i]));
+               break;
+       }
+       default:
+-              printk(KERN_DEBUG "node type %d was not recognized\n",
++              printk(KERN_ERR "node type %d was not recognized\n",
+                      (int)ch->node_type);
+       }
+       spin_unlock(&dbg_lock);
+@@ -574,16 +606,16 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
+ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+ {
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "Budgeting request: new_ino %d, dirtied_ino %d\n",
++      printk(KERN_ERR "Budgeting request: new_ino %d, dirtied_ino %d\n",
+              req->new_ino, req->dirtied_ino);
+-      printk(KERN_DEBUG "\tnew_ino_d   %d, dirtied_ino_d %d\n",
++      printk(KERN_ERR "\tnew_ino_d   %d, dirtied_ino_d %d\n",
+              req->new_ino_d, req->dirtied_ino_d);
+-      printk(KERN_DEBUG "\tnew_page    %d, dirtied_page %d\n",
++      printk(KERN_ERR "\tnew_page    %d, dirtied_page %d\n",
+              req->new_page, req->dirtied_page);
+-      printk(KERN_DEBUG "\tnew_dent    %d, mod_dent     %d\n",
++      printk(KERN_ERR "\tnew_dent    %d, mod_dent     %d\n",
+              req->new_dent, req->mod_dent);
+-      printk(KERN_DEBUG "\tidx_growth  %d\n", req->idx_growth);
+-      printk(KERN_DEBUG "\tdata_growth %d dd_growth     %d\n",
++      printk(KERN_ERR "\tidx_growth  %d\n", req->idx_growth);
++      printk(KERN_ERR "\tdata_growth %d dd_growth     %d\n",
+              req->data_growth, req->dd_growth);
+       spin_unlock(&dbg_lock);
+ }
+@@ -591,18 +623,18 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+ void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
+ {
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, "
++      printk(KERN_ERR "(pid %d) Lprops statistics: empty_lebs %d, "
+              "idx_lebs  %d\n", current->pid, lst->empty_lebs, lst->idx_lebs);
+-      printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, "
++      printk(KERN_ERR "\ttaken_empty_lebs %d, total_free %lld, "
+              "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free,
+              lst->total_dirty);
+-      printk(KERN_DEBUG "\ttotal_used %lld, total_dark %lld, "
++      printk(KERN_ERR "\ttotal_used %lld, total_dark %lld, "
+              "total_dead %lld\n", lst->total_used, lst->total_dark,
+              lst->total_dead);
+       spin_unlock(&dbg_lock);
+ }
+-void dbg_dump_budg(struct ubifs_info *c)
++void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
+ {
+       int i;
+       struct rb_node *rb;
+@@ -610,51 +642,69 @@ void dbg_dump_budg(struct ubifs_info *c)
+       struct ubifs_gced_idx_leb *idx_gc;
+       long long available, outstanding, free;
+-      ubifs_assert(spin_is_locked(&c->space_lock));
++      spin_lock(&c->space_lock);
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
+-             "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
+-             c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
+-      printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
+-             "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
+-             c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth,
+-             c->freeable_cnt);
+-      printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, "
+-             "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs,
+-             c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt);
+-      printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
++      printk(KERN_ERR "(pid %d) Budgeting info: data budget sum %lld, "
++             "total budget sum %lld\n", current->pid,
++             bi->data_growth + bi->dd_growth,
++             bi->data_growth + bi->dd_growth + bi->idx_growth);
++      printk(KERN_ERR "\tbudg_data_growth %lld, budg_dd_growth %lld, "
++             "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth,
++             bi->idx_growth);
++      printk(KERN_ERR "\tmin_idx_lebs %d, old_idx_sz %llu, "
++             "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz,
++             bi->uncommitted_idx);
++      printk(KERN_ERR "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
++             bi->page_budget, bi->inode_budget, bi->dent_budget);
++      printk(KERN_ERR "\tnospace %u, nospace_rp %u\n",
++             bi->nospace, bi->nospace_rp);
++      printk(KERN_ERR "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
++             c->dark_wm, c->dead_wm, c->max_idx_node_sz);
++
++      if (bi != &c->bi)
++              /*
++               * If we are dumping saved budgeting data, do not print
++               * additional information which is about the current state, not
++               * the old one which corresponded to the saved budgeting data.
++               */
++              goto out_unlock;
++
++      printk(KERN_ERR "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
++             c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
++      printk(KERN_ERR "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
+              "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),
+              atomic_long_read(&c->dirty_zn_cnt),
+              atomic_long_read(&c->clean_zn_cnt));
+-      printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
+-             c->dark_wm, c->dead_wm, c->max_idx_node_sz);
+-      printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
++      printk(KERN_ERR "\tgc_lnum %d, ihead_lnum %d\n",
+              c->gc_lnum, c->ihead_lnum);
++
+       /* If we are in R/O mode, journal heads do not exist */
+       if (c->jheads)
+               for (i = 0; i < c->jhead_cnt; i++)
+-                      printk(KERN_DEBUG "\tjhead %s\t LEB %d\n",
++                      printk(KERN_ERR "\tjhead %s\t LEB %d\n",
+                              dbg_jhead(c->jheads[i].wbuf.jhead),
+                              c->jheads[i].wbuf.lnum);
+       for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
+               bud = rb_entry(rb, struct ubifs_bud, rb);
+-              printk(KERN_DEBUG "\tbud LEB %d\n", bud->lnum);
++              printk(KERN_ERR "\tbud LEB %d\n", bud->lnum);
+       }
+       list_for_each_entry(bud, &c->old_buds, list)
+-              printk(KERN_DEBUG "\told bud LEB %d\n", bud->lnum);
++              printk(KERN_ERR "\told bud LEB %d\n", bud->lnum);
+       list_for_each_entry(idx_gc, &c->idx_gc, list)
+-              printk(KERN_DEBUG "\tGC'ed idx LEB %d unmap %d\n",
++              printk(KERN_ERR "\tGC'ed idx LEB %d unmap %d\n",
+                      idx_gc->lnum, idx_gc->unmap);
+-      printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
++      printk(KERN_ERR "\tcommit state %d\n", c->cmt_state);
+       /* Print budgeting predictions */
+-      available = ubifs_calc_available(c, c->min_idx_lebs);
+-      outstanding = c->budg_data_growth + c->budg_dd_growth;
++      available = ubifs_calc_available(c, c->bi.min_idx_lebs);
++      outstanding = c->bi.data_growth + c->bi.dd_growth;
+       free = ubifs_get_free_space_nolock(c);
+-      printk(KERN_DEBUG "Budgeting predictions:\n");
+-      printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
++      printk(KERN_ERR "Budgeting predictions:\n");
++      printk(KERN_ERR "\tavailable: %lld, outstanding %lld, free %lld\n",
+              available, outstanding, free);
++out_unlock:
+       spin_unlock(&dbg_lock);
++      spin_unlock(&c->space_lock);
+ }
+ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+@@ -670,11 +720,11 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+               dark = ubifs_calc_dark(c, spc);
+       if (lp->flags & LPROPS_INDEX)
+-              printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
++              printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
+                      "free + dirty %-8d flags %#x (", lp->lnum, lp->free,
+                      lp->dirty, c->leb_size - spc, spc, lp->flags);
+       else
+-              printk(KERN_DEBUG "LEB %-7d free %-8d dirty %-8d used %-8d "
++              printk(KERN_ERR "LEB %-7d free %-8d dirty %-8d used %-8d "
+                      "free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d "
+                      "flags %#-4x (", lp->lnum, lp->free, lp->dirty,
+                      c->leb_size - spc, spc, dark, dead,
+@@ -729,7 +779,13 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+               if (bud->lnum == lp->lnum) {
+                       int head = 0;
+                       for (i = 0; i < c->jhead_cnt; i++) {
+-                              if (lp->lnum == c->jheads[i].wbuf.lnum) {
++                              /*
++                               * Note, if we are in R/O mode or in the middle
++                               * of mounting/re-mounting, the write-buffers do
++                               * not exist.
++                               */
++                              if (c->jheads &&
++                                  lp->lnum == c->jheads[i].wbuf.lnum) {
+                                       printk(KERN_CONT ", jhead %s",
+                                              dbg_jhead(i));
+                                       head = 1;
+@@ -751,7 +807,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
+       struct ubifs_lprops lp;
+       struct ubifs_lp_stats lst;
+-      printk(KERN_DEBUG "(pid %d) start dumping LEB properties\n",
++      printk(KERN_ERR "(pid %d) start dumping LEB properties\n",
+              current->pid);
+       ubifs_get_lp_stats(c, &lst);
+       dbg_dump_lstats(&lst);
+@@ -763,7 +819,7 @@ void dbg_dump_lprops(struct ubifs_info *c)
+               dbg_dump_lprop(c, &lp);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping LEB properties\n",
++      printk(KERN_ERR "(pid %d) finish dumping LEB properties\n",
+              current->pid);
+ }
+@@ -772,69 +828,96 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
+       int i;
+       spin_lock(&dbg_lock);
+-      printk(KERN_DEBUG "(pid %d) dumping LPT information\n", current->pid);
+-      printk(KERN_DEBUG "\tlpt_sz:        %lld\n", c->lpt_sz);
+-      printk(KERN_DEBUG "\tpnode_sz:      %d\n", c->pnode_sz);
+-      printk(KERN_DEBUG "\tnnode_sz:      %d\n", c->nnode_sz);
+-      printk(KERN_DEBUG "\tltab_sz:       %d\n", c->ltab_sz);
+-      printk(KERN_DEBUG "\tlsave_sz:      %d\n", c->lsave_sz);
+-      printk(KERN_DEBUG "\tbig_lpt:       %d\n", c->big_lpt);
+-      printk(KERN_DEBUG "\tlpt_hght:      %d\n", c->lpt_hght);
+-      printk(KERN_DEBUG "\tpnode_cnt:     %d\n", c->pnode_cnt);
+-      printk(KERN_DEBUG "\tnnode_cnt:     %d\n", c->nnode_cnt);
+-      printk(KERN_DEBUG "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
+-      printk(KERN_DEBUG "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
+-      printk(KERN_DEBUG "\tlsave_cnt:     %d\n", c->lsave_cnt);
+-      printk(KERN_DEBUG "\tspace_bits:    %d\n", c->space_bits);
+-      printk(KERN_DEBUG "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
+-      printk(KERN_DEBUG "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
+-      printk(KERN_DEBUG "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
+-      printk(KERN_DEBUG "\tpcnt_bits:     %d\n", c->pcnt_bits);
+-      printk(KERN_DEBUG "\tlnum_bits:     %d\n", c->lnum_bits);
+-      printk(KERN_DEBUG "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
+-      printk(KERN_DEBUG "\tLPT head is at %d:%d\n",
++      printk(KERN_ERR "(pid %d) dumping LPT information\n", current->pid);
++      printk(KERN_ERR "\tlpt_sz:        %lld\n", c->lpt_sz);
++      printk(KERN_ERR "\tpnode_sz:      %d\n", c->pnode_sz);
++      printk(KERN_ERR "\tnnode_sz:      %d\n", c->nnode_sz);
++      printk(KERN_ERR "\tltab_sz:       %d\n", c->ltab_sz);
++      printk(KERN_ERR "\tlsave_sz:      %d\n", c->lsave_sz);
++      printk(KERN_ERR "\tbig_lpt:       %d\n", c->big_lpt);
++      printk(KERN_ERR "\tlpt_hght:      %d\n", c->lpt_hght);
++      printk(KERN_ERR "\tpnode_cnt:     %d\n", c->pnode_cnt);
++      printk(KERN_ERR "\tnnode_cnt:     %d\n", c->nnode_cnt);
++      printk(KERN_ERR "\tdirty_pn_cnt:  %d\n", c->dirty_pn_cnt);
++      printk(KERN_ERR "\tdirty_nn_cnt:  %d\n", c->dirty_nn_cnt);
++      printk(KERN_ERR "\tlsave_cnt:     %d\n", c->lsave_cnt);
++      printk(KERN_ERR "\tspace_bits:    %d\n", c->space_bits);
++      printk(KERN_ERR "\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
++      printk(KERN_ERR "\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
++      printk(KERN_ERR "\tlpt_spc_bits:  %d\n", c->lpt_spc_bits);
++      printk(KERN_ERR "\tpcnt_bits:     %d\n", c->pcnt_bits);
++      printk(KERN_ERR "\tlnum_bits:     %d\n", c->lnum_bits);
++      printk(KERN_ERR "\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
++      printk(KERN_ERR "\tLPT head is at %d:%d\n",
+              c->nhead_lnum, c->nhead_offs);
+-      printk(KERN_DEBUG "\tLPT ltab is at %d:%d\n",
++      printk(KERN_ERR "\tLPT ltab is at %d:%d\n",
+              c->ltab_lnum, c->ltab_offs);
+       if (c->big_lpt)
+-              printk(KERN_DEBUG "\tLPT lsave is at %d:%d\n",
++              printk(KERN_ERR "\tLPT lsave is at %d:%d\n",
+                      c->lsave_lnum, c->lsave_offs);
+       for (i = 0; i < c->lpt_lebs; i++)
+-              printk(KERN_DEBUG "\tLPT LEB %d free %d dirty %d tgc %d "
++              printk(KERN_ERR "\tLPT LEB %d free %d dirty %d tgc %d "
+                      "cmt %d\n", i + c->lpt_first, c->ltab[i].free,
+                      c->ltab[i].dirty, c->ltab[i].tgc, c->ltab[i].cmt);
+       spin_unlock(&dbg_lock);
+ }
++void dbg_dump_sleb(const struct ubifs_info *c,
++                 const struct ubifs_scan_leb *sleb, int offs)
++{
++      struct ubifs_scan_node *snod;
++
++      printk(KERN_ERR "(pid %d) start dumping scanned data from LEB %d:%d\n",
++             current->pid, sleb->lnum, offs);
++
++      list_for_each_entry(snod, &sleb->nodes, list) {
++              cond_resched();
++              printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
++                     snod->offs, snod->len);
++              dbg_dump_node(c, snod->node);
++      }
++}
++
+ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
+ {
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
++      void *buf;
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+-      printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
++      printk(KERN_ERR "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+-      sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
++
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory for dumping LEB %d", lnum);
++              return;
++      }
++
++      sleb = ubifs_scan(c, lnum, 0, buf, 0);
+       if (IS_ERR(sleb)) {
+               ubifs_err("scan error %d", (int)PTR_ERR(sleb));
+-              return;
++              goto out;
+       }
+-      printk(KERN_DEBUG "LEB %d has %d nodes ending at %d\n", lnum,
++      printk(KERN_ERR "LEB %d has %d nodes ending at %d\n", lnum,
+              sleb->nodes_cnt, sleb->endpt);
+       list_for_each_entry(snod, &sleb->nodes, list) {
+               cond_resched();
+-              printk(KERN_DEBUG "Dumping node at LEB %d:%d len %d\n", lnum,
++              printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", lnum,
+                      snod->offs, snod->len);
+               dbg_dump_node(c, snod->node);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
++      printk(KERN_ERR "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
+       ubifs_scan_destroy(sleb);
++
++out:
++      vfree(buf);
+       return;
+ }
+@@ -843,6 +926,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
+ {
+       int n;
+       const struct ubifs_zbranch *zbr;
++      char key_buf[DBG_KEY_BUF_LEN];
+       spin_lock(&dbg_lock);
+       if (znode->parent)
+@@ -850,7 +934,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
+       else
+               zbr = &c->zroot;
+-      printk(KERN_DEBUG "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
++      printk(KERN_ERR "znode %p, LEB %d:%d len %d parent %p iip %d level %d"
+              " child_cnt %d flags %lx\n", znode, zbr->lnum, zbr->offs,
+              zbr->len, znode->parent, znode->iip, znode->level,
+              znode->child_cnt, znode->flags);
+@@ -860,19 +944,23 @@ void dbg_dump_znode(const struct ubifs_info *c,
+               return;
+       }
+-      printk(KERN_DEBUG "zbranches:\n");
++      printk(KERN_ERR "zbranches:\n");
+       for (n = 0; n < znode->child_cnt; n++) {
+               zbr = &znode->zbranch[n];
+               if (znode->level > 0)
+-                      printk(KERN_DEBUG "\t%d: znode %p LEB %d:%d len %d key "
++                      printk(KERN_ERR "\t%d: znode %p LEB %d:%d len %d key "
+                                         "%s\n", n, zbr->znode, zbr->lnum,
+                                         zbr->offs, zbr->len,
+-                                        DBGKEY(&zbr->key));
++                                        dbg_snprintf_key(c, &zbr->key,
++                                                         key_buf,
++                                                         DBG_KEY_BUF_LEN));
+               else
+-                      printk(KERN_DEBUG "\t%d: LNC %p LEB %d:%d len %d key "
++                      printk(KERN_ERR "\t%d: LNC %p LEB %d:%d len %d key "
+                                         "%s\n", n, zbr->znode, zbr->lnum,
+                                         zbr->offs, zbr->len,
+-                                        DBGKEY(&zbr->key));
++                                        dbg_snprintf_key(c, &zbr->key,
++                                                         key_buf,
++                                                         DBG_KEY_BUF_LEN));
+       }
+       spin_unlock(&dbg_lock);
+ }
+@@ -881,16 +969,16 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
+ {
+       int i;
+-      printk(KERN_DEBUG "(pid %d) start dumping heap cat %d (%d elements)\n",
++      printk(KERN_ERR "(pid %d) start dumping heap cat %d (%d elements)\n",
+              current->pid, cat, heap->cnt);
+       for (i = 0; i < heap->cnt; i++) {
+               struct ubifs_lprops *lprops = heap->arr[i];
+-              printk(KERN_DEBUG "\t%d. LEB %d hpos %d free %d dirty %d "
++              printk(KERN_ERR "\t%d. LEB %d hpos %d free %d dirty %d "
+                      "flags %d\n", i, lprops->lnum, lprops->hpos,
+                      lprops->free, lprops->dirty, lprops->flags);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping heap\n", current->pid);
++      printk(KERN_ERR "(pid %d) finish dumping heap\n", current->pid);
+ }
+ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+@@ -898,15 +986,15 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+ {
+       int i;
+-      printk(KERN_DEBUG "(pid %d) dumping pnode:\n", current->pid);
+-      printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n",
++      printk(KERN_ERR "(pid %d) dumping pnode:\n", current->pid);
++      printk(KERN_ERR "\taddress %zx parent %zx cnext %zx\n",
+              (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
+-      printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n",
++      printk(KERN_ERR "\tflags %lu iip %d level %d num %d\n",
+              pnode->flags, iip, pnode->level, pnode->num);
+       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+               struct ubifs_lprops *lp = &pnode->lprops[i];
+-              printk(KERN_DEBUG "\t%d: free %d dirty %d flags %d lnum %d\n",
++              printk(KERN_ERR "\t%d: free %d dirty %d flags %d lnum %d\n",
+                      i, lp->free, lp->dirty, lp->flags, lp->lnum);
+       }
+ }
+@@ -916,20 +1004,20 @@ void dbg_dump_tnc(struct ubifs_info *c)
+       struct ubifs_znode *znode;
+       int level;
+-      printk(KERN_DEBUG "\n");
+-      printk(KERN_DEBUG "(pid %d) start dumping TNC tree\n", current->pid);
++      printk(KERN_ERR "\n");
++      printk(KERN_ERR "(pid %d) start dumping TNC tree\n", current->pid);
+       znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
+       level = znode->level;
+-      printk(KERN_DEBUG "== Level %d ==\n", level);
++      printk(KERN_ERR "== Level %d ==\n", level);
+       while (znode) {
+               if (level != znode->level) {
+                       level = znode->level;
+-                      printk(KERN_DEBUG "== Level %d ==\n", level);
++                      printk(KERN_ERR "== Level %d ==\n", level);
+               }
+               dbg_dump_znode(c, znode);
+               znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
+       }
+-      printk(KERN_DEBUG "(pid %d) finish dumping TNC tree\n", current->pid);
++      printk(KERN_ERR "(pid %d) finish dumping TNC tree\n", current->pid);
+ }
+ static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
+@@ -961,11 +1049,41 @@ void dbg_dump_index(struct ubifs_info *c)
+ void dbg_save_space_info(struct ubifs_info *c)
+ {
+       struct ubifs_debug_info *d = c->dbg;
+-
+-      ubifs_get_lp_stats(c, &d->saved_lst);
++      int freeable_cnt;
+       spin_lock(&c->space_lock);
++      memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats));
++      memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info));
++      d->saved_idx_gc_cnt = c->idx_gc_cnt;
++
++      /*
++       * We use a dirty hack here and zero out @c->freeable_cnt, because it
++       * affects the free space calculations, and UBIFS might not know about
++       * all freeable eraseblocks. Indeed, we know about freeable eraseblocks
++       * only when we read their lprops, and we do this only lazily, upon the
++       * need. So at any given point of time @c->freeable_cnt might be not
++       * exactly accurate.
++       *
++       * Just one example about the issue we hit when we did not zero
++       * @c->freeable_cnt.
++       * 1. The file-system is mounted R/O, c->freeable_cnt is %0. We save the
++       *    amount of free space in @d->saved_free
++       * 2. We re-mount R/W, which makes UBIFS to read the "lsave"
++       *    information from flash, where we cache LEBs from various
++       *    categories ('ubifs_remount_fs()' -> 'ubifs_lpt_init()'
++       *    -> 'lpt_init_wr()' -> 'read_lsave()' -> 'ubifs_lpt_lookup()'
++       *    -> 'ubifs_get_pnode()' -> 'update_cats()'
++       *    -> 'ubifs_add_to_cat()').
++       * 3. Lsave contains a freeable eraseblock, and @c->freeable_cnt
++       *    becomes %1.
++       * 4. We calculate the amount of free space when the re-mount is
++       *    finished in 'dbg_check_space_info()' and it does not match
++       *    @d->saved_free.
++       */
++      freeable_cnt = c->freeable_cnt;
++      c->freeable_cnt = 0;
+       d->saved_free = ubifs_get_free_space_nolock(c);
++      c->freeable_cnt = freeable_cnt;
+       spin_unlock(&c->space_lock);
+ }
+@@ -982,12 +1100,15 @@ int dbg_check_space_info(struct ubifs_info *c)
+ {
+       struct ubifs_debug_info *d = c->dbg;
+       struct ubifs_lp_stats lst;
+-      long long avail, free;
++      long long free;
++      int freeable_cnt;
+       spin_lock(&c->space_lock);
+-      avail = ubifs_calc_available(c, c->min_idx_lebs);
++      freeable_cnt = c->freeable_cnt;
++      c->freeable_cnt = 0;
++      free = ubifs_get_free_space_nolock(c);
++      c->freeable_cnt = freeable_cnt;
+       spin_unlock(&c->space_lock);
+-      free = ubifs_get_free_space(c);
+       if (free != d->saved_free) {
+               ubifs_err("free space changed from %lld to %lld",
+@@ -1000,20 +1121,21 @@ int dbg_check_space_info(struct ubifs_info *c)
+ out:
+       ubifs_msg("saved lprops statistics dump");
+       dbg_dump_lstats(&d->saved_lst);
+-      ubifs_get_lp_stats(c, &lst);
+-
++      ubifs_msg("saved budgeting info dump");
++      dbg_dump_budg(c, &d->saved_bi);
++      ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
+       ubifs_msg("current lprops statistics dump");
++      ubifs_get_lp_stats(c, &lst);
+       dbg_dump_lstats(&lst);
+-
+-      spin_lock(&c->space_lock);
+-      dbg_dump_budg(c);
+-      spin_unlock(&c->space_lock);
++      ubifs_msg("current budgeting info dump");
++      dbg_dump_budg(c, &c->bi);
+       dump_stack();
+       return -EINVAL;
+ }
+ /**
+  * dbg_check_synced_i_size - check synchronized inode size.
++ * @c: UBIFS file-system description object
+  * @inode: inode to check
+  *
+  * If inode is clean, synchronized inode size has to be equivalent to current
+@@ -1021,12 +1143,12 @@ out:
+  * has to be locked). Returns %0 if synchronized inode size if correct, and
+  * %-EINVAL if not.
+  */
+-int dbg_check_synced_i_size(struct inode *inode)
++int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode)
+ {
+       int err = 0;
+       struct ubifs_inode *ui = ubifs_inode(inode);
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (!S_ISREG(inode->i_mode))
+               return 0;
+@@ -1059,7 +1181,7 @@ int dbg_check_synced_i_size(struct inode *inode)
+  * Note, it is good idea to make sure the @dir->i_mutex is locked before
+  * calling this function.
+  */
+-int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
++int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
+ {
+       unsigned int nlink = 2;
+       union ubifs_key key;
+@@ -1067,7 +1189,7 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
+       struct qstr nm = { .name = NULL };
+       loff_t size = UBIFS_INO_NODE_SZ;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (!S_ISDIR(dir->i_mode))
+@@ -1101,12 +1223,14 @@ int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir)
+                         "but calculated size is %llu", dir->i_ino,
+                         (unsigned long long)i_size_read(dir),
+                         (unsigned long long)size);
++              dbg_dump_inode(c, dir);
+               dump_stack();
+               return -EINVAL;
+       }
+       if (dir->i_nlink != nlink) {
+               ubifs_err("directory inode %lu has nlink %u, but calculated "
+                         "nlink is %u", dir->i_ino, dir->i_nlink, nlink);
++              dbg_dump_inode(c, dir);
+               dump_stack();
+               return -EINVAL;
+       }
+@@ -1133,6 +1257,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       int err, nlen1, nlen2, cmp;
+       struct ubifs_dent_node *dent1, *dent2;
+       union ubifs_key key;
++      char key_buf[DBG_KEY_BUF_LEN];
+       ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key));
+       dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
+@@ -1163,9 +1288,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       key_read(c, &dent1->key, &key);
+       if (keys_cmp(c, &zbr1->key, &key)) {
+               dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
+-                      zbr1->offs, DBGKEY(&key));
++                      zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
++                                                   DBG_KEY_BUF_LEN));
+               dbg_err("but it should have key %s according to tnc",
+-                      DBGKEY(&zbr1->key));
++                      dbg_snprintf_key(c, &zbr1->key, key_buf,
++                                       DBG_KEY_BUF_LEN));
+               dbg_dump_node(c, dent1);
+               goto out_free;
+       }
+@@ -1173,9 +1300,11 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+       key_read(c, &dent2->key, &key);
+       if (keys_cmp(c, &zbr2->key, &key)) {
+               dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
+-                      zbr1->offs, DBGKEY(&key));
++                      zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
++                                                   DBG_KEY_BUF_LEN));
+               dbg_err("but it should have key %s according to tnc",
+-                      DBGKEY(&zbr2->key));
++                      dbg_snprintf_key(c, &zbr2->key, key_buf,
++                                       DBG_KEY_BUF_LEN));
+               dbg_dump_node(c, dent2);
+               goto out_free;
+       }
+@@ -1192,7 +1321,7 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+               dbg_err("2 xent/dent nodes with the same name");
+       else
+               dbg_err("bad order of colliding key %s",
+-                      DBGKEY(&key));
++                      dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+       ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
+       dbg_dump_node(c, dent1);
+@@ -1423,7 +1552,7 @@ int dbg_check_tnc(struct ubifs_info *c, int extra)
+       long clean_cnt = 0, dirty_cnt = 0;
+       int err, last;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_TNC))
++      if (!dbg_is_chk_index(c))
+               return 0;
+       ubifs_assert(mutex_is_locked(&c->tnc_mutex));
+@@ -1670,7 +1799,7 @@ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
+       int err;
+       long long calc = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_IDX_SZ))
++      if (!dbg_is_chk_index(c))
+               return 0;
+       err = dbg_walk_index(c, NULL, add_size, &calc);
+@@ -1751,6 +1880,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
+       struct rb_node **p, *parent = NULL;
+       struct fsck_inode *fscki;
+       ino_t inum = key_inum_flash(c, &ino->key);
++      struct inode *inode;
++      struct ubifs_inode *ui;
+       p = &fsckd->inodes.rb_node;
+       while (*p) {
+@@ -1774,19 +1905,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
+       if (!fscki)
+               return ERR_PTR(-ENOMEM);
++      inode = ilookup(c->vfs_sb, inum);
++
+       fscki->inum = inum;
+-      fscki->nlink = le32_to_cpu(ino->nlink);
+-      fscki->size = le64_to_cpu(ino->size);
+-      fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
+-      fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
+-      fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
+-      fscki->mode = le32_to_cpu(ino->mode);
++      /*
++       * If the inode is present in the VFS inode cache, use it instead of
++       * the on-flash inode which might be out-of-date. E.g., the size might
++       * be out-of-date. If we do not do this, the following may happen, for
++       * example:
++       *   1. A power cut happens
++       *   2. We mount the file-system R/O, the replay process fixes up the
++       *      inode size in the VFS cache, but on on-flash.
++       *   3. 'check_leaf()' fails because it hits a data node beyond inode
++       *      size.
++       */
++      if (!inode) {
++              fscki->nlink = le32_to_cpu(ino->nlink);
++              fscki->size = le64_to_cpu(ino->size);
++              fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
++              fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
++              fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
++              fscki->mode = le32_to_cpu(ino->mode);
++      } else {
++              ui = ubifs_inode(inode);
++              fscki->nlink = inode->i_nlink;
++              fscki->size = inode->i_size;
++              fscki->xattr_cnt = ui->xattr_cnt;
++              fscki->xattr_sz = ui->xattr_size;
++              fscki->xattr_nms = ui->xattr_names;
++              fscki->mode = inode->i_mode;
++              iput(inode);
++      }
++
+       if (S_ISDIR(fscki->mode)) {
+               fscki->calc_sz = UBIFS_INO_NODE_SZ;
+               fscki->calc_cnt = 2;
+       }
++
+       rb_link_node(&fscki->rb, parent, p);
+       rb_insert_color(&fscki->rb, &fsckd->inodes);
++
+       return fscki;
+ }
+@@ -2217,7 +2375,7 @@ int dbg_check_filesystem(struct ubifs_info *c)
+       int err;
+       struct fsck_data fsckd;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_FS))
++      if (!dbg_is_chk_fs(c))
+               return 0;
+       fsckd.inodes = RB_ROOT;
+@@ -2252,7 +2410,7 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+@@ -2319,7 +2477,7 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+       struct list_head *cur;
+       struct ubifs_scan_node *sa, *sb;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       for (cur = head->next; cur->next != head; cur = cur->next) {
+@@ -2379,7 +2537,8 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+               hashb = key_block(c, &sb->key);
+               if (hasha > hashb) {
+-                      ubifs_err("larger hash %u goes before %u", hasha, hashb);
++                      ubifs_err("larger hash %u goes before %u",
++                                hasha, hashb);
+                       goto error_dump;
+               }
+       }
+@@ -2395,393 +2554,351 @@ error_dump:
+       return 0;
+ }
+-static int invocation_cnt;
+-
+-int dbg_force_in_the_gaps(void)
+-{
+-      if (!dbg_force_in_the_gaps_enabled)
+-              return 0;
+-      /* Force in-the-gaps every 8th commit */
+-      return !((invocation_cnt++) & 0x7);
+-}
+-
+-/* Failure mode for recovery testing */
+-
+-#define chance(n, d) (simple_rand() <= (n) * 32768LL / (d))
+-
+-struct failure_mode_info {
+-      struct list_head list;
+-      struct ubifs_info *c;
+-};
+-
+-static LIST_HEAD(fmi_list);
+-static DEFINE_SPINLOCK(fmi_lock);
+-
+-static unsigned int next;
+-
+-static int simple_rand(void)
+-{
+-      if (next == 0)
+-              next = current->pid;
+-      next = next * 1103515245 + 12345;
+-      return (next >> 16) & 32767;
+-}
+-
+-static void failure_mode_init(struct ubifs_info *c)
+-{
+-      struct failure_mode_info *fmi;
+-
+-      fmi = kmalloc(sizeof(struct failure_mode_info), GFP_NOFS);
+-      if (!fmi) {
+-              ubifs_err("Failed to register failure mode - no memory");
+-              return;
+-      }
+-      fmi->c = c;
+-      spin_lock(&fmi_lock);
+-      list_add_tail(&fmi->list, &fmi_list);
+-      spin_unlock(&fmi_lock);
+-}
+-
+-static void failure_mode_exit(struct ubifs_info *c)
+-{
+-      struct failure_mode_info *fmi, *tmp;
+-
+-      spin_lock(&fmi_lock);
+-      list_for_each_entry_safe(fmi, tmp, &fmi_list, list)
+-              if (fmi->c == c) {
+-                      list_del(&fmi->list);
+-                      kfree(fmi);
+-              }
+-      spin_unlock(&fmi_lock);
+-}
+-
+-static struct ubifs_info *dbg_find_info(struct ubi_volume_desc *desc)
++static inline int chance(unsigned int n, unsigned int out_of)
+ {
+-      struct failure_mode_info *fmi;
+-
+-      spin_lock(&fmi_lock);
+-      list_for_each_entry(fmi, &fmi_list, list)
+-              if (fmi->c->ubi == desc) {
+-                      struct ubifs_info *c = fmi->c;
++      return !!((random32() % out_of) + 1 <= n);
+-                      spin_unlock(&fmi_lock);
+-                      return c;
+-              }
+-      spin_unlock(&fmi_lock);
+-      return NULL;
+ }
+-static int in_failure_mode(struct ubi_volume_desc *desc)
++static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
+ {
+-      struct ubifs_info *c = dbg_find_info(desc);
+-
+-      if (c && dbg_failure_mode)
+-              return c->dbg->failure_mode;
+-      return 0;
+-}
++      struct ubifs_debug_info *d = c->dbg;
+-static int do_fail(struct ubi_volume_desc *desc, int lnum, int write)
+-{
+-      struct ubifs_info *c = dbg_find_info(desc);
+-      struct ubifs_debug_info *d;
++      ubifs_assert(dbg_is_tst_rcvry(c));
+-      if (!c || !dbg_failure_mode)
+-              return 0;
+-      d = c->dbg;
+-      if (d->failure_mode)
+-              return 1;
+-      if (!d->fail_cnt) {
+-              /* First call - decide delay to failure */
++      if (!d->pc_cnt) {
++              /* First call - decide delay to the power cut */
+               if (chance(1, 2)) {
+-                      unsigned int delay = 1 << (simple_rand() >> 11);
++                      unsigned long delay;
+                       if (chance(1, 2)) {
+-                              d->fail_delay = 1;
+-                              d->fail_timeout = jiffies +
+-                                                msecs_to_jiffies(delay);
+-                              dbg_rcvry("failing after %ums", delay);
++                              d->pc_delay = 1;
++                              /* Fail withing 1 minute */
++                              delay = random32() % 60000;
++                              d->pc_timeout = jiffies;
++                              d->pc_timeout += msecs_to_jiffies(delay);
++                              ubifs_warn("failing after %lums", delay);
+                       } else {
+-                              d->fail_delay = 2;
+-                              d->fail_cnt_max = delay;
+-                              dbg_rcvry("failing after %u calls", delay);
++                              d->pc_delay = 2;
++                              delay = random32() % 10000;
++                              /* Fail within 10000 operations */
++                              d->pc_cnt_max = delay;
++                              ubifs_warn("failing after %lu calls", delay);
+                       }
+               }
+-              d->fail_cnt += 1;
++
++              d->pc_cnt += 1;
+       }
++
+       /* Determine if failure delay has expired */
+-      if (d->fail_delay == 1) {
+-              if (time_before(jiffies, d->fail_timeout))
++      if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
+                       return 0;
+-      } else if (d->fail_delay == 2)
+-              if (d->fail_cnt++ < d->fail_cnt_max)
++      if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
+                       return 0;
++
+       if (lnum == UBIFS_SB_LNUM) {
+-              if (write) {
+-                      if (chance(1, 2))
+-                              return 0;
+-              } else if (chance(19, 20))
++              if (write && chance(1, 2))
+                       return 0;
+-              dbg_rcvry("failing in super block LEB %d", lnum);
++              if (chance(19, 20))
++                      return 0;
++              ubifs_warn("failing in super block LEB %d", lnum);
+       } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
+               if (chance(19, 20))
+                       return 0;
+-              dbg_rcvry("failing in master LEB %d", lnum);
++              ubifs_warn("failing in master LEB %d", lnum);
+       } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
+-              if (write) {
+-                      if (chance(99, 100))
+-                              return 0;
+-              } else if (chance(399, 400))
++              if (write && chance(99, 100))
++                      return 0;
++              if (chance(399, 400))
+                       return 0;
+-              dbg_rcvry("failing in log LEB %d", lnum);
++              ubifs_warn("failing in log LEB %d", lnum);
+       } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
+-              if (write) {
+-                      if (chance(7, 8))
+-                              return 0;
+-              } else if (chance(19, 20))
++              if (write && chance(7, 8))
+                       return 0;
+-              dbg_rcvry("failing in LPT LEB %d", lnum);
++              if (chance(19, 20))
++                      return 0;
++              ubifs_warn("failing in LPT LEB %d", lnum);
+       } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
+-              if (write) {
+-                      if (chance(1, 2))
+-                              return 0;
+-              } else if (chance(9, 10))
++              if (write && chance(1, 2))
+                       return 0;
+-              dbg_rcvry("failing in orphan LEB %d", lnum);
++              if (chance(9, 10))
++                      return 0;
++              ubifs_warn("failing in orphan LEB %d", lnum);
+       } else if (lnum == c->ihead_lnum) {
+               if (chance(99, 100))
+                       return 0;
+-              dbg_rcvry("failing in index head LEB %d", lnum);
++              ubifs_warn("failing in index head LEB %d", lnum);
+       } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
+               if (chance(9, 10))
+                       return 0;
+-              dbg_rcvry("failing in GC head LEB %d", lnum);
++              ubifs_warn("failing in GC head LEB %d", lnum);
+       } else if (write && !RB_EMPTY_ROOT(&c->buds) &&
+                  !ubifs_search_bud(c, lnum)) {
+               if (chance(19, 20))
+                       return 0;
+-              dbg_rcvry("failing in non-bud LEB %d", lnum);
++              ubifs_warn("failing in non-bud LEB %d", lnum);
+       } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
+                  c->cmt_state == COMMIT_RUNNING_REQUIRED) {
+               if (chance(999, 1000))
+                       return 0;
+-              dbg_rcvry("failing in bud LEB %d commit running", lnum);
++              ubifs_warn("failing in bud LEB %d commit running", lnum);
+       } else {
+               if (chance(9999, 10000))
+                       return 0;
+-              dbg_rcvry("failing in bud LEB %d commit not running", lnum);
++              ubifs_warn("failing in bud LEB %d commit not running", lnum);
+       }
+-      ubifs_err("*** SETTING FAILURE MODE ON (LEB %d) ***", lnum);
+-      d->failure_mode = 1;
++
++      d->pc_happened = 1;
++      ubifs_warn("========== Power cut emulated ==========");
+       dump_stack();
+       return 1;
+ }
+-static void cut_data(const void *buf, int len)
++static void cut_data(const void *buf, unsigned int len)
+ {
+-      int flen, i;
++      unsigned int from, to, i, ffs = chance(1, 2);
+       unsigned char *p = (void *)buf;
+-      flen = (len * (long long)simple_rand()) >> 15;
+-      for (i = flen; i < len; i++)
+-              p[i] = 0xff;
+-}
++      from = random32() % (len + 1);
++      if (chance(1, 2))
++              to = random32() % (len - from + 1);
++      else
++              to = len;
+-int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+-               int len, int check)
+-{
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      return ubi_leb_read(desc, lnum, buf, offset, len, check);
++      if (from < to)
++              ubifs_warn("filled bytes %u-%u with %s", from, to - 1,
++                         ffs ? "0xFFs" : "random data");
++
++      if (ffs)
++              for (i = from; i < to; i++)
++                      p[i] = 0xFF;
++      else
++              for (i = from; i < to; i++)
++                      p[i] = random32() % 0x100;
+ }
+-int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                int offset, int len, int dtype)
++int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
++                int offs, int len, int dtype)
+ {
+       int err, failing;
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      failing = do_fail(desc, lnum, 1);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++
++      failing = power_cut_emulated(c, lnum, 1);
+       if (failing)
+               cut_data(buf, len);
+-      err = ubi_leb_write(desc, lnum, buf, offset, len, dtype);
++      err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+       if (err)
+               return err;
+       if (failing)
+-              return -EIO;
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
++int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
+                  int len, int dtype)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 1))
+-              return -EIO;
+-      err = ubi_leb_change(desc, lnum, buf, len, dtype);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 1))
++              return -EROFS;
++      err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 1))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 1))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)
++int dbg_leb_unmap(struct ubifs_info *c, int lnum)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_erase(desc, lnum);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
++      err = ubi_leb_unmap(c->ubi, lnum);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
++int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
+ {
+       int err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_unmap(desc, lnum);
++      if (c->dbg->pc_happened)
++              return -EROFS;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
++      err = ubi_leb_map(c->ubi, lnum, dtype);
+       if (err)
+               return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
++      if (power_cut_emulated(c, lnum, 0))
++              return -EROFS;
+       return 0;
+ }
+-int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)
+-{
+-      if (in_failure_mode(desc))
+-              return -EIO;
+-      return ubi_is_mapped(desc, lnum);
+-}
++/*
++ * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
++ * contain the stuff specific to particular file-system mounts.
++ */
++static struct dentry *dfs_rootdir;
+-int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
++static int dfs_file_open(struct inode *inode, struct file *file)
+ {
+-      int err;
+-
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      err = ubi_leb_map(desc, lnum, dtype);
+-      if (err)
+-              return err;
+-      if (do_fail(desc, lnum, 0))
+-              return -EIO;
+-      return 0;
++      file->private_data = inode->i_private;
++      return nonseekable_open(inode, file);
+ }
+ /**
+- * ubifs_debugging_init - initialize UBIFS debugging.
+- * @c: UBIFS file-system description object
++ * provide_user_output - provide output to the user reading a debugfs file.
++ * @val: boolean value for the answer
++ * @u: the buffer to store the answer at
++ * @count: size of the buffer
++ * @ppos: position in the @u output buffer
+  *
+- * This function initializes debugging-related data for the file system.
+- * Returns zero in case of success and a negative error code in case of
++ * This is a simple helper function which stores @val boolean value in the user
++ * buffer when the user reads one of UBIFS debugfs files. Returns amount of
++ * bytes written to @u in case of success and a negative error code in case of
+  * failure.
+  */
+-int ubifs_debugging_init(struct ubifs_info *c)
++static int provide_user_output(int val, char __user *u, size_t count,
++                             loff_t *ppos)
+ {
+-      c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
+-      if (!c->dbg)
+-              return -ENOMEM;
+-
+-      c->dbg->buf = vmalloc(c->leb_size);
+-      if (!c->dbg->buf)
+-              goto out;
++      char buf[3];
+-      failure_mode_init(c);
+-      return 0;
++      if (val)
++              buf[0] = '1';
++      else
++              buf[0] = '0';
++      buf[1] = '\n';
++      buf[2] = 0x00;
+-out:
+-      kfree(c->dbg);
+-      return -ENOMEM;
++      return simple_read_from_buffer(u, count, ppos, buf, 2);
+ }
+-/**
+- * ubifs_debugging_exit - free debugging data.
+- * @c: UBIFS file-system description object
+- */
+-void ubifs_debugging_exit(struct ubifs_info *c)
++static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
++                           loff_t *ppos)
+ {
+-      failure_mode_exit(c);
+-      vfree(c->dbg->buf);
+-      kfree(c->dbg);
+-}
++      struct dentry *dent = file->f_path.dentry;
++      struct ubifs_info *c = file->private_data;
++      struct ubifs_debug_info *d = c->dbg;
++      int val;
++
++      if (dent == d->dfs_chk_gen)
++              val = d->chk_gen;
++      else if (dent == d->dfs_chk_index)
++              val = d->chk_index;
++      else if (dent == d->dfs_chk_orph)
++              val = d->chk_orph;
++      else if (dent == d->dfs_chk_lprops)
++              val = d->chk_lprops;
++      else if (dent == d->dfs_chk_fs)
++              val = d->chk_fs;
++      else if (dent == d->dfs_tst_rcvry)
++              val = d->tst_rcvry;
++      else
++              return -EINVAL;
+-/*
+- * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
+- * contain the stuff specific to particular file-system mounts.
+- */
+-static struct dentry *dfs_rootdir;
++      return provide_user_output(val, u, count, ppos);
++}
+ /**
+- * dbg_debugfs_init - initialize debugfs file-system.
++ * interpret_user_input - interpret user debugfs file input.
++ * @u: user-provided buffer with the input
++ * @count: buffer size
+  *
+- * UBIFS uses debugfs file-system to expose various debugging knobs to
+- * user-space. This function creates "ubifs" directory in the debugfs
+- * file-system. Returns zero in case of success and a negative error code in
+- * case of failure.
++ * This is a helper function which interpret user input to a boolean UBIFS
++ * debugfs file. Returns %0 or %1 in case of success and a negative error code
++ * in case of failure.
+  */
+-int dbg_debugfs_init(void)
++static int interpret_user_input(const char __user *u, size_t count)
+ {
+-      dfs_rootdir = debugfs_create_dir("ubifs", NULL);
+-      if (IS_ERR(dfs_rootdir)) {
+-              int err = PTR_ERR(dfs_rootdir);
+-              ubifs_err("cannot create \"ubifs\" debugfs directory, "
+-                        "error %d\n", err);
+-              return err;
+-      }
++      size_t buf_size;
++      char buf[8];
+-      return 0;
+-}
++      buf_size = min_t(size_t, count, (sizeof(buf) - 1));
++      if (copy_from_user(buf, u, buf_size))
++              return -EFAULT;
+-/**
+- * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
+- */
+-void dbg_debugfs_exit(void)
+-{
+-      debugfs_remove(dfs_rootdir);
+-}
++      if (buf[0] == '1')
++              return 1;
++      else if (buf[0] == '0')
++              return 0;
+-static int open_debugfs_file(struct inode *inode, struct file *file)
+-{
+-      file->private_data = inode->i_private;
+-      return 0;
++      return -EINVAL;
+ }
+-static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
+-                                size_t count, loff_t *ppos)
++static ssize_t dfs_file_write(struct file *file, const char __user *u,
++                            size_t count, loff_t *ppos)
+ {
+       struct ubifs_info *c = file->private_data;
+       struct ubifs_debug_info *d = c->dbg;
++      struct dentry *dent = file->f_path.dentry;
++      int val;
+-      if (file->f_path.dentry == d->dfs_dump_lprops)
++      /*
++       * TODO: this is racy - the file-system might have already been
++       * unmounted and we'd oops in this case. The plan is to fix it with
++       * help of 'iterate_supers_type()' which we should have in v3.0: when
++       * a debugfs opened, we rember FS's UUID in file->private_data. Then
++       * whenever we access the FS via a debugfs file, we iterate all UBIFS
++       * superblocks and fine the one with the same UUID, and take the
++       * locking right.
++       *
++       * The other way to go suggested by Al Viro is to create a separate
++       * 'ubifs-debug' file-system instead.
++       */
++      if (file->f_path.dentry == d->dfs_dump_lprops) {
+               dbg_dump_lprops(c);
+-      else if (file->f_path.dentry == d->dfs_dump_budg) {
+-              spin_lock(&c->space_lock);
+-              dbg_dump_budg(c);
+-              spin_unlock(&c->space_lock);
+-      } else if (file->f_path.dentry == d->dfs_dump_tnc) {
++              return count;
++      }
++      if (file->f_path.dentry == d->dfs_dump_budg) {
++              dbg_dump_budg(c, &c->bi);
++              return count;
++      }
++      if (file->f_path.dentry == d->dfs_dump_tnc) {
+               mutex_lock(&c->tnc_mutex);
+               dbg_dump_tnc(c);
+               mutex_unlock(&c->tnc_mutex);
+-      } else
++              return count;
++      }
++
++      val = interpret_user_input(u, count);
++      if (val < 0)
++              return val;
++
++      if (dent == d->dfs_chk_gen)
++              d->chk_gen = val;
++      else if (dent == d->dfs_chk_index)
++              d->chk_index = val;
++      else if (dent == d->dfs_chk_orph)
++              d->chk_orph = val;
++      else if (dent == d->dfs_chk_lprops)
++              d->chk_lprops = val;
++      else if (dent == d->dfs_chk_fs)
++              d->chk_fs = val;
++      else if (dent == d->dfs_tst_rcvry)
++              d->tst_rcvry = val;
++      else
+               return -EINVAL;
+-      *ppos += count;
+       return count;
+ }
+ static const struct file_operations dfs_fops = {
+-      .open = open_debugfs_file,
+-      .write = write_debugfs_file,
++      .open = dfs_file_open,
++      .read = dfs_file_read,
++      .write = dfs_file_write,
+       .owner = THIS_MODULE,
+-      .llseek = default_llseek,
++      .llseek = no_llseek,
+ };
+ /**
+@@ -2798,46 +2915,94 @@ static const struct file_operations dfs_fops = {
+  */
+ int dbg_debugfs_init_fs(struct ubifs_info *c)
+ {
+-      int err;
++      int err, n;
+       const char *fname;
+       struct dentry *dent;
+       struct ubifs_debug_info *d = c->dbg;
+-      sprintf(d->dfs_dir_name, "ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
+-      d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir);
+-      if (IS_ERR(d->dfs_dir)) {
+-              err = PTR_ERR(d->dfs_dir);
+-              ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+-                        d->dfs_dir_name, err);
++      n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
++                   c->vi.ubi_num, c->vi.vol_id);
++      if (n == UBIFS_DFS_DIR_LEN) {
++              /* The array size is too small */
++              fname = UBIFS_DFS_DIR_NAME;
++              dent = ERR_PTR(-EINVAL);
+               goto out;
+       }
++      fname = d->dfs_dir_name;
++      dent = debugfs_create_dir(fname, dfs_rootdir);
++      if (IS_ERR_OR_NULL(dent))
++              goto out;
++      d->dfs_dir = dent;
++
+       fname = "dump_lprops";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_lprops = dent;
+       fname = "dump_budg";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_budg = dent;
+       fname = "dump_tnc";
+-      dent = debugfs_create_file(fname, S_IWUGO, d->dfs_dir, c, &dfs_fops);
+-      if (IS_ERR(dent))
++      dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       d->dfs_dump_tnc = dent;
++      fname = "chk_general";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_gen = dent;
++
++      fname = "chk_index";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_index = dent;
++
++      fname = "chk_orphans";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_orph = dent;
++
++      fname = "chk_lprops";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_lprops = dent;
++
++      fname = "chk_fs";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_chk_fs = dent;
++
++      fname = "tst_recovery";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
++                                 &dfs_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      d->dfs_tst_rcvry = dent;
++
+       return 0;
+ out_remove:
+-      err = PTR_ERR(dent);
+-      ubifs_err("cannot create \"%s\" debugfs directory, error %d\n",
+-                fname, err);
+       debugfs_remove_recursive(d->dfs_dir);
+ out:
++      err = dent ? PTR_ERR(dent) : -ENODEV;
++      ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
++                fname, err);
+       return err;
+ }
+@@ -2850,4 +3015,179 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c)
+       debugfs_remove_recursive(c->dbg->dfs_dir);
+ }
++struct ubifs_global_debug_info ubifs_dbg;
++
++static struct dentry *dfs_chk_gen;
++static struct dentry *dfs_chk_index;
++static struct dentry *dfs_chk_orph;
++static struct dentry *dfs_chk_lprops;
++static struct dentry *dfs_chk_fs;
++static struct dentry *dfs_tst_rcvry;
++
++static ssize_t dfs_global_file_read(struct file *file, char __user *u,
++                                  size_t count, loff_t *ppos)
++{
++      struct dentry *dent = file->f_path.dentry;
++      int val;
++
++      if (dent == dfs_chk_gen)
++              val = ubifs_dbg.chk_gen;
++      else if (dent == dfs_chk_index)
++              val = ubifs_dbg.chk_index;
++      else if (dent == dfs_chk_orph)
++              val = ubifs_dbg.chk_orph;
++      else if (dent == dfs_chk_lprops)
++              val = ubifs_dbg.chk_lprops;
++      else if (dent == dfs_chk_fs)
++              val = ubifs_dbg.chk_fs;
++      else if (dent == dfs_tst_rcvry)
++              val = ubifs_dbg.tst_rcvry;
++      else
++              return -EINVAL;
++
++      return provide_user_output(val, u, count, ppos);
++}
++
++static ssize_t dfs_global_file_write(struct file *file, const char __user *u,
++                                   size_t count, loff_t *ppos)
++{
++      struct dentry *dent = file->f_path.dentry;
++      int val;
++
++      val = interpret_user_input(u, count);
++      if (val < 0)
++              return val;
++
++      if (dent == dfs_chk_gen)
++              ubifs_dbg.chk_gen = val;
++      else if (dent == dfs_chk_index)
++              ubifs_dbg.chk_index = val;
++      else if (dent == dfs_chk_orph)
++              ubifs_dbg.chk_orph = val;
++      else if (dent == dfs_chk_lprops)
++              ubifs_dbg.chk_lprops = val;
++      else if (dent == dfs_chk_fs)
++              ubifs_dbg.chk_fs = val;
++      else if (dent == dfs_tst_rcvry)
++              ubifs_dbg.tst_rcvry = val;
++      else
++              return -EINVAL;
++
++      return count;
++}
++
++static const struct file_operations dfs_global_fops = {
++      .read = dfs_global_file_read,
++      .write = dfs_global_file_write,
++      .owner = THIS_MODULE,
++      .llseek = no_llseek,
++};
++
++/**
++ * dbg_debugfs_init - initialize debugfs file-system.
++ *
++ * UBIFS uses debugfs file-system to expose various debugging knobs to
++ * user-space. This function creates "ubifs" directory in the debugfs
++ * file-system. Returns zero in case of success and a negative error code in
++ * case of failure.
++ */
++int dbg_debugfs_init(void)
++{
++      int err;
++      const char *fname;
++      struct dentry *dent;
++
++      fname = "ubifs";
++      dent = debugfs_create_dir(fname, NULL);
++      if (IS_ERR_OR_NULL(dent))
++              goto out;
++      dfs_rootdir = dent;
++
++      fname = "chk_general";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_gen = dent;
++
++      fname = "chk_index";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_index = dent;
++
++      fname = "chk_orphans";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_orph = dent;
++
++      fname = "chk_lprops";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_lprops = dent;
++
++      fname = "chk_fs";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_chk_fs = dent;
++
++      fname = "tst_recovery";
++      dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
++                                 &dfs_global_fops);
++      if (IS_ERR_OR_NULL(dent))
++              goto out_remove;
++      dfs_tst_rcvry = dent;
++
++      return 0;
++
++out_remove:
++      debugfs_remove_recursive(dfs_rootdir);
++out:
++      err = dent ? PTR_ERR(dent) : -ENODEV;
++      ubifs_err("cannot create \"%s\" debugfs file or directory, error %d\n",
++                fname, err);
++      return err;
++}
++
++/**
++ * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
++ */
++void dbg_debugfs_exit(void)
++{
++      debugfs_remove_recursive(dfs_rootdir);
++}
++
++/**
++ * ubifs_debugging_init - initialize UBIFS debugging.
++ * @c: UBIFS file-system description object
++ *
++ * This function initializes debugging-related data for the file system.
++ * Returns zero in case of success and a negative error code in case of
++ * failure.
++ */
++int ubifs_debugging_init(struct ubifs_info *c)
++{
++      c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
++      if (!c->dbg)
++              return -ENOMEM;
++
++      return 0;
++}
++
++/**
++ * ubifs_debugging_exit - free debugging data.
++ * @c: UBIFS file-system description object
++ */
++void ubifs_debugging_exit(struct ubifs_info *c)
++{
++      kfree(c->dbg);
++}
++
+ #endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
+index 555ba13..13917ce 100644
+--- a/fs/ubifs/debug.h
++++ b/fs/ubifs/debug.h
+@@ -31,17 +31,25 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
+ #ifdef CONFIG_UBIFS_FS_DEBUG
++/*
++ * The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
++ * + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
++ */
++#define UBIFS_DFS_DIR_NAME "ubi%d_%d"
++#define UBIFS_DFS_DIR_LEN  (3 + 1 + 2*2 + 1)
++
+ /**
+  * ubifs_debug_info - per-FS debugging information.
+- * @buf: a buffer of LEB size, used for various purposes
+  * @old_zroot: old index root - used by 'dbg_check_old_index()'
+  * @old_zroot_level: old index root level - used by 'dbg_check_old_index()'
+  * @old_zroot_sqnum: old index root sqnum - used by 'dbg_check_old_index()'
+- * @failure_mode: failure mode for recovery testing
+- * @fail_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
+- * @fail_timeout: time in jiffies when delay of failure mode expires
+- * @fail_cnt: current number of calls to failure mode I/O functions
+- * @fail_cnt_max: number of calls by which to delay failure mode
++ *
++ * @pc_happened: non-zero if an emulated power cut happened
++ * @pc_delay: 0=>don't delay, 1=>delay a time, 2=>delay a number of calls
++ * @pc_timeout: time in jiffies when delay of failure mode expires
++ * @pc_cnt: current number of calls to failure mode I/O functions
++ * @pc_cnt_max: number of calls by which to delay failure mode
++ *
+  * @chk_lpt_sz: used by LPT tree size checker
+  * @chk_lpt_sz2: used by LPT tree size checker
+  * @chk_lpt_wastage: used by LPT tree size checker
+@@ -51,24 +59,40 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
+  * @new_ihead_offs: used by debugging to check @c->ihead_offs
+  *
+  * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
+- * @saved_free: saved free space (used by 'dbg_save_space_info()')
++ * @saved_bi: saved budgeting information
++ * @saved_free: saved amount of free space
++ * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
++ *
++ * @chk_gen: if general extra checks are enabled
++ * @chk_index: if index xtra checks are enabled
++ * @chk_orph: if orphans extra checks are enabled
++ * @chk_lprops: if lprops extra checks are enabled
++ * @chk_fs: if UBIFS contents extra checks are enabled
++ * @tst_rcvry: if UBIFS recovery testing mode enabled
+  *
+- * dfs_dir_name: name of debugfs directory containing this file-system's files
+- * dfs_dir: direntry object of the file-system debugfs directory
+- * dfs_dump_lprops: "dump lprops" debugfs knob
+- * dfs_dump_budg: "dump budgeting information" debugfs knob
+- * dfs_dump_tnc: "dump TNC" debugfs knob
++ * @dfs_dir_name: name of debugfs directory containing this file-system's files
++ * @dfs_dir: direntry object of the file-system debugfs directory
++ * @dfs_dump_lprops: "dump lprops" debugfs knob
++ * @dfs_dump_budg: "dump budgeting information" debugfs knob
++ * @dfs_dump_tnc: "dump TNC" debugfs knob
++ * @dfs_chk_gen: debugfs knob to enable UBIFS general extra checks
++ * @dfs_chk_index: debugfs knob to enable UBIFS index extra checks
++ * @dfs_chk_orph: debugfs knob to enable UBIFS orphans extra checks
++ * @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
++ * @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
++ * @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
+  */
+ struct ubifs_debug_info {
+-      void *buf;
+       struct ubifs_zbranch old_zroot;
+       int old_zroot_level;
+       unsigned long long old_zroot_sqnum;
+-      int failure_mode;
+-      int fail_delay;
+-      unsigned long fail_timeout;
+-      unsigned int fail_cnt;
+-      unsigned int fail_cnt_max;
++
++      int pc_happened;
++      int pc_delay;
++      unsigned long pc_timeout;
++      unsigned int pc_cnt;
++      unsigned int pc_cnt_max;
++
+       long long chk_lpt_sz;
+       long long chk_lpt_sz2;
+       long long chk_lpt_wastage;
+@@ -78,13 +102,47 @@ struct ubifs_debug_info {
+       int new_ihead_offs;
+       struct ubifs_lp_stats saved_lst;
++      struct ubifs_budg_info saved_bi;
+       long long saved_free;
++      int saved_idx_gc_cnt;
++
++      unsigned int chk_gen:1;
++      unsigned int chk_index:1;
++      unsigned int chk_orph:1;
++      unsigned int chk_lprops:1;
++      unsigned int chk_fs:1;
++      unsigned int tst_rcvry:1;
+-      char dfs_dir_name[100];
++      char dfs_dir_name[UBIFS_DFS_DIR_LEN + 1];
+       struct dentry *dfs_dir;
+       struct dentry *dfs_dump_lprops;
+       struct dentry *dfs_dump_budg;
+       struct dentry *dfs_dump_tnc;
++      struct dentry *dfs_chk_gen;
++      struct dentry *dfs_chk_index;
++      struct dentry *dfs_chk_orph;
++      struct dentry *dfs_chk_lprops;
++      struct dentry *dfs_chk_fs;
++      struct dentry *dfs_tst_rcvry;
++};
++
++/**
++ * ubifs_global_debug_info - global (not per-FS) UBIFS debugging information.
++ *
++ * @chk_gen: if general extra checks are enabled
++ * @chk_index: if index xtra checks are enabled
++ * @chk_orph: if orphans extra checks are enabled
++ * @chk_lprops: if lprops extra checks are enabled
++ * @chk_fs: if UBIFS contents extra checks are enabled
++ * @tst_rcvry: if UBIFS recovery testing mode enabled
++ */
++struct ubifs_global_debug_info {
++      unsigned int chk_gen:1;
++      unsigned int chk_index:1;
++      unsigned int chk_orph:1;
++      unsigned int chk_lprops:1;
++      unsigned int chk_fs:1;
++      unsigned int tst_rcvry:1;
+ };
+ #define ubifs_assert(expr) do {                                                \
+@@ -103,173 +161,90 @@ struct ubifs_debug_info {
+       }                                                                      \
+ } while (0)
+-#define dbg_dump_stack() do {                                                  \
+-      if (!dbg_failure_mode)                                                 \
+-              dump_stack();                                                  \
+-} while (0)
+-
+-/* Generic debugging messages */
+-#define dbg_msg(fmt, ...) do {                                                 \
+-      spin_lock(&dbg_lock);                                                  \
+-      printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
+-             __func__, ##__VA_ARGS__);                                       \
+-      spin_unlock(&dbg_lock);                                                \
+-} while (0)
+-
+-#define dbg_do_msg(typ, fmt, ...) do {                                         \
+-      if (ubifs_msg_flags & typ)                                             \
+-              dbg_msg(fmt, ##__VA_ARGS__);                                   \
+-} while (0)
++#define dbg_dump_stack() dump_stack()
+ #define dbg_err(fmt, ...) do {                                                 \
+-      spin_lock(&dbg_lock);                                                  \
+       ubifs_err(fmt, ##__VA_ARGS__);                                         \
+-      spin_unlock(&dbg_lock);                                                \
+ } while (0)
+-const char *dbg_key_str0(const struct ubifs_info *c,
+-                       const union ubifs_key *key);
+-const char *dbg_key_str1(const struct ubifs_info *c,
+-                       const union ubifs_key *key);
++#define ubifs_dbg_msg(type, fmt, ...) \
++      pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
+-/*
+- * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message
+- * macros.
+- */
+-#define DBGKEY(key) dbg_key_str0(c, (key))
+-#define DBGKEY1(key) dbg_key_str1(c, (key))
++#define DBG_KEY_BUF_LEN 32
++#define ubifs_dbg_msg_key(type, key, fmt, ...) do {                            \
++      char __tmp_key_buf[DBG_KEY_BUF_LEN];                                   \
++      pr_debug("UBIFS DBG " type ": " fmt "%s\n", ##__VA_ARGS__,             \
++               dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN));    \
++} while (0)
+-/* General messages */
+-#define dbg_gen(fmt, ...)   dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
++/* Just a debugging messages not related to any specific UBIFS subsystem */
++#define dbg_msg(fmt, ...)                                                      \
++      printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
++             __func__, ##__VA_ARGS__)
++/* General messages */
++#define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
+ /* Additional journal messages */
+-#define dbg_jnl(fmt, ...)   dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
+-
++#define dbg_jnl(fmt, ...)   ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__)
++#define dbg_jnlk(key, fmt, ...) \
++      ubifs_dbg_msg_key("jnl", key, fmt, ##__VA_ARGS__)
+ /* Additional TNC messages */
+-#define dbg_tnc(fmt, ...)   dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
+-
++#define dbg_tnc(fmt, ...)   ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__)
++#define dbg_tnck(key, fmt, ...) \
++      ubifs_dbg_msg_key("tnc", key, fmt, ##__VA_ARGS__)
+ /* Additional lprops messages */
+-#define dbg_lp(fmt, ...)    dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
+-
++#define dbg_lp(fmt, ...)    ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__)
+ /* Additional LEB find messages */
+-#define dbg_find(fmt, ...)  dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
+-
++#define dbg_find(fmt, ...)  ubifs_dbg_msg("find", fmt, ##__VA_ARGS__)
+ /* Additional mount messages */
+-#define dbg_mnt(fmt, ...)   dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
+-
++#define dbg_mnt(fmt, ...)   ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__)
++#define dbg_mntk(key, fmt, ...) \
++      ubifs_dbg_msg_key("mnt", key, fmt, ##__VA_ARGS__)
+ /* Additional I/O messages */
+-#define dbg_io(fmt, ...)    dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
+-
++#define dbg_io(fmt, ...)    ubifs_dbg_msg("io", fmt, ##__VA_ARGS__)
+ /* Additional commit messages */
+-#define dbg_cmt(fmt, ...)   dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
+-
++#define dbg_cmt(fmt, ...)   ubifs_dbg_msg("cmt", fmt, ##__VA_ARGS__)
+ /* Additional budgeting messages */
+-#define dbg_budg(fmt, ...)  dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
+-
++#define dbg_budg(fmt, ...)  ubifs_dbg_msg("budg", fmt, ##__VA_ARGS__)
+ /* Additional log messages */
+-#define dbg_log(fmt, ...)   dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
+-
++#define dbg_log(fmt, ...)   ubifs_dbg_msg("log", fmt, ##__VA_ARGS__)
+ /* Additional gc messages */
+-#define dbg_gc(fmt, ...)    dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
+-
++#define dbg_gc(fmt, ...)    ubifs_dbg_msg("gc", fmt, ##__VA_ARGS__)
+ /* Additional scan messages */
+-#define dbg_scan(fmt, ...)  dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
+-
++#define dbg_scan(fmt, ...)  ubifs_dbg_msg("scan", fmt, ##__VA_ARGS__)
+ /* Additional recovery messages */
+-#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
++#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
+-/*
+- * Debugging message type flags (must match msg_type_names in debug.c).
+- *
+- * UBIFS_MSG_GEN: general messages
+- * UBIFS_MSG_JNL: journal messages
+- * UBIFS_MSG_MNT: mount messages
+- * UBIFS_MSG_CMT: commit messages
+- * UBIFS_MSG_FIND: LEB find messages
+- * UBIFS_MSG_BUDG: budgeting messages
+- * UBIFS_MSG_GC: garbage collection messages
+- * UBIFS_MSG_TNC: TNC messages
+- * UBIFS_MSG_LP: lprops messages
+- * UBIFS_MSG_IO: I/O messages
+- * UBIFS_MSG_LOG: log messages
+- * UBIFS_MSG_SCAN: scan messages
+- * UBIFS_MSG_RCVRY: recovery messages
+- */
+-enum {
+-      UBIFS_MSG_GEN   = 0x1,
+-      UBIFS_MSG_JNL   = 0x2,
+-      UBIFS_MSG_MNT   = 0x4,
+-      UBIFS_MSG_CMT   = 0x8,
+-      UBIFS_MSG_FIND  = 0x10,
+-      UBIFS_MSG_BUDG  = 0x20,
+-      UBIFS_MSG_GC    = 0x40,
+-      UBIFS_MSG_TNC   = 0x80,
+-      UBIFS_MSG_LP    = 0x100,
+-      UBIFS_MSG_IO    = 0x200,
+-      UBIFS_MSG_LOG   = 0x400,
+-      UBIFS_MSG_SCAN  = 0x800,
+-      UBIFS_MSG_RCVRY = 0x1000,
+-};
+-
+-/* Debugging message type flags for each default debug message level */
+-#define UBIFS_MSG_LVL_0 0
+-#define UBIFS_MSG_LVL_1 0x1
+-#define UBIFS_MSG_LVL_2 0x7f
+-#define UBIFS_MSG_LVL_3 0xffff
+-
+-/*
+- * Debugging check flags (must match chk_names in debug.c).
+- *
+- * UBIFS_CHK_GEN: general checks
+- * UBIFS_CHK_TNC: check TNC
+- * UBIFS_CHK_IDX_SZ: check index size
+- * UBIFS_CHK_ORPH: check orphans
+- * UBIFS_CHK_OLD_IDX: check the old index
+- * UBIFS_CHK_LPROPS: check lprops
+- * UBIFS_CHK_FS: check the file-system
+- */
+-enum {
+-      UBIFS_CHK_GEN     = 0x1,
+-      UBIFS_CHK_TNC     = 0x2,
+-      UBIFS_CHK_IDX_SZ  = 0x4,
+-      UBIFS_CHK_ORPH    = 0x8,
+-      UBIFS_CHK_OLD_IDX = 0x10,
+-      UBIFS_CHK_LPROPS  = 0x20,
+-      UBIFS_CHK_FS      = 0x40,
+-};
++extern struct ubifs_global_debug_info ubifs_dbg;
+-/*
+- * Special testing flags (must match tst_names in debug.c).
+- *
+- * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
+- * UBIFS_TST_RCVRY: failure mode for recovery testing
+- */
+-enum {
+-      UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
+-      UBIFS_TST_RCVRY             = 0x4,
+-};
+-
+-#if CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 1
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_1
+-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 2
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_2
+-#elif CONFIG_UBIFS_FS_DEBUG_MSG_LVL == 3
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_3
+-#else
+-#define UBIFS_MSG_FLAGS_DEFAULT UBIFS_MSG_LVL_0
+-#endif
+-
+-#ifdef CONFIG_UBIFS_FS_DEBUG_CHKS
+-#define UBIFS_CHK_FLAGS_DEFAULT 0xffffffff
+-#else
+-#define UBIFS_CHK_FLAGS_DEFAULT 0
+-#endif
+-
+-extern spinlock_t dbg_lock;
+-
+-extern unsigned int ubifs_msg_flags;
+-extern unsigned int ubifs_chk_flags;
+-extern unsigned int ubifs_tst_flags;
++static inline int dbg_is_chk_gen(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen);
++}
++static inline int dbg_is_chk_index(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_index || c->dbg->chk_index);
++}
++static inline int dbg_is_chk_orph(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph);
++}
++static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops);
++}
++static inline int dbg_is_chk_fs(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs);
++}
++static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
++{
++      return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry);
++}
++static inline int dbg_is_power_cut(const struct ubifs_info *c)
++{
++      return !!c->dbg->pc_happened;
++}
+ int ubifs_debugging_init(struct ubifs_info *c);
+ void ubifs_debugging_exit(struct ubifs_info *c);
+@@ -280,17 +255,21 @@ const char *dbg_cstate(int cmt_state);
+ const char *dbg_jhead(int jhead);
+ const char *dbg_get_key_dump(const struct ubifs_info *c,
+                            const union ubifs_key *key);
+-void dbg_dump_inode(const struct ubifs_info *c, const struct inode *inode);
++const char *dbg_snprintf_key(const struct ubifs_info *c,
++                           const union ubifs_key *key, char *buffer, int len);
++void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
+ void dbg_dump_node(const struct ubifs_info *c, const void *node);
+ void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
+                      int offs);
+ void dbg_dump_budget_req(const struct ubifs_budget_req *req);
+ void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
+-void dbg_dump_budg(struct ubifs_info *c);
++void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
+ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
+ void dbg_dump_lprops(struct ubifs_info *c);
+ void dbg_dump_lpt_info(struct ubifs_info *c);
+ void dbg_dump_leb(const struct ubifs_info *c, int lnum);
++void dbg_dump_sleb(const struct ubifs_info *c,
++                 const struct ubifs_scan_leb *sleb, int offs);
+ void dbg_dump_znode(const struct ubifs_info *c,
+                   const struct ubifs_znode *znode);
+ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat);
+@@ -313,14 +292,13 @@ int dbg_check_cats(struct ubifs_info *c);
+ int dbg_check_ltab(struct ubifs_info *c);
+ int dbg_chk_lpt_free_spc(struct ubifs_info *c);
+ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len);
+-int dbg_check_synced_i_size(struct inode *inode);
+-int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir);
++int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode);
++int dbg_check_dir(struct ubifs_info *c, const struct inode *dir);
+ int dbg_check_tnc(struct ubifs_info *c, int extra);
+ int dbg_check_idx_size(struct ubifs_info *c, long long idx_size);
+ int dbg_check_filesystem(struct ubifs_info *c);
+ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
+                   int add_pos);
+-int dbg_check_lprops(struct ubifs_info *c);
+ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
+                       int row, int col);
+ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+@@ -328,57 +306,12 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
+ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
+-/* Force the use of in-the-gaps method for testing */
+-
+-#define dbg_force_in_the_gaps_enabled \
+-      (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS)
+-
+-int dbg_force_in_the_gaps(void);
+-
+-/* Failure mode for recovery testing */
+-
+-#define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
+-
+-#ifndef UBIFS_DBG_PRESERVE_UBI
+-
+-#define ubi_leb_read   dbg_leb_read
+-#define ubi_leb_write  dbg_leb_write
+-#define ubi_leb_change dbg_leb_change
+-#define ubi_leb_erase  dbg_leb_erase
+-#define ubi_leb_unmap  dbg_leb_unmap
+-#define ubi_is_mapped  dbg_is_mapped
+-#define ubi_leb_map    dbg_leb_map
+-
+-#endif
+-
+-int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
+-               int len, int check);
+-int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                int offset, int len, int dtype);
+-int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
+-                 int len, int dtype);
+-int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum);
+-int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum);
+-int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum);
+-int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
+-
+-static inline int dbg_read(struct ubi_volume_desc *desc, int lnum, char *buf,
+-                         int offset, int len)
+-{
+-      return dbg_leb_read(desc, lnum, buf, offset, len, 0);
+-}
+-
+-static inline int dbg_write(struct ubi_volume_desc *desc, int lnum,
+-                          const void *buf, int offset, int len)
+-{
+-      return dbg_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
+-}
+-
+-static inline int dbg_change(struct ubi_volume_desc *desc, int lnum,
+-                                  const void *buf, int len)
+-{
+-      return dbg_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
+-}
++int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                int len, int dtype);
++int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                 int dtype);
++int dbg_leb_unmap(struct ubifs_info *c, int lnum);
++int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
+ /* Debugfs-related stuff */
+ int dbg_debugfs_init(void);
+@@ -390,116 +323,158 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
+ /* Use "if (0)" to make compiler check arguments even if debugging is off */
+ #define ubifs_assert(expr)  do {                                               \
+-      if (0 && (expr))                                                       \
++      if (0)                                                                 \
+               printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
+                      __func__, __LINE__, current->pid);                      \
+ } while (0)
+-#define dbg_err(fmt, ...)   do {                                               \
+-      if (0)                                                                 \
+-              ubifs_err(fmt, ##__VA_ARGS__);                                 \
++#define dbg_err(fmt, ...)   do {                   \
++      if (0)                                     \
++              ubifs_err(fmt, ##__VA_ARGS__);     \
+ } while (0)
+-#define dbg_msg(fmt, ...) do {                                                 \
+-      if (0)                                                                 \
+-              printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n",         \
+-                     current->pid, __func__, ##__VA_ARGS__);                 \
++#define DBGKEY(key)  ((char *)(key))
++#define DBGKEY1(key) ((char *)(key))
++
++#define ubifs_dbg_msg(fmt, ...) do {               \
++      if (0)                                     \
++              pr_debug(fmt "\n", ##__VA_ARGS__); \
+ } while (0)
+ #define dbg_dump_stack()
+ #define ubifs_assert_cmt_locked(c)
+-#define dbg_gen(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_jnl(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_tnc(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_lp(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_find(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_mnt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_io(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_cmt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_budg(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_log(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_gc(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_scan(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
+-#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+-
+-#define DBGKEY(key)  ((char *)(key))
+-#define DBGKEY1(key) ((char *)(key))
+-
+-static inline int ubifs_debugging_init(struct ubifs_info *c)  { return 0; }
+-static inline void ubifs_debugging_exit(struct ubifs_info *c) {}
+-static inline const char *dbg_ntype(int type)                 { return ""; }
+-static inline const char *dbg_cstate(int cmt_state)           { return ""; }
+-static inline const char *dbg_jhead(int jhead)                        { return ""; }
+-static inline const char *dbg_get_key_dump(const struct ubifs_info *c,
+-                           const union ubifs_key *key)        { return ""; }
+-static inline void dbg_dump_inode(const struct ubifs_info *c,
+-      const struct inode *inode) {}
++#define dbg_msg(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_gen(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_jnl(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_jnlk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_tnc(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_tnck(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_lp(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_find(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_mnt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_mntk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_io(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_cmt(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_budg(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_log(fmt, ...)       ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_gc(fmt, ...)        ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_scan(fmt, ...)      ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++#define dbg_rcvry(fmt, ...)     ubifs_dbg_msg(fmt, ##__VA_ARGS__)
++
++static inline int ubifs_debugging_init(struct ubifs_info *c)      { return 0; }
++static inline void ubifs_debugging_exit(struct ubifs_info *c)     { return; }
++static inline const char *dbg_ntype(int type)                     { return ""; }
++static inline const char *dbg_cstate(int cmt_state)               { return ""; }
++static inline const char *dbg_jhead(int jhead)                    { return ""; }
++static inline const char *
++dbg_get_key_dump(const struct ubifs_info *c,
++               const union ubifs_key *key)                      { return ""; }
++static inline const char *
++dbg_snprintf_key(const struct ubifs_info *c,
++               const union ubifs_key *key, char *buffer,
++               int len)                                         { return ""; }
++static inline void dbg_dump_inode(struct ubifs_info *c,
++                                const struct inode *inode)      { return; }
+ static inline void dbg_dump_node(const struct ubifs_info *c,
+-      const void *node)                                       {}
++                               const void *node)                { return; }
+ static inline void dbg_dump_lpt_node(const struct ubifs_info *c,
+-      void *node, int lnum, int offs)                         {}
+-static inline void dbg_dump_budget_req(const struct ubifs_budget_req *req) {}
+-static inline void dbg_dump_lstats(const struct ubifs_lp_stats *lst) {}
+-static inline void dbg_dump_budg(struct ubifs_info *c)                {}
++                                   void *node, int lnum,
++                                   int offs)                    { return; }
++static inline void
++dbg_dump_budget_req(const struct ubifs_budget_req *req)           { return; }
++static inline void
++dbg_dump_lstats(const struct ubifs_lp_stats *lst)                 { return; }
++static inline void
++dbg_dump_budg(struct ubifs_info *c,
++            const struct ubifs_budg_info *bi)                   { return; }
+ static inline void dbg_dump_lprop(const struct ubifs_info *c,
+-      const struct ubifs_lprops *lp)                          {}
+-static inline void dbg_dump_lprops(struct ubifs_info *c)      {}
+-static inline void dbg_dump_lpt_info(struct ubifs_info *c)    {}
+-static inline void dbg_dump_leb(const struct ubifs_info *c, int lnum) {}
+-static inline void dbg_dump_znode(const struct ubifs_info *c,
+-                  const struct ubifs_znode *znode)            {}
++                                const struct ubifs_lprops *lp)  { return; }
++static inline void dbg_dump_lprops(struct ubifs_info *c)          { return; }
++static inline void dbg_dump_lpt_info(struct ubifs_info *c)        { return; }
++static inline void dbg_dump_leb(const struct ubifs_info *c,
++                              int lnum)                         { return; }
++static inline void
++dbg_dump_sleb(const struct ubifs_info *c,
++            const struct ubifs_scan_leb *sleb, int offs)        { return; }
++static inline void
++dbg_dump_znode(const struct ubifs_info *c,
++             const struct ubifs_znode *znode)                   { return; }
+ static inline void dbg_dump_heap(struct ubifs_info *c,
+-      struct ubifs_lpt_heap *heap, int cat)                   {}
++                               struct ubifs_lpt_heap *heap,
++                               int cat)                         { return; }
+ static inline void dbg_dump_pnode(struct ubifs_info *c,
+-      struct ubifs_pnode *pnode, struct ubifs_nnode *parent, int iip) {}
+-static inline void dbg_dump_tnc(struct ubifs_info *c)         {}
+-static inline void dbg_dump_index(struct ubifs_info *c)               {}
+-static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c) {}
++                                struct ubifs_pnode *pnode,
++                                struct ubifs_nnode *parent,
++                                int iip)                        { return; }
++static inline void dbg_dump_tnc(struct ubifs_info *c)             { return; }
++static inline void dbg_dump_index(struct ubifs_info *c)           { return; }
++static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c)  { return; }
+ static inline int dbg_walk_index(struct ubifs_info *c,
+-      dbg_leaf_callback leaf_cb, dbg_znode_callback znode_cb, void *priv)
+-                                                              { return 0; }
+-
+-/* Checking functions */
+-static inline void dbg_save_space_info(struct ubifs_info *c)  {}
+-static inline int dbg_check_space_info(struct ubifs_info *c)  { return 0; }
+-static inline int dbg_check_lprops(struct ubifs_info *c)      { return 0; }
+-static inline int dbg_old_index_check_init(struct ubifs_info *c,
+-      struct ubifs_zbranch *zroot)                            { return 0; }
+-static inline int dbg_check_old_index(struct ubifs_info *c,
+-      struct ubifs_zbranch *zroot)                            { return 0; }
+-static inline int dbg_check_cats(struct ubifs_info *c)                { return 0; }
+-static inline int dbg_check_ltab(struct ubifs_info *c)                { return 0; }
+-static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)  { return 0; }
++                               dbg_leaf_callback leaf_cb,
++                               dbg_znode_callback znode_cb,
++                               void *priv)                      { return 0; }
++static inline void dbg_save_space_info(struct ubifs_info *c)      { return; }
++static inline int dbg_check_space_info(struct ubifs_info *c)      { return 0; }
++static inline int dbg_check_lprops(struct ubifs_info *c)          { return 0; }
++static inline int
++dbg_old_index_check_init(struct ubifs_info *c,
++                       struct ubifs_zbranch *zroot)             { return 0; }
++static inline int
++dbg_check_old_index(struct ubifs_info *c,
++                  struct ubifs_zbranch *zroot)                  { return 0; }
++static inline int dbg_check_cats(struct ubifs_info *c)            { return 0; }
++static inline int dbg_check_ltab(struct ubifs_info *c)            { return 0; }
++static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c)      { return 0; }
+ static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
+-      int action, int len)                                    { return 0; }
+-static inline int dbg_check_synced_i_size(struct inode *inode)        { return 0; }
+-static inline int dbg_check_dir_size(struct ubifs_info *c,
+-      const struct inode *dir)                                { return 0; }
+-static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; }
++                               int action, int len)             { return 0; }
++static inline int
++dbg_check_synced_i_size(const struct ubifs_info *c,
++                      struct inode *inode)                      { return 0; }
++static inline int dbg_check_dir(struct ubifs_info *c,
++                              const struct inode *dir)          { return 0; }
++static inline int dbg_check_tnc(struct ubifs_info *c, int extra)  { return 0; }
+ static inline int dbg_check_idx_size(struct ubifs_info *c,
+-      long long idx_size)                                     { return 0; }
+-static inline int dbg_check_filesystem(struct ubifs_info *c)  { return 0; }
++                                   long long idx_size)          { return 0; }
++static inline int dbg_check_filesystem(struct ubifs_info *c)      { return 0; }
+ static inline void dbg_check_heap(struct ubifs_info *c,
+-      struct ubifs_lpt_heap *heap, int cat, int add_pos)      {}
++                                struct ubifs_lpt_heap *heap,
++                                int cat, int add_pos)           { return; }
+ static inline int dbg_check_lpt_nodes(struct ubifs_info *c,
+-      struct ubifs_cnode *cnode, int row, int col)            { return 0; }
++      struct ubifs_cnode *cnode, int row, int col)              { return 0; }
+ static inline int dbg_check_inode_size(struct ubifs_info *c,
+-      const struct inode *inode, loff_t size)                 { return 0; }
+-static inline int dbg_check_data_nodes_order(struct ubifs_info *c,
+-      struct list_head *head)                                 { return 0; }
+-static inline int dbg_check_nondata_nodes_order(struct ubifs_info *c,
+-      struct list_head *head)                                 { return 0; }
+-
+-#define dbg_force_in_the_gaps_enabled                         0
+-static inline int dbg_force_in_the_gaps(void)                 { return 0; }
+-#define dbg_failure_mode                                      0
+-
+-static inline int dbg_debugfs_init(void)                      { return 0; }
+-static inline void dbg_debugfs_exit(void)                     {}
+-static inline int dbg_debugfs_init_fs(struct ubifs_info *c)   { return 0; }
+-static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)   { return 0; }
++                                     const struct inode *inode,
++                                     loff_t size)               { return 0; }
++static inline int
++dbg_check_data_nodes_order(struct ubifs_info *c,
++                         struct list_head *head)                { return 0; }
++static inline int
++dbg_check_nondata_nodes_order(struct ubifs_info *c,
++                            struct list_head *head)             { return 0; }
++
++static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
++                              const void *buf, int offset,
++                              int len, int dtype)               { return 0; }
++static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
++                               const void *buf, int len,
++                               int dtype)                       { return 0; }
++static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum)   { return 0; }
++static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
++                            int dtype)                          { return 0; }
++
++static inline int dbg_is_chk_gen(const struct ubifs_info *c)      { return 0; }
++static inline int dbg_is_chk_index(const struct ubifs_info *c)    { return 0; }
++static inline int dbg_is_chk_orph(const struct ubifs_info *c)     { return 0; }
++static inline int dbg_is_chk_lprops(const struct ubifs_info *c)   { return 0; }
++static inline int dbg_is_chk_fs(const struct ubifs_info *c)       { return 0; }
++static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)    { return 0; }
++static inline int dbg_is_power_cut(const struct ubifs_info *c)    { return 0; }
++
++static inline int dbg_debugfs_init(void)                          { return 0; }
++static inline void dbg_debugfs_exit(void)                         { return; }
++static inline int dbg_debugfs_init_fs(struct ubifs_info *c)       { return 0; }
++static inline int dbg_debugfs_exit_fs(struct ubifs_info *c)       { return 0; }
+ #endif /* !CONFIG_UBIFS_FS_DEBUG */
+ #endif /* !__UBIFS_DEBUG_H__ */
+diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
+index 14f64b6..9c5e3c5 100644
+--- a/fs/ubifs/dir.c
++++ b/fs/ubifs/dir.c
+@@ -102,7 +102,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+        * UBIFS has to fully control "clean <-> dirty" transitions of inodes
+        * to make budgeting work.
+        */
+-      inode->i_flags |= (S_NOCMTIME);
++      inode->i_flags |= S_NOCMTIME;
+       inode_init_owner(inode, dir, mode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime =
+@@ -172,9 +172,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+-static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
++static int dbg_check_name(const struct ubifs_info *c,
++                        const struct ubifs_dent_node *dent,
++                        const struct qstr *nm)
+ {
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       if (le16_to_cpu(dent->nlen) != nm->len)
+               return -EINVAL;
+@@ -185,7 +187,7 @@ static int dbg_check_name(struct ubifs_dent_node *dent, struct qstr *nm)
+ #else
+-#define dbg_check_name(dent, nm) 0
++#define dbg_check_name(c, dent, nm) 0
+ #endif
+@@ -219,7 +221,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
+               goto out;
+       }
+-      if (dbg_check_name(dent, &dentry->d_name)) {
++      if (dbg_check_name(c, dent, &dentry->d_name)) {
+               err = -EINVAL;
+               goto out;
+       }
+@@ -540,7 +542,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
+        if (inode->i_nlink == 0)
+                return -ENOENT;
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -595,7 +597,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
+               inode->i_nlink, dir->i_ino);
+       ubifs_assert(mutex_is_locked(&dir->i_mutex));
+       ubifs_assert(mutex_is_locked(&inode->i_mutex));
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -621,7 +623,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
+               ubifs_release_budget(c, &req);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return 0;
+@@ -711,7 +713,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
+               ubifs_release_budget(c, &req);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return 0;
+diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
+index d77db7e..7cf738a 100644
+--- a/fs/ubifs/file.c
++++ b/fs/ubifs/file.c
+@@ -212,7 +212,7 @@ static void release_new_page_budget(struct ubifs_info *c)
+  */
+ static void release_existing_page_budget(struct ubifs_info *c)
+ {
+-      struct ubifs_budget_req req = { .dd_growth = c->page_budget};
++      struct ubifs_budget_req req = { .dd_growth = c->bi.page_budget};
+       ubifs_release_budget(c, &req);
+ }
+@@ -448,10 +448,12 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping,
+               if (!(pos & ~PAGE_CACHE_MASK) && len == PAGE_CACHE_SIZE) {
+                       /*
+                        * We change whole page so no need to load it. But we
+-                       * have to set the @PG_checked flag to make the further
+-                       * code know that the page is new. This might be not
+-                       * true, but it is better to budget more than to read
+-                       * the page from the media.
++                       * do not know whether this page exists on the media or
++                       * not, so we assume the latter because it requires
++                       * larger budget. The assumption is that it is better
++                       * to budget a bit more than to read the page from the
++                       * media. Thus, we are setting the @PG_checked flag
++                       * here.
+                        */
+                       SetPageChecked(page);
+                       skipped_read = 1;
+@@ -559,6 +561,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping,
+               dbg_gen("copied %d instead of %d, read page and repeat",
+                       copied, len);
+               cancel_budget(c, page, ui, appending);
++              ClearPageChecked(page);
+               /*
+                * Return 0 to force VFS to repeat the whole operation, or the
+@@ -968,11 +971,11 @@ static int do_writepage(struct page *page, int len)
+  * the page locked, and it locks @ui_mutex. However, write-back does take inode
+  * @i_mutex, which means other VFS operations may be run on this inode at the
+  * same time. And the problematic one is truncation to smaller size, from where
+- * we have to call 'truncate_setsize()', which first changes @inode->i_size, then
+- * drops the truncated pages. And while dropping the pages, it takes the page
+- * lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' with
+- * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
+- * means that @inode->i_size is changed while @ui_mutex is unlocked.
++ * we have to call 'truncate_setsize()', which first changes @inode->i_size,
++ * then drops the truncated pages. And while dropping the pages, it takes the
++ * page lock. This means that 'do_truncation()' cannot call 'truncate_setsize()'
++ * with @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'.
++ * This means that @inode->i_size is changed while @ui_mutex is unlocked.
+  *
+  * XXX(truncate): with the new truncate sequence this is not true anymore,
+  * and the calls to truncate_setsize can be move around freely.  They should
+@@ -1186,7 +1189,7 @@ out_budg:
+       if (budgeted)
+               ubifs_release_budget(c, &req);
+       else {
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+       return err;
+@@ -1260,7 +1263,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
+       if (err)
+               return err;
+-      err = dbg_check_synced_i_size(inode);
++      err = dbg_check_synced_i_size(c, inode);
+       if (err)
+               return err;
+@@ -1309,6 +1312,13 @@ int ubifs_fsync(struct file *file, int datasync)
+       dbg_gen("syncing inode %lu", inode->i_ino);
++      if (c->ro_mount)
++              /*
++               * For some really strange reasons VFS does not filter out
++               * 'fsync()' for R/O mounted file-systems as per 2.6.39.
++               */
++              return 0;
++
+       /*
+        * VFS has already synchronized dirty pages for this inode. Synchronize
+        * the inode unless this is a 'datasync()' call.
+@@ -1426,10 +1436,11 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
+ }
+ /*
+- * mmap()d file has taken write protection fault and is being made
+- * writable. UBIFS must ensure page is budgeted for.
++ * mmap()d file has taken write protection fault and is being made writable.
++ * UBIFS must ensure page is budgeted for.
+  */
+-static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
++static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma,
++                               struct vm_fault *vmf)
+ {
+       struct page *page = vmf->page;
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+@@ -1530,7 +1541,6 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+       int err;
+-      /* 'generic_file_mmap()' takes care of NOMMU case */
+       err = generic_file_mmap(file, vma);
+       if (err)
+               return err;
+diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
+index 1d54383..2559d17 100644
+--- a/fs/ubifs/find.c
++++ b/fs/ubifs/find.c
+@@ -252,8 +252,8 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+                * But if the index takes fewer LEBs than it is reserved for it,
+                * this function must avoid picking those reserved LEBs.
+                */
+-              if (c->min_idx_lebs >= c->lst.idx_lebs) {
+-                      rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++              if (c->bi.min_idx_lebs >= c->lst.idx_lebs) {
++                      rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
+                       exclude_index = 1;
+               }
+               spin_unlock(&c->space_lock);
+@@ -276,7 +276,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
+                       pick_free = 0;
+       } else {
+               spin_lock(&c->space_lock);
+-              exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs);
++              exclude_index = (c->bi.min_idx_lebs >= c->lst.idx_lebs);
+               spin_unlock(&c->space_lock);
+       }
+@@ -501,8 +501,8 @@ int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *offs,
+       /* Check if there are enough empty LEBs for commit */
+       spin_lock(&c->space_lock);
+-      if (c->min_idx_lebs > c->lst.idx_lebs)
+-              rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
++      if (c->bi.min_idx_lebs > c->lst.idx_lebs)
++              rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
+       else
+               rsvd_idx_lebs = 0;
+       lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
+diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
+index 151f108..ded29f6 100644
+--- a/fs/ubifs/gc.c
++++ b/fs/ubifs/gc.c
+@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c)
+       if (err)
+               return err;
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (err)
++              return err;
++
+       err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
+       if (err)
+               return err;
+@@ -118,7 +122,7 @@ static int switch_gc_head(struct ubifs_info *c)
+  * This function compares data nodes @a and @b. Returns %1 if @a has greater
+  * inode or block number, and %-1 otherwise.
+  */
+-int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
++static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+ {
+       ino_t inuma, inumb;
+       struct ubifs_info *c = priv;
+@@ -161,7 +165,8 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+  * first and sorted by length in descending order. Directory entry nodes go
+  * after inode nodes and are sorted in ascending hash valuer order.
+  */
+-int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
++static int nondata_nodes_cmp(void *priv, struct list_head *a,
++                           struct list_head *b)
+ {
+       ino_t inuma, inumb;
+       struct ubifs_info *c = priv;
+@@ -473,6 +478,37 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
+       ubifs_assert(c->gc_lnum != lnum);
+       ubifs_assert(wbuf->lnum != lnum);
++      if (lp->free + lp->dirty == c->leb_size) {
++              /* Special case - a free LEB  */
++              dbg_gc("LEB %d is free, return it", lp->lnum);
++              ubifs_assert(!(lp->flags & LPROPS_INDEX));
++
++              if (lp->free != c->leb_size) {
++                      /*
++                       * Write buffers must be sync'd before unmapping
++                       * freeable LEBs, because one of them may contain data
++                       * which obsoletes something in 'lp->pnum'.
++                       */
++                      err = gc_sync_wbufs(c);
++                      if (err)
++                              return err;
++                      err = ubifs_change_one_lp(c, lp->lnum, c->leb_size,
++                                                0, 0, 0, 0);
++                      if (err)
++                              return err;
++              }
++              err = ubifs_leb_unmap(c, lp->lnum);
++              if (err)
++                      return err;
++
++              if (c->gc_lnum == -1) {
++                      c->gc_lnum = lnum;
++                      return LEB_RETAINED;
++              }
++
++              return LEB_FREED;
++      }
++
+       /*
+        * We scan the entire LEB even though we only really need to scan up to
+        * (c->leb_size - lp->free).
+@@ -682,37 +718,6 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
+                      "(min. space %d)", lp.lnum, lp.free, lp.dirty,
+                      lp.free + lp.dirty, min_space);
+-              if (lp.free + lp.dirty == c->leb_size) {
+-                      /* An empty LEB was returned */
+-                      dbg_gc("LEB %d is free, return it", lp.lnum);
+-                      /*
+-                       * ubifs_find_dirty_leb() doesn't return freeable index
+-                       * LEBs.
+-                       */
+-                      ubifs_assert(!(lp.flags & LPROPS_INDEX));
+-                      if (lp.free != c->leb_size) {
+-                              /*
+-                               * Write buffers must be sync'd before
+-                               * unmapping freeable LEBs, because one of them
+-                               * may contain data which obsoletes something
+-                               * in 'lp.pnum'.
+-                               */
+-                              ret = gc_sync_wbufs(c);
+-                              if (ret)
+-                                      goto out;
+-                              ret = ubifs_change_one_lp(c, lp.lnum,
+-                                                        c->leb_size, 0, 0, 0,
+-                                                        0);
+-                              if (ret)
+-                                      goto out;
+-                      }
+-                      ret = ubifs_leb_unmap(c, lp.lnum);
+-                      if (ret)
+-                              goto out;
+-                      ret = lp.lnum;
+-                      break;
+-              }
+-
+               space_before = c->leb_size - wbuf->offs - wbuf->used;
+               if (wbuf->lnum == -1)
+                       space_before = 0;
+diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
+index d821731..9228950 100644
+--- a/fs/ubifs/io.c
++++ b/fs/ubifs/io.c
+@@ -31,6 +31,26 @@
+  * buffer is full or when it is not used for some time (by timer). This is
+  * similar to the mechanism is used by JFFS2.
+  *
++ * UBIFS distinguishes between minimum write size (@c->min_io_size) and maximum
++ * write size (@c->max_write_size). The latter is the maximum amount of bytes
++ * the underlying flash is able to program at a time, and writing in
++ * @c->max_write_size units should presumably be faster. Obviously,
++ * @c->min_io_size <= @c->max_write_size. Write-buffers are of
++ * @c->max_write_size bytes in size for maximum performance. However, when a
++ * write-buffer is flushed, only the portion of it (aligned to @c->min_io_size
++ * boundary) which contains data is written, not the whole write-buffer,
++ * because this is more space-efficient.
++ *
++ * This optimization adds few complications to the code. Indeed, on the one
++ * hand, we want to write in optimal @c->max_write_size bytes chunks, which
++ * also means aligning writes at the @c->max_write_size bytes offsets. On the
++ * other hand, we do not want to waste space when synchronizing the write
++ * buffer, so during synchronization we writes in smaller chunks. And this makes
++ * the next write offset to be not aligned to @c->max_write_size bytes. So the
++ * have to make sure that the write-buffer offset (@wbuf->offs) becomes aligned
++ * to @c->max_write_size bytes again. We do this by temporarily shrinking
++ * write-buffer size (@wbuf->size).
++ *
+  * Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
+  * mutexes defined inside these objects. Since sometimes upper-level code
+  * has to lock the write-buffer (e.g. journal space reservation code), many
+@@ -46,8 +66,8 @@
+  * UBIFS uses padding when it pads to the next min. I/O unit. In this case it
+  * uses padding nodes or padding bytes, if the padding node does not fit.
+  *
+- * All UBIFS nodes are protected by CRC checksums and UBIFS checks all nodes
+- * every time they are read from the flash media.
++ * All UBIFS nodes are protected by CRC checksums and UBIFS checks CRC when
++ * they are read from the flash media.
+  */
+ #include <linux/crc32.h>
+@@ -66,8 +86,125 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
+               c->no_chk_data_crc = 0;
+               c->vfs_sb->s_flags |= MS_RDONLY;
+               ubifs_warn("switched to read-only mode, error %d", err);
++              dump_stack();
++      }
++}
++
++/*
++ * Below are simple wrappers over UBI I/O functions which include some
++ * additional checks and UBIFS debugging stuff. See corresponding UBI function
++ * for more information.
++ */
++
++int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
++                 int len, int even_ebadmsg)
++{
++      int err;
++
++      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      /*
++       * In case of %-EBADMSG print the error message only if the
++       * @even_ebadmsg is true.
++       */
++      if (err && (err != -EBADMSG || even_ebadmsg)) {
++              ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
++                        len, lnum, offs, err);
+               dbg_dump_stack();
+       }
++      return err;
++}
++
++int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                  int len, int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
++      else
++              err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
++      if (err) {
++              ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
++                        len, lnum, offs, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                   int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
++      else
++              err = dbg_leb_change(c, lnum, buf, len, dtype);
++      if (err) {
++              ubifs_err("changing %d bytes in LEB %d failed, error %d",
++                        len, lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_unmap(c->ubi, lnum);
++      else
++              err = dbg_leb_unmap(c, lnum);
++      if (err) {
++              ubifs_err("unmap LEB %d failed, error %d", lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
++{
++      int err;
++
++      ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->ro_error)
++              return -EROFS;
++      if (!dbg_is_tst_rcvry(c))
++              err = ubi_leb_map(c->ubi, lnum, dtype);
++      else
++              err = dbg_leb_map(c, lnum, dtype);
++      if (err) {
++              ubifs_err("mapping LEB %d failed, error %d", lnum, err);
++              ubifs_ro_mode(c, err);
++              dbg_dump_stack();
++      }
++      return err;
++}
++
++int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
++{
++      int err;
++
++      err = ubi_is_mapped(c->ubi, lnum);
++      if (err < 0) {
++              ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
++                        lnum, err);
++              dbg_dump_stack();
++      }
++      return err;
+ }
+ /**
+@@ -88,8 +225,12 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
+  * This function may skip data nodes CRC checking if @c->no_chk_data_crc is
+  * true, which is controlled by corresponding UBIFS mount option. However, if
+  * @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
+- * checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
+- * ignored and CRC is checked.
++ * checked. Similarly, if @c->mounting or @c->remounting_rw is true (we are
++ * mounting or re-mounting to R/W mode), @c->no_chk_data_crc is ignored and CRC
++ * is checked. This is because during mounting or re-mounting from R/O mode to
++ * R/W mode we may read journal nodes (when replying the journal or doing the
++ * recovery) and the journal nodes may potentially be corrupted, so checking is
++ * required.
+  *
+  * This function returns zero in case of success and %-EUCLEAN in case of bad
+  * CRC or magic.
+@@ -131,8 +272,8 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+                  node_len > c->ranges[type].max_len)
+               goto out_len;
+-      if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
+-           c->no_chk_data_crc)
++      if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->mounting &&
++          !c->remounting_rw && c->no_chk_data_crc)
+               return 0;
+       crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+@@ -343,11 +484,17 @@ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
+  *
+  * This function synchronizes write-buffer @buf and returns zero in case of
+  * success or a negative error code in case of failure.
++ *
++ * Note, although write-buffers are of @c->max_write_size, this function does
++ * not necessarily writes all @c->max_write_size bytes to the flash. Instead,
++ * if the write-buffer is only partially filled with data, only the used part
++ * of the write-buffer (aligned on @c->min_io_size boundary) is synchronized.
++ * This way we waste less space.
+  */
+ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+ {
+       struct ubifs_info *c = wbuf->c;
+-      int err, dirt;
++      int err, dirt, sync_len;
+       cancel_wbuf_timer_nolock(wbuf);
+       if (!wbuf->used || wbuf->lnum == -1)
+@@ -357,27 +504,49 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+       dbg_io("LEB %d:%d, %d bytes, jhead %s",
+              wbuf->lnum, wbuf->offs, wbuf->used, dbg_jhead(wbuf->jhead));
+       ubifs_assert(!(wbuf->avail & 7));
+-      ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size);
++      ubifs_assert(wbuf->offs + wbuf->size <= c->leb_size);
++      ubifs_assert(wbuf->size >= c->min_io_size);
++      ubifs_assert(wbuf->size <= c->max_write_size);
++      ubifs_assert(wbuf->size % c->min_io_size == 0);
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
+       if (c->ro_error)
+               return -EROFS;
+-      ubifs_pad(c, wbuf->buf + wbuf->used, wbuf->avail);
+-      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
+-                          c->min_io_size, wbuf->dtype);
+-      if (err) {
+-              ubifs_err("cannot write %d bytes to LEB %d:%d",
+-                        c->min_io_size, wbuf->lnum, wbuf->offs);
+-              dbg_dump_stack();
++      /*
++       * Do not write whole write buffer but write only the minimum necessary
++       * amount of min. I/O units.
++       */
++      sync_len = ALIGN(wbuf->used, c->min_io_size);
++      dirt = sync_len - wbuf->used;
++      if (dirt)
++              ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
++      err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
++                            wbuf->dtype);
++      if (err)
+               return err;
+-      }
+-
+-      dirt = wbuf->avail;
+       spin_lock(&wbuf->lock);
+-      wbuf->offs += c->min_io_size;
+-      wbuf->avail = c->min_io_size;
++      wbuf->offs += sync_len;
++      /*
++       * Now @wbuf->offs is not necessarily aligned to @c->max_write_size.
++       * But our goal is to optimize writes and make sure we write in
++       * @c->max_write_size chunks and to @c->max_write_size-aligned offset.
++       * Thus, if @wbuf->offs is not aligned to @c->max_write_size now, make
++       * sure that @wbuf->offs + @wbuf->size is aligned to
++       * @c->max_write_size. This way we make sure that after next
++       * write-buffer flush we are again at the optimal offset (aligned to
++       * @c->max_write_size).
++       */
++      if (c->leb_size - wbuf->offs < c->max_write_size)
++              wbuf->size = c->leb_size - wbuf->offs;
++      else if (wbuf->offs & (c->max_write_size - 1))
++              wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
++      else
++              wbuf->size = c->max_write_size;
++      wbuf->avail = wbuf->size;
+       wbuf->used = 0;
+       wbuf->next_ino = 0;
+       spin_unlock(&wbuf->lock);
+@@ -396,8 +565,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+  * @dtype: data type
+  *
+  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
+- * The write-buffer is synchronized if it is not empty. Returns zero in case of
+- * success and a negative error code in case of failure.
++ * The write-buffer has to be empty. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+                          int dtype)
+@@ -409,18 +578,18 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+       ubifs_assert(offs >= 0 && offs <= c->leb_size);
+       ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
+       ubifs_assert(lnum != wbuf->lnum);
+-
+-      if (wbuf->used > 0) {
+-              int err = ubifs_wbuf_sync_nolock(wbuf);
+-
+-              if (err)
+-                      return err;
+-      }
++      ubifs_assert(wbuf->used == 0);
+       spin_lock(&wbuf->lock);
+       wbuf->lnum = lnum;
+       wbuf->offs = offs;
+-      wbuf->avail = c->min_io_size;
++      if (c->leb_size - wbuf->offs < c->max_write_size)
++              wbuf->size = c->leb_size - wbuf->offs;
++      else if (wbuf->offs & (c->max_write_size - 1))
++              wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
++      else
++              wbuf->size = c->max_write_size;
++      wbuf->avail = wbuf->size;
+       wbuf->used = 0;
+       spin_unlock(&wbuf->lock);
+       wbuf->dtype = dtype;
+@@ -500,8 +669,9 @@ out_timers:
+  *
+  * This function writes data to flash via write-buffer @wbuf. This means that
+  * the last piece of the node won't reach the flash media immediately if it
+- * does not take whole minimal I/O unit. Instead, the node will sit in RAM
+- * until the write-buffer is synchronized (e.g., by timer).
++ * does not take whole max. write unit (@c->max_write_size). Instead, the node
++ * will sit in RAM until the write-buffer is synchronized (e.g., by timer, or
++ * because more data are appended to the write-buffer).
+  *
+  * This function returns zero in case of success and a negative error code in
+  * case of failure. If the node cannot be written because there is no more
+@@ -510,7 +680,7 @@ out_timers:
+ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+ {
+       struct ubifs_info *c = wbuf->c;
+-      int err, written, n, aligned_len = ALIGN(len, 8), offs;
++      int err, written, n, aligned_len = ALIGN(len, 8);
+       dbg_io("%d bytes (%s) to jhead %s wbuf at LEB %d:%d", len,
+              dbg_ntype(((struct ubifs_ch *)buf)->node_type),
+@@ -518,9 +688,15 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+       ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
+       ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
+       ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
+-      ubifs_assert(wbuf->avail > 0 && wbuf->avail <= c->min_io_size);
++      ubifs_assert(wbuf->avail > 0 && wbuf->avail <= wbuf->size);
++      ubifs_assert(wbuf->size >= c->min_io_size);
++      ubifs_assert(wbuf->size <= c->max_write_size);
++      ubifs_assert(wbuf->size % c->min_io_size == 0);
+       ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      ubifs_assert(!c->space_fixup);
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
+       if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
+               err = -ENOSPC;
+@@ -542,15 +718,19 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+               if (aligned_len == wbuf->avail) {
+                       dbg_io("flush jhead %s wbuf to LEB %d:%d",
+                              dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
+-                      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf,
+-                                          wbuf->offs, c->min_io_size,
+-                                          wbuf->dtype);
++                      err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
++                                            wbuf->offs, wbuf->size,
++                                            wbuf->dtype);
+                       if (err)
+                               goto out;
+                       spin_lock(&wbuf->lock);
+-                      wbuf->offs += c->min_io_size;
+-                      wbuf->avail = c->min_io_size;
++                      wbuf->offs += wbuf->size;
++                      if (c->leb_size - wbuf->offs >= c->max_write_size)
++                              wbuf->size = c->max_write_size;
++                      else
++                              wbuf->size = c->leb_size - wbuf->offs;
++                      wbuf->avail = wbuf->size;
+                       wbuf->used = 0;
+                       wbuf->next_ino = 0;
+                       spin_unlock(&wbuf->lock);
+@@ -564,39 +744,63 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+               goto exit;
+       }
+-      /*
+-       * The node is large enough and does not fit entirely within current
+-       * minimal I/O unit. We have to fill and flush write-buffer and switch
+-       * to the next min. I/O unit.
+-       */
+-      dbg_io("flush jhead %s wbuf to LEB %d:%d",
+-             dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
+-      memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
+-      err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs,
+-                          c->min_io_size, wbuf->dtype);
+-      if (err)
+-              goto out;
++      written = 0;
++
++      if (wbuf->used) {
++              /*
++               * The node is large enough and does not fit entirely within
++               * current available space. We have to fill and flush
++               * write-buffer and switch to the next max. write unit.
++               */
++              dbg_io("flush jhead %s wbuf to LEB %d:%d",
++                     dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
++              memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
++              err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
++                                    wbuf->size, wbuf->dtype);
++              if (err)
++                      goto out;
++
++              wbuf->offs += wbuf->size;
++              len -= wbuf->avail;
++              aligned_len -= wbuf->avail;
++              written += wbuf->avail;
++      } else if (wbuf->offs & (c->max_write_size - 1)) {
++              /*
++               * The write-buffer offset is not aligned to
++               * @c->max_write_size and @wbuf->size is less than
++               * @c->max_write_size. Write @wbuf->size bytes to make sure the
++               * following writes are done in optimal @c->max_write_size
++               * chunks.
++               */
++              dbg_io("write %d bytes to LEB %d:%d",
++                     wbuf->size, wbuf->lnum, wbuf->offs);
++              err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
++                                    wbuf->size, wbuf->dtype);
++              if (err)
++                      goto out;
+-      offs = wbuf->offs + c->min_io_size;
+-      len -= wbuf->avail;
+-      aligned_len -= wbuf->avail;
+-      written = wbuf->avail;
++              wbuf->offs += wbuf->size;
++              len -= wbuf->size;
++              aligned_len -= wbuf->size;
++              written += wbuf->size;
++      }
+       /*
+-       * The remaining data may take more whole min. I/O units, so write the
+-       * remains multiple to min. I/O unit size directly to the flash media.
++       * The remaining data may take more whole max. write units, so write the
++       * remains multiple to max. write unit size directly to the flash media.
+        * We align node length to 8-byte boundary because we anyway flash wbuf
+        * if the remaining space is less than 8 bytes.
+        */
+-      n = aligned_len >> c->min_io_shift;
++      n = aligned_len >> c->max_write_shift;
+       if (n) {
+-              n <<= c->min_io_shift;
+-              dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
+-              err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
+-                                  wbuf->dtype);
++              n <<= c->max_write_shift;
++              dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
++                     wbuf->offs);
++              err = ubifs_leb_write(c, wbuf->lnum, buf + written,
++                                    wbuf->offs, n, wbuf->dtype);
+               if (err)
+                       goto out;
+-              offs += n;
++              wbuf->offs += n;
+               aligned_len -= n;
+               len -= n;
+               written += n;
+@@ -606,14 +810,17 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+       if (aligned_len)
+               /*
+                * And now we have what's left and what does not take whole
+-               * min. I/O unit, so write it to the write-buffer and we are
++               * max. write unit, so write it to the write-buffer and we are
+                * done.
+                */
+               memcpy(wbuf->buf, buf + written, len);
+-      wbuf->offs = offs;
++      if (c->leb_size - wbuf->offs >= c->max_write_size)
++              wbuf->size = c->max_write_size;
++      else
++              wbuf->size = c->leb_size - wbuf->offs;
++      wbuf->avail = wbuf->size - aligned_len;
+       wbuf->used = aligned_len;
+-      wbuf->avail = c->min_io_size - aligned_len;
+       wbuf->next_ino = 0;
+       spin_unlock(&wbuf->lock);
+@@ -666,18 +873,15 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
+       ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+       ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
+       ubifs_assert(!c->ro_media && !c->ro_mount);
++      ubifs_assert(!c->space_fixup);
+       if (c->ro_error)
+               return -EROFS;
+       ubifs_prepare_node(c, buf, len, 1);
+-      err = ubi_leb_write(c->ubi, lnum, buf, offs, buf_len, dtype);
+-      if (err) {
+-              ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
+-                        buf_len, lnum, offs, err);
++      err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
++      if (err)
+               dbg_dump_node(c, buf);
+-              dbg_dump_stack();
+-      }
+       return err;
+ }
+@@ -729,13 +933,9 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+       if (rlen > 0) {
+               /* Read everything that goes before write-buffer */
+-              err = ubi_read(c->ubi, lnum, buf, offs, rlen);
+-              if (err && err != -EBADMSG) {
+-                      ubifs_err("failed to read node %d from LEB %d:%d, "
+-                                "error %d", type, lnum, offs, err);
+-                      dbg_dump_stack();
++              err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
++              if (err && err != -EBADMSG)
+                       return err;
+-              }
+       }
+       if (type != ch->node_type) {
+@@ -790,12 +990,9 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
+       ubifs_assert(!(offs & 7) && offs < c->leb_size);
+       ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
+-      if (err && err != -EBADMSG) {
+-              ubifs_err("cannot read node %d from LEB %d:%d, error %d",
+-                        type, lnum, offs, err);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
++      if (err && err != -EBADMSG)
+               return err;
+-      }
+       if (type != ch->node_type) {
+               ubifs_err("bad node type (%d but expected %d)",
+@@ -837,11 +1034,11 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
+ {
+       size_t size;
+-      wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
++      wbuf->buf = kmalloc(c->max_write_size, GFP_KERNEL);
+       if (!wbuf->buf)
+               return -ENOMEM;
+-      size = (c->min_io_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
++      size = (c->max_write_size / UBIFS_CH_SZ + 1) * sizeof(ino_t);
+       wbuf->inodes = kmalloc(size, GFP_KERNEL);
+       if (!wbuf->inodes) {
+               kfree(wbuf->buf);
+@@ -851,7 +1048,14 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
+       wbuf->used = 0;
+       wbuf->lnum = wbuf->offs = -1;
+-      wbuf->avail = c->min_io_size;
++      /*
++       * If the LEB starts at the max. write size aligned address, then
++       * write-buffer size has to be set to @c->max_write_size. Otherwise,
++       * set it to something smaller so that it ends at the closest max.
++       * write size boundary.
++       */
++      size = c->max_write_size - (c->leb_start % c->max_write_size);
++      wbuf->avail = wbuf->size = size;
+       wbuf->dtype = UBI_UNKNOWN;
+       wbuf->sync_callback = NULL;
+       mutex_init(&wbuf->io_mutex);
+diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
+index 914f1bd..2f438ab 100644
+--- a/fs/ubifs/journal.c
++++ b/fs/ubifs/journal.c
+@@ -141,14 +141,8 @@ again:
+        * LEB with some empty space.
+        */
+       lnum = ubifs_find_free_space(c, len, &offs, squeeze);
+-      if (lnum >= 0) {
+-              /* Found an LEB, add it to the journal head */
+-              err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
+-              if (err)
+-                      goto out_return;
+-              /* A new bud was successfully allocated and added to the log */
++      if (lnum >= 0)
+               goto out;
+-      }
+       err = lnum;
+       if (err != -ENOSPC)
+@@ -203,12 +197,23 @@ again:
+               return 0;
+       }
+-      err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
+-      if (err)
+-              goto out_return;
+       offs = 0;
+ out:
++      /*
++       * Make sure we synchronize the write-buffer before we add the new bud
++       * to the log. Otherwise we may have a power cut after the log
++       * reference node for the last bud (@lnum) is written but before the
++       * write-buffer data are written to the next-to-last bud
++       * (@wbuf->lnum). And the effect would be that the recovery would see
++       * that there is corruption in the next-to-last bud.
++       */
++      err = ubifs_wbuf_sync_nolock(wbuf);
++      if (err)
++              goto out_return;
++      err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
++      if (err)
++              goto out_return;
+       err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
+       if (err)
+               goto out_unlock;
+@@ -380,10 +385,8 @@ out:
+       if (err == -ENOSPC) {
+               /* This are some budgeting problems, print useful information */
+               down_write(&c->commit_sem);
+-              spin_lock(&c->space_lock);
+               dbg_dump_stack();
+-              dbg_dump_budg(c);
+-              spin_unlock(&c->space_lock);
++              dbg_dump_budg(c, &c->bi);
+               dbg_dump_lprops(c);
+               cmt_retries = dbg_check_lprops(c);
+               up_write(&c->commit_sem);
+@@ -666,6 +669,7 @@ out_free:
+ out_release:
+       release_head(c, BASEHD);
++      kfree(dent);
+ out_ro:
+       ubifs_ro_mode(c, err);
+       if (last_reference)
+@@ -690,17 +694,26 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+ {
+       struct ubifs_data_node *data;
+       int err, lnum, offs, compr_type, out_len;
+-      int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR;
++      int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
+       struct ubifs_inode *ui = ubifs_inode(inode);
+-      dbg_jnl("ino %lu, blk %u, len %d, key %s",
+-              (unsigned long)key_inum(c, key), key_block(c, key), len,
+-              DBGKEY(key));
++      dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
++              (unsigned long)key_inum(c, key), key_block(c, key), len);
+       ubifs_assert(len <= UBIFS_BLOCK_SIZE);
+-      data = kmalloc(dlen, GFP_NOFS);
+-      if (!data)
+-              return -ENOMEM;
++      data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
++      if (!data) {
++              /*
++               * Fall-back to the write reserve buffer. Note, we might be
++               * currently on the memory reclaim path, when the kernel is
++               * trying to free some memory by writing out dirty pages. The
++               * write reserve buffer helps us to guarantee that we are
++               * always able to write the data.
++               */
++              allocated = 0;
++              mutex_lock(&c->write_reserve_mutex);
++              data = c->write_reserve_buf;
++      }
+       data->ch.node_type = UBIFS_DATA_NODE;
+       key_write(c, key, &data->key);
+@@ -736,7 +749,10 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
+               goto out_ro;
+       finish_reservation(c);
+-      kfree(data);
++      if (!allocated)
++              mutex_unlock(&c->write_reserve_mutex);
++      else
++              kfree(data);
+       return 0;
+ out_release:
+@@ -745,7 +761,10 @@ out_ro:
+       ubifs_ro_mode(c, err);
+       finish_reservation(c);
+ out_free:
+-      kfree(data);
++      if (!allocated)
++              mutex_unlock(&c->write_reserve_mutex);
++      else
++              kfree(data);
+       return err;
+ }
+@@ -1157,7 +1176,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
+               dn = (void *)trun + UBIFS_TRUN_NODE_SZ;
+               blk = new_size >> UBIFS_BLOCK_SHIFT;
+               data_key_init(c, &key, inum, blk);
+-              dbg_jnl("last block key %s", DBGKEY(&key));
++              dbg_jnlk(&key, "last block key ");
+               err = ubifs_tnc_lookup(c, &key, dn);
+               if (err == -ENOENT)
+                       dlen = 0; /* Not found (so it is a hole) */
+diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
+index 4d0cb12..f9fd068 100644
+--- a/fs/ubifs/log.c
++++ b/fs/ubifs/log.c
+@@ -100,20 +100,6 @@ struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
+ }
+ /**
+- * next_log_lnum - switch to the next log LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: current log LEB
+- */
+-static inline int next_log_lnum(const struct ubifs_info *c, int lnum)
+-{
+-      lnum += 1;
+-      if (lnum > c->log_last)
+-              lnum = UBIFS_LOG_LNUM;
+-
+-      return lnum;
+-}
+-
+-/**
+  * empty_log_bytes - calculate amount of empty space in the log.
+  * @c: UBIFS file-system description object
+  */
+@@ -175,26 +161,6 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
+ }
+ /**
+- * ubifs_create_buds_lists - create journal head buds lists for remount rw.
+- * @c: UBIFS file-system description object
+- */
+-void ubifs_create_buds_lists(struct ubifs_info *c)
+-{
+-      struct rb_node *p;
+-
+-      spin_lock(&c->buds_lock);
+-      p = rb_first(&c->buds);
+-      while (p) {
+-              struct ubifs_bud *bud = rb_entry(p, struct ubifs_bud, rb);
+-              struct ubifs_jhead *jhead = &c->jheads[bud->jhead];
+-
+-              list_add_tail(&bud->list, &jhead->buds_list);
+-              p = rb_next(p);
+-      }
+-      spin_unlock(&c->buds_lock);
+-}
+-
+-/**
+  * ubifs_add_bud_to_log - add a new bud to the log.
+  * @c: UBIFS file-system description object
+  * @jhead: journal head the bud belongs to
+@@ -277,7 +243,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+       ref->jhead = cpu_to_le32(jhead);
+       if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -296,7 +262,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+                * an unclean reboot, because the target LEB might have been
+                * unmapped, but not yet physically erased.
+                */
+-              err = ubi_leb_map(c->ubi, bud->lnum, UBI_SHORTTERM);
++              err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
+               if (err)
+                       goto out_unlock;
+       }
+@@ -317,8 +283,6 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+       return 0;
+ out_unlock:
+-      if (err != -EAGAIN)
+-              ubifs_ro_mode(c, err);
+       mutex_unlock(&c->log_mutex);
+       kfree(ref);
+       kfree(bud);
+@@ -445,7 +409,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
+       /* Switch to the next log LEB */
+       if (c->lhead_offs) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -466,7 +430,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
+       c->lhead_offs += len;
+       if (c->lhead_offs == c->leb_size) {
+-              c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
++              c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+               c->lhead_offs = 0;
+       }
+@@ -553,7 +517,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
+       }
+       mutex_lock(&c->log_mutex);
+       for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
+-           lnum = next_log_lnum(c, lnum)) {
++           lnum = ubifs_next_log_lnum(c, lnum)) {
+               dbg_log("unmap log LEB %d", lnum);
+               err = ubifs_leb_unmap(c, lnum);
+               if (err)
+@@ -662,7 +626,7 @@ static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
+               err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
+               if (err)
+                       return err;
+-              *lnum = next_log_lnum(c, *lnum);
++              *lnum = ubifs_next_log_lnum(c, *lnum);
+               *offs = 0;
+       }
+       memcpy(buf + *offs, node, len);
+@@ -732,7 +696,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
+               ubifs_scan_destroy(sleb);
+               if (lnum == c->lhead_lnum)
+                       break;
+-              lnum = next_log_lnum(c, lnum);
++              lnum = ubifs_next_log_lnum(c, lnum);
+       }
+       if (offs) {
+               int sz = ALIGN(offs, c->min_io_size);
+@@ -752,7 +716,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
+       /* Unmap remaining LEBs */
+       lnum = write_lnum;
+       do {
+-              lnum = next_log_lnum(c, lnum);
++              lnum = ubifs_next_log_lnum(c, lnum);
+               err = ubifs_leb_unmap(c, lnum);
+               if (err)
+                       return err;
+@@ -786,7 +750,7 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
+       struct ubifs_bud *bud;
+       long long bud_bytes = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       spin_lock(&c->buds_lock);
+diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
+index 4d4ca38..f8a181e 100644
+--- a/fs/ubifs/lprops.c
++++ b/fs/ubifs/lprops.c
+@@ -504,7 +504,7 @@ static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
+       pnode = (struct ubifs_pnode *)container_of(lprops - pos,
+                                                  struct ubifs_pnode,
+                                                  lprops[0]);
+-      return !test_bit(COW_ZNODE, &pnode->flags) &&
++      return !test_bit(COW_CNODE, &pnode->flags) &&
+              test_bit(DIRTY_CNODE, &pnode->flags);
+ }
+@@ -860,7 +860,7 @@ int dbg_check_cats(struct ubifs_info *c)
+       struct list_head *pos;
+       int i, cat;
+-      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++      if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
+               return 0;
+       list_for_each_entry(lprops, &c->empty_list, list) {
+@@ -958,7 +958,7 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
+ {
+       int i = 0, j, err = 0;
+-      if (!(ubifs_chk_flags & (UBIFS_CHK_GEN | UBIFS_CHK_LPROPS)))
++      if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
+               return;
+       for (i = 0; i < heap->cnt; i++) {
+@@ -1007,21 +1007,11 @@ out:
+ }
+ /**
+- * struct scan_check_data - data provided to scan callback function.
+- * @lst: LEB properties statistics
+- * @err: error code
+- */
+-struct scan_check_data {
+-      struct ubifs_lp_stats lst;
+-      int err;
+-};
+-
+-/**
+  * scan_check_cb - scan callback.
+  * @c: the UBIFS file-system description object
+  * @lp: LEB properties to scan
+  * @in_tree: whether the LEB properties are in main memory
+- * @data: information passed to and from the caller of the scan
++ * @lst: lprops statistics to update
+  *
+  * This function returns a code that indicates whether the scan should continue
+  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
+@@ -1030,12 +1020,12 @@ struct scan_check_data {
+  */
+ static int scan_check_cb(struct ubifs_info *c,
+                        const struct ubifs_lprops *lp, int in_tree,
+-                       struct scan_check_data *data)
++                       struct ubifs_lp_stats *lst)
+ {
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
+-      struct ubifs_lp_stats *lst = &data->lst;
+-      int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty;
++      int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
++      void *buf = NULL;
+       cat = lp->flags & LPROPS_CAT_MASK;
+       if (cat != LPROPS_UNCAT) {
+@@ -1043,7 +1033,7 @@ static int scan_check_cb(struct ubifs_info *c,
+               if (cat != (lp->flags & LPROPS_CAT_MASK)) {
+                       ubifs_err("bad LEB category %d expected %d",
+                                 (lp->flags & LPROPS_CAT_MASK), cat);
+-                      goto out;
++                      return -EINVAL;
+               }
+       }
+@@ -1077,7 +1067,7 @@ static int scan_check_cb(struct ubifs_info *c,
+                       }
+                       if (!found) {
+                               ubifs_err("bad LPT list (category %d)", cat);
+-                              goto out;
++                              return -EINVAL;
+                       }
+               }
+       }
+@@ -1089,36 +1079,40 @@ static int scan_check_cb(struct ubifs_info *c,
+               if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
+                   lp != heap->arr[lp->hpos]) {
+                       ubifs_err("bad LPT heap (category %d)", cat);
+-                      goto out;
++                      return -EINVAL;
+               }
+       }
+-      sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
+-      if (IS_ERR(sleb)) {
+-              /*
+-               * After an unclean unmount, empty and freeable LEBs
+-               * may contain garbage.
+-               */
+-              if (lp->free == c->leb_size) {
+-                      ubifs_err("scan errors were in empty LEB "
+-                                "- continuing checking");
+-                      lst->empty_lebs += 1;
+-                      lst->total_free += c->leb_size;
+-                      lst->total_dark += ubifs_calc_dark(c, c->leb_size);
+-                      return LPT_SCAN_CONTINUE;
+-              }
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf)
++              return -ENOMEM;
+-              if (lp->free + lp->dirty == c->leb_size &&
+-                  !(lp->flags & LPROPS_INDEX)) {
+-                      ubifs_err("scan errors were in freeable LEB "
+-                                "- continuing checking");
+-                      lst->total_free  += lp->free;
+-                      lst->total_dirty += lp->dirty;
+-                      lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
+-                      return LPT_SCAN_CONTINUE;
++      /*
++       * After an unclean unmount, empty and freeable LEBs
++       * may contain garbage - do not scan them.
++       */
++      if (lp->free == c->leb_size) {
++              lst->empty_lebs += 1;
++              lst->total_free += c->leb_size;
++              lst->total_dark += ubifs_calc_dark(c, c->leb_size);
++              return LPT_SCAN_CONTINUE;
++      }
++      if (lp->free + lp->dirty == c->leb_size &&
++          !(lp->flags & LPROPS_INDEX)) {
++              lst->total_free  += lp->free;
++              lst->total_dirty += lp->dirty;
++              lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
++              return LPT_SCAN_CONTINUE;
++      }
++
++      sleb = ubifs_scan(c, lnum, 0, buf, 0);
++      if (IS_ERR(sleb)) {
++              ret = PTR_ERR(sleb);
++              if (ret == -EUCLEAN) {
++                      dbg_dump_lprops(c);
++                      dbg_dump_budg(c, &c->bi);
+               }
+-              data->err = PTR_ERR(sleb);
+-              return LPT_SCAN_STOP;
++              goto out;
+       }
+       is_idx = -1;
+@@ -1236,6 +1230,7 @@ static int scan_check_cb(struct ubifs_info *c,
+       }
+       ubifs_scan_destroy(sleb);
++      vfree(buf);
+       return LPT_SCAN_CONTINUE;
+ out_print:
+@@ -1245,9 +1240,10 @@ out_print:
+       dbg_dump_leb(c, lnum);
+ out_destroy:
+       ubifs_scan_destroy(sleb);
++      ret = -EINVAL;
+ out:
+-      data->err = -EINVAL;
+-      return LPT_SCAN_STOP;
++      vfree(buf);
++      return ret;
+ }
+ /**
+@@ -1264,10 +1260,9 @@ out:
+ int dbg_check_lprops(struct ubifs_info *c)
+ {
+       int i, err;
+-      struct scan_check_data data;
+-      struct ubifs_lp_stats *lst = &data.lst;
++      struct ubifs_lp_stats lst;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       /*
+@@ -1280,29 +1275,23 @@ int dbg_check_lprops(struct ubifs_info *c)
+                       return err;
+       }
+-      memset(lst, 0, sizeof(struct ubifs_lp_stats));
+-
+-      data.err = 0;
++      memset(&lst, 0, sizeof(struct ubifs_lp_stats));
+       err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
+                                   (ubifs_lpt_scan_callback)scan_check_cb,
+-                                  &data);
++                                  &lst);
+       if (err && err != -ENOSPC)
+               goto out;
+-      if (data.err) {
+-              err = data.err;
+-              goto out;
+-      }
+-      if (lst->empty_lebs != c->lst.empty_lebs ||
+-          lst->idx_lebs != c->lst.idx_lebs ||
+-          lst->total_free != c->lst.total_free ||
+-          lst->total_dirty != c->lst.total_dirty ||
+-          lst->total_used != c->lst.total_used) {
++      if (lst.empty_lebs != c->lst.empty_lebs ||
++          lst.idx_lebs != c->lst.idx_lebs ||
++          lst.total_free != c->lst.total_free ||
++          lst.total_dirty != c->lst.total_dirty ||
++          lst.total_used != c->lst.total_used) {
+               ubifs_err("bad overall accounting");
+               ubifs_err("calculated: empty_lebs %d, idx_lebs %d, "
+                         "total_free %lld, total_dirty %lld, total_used %lld",
+-                        lst->empty_lebs, lst->idx_lebs, lst->total_free,
+-                        lst->total_dirty, lst->total_used);
++                        lst.empty_lebs, lst.idx_lebs, lst.total_free,
++                        lst.total_dirty, lst.total_used);
+               ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, "
+                         "total_free %lld, total_dirty %lld, total_used %lld",
+                         c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
+@@ -1311,11 +1300,11 @@ int dbg_check_lprops(struct ubifs_info *c)
+               goto out;
+       }
+-      if (lst->total_dead != c->lst.total_dead ||
+-          lst->total_dark != c->lst.total_dark) {
++      if (lst.total_dead != c->lst.total_dead ||
++          lst.total_dark != c->lst.total_dark) {
+               ubifs_err("bad dead/dark space accounting");
+               ubifs_err("calculated: total_dead %lld, total_dark %lld",
+-                        lst->total_dead, lst->total_dark);
++                        lst.total_dead, lst.total_dark);
+               ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
+                         c->lst.total_dead, c->lst.total_dark);
+               err = -EINVAL;
+diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
+index 72775d3..66d59d0 100644
+--- a/fs/ubifs/lpt.c
++++ b/fs/ubifs/lpt.c
+@@ -701,8 +701,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+-                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                           UBI_SHORTTERM);
++                      err = ubifs_leb_change(c, lnum++, buf, alen,
++                                             UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+@@ -732,8 +732,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                               set_ltab(c, lnum, c->leb_size - alen,
+                                           alen - len);
+                               memset(p, 0xff, alen - len);
+-                              err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                                   UBI_SHORTTERM);
++                              err = ubifs_leb_change(c, lnum++, buf, alen,
++                                                     UBI_SHORTTERM);
+                               if (err)
+                                       goto out;
+                               p = buf;
+@@ -780,8 +780,8 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+                       alen = ALIGN(len, c->min_io_size);
+                       set_ltab(c, lnum, c->leb_size - alen, alen - len);
+                       memset(p, 0xff, alen - len);
+-                      err = ubi_leb_change(c->ubi, lnum++, buf, alen,
+-                                           UBI_SHORTTERM);
++                      err = ubifs_leb_change(c, lnum++, buf, alen,
++                                             UBI_SHORTTERM);
+                       if (err)
+                               goto out;
+                       p = buf;
+@@ -806,7 +806,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+               alen = ALIGN(len, c->min_io_size);
+               set_ltab(c, lnum, c->leb_size - alen, alen - len);
+               memset(p, 0xff, alen - len);
+-              err = ubi_leb_change(c->ubi, lnum++, buf, alen, UBI_SHORTTERM);
++              err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
+               if (err)
+                       goto out;
+               p = buf;
+@@ -826,7 +826,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
+       /* Write remaining buffer */
+       memset(p, 0xff, alen - len);
+-      err = ubi_leb_change(c->ubi, lnum, buf, alen, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
+       if (err)
+               goto out;
+@@ -1222,7 +1222,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+               if (c->big_lpt)
+                       nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+       } else {
+-              err = ubi_read(c->ubi, lnum, buf, offs, c->nnode_sz);
++              err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
+               if (err)
+                       goto out;
+               err = ubifs_unpack_nnode(c, buf, nnode);
+@@ -1247,6 +1247,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+ out:
+       ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
++      dbg_dump_stack();
+       kfree(nnode);
+       return err;
+ }
+@@ -1270,10 +1271,9 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+       lnum = branch->lnum;
+       offs = branch->offs;
+       pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+-      if (!pnode) {
+-              err = -ENOMEM;
+-              goto out;
+-      }
++      if (!pnode)
++              return -ENOMEM;
++
+       if (lnum == 0) {
+               /*
+                * This pnode was not written which just means that the LEB
+@@ -1291,7 +1291,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+                       lprops->flags = ubifs_categorize_lprops(c, lprops);
+               }
+       } else {
+-              err = ubi_read(c->ubi, lnum, buf, offs, c->pnode_sz);
++              err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
+               if (err)
+                       goto out;
+               err = unpack_pnode(c, buf, pnode);
+@@ -1313,6 +1313,7 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
+ out:
+       ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
+       dbg_dump_pnode(c, pnode, parent, iip);
++      dbg_dump_stack();
+       dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
+       kfree(pnode);
+       return err;
+@@ -1332,7 +1333,7 @@ static int read_ltab(struct ubifs_info *c)
+       buf = vmalloc(c->ltab_sz);
+       if (!buf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz);
++      err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
+       if (err)
+               goto out;
+       err = unpack_ltab(c, buf);
+@@ -1355,7 +1356,8 @@ static int read_lsave(struct ubifs_info *c)
+       buf = vmalloc(c->lsave_sz);
+       if (!buf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, c->lsave_lnum, buf, c->lsave_offs, c->lsave_sz);
++      err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
++                           c->lsave_sz, 1);
+       if (err)
+               goto out;
+       err = unpack_lsave(c, buf);
+@@ -1815,8 +1817,8 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
+               if (c->big_lpt)
+                       nnode->num = calc_nnode_num_from_parent(c, parent, iip);
+       } else {
+-              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
+-                             c->nnode_sz);
++              err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
++                                   c->nnode_sz, 1);
+               if (err)
+                       return ERR_PTR(err);
+               err = ubifs_unpack_nnode(c, buf, nnode);
+@@ -1884,8 +1886,8 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
+               ubifs_assert(branch->lnum >= c->lpt_first &&
+                            branch->lnum <= c->lpt_last);
+               ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
+-              err = ubi_read(c->ubi, branch->lnum, buf, branch->offs,
+-                             c->pnode_sz);
++              err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
++                                   c->pnode_sz, 1);
+               if (err)
+                       return ERR_PTR(err);
+               err = unpack_pnode(c, buf, pnode);
+@@ -1984,12 +1986,11 @@ again:
+                               if (path[h].in_tree)
+                                       continue;
+-                              nnode = kmalloc(sz, GFP_NOFS);
++                              nnode = kmemdup(&path[h].nnode, sz, GFP_NOFS);
+                               if (!nnode) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
+-                              memcpy(nnode, &path[h].nnode, sz);
+                               parent = nnode->parent;
+                               parent->nbranch[nnode->iip].nnode = nnode;
+                               path[h].ptr.nnode = nnode;
+@@ -2002,12 +2003,11 @@ again:
+                               const size_t sz = sizeof(struct ubifs_pnode);
+                               struct ubifs_nnode *parent;
+-                              pnode = kmalloc(sz, GFP_NOFS);
++                              pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS);
+                               if (!pnode) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
+-                              memcpy(pnode, &path[h].pnode, sz);
+                               parent = pnode->parent;
+                               parent->nbranch[pnode->iip].pnode = pnode;
+                               path[h].ptr.pnode = pnode;
+@@ -2225,7 +2225,7 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
+       struct ubifs_cnode *cn;
+       int num, iip = 0, err;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       while (cnode) {
+diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
+index 5c90dec..cddd6bd 100644
+--- a/fs/ubifs/lpt_commit.c
++++ b/fs/ubifs/lpt_commit.c
+@@ -27,8 +27,15 @@
+ #include <linux/crc16.h>
+ #include <linux/slab.h>
++#include <linux/random.h>
+ #include "ubifs.h"
++#ifdef CONFIG_UBIFS_FS_DEBUG
++static int dbg_populate_lsave(struct ubifs_info *c);
++#else
++#define dbg_populate_lsave(c) 0
++#endif
++
+ /**
+  * first_dirty_cnode - find first dirty cnode.
+  * @c: UBIFS file-system description object
+@@ -110,8 +117,8 @@ static int get_cnodes_to_commit(struct ubifs_info *c)
+               return 0;
+       cnt += 1;
+       while (1) {
+-              ubifs_assert(!test_bit(COW_ZNODE, &cnode->flags));
+-              __set_bit(COW_ZNODE, &cnode->flags);
++              ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
++              __set_bit(COW_CNODE, &cnode->flags);
+               cnext = next_dirty_cnode(cnode);
+               if (!cnext) {
+                       cnode->cnext = c->lpt_cnext;
+@@ -459,7 +466,7 @@ static int write_cnodes(struct ubifs_info *c)
+                */
+               clear_bit(DIRTY_CNODE, &cnode->flags);
+               smp_mb__before_clear_bit();
+-              clear_bit(COW_ZNODE, &cnode->flags);
++              clear_bit(COW_CNODE, &cnode->flags);
+               smp_mb__after_clear_bit();
+               offs += len;
+               dbg_chk_lpt_sz(c, 1, len);
+@@ -586,7 +593,7 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
+                       if (nnode->nbranch[iip].lnum)
+                               break;
+               }
+-       } while (iip >= UBIFS_LPT_FANOUT);
++      } while (iip >= UBIFS_LPT_FANOUT);
+       /* Go right */
+       nnode = ubifs_get_nnode(c, nnode, iip);
+@@ -815,6 +822,10 @@ static void populate_lsave(struct ubifs_info *c)
+               c->lpt_drty_flgs |= LSAVE_DIRTY;
+               ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
+       }
++
++      if (dbg_populate_lsave(c))
++              return;
++
+       list_for_each_entry(lprops, &c->empty_list, list) {
+               c->lsave[cnt++] = lprops->lnum;
+               if (cnt >= c->lsave_cnt)
+@@ -1150,11 +1161,11 @@ static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
+       void *buf = c->lpt_buf;
+       dbg_lp("LEB %d", lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              ubifs_err("cannot read LEB %d, error %d", lnum, err);
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
+               return err;
+-      }
++
+       while (1) {
+               if (!is_a_node(c, buf, len)) {
+                       int pad_len;
+@@ -1628,29 +1639,35 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
+ {
+       int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
+       int ret;
+-      void *buf = c->dbg->buf;
++      void *buf, *p;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+-      dbg_lp("LEB %d", lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              dbg_msg("ubi_read failed, LEB %d, error %d", lnum, err);
+-              return err;
++      buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory for ltab checking");
++              return 0;
+       }
++
++      dbg_lp("LEB %d", lnum);
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
++              goto out;
++
+       while (1) {
+-              if (!is_a_node(c, buf, len)) {
++              if (!is_a_node(c, p, len)) {
+                       int i, pad_len;
+-                      pad_len = get_pad_len(c, buf, len);
++                      pad_len = get_pad_len(c, p, len);
+                       if (pad_len) {
+-                              buf += pad_len;
++                              p += pad_len;
+                               len -= pad_len;
+                               dirty += pad_len;
+                               continue;
+                       }
+-                      if (!dbg_is_all_ff(buf, len)) {
++                      if (!dbg_is_all_ff(p, len)) {
+                               dbg_msg("invalid empty space in LEB %d at %d",
+                                       lnum, c->leb_size - len);
+                               err = -EINVAL;
+@@ -1668,16 +1685,21 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
+                                       lnum, dirty, c->ltab[i].dirty);
+                               err = -EINVAL;
+                       }
+-                      return err;
++                      goto out;
+               }
+-              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_type = get_lpt_node_type(c, p, &node_num);
+               node_len = get_lpt_node_len(c, node_type);
+               ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len);
+               if (ret == 1)
+                       dirty += node_len;
+-              buf += node_len;
++              p += node_len;
+               len -= node_len;
+       }
++
++      err = 0;
++out:
++      vfree(buf);
++      return err;
+ }
+ /**
+@@ -1690,7 +1712,7 @@ int dbg_check_ltab(struct ubifs_info *c)
+ {
+       int lnum, err, i, cnt;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       /* Bring the entire tree into memory */
+@@ -1733,7 +1755,7 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
+       long long free = 0;
+       int i;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       for (i = 0; i < c->lpt_lebs; i++) {
+@@ -1775,7 +1797,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+       long long chk_lpt_sz, lpt_sz;
+       int err = 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
++      if (!dbg_is_chk_lprops(c))
+               return 0;
+       switch (action) {
+@@ -1870,25 +1892,30 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+ {
+       int err, len = c->leb_size, node_type, node_num, node_len, offs;
+-      void *buf = c->dbg->buf;
++      void *buf, *p;
+       printk(KERN_DEBUG "(pid %d) start dumping LEB %d\n",
+              current->pid, lnum);
+-      err = ubi_read(c->ubi, lnum, buf, 0, c->leb_size);
+-      if (err) {
+-              ubifs_err("cannot read LEB %d, error %d", lnum, err);
++      buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory to dump LPT");
+               return;
+       }
++
++      err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
++      if (err)
++              goto out;
++
+       while (1) {
+               offs = c->leb_size - len;
+-              if (!is_a_node(c, buf, len)) {
++              if (!is_a_node(c, p, len)) {
+                       int pad_len;
+-                      pad_len = get_pad_len(c, buf, len);
++                      pad_len = get_pad_len(c, p, len);
+                       if (pad_len) {
+                               printk(KERN_DEBUG "LEB %d:%d, pad %d bytes\n",
+                                      lnum, offs, pad_len);
+-                              buf += pad_len;
++                              p += pad_len;
+                               len -= pad_len;
+                               continue;
+                       }
+@@ -1898,7 +1925,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       break;
+               }
+-              node_type = get_lpt_node_type(c, buf, &node_num);
++              node_type = get_lpt_node_type(c, p, &node_num);
+               switch (node_type) {
+               case UBIFS_LPT_PNODE:
+               {
+@@ -1923,7 +1950,7 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       else
+                               printk(KERN_DEBUG "LEB %d:%d, nnode, ",
+                                      lnum, offs);
+-                      err = ubifs_unpack_nnode(c, buf, &nnode);
++                      err = ubifs_unpack_nnode(c, p, &nnode);
+                       for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
+                               printk(KERN_CONT "%d:%d", nnode.nbranch[i].lnum,
+                                      nnode.nbranch[i].offs);
+@@ -1944,15 +1971,18 @@ static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+                       break;
+               default:
+                       ubifs_err("LPT node type %d not recognized", node_type);
+-                      return;
++                      goto out;
+               }
+-              buf += node_len;
++              p += node_len;
+               len -= node_len;
+       }
+       printk(KERN_DEBUG "(pid %d) finish dumping LEB %d\n",
+              current->pid, lnum);
++out:
++      vfree(buf);
++      return;
+ }
+ /**
+@@ -1974,4 +2004,47 @@ void dbg_dump_lpt_lebs(const struct ubifs_info *c)
+              current->pid);
+ }
++/**
++ * dbg_populate_lsave - debugging version of 'populate_lsave()'
++ * @c: UBIFS file-system description object
++ *
++ * This is a debugging version for 'populate_lsave()' which populates lsave
++ * with random LEBs instead of useful LEBs, which is good for test coverage.
++ * Returns zero if lsave has not been populated (this debugging feature is
++ * disabled) an non-zero if lsave has been populated.
++ */
++static int dbg_populate_lsave(struct ubifs_info *c)
++{
++      struct ubifs_lprops *lprops;
++      struct ubifs_lpt_heap *heap;
++      int i;
++
++      if (!dbg_is_chk_gen(c))
++              return 0;
++      if (random32() & 3)
++              return 0;
++
++      for (i = 0; i < c->lsave_cnt; i++)
++              c->lsave[i] = c->main_first;
++
++      list_for_each_entry(lprops, &c->empty_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++      list_for_each_entry(lprops, &c->freeable_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++      list_for_each_entry(lprops, &c->frdi_idx_list, list)
++              c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
++
++      heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++      heap = &c->lpt_heap[LPROPS_DIRTY - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++      heap = &c->lpt_heap[LPROPS_FREE - 1];
++      for (i = 0; i < heap->cnt; i++)
++              c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
++
++      return 1;
++}
++
+ #endif /* CONFIG_UBIFS_FS_DEBUG */
+diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
+index 21f47af..278c238 100644
+--- a/fs/ubifs/master.c
++++ b/fs/ubifs/master.c
+@@ -148,7 +148,7 @@ static int validate_master(const struct ubifs_info *c)
+       }
+       main_sz = (long long)c->main_lebs * c->leb_size;
+-      if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
++      if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
+               err = 9;
+               goto out;
+       }
+@@ -218,7 +218,7 @@ static int validate_master(const struct ubifs_info *c)
+       }
+       if (c->lst.total_dead + c->lst.total_dark +
+-          c->lst.total_used + c->old_idx_sz > main_sz) {
++          c->lst.total_used + c->bi.old_idx_sz > main_sz) {
+               err = 21;
+               goto out;
+       }
+@@ -286,7 +286,7 @@ int ubifs_read_master(struct ubifs_info *c)
+       c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
+       c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
+       c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
+-      c->old_idx_sz      = le64_to_cpu(c->mst_node->index_size);
++      c->bi.old_idx_sz   = le64_to_cpu(c->mst_node->index_size);
+       c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
+       c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
+       c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
+@@ -305,7 +305,7 @@ int ubifs_read_master(struct ubifs_info *c)
+       c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
+       c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
+-      c->calc_idx_sz = c->old_idx_sz;
++      c->calc_idx_sz = c->bi.old_idx_sz;
+       if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
+               c->no_orphs = 1;
+diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
+index c3de04d..ee7cb5e 100644
+--- a/fs/ubifs/misc.h
++++ b/fs/ubifs/misc.h
+@@ -39,6 +39,29 @@ static inline int ubifs_zn_dirty(const struct ubifs_znode *znode)
+ }
+ /**
++ * ubifs_zn_obsolete - check if znode is obsolete.
++ * @znode: znode to check
++ *
++ * This helper function returns %1 if @znode is obsolete and %0 otherwise.
++ */
++static inline int ubifs_zn_obsolete(const struct ubifs_znode *znode)
++{
++      return !!test_bit(OBSOLETE_ZNODE, &znode->flags);
++}
++
++/**
++ * ubifs_zn_cow - check if znode has to be copied on write.
++ * @znode: znode to check
++ *
++ * This helper function returns %1 if @znode is has COW flag set and %0
++ * otherwise.
++ */
++static inline int ubifs_zn_cow(const struct ubifs_znode *znode)
++{
++      return !!test_bit(COW_ZNODE, &znode->flags);
++}
++
++/**
+  * ubifs_wake_up_bgt - wake up background thread.
+  * @c: UBIFS file-system description object
+  */
+@@ -122,86 +145,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
+ }
+ /**
+- * ubifs_leb_unmap - unmap an LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to unmap
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_unmap(const struct ubifs_info *c, int lnum)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_unmap(c->ubi, lnum);
+-      if (err) {
+-              ubifs_err("unmap LEB %d failed, error %d", lnum, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+- * ubifs_leb_write - write to a LEB.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to write
+- * @buf: buffer to write from
+- * @offs: offset within LEB to write to
+- * @len: length to write
+- * @dtype: data type
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_write(const struct ubifs_info *c, int lnum,
+-                                const void *buf, int offs, int len, int dtype)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+-      if (err) {
+-              ubifs_err("writing %d bytes at %d:%d, error %d",
+-                        len, lnum, offs, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+- * ubifs_leb_change - atomic LEB change.
+- * @c: UBIFS file-system description object
+- * @lnum: LEB number to write
+- * @buf: buffer to write from
+- * @len: length to write
+- * @dtype: data type
+- *
+- * This function returns %0 on success and a negative error code on failure.
+- */
+-static inline int ubifs_leb_change(const struct ubifs_info *c, int lnum,
+-                                 const void *buf, int len, int dtype)
+-{
+-      int err;
+-
+-      ubifs_assert(!c->ro_media && !c->ro_mount);
+-      if (c->ro_error)
+-              return -EROFS;
+-      err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+-      if (err) {
+-              ubifs_err("changing %d bytes in LEB %d, error %d",
+-                        len, lnum, err);
+-              return err;
+-      }
+-
+-      return 0;
+-}
+-
+-/**
+  * ubifs_encode_dev - encode device node IDs.
+  * @dev: UBIFS device node information
+  * @rdev: device IDs to encode
+@@ -340,4 +283,21 @@ static inline void ubifs_release_lprops(struct ubifs_info *c)
+       mutex_unlock(&c->lp_mutex);
+ }
++/**
++ * ubifs_next_log_lnum - switch to the next log LEB.
++ * @c: UBIFS file-system description object
++ * @lnum: current log LEB
++ *
++ * This helper function returns the log LEB number which goes next after LEB
++ * 'lnum'.
++ */
++static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
++{
++      lnum += 1;
++      if (lnum > c->log_last)
++              lnum = UBIFS_LOG_LNUM;
++
++      return lnum;
++}
++
+ #endif /* __UBIFS_MISC_H__ */
+diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
+index 82009c7..c542c73 100644
+--- a/fs/ubifs/orphan.c
++++ b/fs/ubifs/orphan.c
+@@ -673,7 +673,8 @@ static int kill_orphans(struct ubifs_info *c)
+               sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
+               if (IS_ERR(sleb)) {
+                       if (PTR_ERR(sleb) == -EUCLEAN)
+-                              sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
++                              sleb = ubifs_recover_leb(c, lnum, 0,
++                                                       c->sbuf, -1);
+                       if (IS_ERR(sleb)) {
+                               err = PTR_ERR(sleb);
+                               break;
+@@ -892,15 +893,22 @@ static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb)
+ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
+ {
+       int lnum, err = 0;
++      void *buf;
+       /* Check no-orphans flag and skip this if no orphans */
+       if (c->no_orphs)
+               return 0;
++      buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
++      if (!buf) {
++              ubifs_err("cannot allocate memory to check orphans");
++              return 0;
++      }
++
+       for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+               struct ubifs_scan_leb *sleb;
+-              sleb = ubifs_scan(c, lnum, 0, c->dbg->buf, 0);
++              sleb = ubifs_scan(c, lnum, 0, buf, 0);
+               if (IS_ERR(sleb)) {
+                       err = PTR_ERR(sleb);
+                       break;
+@@ -912,6 +920,7 @@ static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
+                       break;
+       }
++      vfree(buf);
+       return err;
+ }
+@@ -920,7 +929,7 @@ static int dbg_check_orphans(struct ubifs_info *c)
+       struct check_info ci;
+       int err;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_ORPH))
++      if (!dbg_is_chk_orph(c))
+               return 0;
+       ci.last_ino = 0;
+diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
+index 77e9b87..2a935b3 100644
+--- a/fs/ubifs/recovery.c
++++ b/fs/ubifs/recovery.c
+@@ -28,6 +28,23 @@
+  * UBIFS always cleans away all remnants of an unclean un-mount, so that
+  * errors do not accumulate. However UBIFS defers recovery if it is mounted
+  * read-only, and the flash is not modified in that case.
++ *
++ * The general UBIFS approach to the recovery is that it recovers from
++ * corruptions which could be caused by power cuts, but it refuses to recover
++ * from corruption caused by other reasons. And UBIFS tries to distinguish
++ * between these 2 reasons of corruptions and silently recover in the former
++ * case and loudly complain in the latter case.
++ *
++ * UBIFS writes only to erased LEBs, so it writes only to the flash space
++ * containing only 0xFFs. UBIFS also always writes strictly from the beginning
++ * of the LEB to the end. And UBIFS assumes that the underlying flash media
++ * writes in @c->max_write_size bytes at a time.
++ *
++ * Hence, if UBIFS finds a corrupted node at offset X, it expects only the min.
++ * I/O unit corresponding to offset X to contain corrupted data, all the
++ * following min. I/O units have to contain empty space (all 0xFFs). If this is
++ * not true, the corruption cannot be the result of a power cut, and UBIFS
++ * refuses to mount.
+  */
+ #include <linux/crc32.h>
+@@ -100,7 +117,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
+       if (!sbuf)
+               return -ENOMEM;
+-      err = ubi_read(c->ubi, lnum, sbuf, 0, c->leb_size);
++      err = ubifs_leb_read(c, lnum, sbuf, 0, c->leb_size, 0);
+       if (err && err != -EBADMSG)
+               goto out_free;
+@@ -196,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
+       mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
+       ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
+-      err = ubi_leb_change(c->ubi, lnum, mst, sz, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
+       if (err)
+               goto out;
+-      err = ubi_leb_change(c->ubi, lnum + 1, mst, sz, UBI_SHORTTERM);
++      err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
+       if (err)
+               goto out;
+ out:
+@@ -257,7 +274,8 @@ int ubifs_recover_master_node(struct ubifs_info *c)
+                               if (cor1)
+                                       goto out_err;
+                               mst = mst1;
+-                      } else if (offs1 == 0 && offs2 + sz >= c->leb_size) {
++                      } else if (offs1 == 0 &&
++                                 c->leb_size - offs2 - sz < sz) {
+                               /* 1st LEB was unmapped and written, 2nd not */
+                               if (cor1)
+                                       goto out_err;
+@@ -300,6 +318,32 @@ int ubifs_recover_master_node(struct ubifs_info *c)
+                       goto out_free;
+               }
+               memcpy(c->rcvrd_mst_node, c->mst_node, UBIFS_MST_NODE_SZ);
++
++              /*
++               * We had to recover the master node, which means there was an
++               * unclean reboot. However, it is possible that the master node
++               * is clean at this point, i.e., %UBIFS_MST_DIRTY is not set.
++               * E.g., consider the following chain of events:
++               *
++               * 1. UBIFS was cleanly unmounted, so the master node is clean
++               * 2. UBIFS is being mounted R/W and starts changing the master
++               *    node in the first (%UBIFS_MST_LNUM). A power cut happens,
++               *    so this LEB ends up with some amount of garbage at the
++               *    end.
++               * 3. UBIFS is being mounted R/O. We reach this place and
++               *    recover the master node from the second LEB
++               *    (%UBIFS_MST_LNUM + 1). But we cannot update the media
++               *    because we are being mounted R/O. We have to defer the
++               *    operation.
++               * 4. However, this master node (@c->mst_node) is marked as
++               *    clean (since the step 1). And if we just return, the
++               *    mount code will be confused and won't recover the master
++               *    node when it is re-mounter R/W later.
++               *
++               *    Thus, to force the recovery by marking the master node as
++               *    dirty.
++               */
++              c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+       } else {
+               /* Write the recovered master node */
+               c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;
+@@ -362,8 +406,9 @@ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
+  * @offs: offset to check
+  *
+  * This function returns %1 if @offs was in the last write to the LEB whose data
+- * is in @buf, otherwise %0 is returned.  The determination is made by checking
+- * for subsequent empty space starting from the next @c->min_io_size boundary.
++ * is in @buf, otherwise %0 is returned. The determination is made by checking
++ * for subsequent empty space starting from the next @c->max_write_size
++ * boundary.
+  */
+ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+ {
+@@ -371,10 +416,10 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs)
+       uint8_t *p;
+       /*
+-       * Round up to the next @c->min_io_size boundary i.e. @offs is in the
+-       * last wbuf written. After that should be empty space.
++       * Round up to the next @c->max_write_size boundary i.e. @offs is in
++       * the last wbuf written. After that should be empty space.
+        */
+-      empty_offs = ALIGN(offs + 1, c->min_io_size);
++      empty_offs = ALIGN(offs + 1, c->max_write_size);
+       check_len = c->leb_size - empty_offs;
+       p = buf + empty_offs - offs;
+       return is_empty(p, check_len);
+@@ -429,7 +474,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+       int skip, dlen = le32_to_cpu(ch->len);
+       /* Check for empty space after the corrupt node's common header */
+-      skip = ALIGN(offs + UBIFS_CH_SZ, c->min_io_size) - offs;
++      skip = ALIGN(offs + UBIFS_CH_SZ, c->max_write_size) - offs;
+       if (is_empty(buf + skip, len - skip))
+               return 1;
+       /*
+@@ -441,7 +486,7 @@ static int no_more_nodes(const struct ubifs_info *c, void *buf, int len,
+               return 0;
+       }
+       /* Now we know the corrupt node's length we can skip over it */
+-      skip = ALIGN(offs + dlen, c->min_io_size) - offs;
++      skip = ALIGN(offs + dlen, c->max_write_size) - offs;
+       /* After which there should be empty space */
+       if (is_empty(buf + skip, len - skip))
+               return 1;
+@@ -495,8 +540,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+                       int len = ALIGN(endpt, c->min_io_size);
+                       if (start) {
+-                              err = ubi_read(c->ubi, lnum, sleb->buf, 0,
+-                                             start);
++                              err = ubifs_leb_read(c, lnum, sleb->buf, 0,
++                                                   start, 1);
+                               if (err)
+                                       return err;
+                       }
+@@ -510,8 +555,8 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+                                       ubifs_pad(c, buf, pad_len);
+                               }
+                       }
+-                      err = ubi_leb_change(c->ubi, lnum, sleb->buf, len,
+-                                           UBI_UNKNOWN);
++                      err = ubifs_leb_change(c, lnum, sleb->buf, len,
++                                             UBI_UNKNOWN);
+                       if (err)
+                               return err;
+               }
+@@ -520,16 +565,15 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
+ }
+ /**
+- * drop_incomplete_group - drop nodes from an incomplete group.
++ * drop_last_group - drop the last group of nodes.
+  * @sleb: scanned LEB information
+  * @offs: offset of dropped nodes is returned here
+  *
+- * This function returns %1 if nodes are dropped and %0 otherwise.
++ * This is a helper function for 'ubifs_recover_leb()' which drops the last
++ * group of nodes of the scanned LEB.
+  */
+-static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
++static void drop_last_group(struct ubifs_scan_leb *sleb, int *offs)
+ {
+-      int dropped = 0;
+-
+       while (!list_empty(&sleb->nodes)) {
+               struct ubifs_scan_node *snod;
+               struct ubifs_ch *ch;
+@@ -538,15 +582,40 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+                                 list);
+               ch = snod->node;
+               if (ch->group_type != UBIFS_IN_NODE_GROUP)
+-                      return dropped;
+-              dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
++                      break;
++
++              dbg_rcvry("dropping grouped node at %d:%d",
++                        sleb->lnum, snod->offs);
++              *offs = snod->offs;
++              list_del(&snod->list);
++              kfree(snod);
++              sleb->nodes_cnt -= 1;
++      }
++}
++
++/**
++ * drop_last_node - drop the last node.
++ * @sleb: scanned LEB information
++ * @offs: offset of dropped nodes is returned here
++ * @grouped: non-zero if whole group of nodes have to be dropped
++ *
++ * This is a helper function for 'ubifs_recover_leb()' which drops the last
++ * node of the scanned LEB.
++ */
++static void drop_last_node(struct ubifs_scan_leb *sleb, int *offs)
++{
++      struct ubifs_scan_node *snod;
++
++      if (!list_empty(&sleb->nodes)) {
++              snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
++                                list);
++
++              dbg_rcvry("dropping last node at %d:%d", sleb->lnum, snod->offs);
+               *offs = snod->offs;
+               list_del(&snod->list);
+               kfree(snod);
+               sleb->nodes_cnt -= 1;
+-              dropped = 1;
+       }
+-      return dropped;
+ }
+ /**
+@@ -555,7 +624,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+  * @lnum: LEB number
+  * @offs: offset
+  * @sbuf: LEB-sized buffer to use
+- * @grouped: nodes may be grouped for recovery
++ * @jhead: journal head number this LEB belongs to (%-1 if the LEB does not
++ *         belong to any journal head)
+  *
+  * This function does a scan of a LEB, but caters for errors that might have
+  * been caused by the unclean unmount from which we are attempting to recover.
+@@ -563,25 +633,21 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+  * found, and a negative error code in case of failure.
+  */
+ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+-                                       int offs, void *sbuf, int grouped)
++                                       int offs, void *sbuf, int jhead)
+ {
+-      int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
+-      int empty_chkd = 0, start = offs;
++      int ret = 0, err, len = c->leb_size - offs, start = offs, min_io_unit;
++      int grouped = jhead == -1 ? 0 : c->jheads[jhead].grouped;
+       struct ubifs_scan_leb *sleb;
+       void *buf = sbuf + offs;
+-      dbg_rcvry("%d:%d", lnum, offs);
++      dbg_rcvry("%d:%d, jhead %d, grouped %d", lnum, offs, jhead, grouped);
+       sleb = ubifs_start_scan(c, lnum, offs, sbuf);
+       if (IS_ERR(sleb))
+               return sleb;
+-      if (sleb->ecc)
+-              need_clean = 1;
+-
++      ubifs_assert(len >= 8);
+       while (len >= 8) {
+-              int ret;
+-
+               dbg_scan("look at LEB %d:%d (%d bytes left)",
+                        lnum, offs, len);
+@@ -591,8 +657,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+                * Scan quietly until there is an error from which we cannot
+                * recover
+                */
+-              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
+-
++              ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+               if (ret == SCANNED_A_NODE) {
+                       /* A valid node, and not a padding node */
+                       struct ubifs_ch *ch = buf;
+@@ -605,104 +670,127 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+                       offs += node_len;
+                       buf += node_len;
+                       len -= node_len;
+-                      continue;
+-              }
+-
+-              if (ret > 0) {
++              } else if (ret > 0) {
+                       /* Padding bytes or a valid padding node */
+                       offs += ret;
+                       buf += ret;
+                       len -= ret;
+-                      continue;
+-              }
+-
+-              if (ret == SCANNED_EMPTY_SPACE) {
+-                      if (!is_empty(buf, len)) {
+-                              if (!is_last_write(c, buf, offs))
+-                                      break;
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                      }
+-                      empty_chkd = 1;
++              } else if (ret == SCANNED_EMPTY_SPACE ||
++                         ret == SCANNED_GARBAGE     ||
++                         ret == SCANNED_A_BAD_PAD_NODE ||
++                         ret == SCANNED_A_CORRUPT_NODE) {
++                      dbg_rcvry("found corruption (%d) at %d:%d",
++                                ret, lnum, offs);
+                       break;
+-              }
+-
+-              if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
+-                      if (is_last_write(c, buf, offs)) {
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                              empty_chkd = 1;
+-                              break;
+-                      }
+-
+-              if (ret == SCANNED_A_CORRUPT_NODE)
+-                      if (no_more_nodes(c, buf, len, lnum, offs)) {
+-                              clean_buf(c, &buf, lnum, &offs, &len);
+-                              need_clean = 1;
+-                              empty_chkd = 1;
+-                              break;
+-                      }
+-
+-              if (quiet) {
+-                      /* Redo the last scan but noisily */
+-                      quiet = 0;
+-                      continue;
+-              }
+-
+-              switch (ret) {
+-              case SCANNED_GARBAGE:
+-                      dbg_err("garbage");
+-                      goto corrupted;
+-              case SCANNED_A_CORRUPT_NODE:
+-              case SCANNED_A_BAD_PAD_NODE:
+-                      dbg_err("bad node");
+-                      goto corrupted;
+-              default:
+-                      dbg_err("unknown");
++              } else {
++                      dbg_err("unexpected return value %d", ret);
+                       err = -EINVAL;
+                       goto error;
+               }
+       }
+-      if (!empty_chkd && !is_empty(buf, len)) {
+-              if (is_last_write(c, buf, offs)) {
+-                      clean_buf(c, &buf, lnum, &offs, &len);
+-                      need_clean = 1;
+-              } else {
++      if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE) {
++              if (!is_last_write(c, buf, offs))
++                      goto corrupted_rescan;
++      } else if (ret == SCANNED_A_CORRUPT_NODE) {
++              if (!no_more_nodes(c, buf, len, lnum, offs))
++                      goto corrupted_rescan;
++      } else if (!is_empty(buf, len)) {
++              if (!is_last_write(c, buf, offs)) {
+                       int corruption = first_non_ff(buf, len);
++                      /*
++                       * See header comment for this file for more
++                       * explanations about the reasons we have this check.
++                       */
+                       ubifs_err("corrupt empty space LEB %d:%d, corruption "
+                                 "starts at %d", lnum, offs, corruption);
+                       /* Make sure we dump interesting non-0xFF data */
+-                      offs = corruption;
++                      offs += corruption;
+                       buf += corruption;
+                       goto corrupted;
+               }
+       }
+-      /* Drop nodes from incomplete group */
+-      if (grouped && drop_incomplete_group(sleb, &offs)) {
+-              buf = sbuf + offs;
+-              len = c->leb_size - offs;
+-              clean_buf(c, &buf, lnum, &offs, &len);
+-              need_clean = 1;
+-      }
++      min_io_unit = round_down(offs, c->min_io_size);
++      if (grouped)
++              /*
++               * If nodes are grouped, always drop the incomplete group at
++               * the end.
++               */
++              drop_last_group(sleb, &offs);
+-      if (offs % c->min_io_size) {
+-              clean_buf(c, &buf, lnum, &offs, &len);
+-              need_clean = 1;
++      if (jhead == GCHD) {
++              /*
++               * If this LEB belongs to the GC head then while we are in the
++               * middle of the same min. I/O unit keep dropping nodes. So
++               * basically, what we want is to make sure that the last min.
++               * I/O unit where we saw the corruption is dropped completely
++               * with all the uncorrupted nodes which may possibly sit there.
++               *
++               * In other words, let's name the min. I/O unit where the
++               * corruption starts B, and the previous min. I/O unit A. The
++               * below code tries to deal with a situation when half of B
++               * contains valid nodes or the end of a valid node, and the
++               * second half of B contains corrupted data or garbage. This
++               * means that UBIFS had been writing to B just before the power
++               * cut happened. I do not know how realistic is this scenario
++               * that half of the min. I/O unit had been written successfully
++               * and the other half not, but this is possible in our 'failure
++               * mode emulation' infrastructure at least.
++               *
++               * So what is the problem, why we need to drop those nodes? Why
++               * can't we just clean-up the second half of B by putting a
++               * padding node there? We can, and this works fine with one
++               * exception which was reproduced with power cut emulation
++               * testing and happens extremely rarely.
++               *
++               * Imagine the file-system is full, we run GC which starts
++               * moving valid nodes from LEB X to LEB Y (obviously, LEB Y is
++               * the current GC head LEB). The @c->gc_lnum is -1, which means
++               * that GC will retain LEB X and will try to continue. Imagine
++               * that LEB X is currently the dirtiest LEB, and the amount of
++               * used space in LEB Y is exactly the same as amount of free
++               * space in LEB X.
++               *
++               * And a power cut happens when nodes are moved from LEB X to
++               * LEB Y. We are here trying to recover LEB Y which is the GC
++               * head LEB. We find the min. I/O unit B as described above.
++               * Then we clean-up LEB Y by padding min. I/O unit. And later
++               * 'ubifs_rcvry_gc_commit()' function fails, because it cannot
++               * find a dirty LEB which could be GC'd into LEB Y! Even LEB X
++               * does not match because the amount of valid nodes there does
++               * not fit the free space in LEB Y any more! And this is
++               * because of the padding node which we added to LEB Y. The
++               * user-visible effect of this which I once observed and
++               * analysed is that we cannot mount the file-system with
++               * -ENOSPC error.
++               *
++               * So obviously, to make sure that situation does not happen we
++               * should free min. I/O unit B in LEB Y completely and the last
++               * used min. I/O unit in LEB Y should be A. This is basically
++               * what the below code tries to do.
++               */
++              while (offs > min_io_unit)
++                      drop_last_node(sleb, &offs);
+       }
++      buf = sbuf + offs;
++      len = c->leb_size - offs;
++
++      clean_buf(c, &buf, lnum, &offs, &len);
+       ubifs_end_scan(c, sleb, lnum, offs);
+-      if (need_clean) {
+-              err = fix_unclean_leb(c, sleb, start);
+-              if (err)
+-                      goto error;
+-      }
++      err = fix_unclean_leb(c, sleb, start);
++      if (err)
++              goto error;
+       return sleb;
++corrupted_rescan:
++      /* Re-scan the corrupted data with verbose messages */
++      dbg_err("corruptio %d", ret);
++      ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ corrupted:
+       ubifs_scanned_corruption(c, lnum, offs, buf);
+       err = -EUCLEAN;
+@@ -733,7 +821,8 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
+               return -ENOMEM;
+       if (c->leb_size - offs < UBIFS_CS_NODE_SZ)
+               goto out_err;
+-      err = ubi_read(c->ubi, lnum, (void *)cs_node, offs, UBIFS_CS_NODE_SZ);
++      err = ubifs_leb_read(c, lnum, (void *)cs_node, offs,
++                           UBIFS_CS_NODE_SZ, 0);
+       if (err && err != -EBADMSG)
+               goto out_free;
+       ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
+@@ -819,7 +908,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+               }
+               ubifs_scan_destroy(sleb);
+       }
+-      return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
++      return ubifs_recover_leb(c, lnum, offs, sbuf, -1);
+ }
+ /**
+@@ -833,15 +922,10 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+-                      void *sbuf)
++static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
+ {
+-      int len, err;
++      int len = c->max_write_size, err;
+-      if (c->min_io_size > 1)
+-              len = c->min_io_size;
+-      else
+-              len = 512;
+       if (offs + len > c->leb_size)
+               len = c->leb_size - offs;
+@@ -849,15 +933,15 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+               return 0;
+       /* Read at the head location and check it is empty flash */
+-      err = ubi_read(c->ubi, lnum, sbuf, offs, len);
++      err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
+       if (err || !is_empty(sbuf, len)) {
+               dbg_rcvry("cleaning head at %d:%d", lnum, offs);
+               if (offs == 0)
+                       return ubifs_leb_unmap(c, lnum);
+-              err = ubi_read(c->ubi, lnum, sbuf, 0, offs);
++              err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
+               if (err)
+                       return err;
+-              return ubi_leb_change(c->ubi, lnum, sbuf, offs, UBI_UNKNOWN);
++              return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
+       }
+       return 0;
+@@ -880,7 +964,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
++int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
+ {
+       int err;
+@@ -900,7 +984,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+ }
+ /**
+- *  clean_an_unclean_leb - read and write a LEB to remove corruption.
++ * clean_an_unclean_leb - read and write a LEB to remove corruption.
+  * @c: UBIFS file-system description object
+  * @ucleb: unclean LEB information
+  * @sbuf: LEB-sized buffer to use
+@@ -911,7 +995,7 @@ int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf)
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-static int clean_an_unclean_leb(const struct ubifs_info *c,
++static int clean_an_unclean_leb(struct ubifs_info *c,
+                               struct ubifs_unclean_leb *ucleb, void *sbuf)
+ {
+       int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
+@@ -927,7 +1011,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+               return 0;
+       }
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
+       if (err && err != -EBADMSG)
+               return err;
+@@ -987,7 +1071,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+       }
+       /* Write back the LEB atomically */
+-      err = ubi_leb_change(c->ubi, lnum, sbuf, len, UBI_UNKNOWN);
++      err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
+       if (err)
+               return err;
+@@ -1007,7 +1091,7 @@ static int clean_an_unclean_leb(const struct ubifs_info *c,
+  *
+  * This function returns %0 on success and a negative error code on failure.
+  */
+-int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
++int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
+ {
+       dbg_rcvry("recovery");
+       while (!list_empty(&c->unclean_leb_list)) {
+@@ -1026,6 +1110,53 @@ int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
+ }
+ /**
++ * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit.
++ * @c: UBIFS file-system description object
++ *
++ * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty
++ * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns
++ * zero in case of success and a negative error code in case of failure.
++ */
++static int grab_empty_leb(struct ubifs_info *c)
++{
++      int lnum, err;
++
++      /*
++       * Note, it is very important to first search for an empty LEB and then
++       * run the commit, not vice-versa. The reason is that there might be
++       * only one empty LEB at the moment, the one which has been the
++       * @c->gc_lnum just before the power cut happened. During the regular
++       * UBIFS operation (not now) @c->gc_lnum is marked as "taken", so no
++       * one but GC can grab it. But at this moment this single empty LEB is
++       * not marked as taken, so if we run commit - what happens? Right, the
++       * commit will grab it and write the index there. Remember that the
++       * index always expands as long as there is free space, and it only
++       * starts consolidating when we run out of space.
++       *
++       * IOW, if we run commit now, we might not be able to find a free LEB
++       * after this.
++       */
++      lnum = ubifs_find_free_leb_for_idx(c);
++      if (lnum < 0) {
++              dbg_err("could not find an empty LEB");
++              dbg_dump_lprops(c);
++              dbg_dump_budg(c, &c->bi);
++              return lnum;
++      }
++
++      /* Reset the index flag */
++      err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
++                                LPROPS_INDEX, 0);
++      if (err)
++              return err;
++
++      c->gc_lnum = lnum;
++      dbg_rcvry("found empty LEB %d, run commit", lnum);
++
++      return ubifs_run_commit(c);
++}
++
++/**
+  * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit.
+  * @c: UBIFS file-system description object
+  *
+@@ -1047,71 +1178,26 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+ {
+       struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
+       struct ubifs_lprops lp;
+-      int lnum, err;
++      int err;
++
++      dbg_rcvry("GC head LEB %d, offs %d", wbuf->lnum, wbuf->offs);
+       c->gc_lnum = -1;
+-      if (wbuf->lnum == -1) {
+-              dbg_rcvry("no GC head LEB");
+-              goto find_free;
+-      }
+-      /*
+-       * See whether the used space in the dirtiest LEB fits in the GC head
+-       * LEB.
+-       */
+-      if (wbuf->offs == c->leb_size) {
+-              dbg_rcvry("no room in GC head LEB");
+-              goto find_free;
+-      }
++      if (wbuf->lnum == -1 || wbuf->offs == c->leb_size)
++              return grab_empty_leb(c);
++
+       err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
+       if (err) {
+-              /*
+-               * There are no dirty or empty LEBs subject to here being
+-               * enough for the index. Try to use
+-               * 'ubifs_find_free_leb_for_idx()', which will return any empty
+-               * LEBs (ignoring index requirements). If the index then
+-               * doesn't have enough LEBs the recovery commit will fail -
+-               * which is the  same result anyway i.e. recovery fails. So
+-               * there is no problem ignoring index  requirements and just
+-               * grabbing a free LEB since we have already established there
+-               * is not a dirty LEB we could have used instead.
+-               */
+-              if (err == -ENOSPC) {
+-                      dbg_rcvry("could not find a dirty LEB");
+-                      goto find_free;
+-              }
+-              return err;
+-      }
+-      ubifs_assert(!(lp.flags & LPROPS_INDEX));
+-      lnum = lp.lnum;
+-      if (lp.free + lp.dirty == c->leb_size) {
+-              /* An empty LEB was returned */
+-              if (lp.free != c->leb_size) {
+-                      err = ubifs_change_one_lp(c, lnum, c->leb_size,
+-                                                0, 0, 0, 0);
+-                      if (err)
+-                              return err;
+-              }
+-              err = ubifs_leb_unmap(c, lnum);
+-              if (err)
+-                      return err;
+-              c->gc_lnum = lnum;
+-              dbg_rcvry("allocated LEB %d for GC", lnum);
+-              /* Run the commit */
+-              dbg_rcvry("committing");
+-              return ubifs_run_commit(c);
+-      }
+-      /*
+-       * There was no empty LEB so the used space in the dirtiest LEB must fit
+-       * in the GC head LEB.
+-       */
+-      if (lp.free + lp.dirty < wbuf->offs) {
+-              dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d",
+-                        lnum, wbuf->lnum, wbuf->offs);
+-              err = ubifs_return_leb(c, lnum);
+-              if (err)
++              if (err != -ENOSPC)
+                       return err;
+-              goto find_free;
++
++              dbg_rcvry("could not find a dirty LEB");
++              return grab_empty_leb(c);
+       }
++
++      ubifs_assert(!(lp.flags & LPROPS_INDEX));
++      ubifs_assert(lp.free + lp.dirty >= wbuf->offs);
++
+       /*
+        * We run the commit before garbage collection otherwise subsequent
+        * mounts will see the GC and orphan deletion in a different order.
+@@ -1120,11 +1206,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+       err = ubifs_run_commit(c);
+       if (err)
+               return err;
+-      /*
+-       * The data in the dirtiest LEB fits in the GC head LEB, so do the GC
+-       * - use locking to keep 'ubifs_assert()' happy.
+-       */
+-      dbg_rcvry("GC'ing LEB %d", lnum);
++
++      dbg_rcvry("GC'ing LEB %d", lp.lnum);
+       mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
+       err = ubifs_garbage_collect_leb(c, &lp);
+       if (err >= 0) {
+@@ -1140,37 +1223,17 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
+                       err = -EINVAL;
+               return err;
+       }
+-      if (err != LEB_RETAINED) {
+-              dbg_err("GC returned %d", err);
++
++      ubifs_assert(err == LEB_RETAINED);
++      if (err != LEB_RETAINED)
+               return -EINVAL;
+-      }
++
+       err = ubifs_leb_unmap(c, c->gc_lnum);
+       if (err)
+               return err;
+-      dbg_rcvry("allocated LEB %d for GC", lnum);
+-      return 0;
+-find_free:
+-      /*
+-       * There is no GC head LEB or the free space in the GC head LEB is too
+-       * small, or there are not dirty LEBs. Allocate gc_lnum by calling
+-       * 'ubifs_find_free_leb_for_idx()' so GC is not run.
+-       */
+-      lnum = ubifs_find_free_leb_for_idx(c);
+-      if (lnum < 0) {
+-              dbg_err("could not find an empty LEB");
+-              return lnum;
+-      }
+-      /* And reset the index flag */
+-      err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+-                                LPROPS_INDEX, 0);
+-      if (err)
+-              return err;
+-      c->gc_lnum = lnum;
+-      dbg_rcvry("allocated LEB %d for GC", lnum);
+-      /* Run the commit */
+-      dbg_rcvry("committing");
+-      return ubifs_run_commit(c);
++      dbg_rcvry("allocated LEB %d for GC", lp.lnum);
++      return 0;
+ }
+ /**
+@@ -1393,7 +1456,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
+       if (i_size >= e->d_size)
+               return 0;
+       /* Read the LEB */
+-      err = ubi_read(c->ubi, lnum, c->sbuf, 0, c->leb_size);
++      err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
+       if (err)
+               goto out;
+       /* Change the size field and recalculate the CRC */
+@@ -1409,10 +1472,10 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
+               len -= 1;
+       len = ALIGN(len + 1, c->min_io_size);
+       /* Atomically write the fixed LEB back again */
+-      err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
++      err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
+       if (err)
+               goto out;
+-      dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ",
++      dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
+                 (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
+       return 0;
+@@ -1461,20 +1524,27 @@ int ubifs_recover_size(struct ubifs_info *c)
+                               e->i_size = le64_to_cpu(ino->size);
+                       }
+               }
++
+               if (e->exists && e->i_size < e->d_size) {
+-                      if (!e->inode && c->ro_mount) {
++                      if (c->ro_mount) {
+                               /* Fix the inode size and pin it in memory */
+                               struct inode *inode;
++                              struct ubifs_inode *ui;
++
++                              ubifs_assert(!e->inode);
+                               inode = ubifs_iget(c->vfs_sb, e->inum);
+                               if (IS_ERR(inode))
+                                       return PTR_ERR(inode);
++
++                              ui = ubifs_inode(inode);
+                               if (inode->i_size < e->d_size) {
+                                       dbg_rcvry("ino %lu size %lld -> %lld",
+                                                 (unsigned long)e->inum,
+-                                                e->d_size, inode->i_size);
++                                                inode->i_size, e->d_size);
+                                       inode->i_size = e->d_size;
+-                                      ubifs_inode(inode)->ui_size = e->d_size;
++                                      ui->ui_size = e->d_size;
++                                      ui->synced_i_size = e->d_size;
+                                       e->inode = inode;
+                                       this = rb_next(this);
+                                       continue;
+@@ -1489,9 +1559,11 @@ int ubifs_recover_size(struct ubifs_info *c)
+                                       iput(e->inode);
+                       }
+               }
++
+               this = rb_next(this);
+               rb_erase(&e->rb, &c->size_tree);
+               kfree(e);
+       }
++
+       return 0;
+ }
+diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
+index eed0fcf..b007637 100644
+--- a/fs/ubifs/replay.c
++++ b/fs/ubifs/replay.c
+@@ -33,43 +33,32 @@
+  */
+ #include "ubifs.h"
+-
+-/*
+- * Replay flags.
+- *
+- * REPLAY_DELETION: node was deleted
+- * REPLAY_REF: node is a reference node
+- */
+-enum {
+-      REPLAY_DELETION = 1,
+-      REPLAY_REF = 2,
+-};
++#include <linux/list_sort.h>
+ /**
+- * struct replay_entry - replay tree entry.
++ * struct replay_entry - replay list entry.
+  * @lnum: logical eraseblock number of the node
+  * @offs: node offset
+  * @len: node length
++ * @deletion: non-zero if this entry corresponds to a node deletion
+  * @sqnum: node sequence number
+- * @flags: replay flags
+- * @rb: links the replay tree
++ * @list: links the replay list
+  * @key: node key
+  * @nm: directory entry name
+  * @old_size: truncation old size
+  * @new_size: truncation new size
+- * @free: amount of free space in a bud
+- * @dirty: amount of dirty space in a bud from padding and deletion nodes
+  *
+- * UBIFS journal replay must compare node sequence numbers, which means it must
+- * build a tree of node information to insert into the TNC.
++ * The replay process first scans all buds and builds the replay list, then
++ * sorts the replay list in nodes sequence number order, and then inserts all
++ * the replay entries to the TNC.
+  */
+ struct replay_entry {
+       int lnum;
+       int offs;
+       int len;
++      unsigned int deletion:1;
+       unsigned long long sqnum;
+-      int flags;
+-      struct rb_node rb;
++      struct list_head list;
+       union ubifs_key key;
+       union {
+               struct qstr nm;
+@@ -77,10 +66,6 @@ struct replay_entry {
+                       loff_t old_size;
+                       loff_t new_size;
+               };
+-              struct {
+-                      int free;
+-                      int dirty;
+-              };
+       };
+ };
+@@ -88,57 +73,64 @@ struct replay_entry {
+  * struct bud_entry - entry in the list of buds to replay.
+  * @list: next bud in the list
+  * @bud: bud description object
+- * @free: free bytes in the bud
+  * @sqnum: reference node sequence number
++ * @free: free bytes in the bud
++ * @dirty: dirty bytes in the bud
+  */
+ struct bud_entry {
+       struct list_head list;
+       struct ubifs_bud *bud;
+-      int free;
+       unsigned long long sqnum;
++      int free;
++      int dirty;
+ };
+ /**
+  * set_bud_lprops - set free and dirty space used by a bud.
+  * @c: UBIFS file-system description object
+- * @r: replay entry of bud
++ * @b: bud entry which describes the bud
++ *
++ * This function makes sure the LEB properties of bud @b are set correctly
++ * after the replay. Returns zero in case of success and a negative error code
++ * in case of failure.
+  */
+-static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
++static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
+ {
+       const struct ubifs_lprops *lp;
+       int err = 0, dirty;
+       ubifs_get_lprops(c);
+-      lp = ubifs_lpt_lookup_dirty(c, r->lnum);
++      lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
+       if (IS_ERR(lp)) {
+               err = PTR_ERR(lp);
+               goto out;
+       }
+       dirty = lp->dirty;
+-      if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
++      if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+               /*
+                * The LEB was added to the journal with a starting offset of
+                * zero which means the LEB must have been empty. The LEB
+-               * property values should be lp->free == c->leb_size and
+-               * lp->dirty == 0, but that is not the case. The reason is that
+-               * the LEB was garbage collected. The garbage collector resets
+-               * the free and dirty space without recording it anywhere except
+-               * lprops, so if there is not a commit then lprops does not have
+-               * that information next time the file system is mounted.
++               * property values should be @lp->free == @c->leb_size and
++               * @lp->dirty == 0, but that is not the case. The reason is that
++               * the LEB had been garbage collected before it became the bud,
++               * and there was not commit inbetween. The garbage collector
++               * resets the free and dirty space without recording it
++               * anywhere except lprops, so if there was no commit then
++               * lprops does not have that information.
+                *
+                * We do not need to adjust free space because the scan has told
+                * us the exact value which is recorded in the replay entry as
+-               * r->free.
++               * @b->free.
+                *
+                * However we do need to subtract from the dirty space the
+                * amount of space that the garbage collector reclaimed, which
+                * is the whole LEB minus the amount of space that was free.
+                */
+-              dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++              dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
+                       lp->free, lp->dirty);
+-              dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
++              dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
+                       lp->free, lp->dirty);
+               dirty -= c->leb_size - lp->free;
+               /*
+@@ -150,21 +142,48 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+                */
+               if (dirty != 0)
+                       dbg_msg("LEB %d lp: %d free %d dirty "
+-                              "replay: %d free %d dirty", r->lnum, lp->free,
+-                              lp->dirty, r->free, r->dirty);
++                              "replay: %d free %d dirty", b->bud->lnum,
++                              lp->free, lp->dirty, b->free, b->dirty);
+       }
+-      lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
++      lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
+                            lp->flags | LPROPS_TAKEN, 0);
+       if (IS_ERR(lp)) {
+               err = PTR_ERR(lp);
+               goto out;
+       }
++
++      /* Make sure the journal head points to the latest bud */
++      err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
++                                   b->bud->lnum, c->leb_size - b->free,
++                                   UBI_SHORTTERM);
++
+ out:
+       ubifs_release_lprops(c);
+       return err;
+ }
+ /**
++ * set_buds_lprops - set free and dirty space for all replayed buds.
++ * @c: UBIFS file-system description object
++ *
++ * This function sets LEB properties for all replayed buds. Returns zero in
++ * case of success and a negative error code in case of failure.
++ */
++static int set_buds_lprops(struct ubifs_info *c)
++{
++      struct bud_entry *b;
++      int err;
++
++      list_for_each_entry(b, &c->replay_buds, list) {
++              err = set_bud_lprops(c, b);
++              if (err)
++                      return err;
++      }
++
++      return 0;
++}
++
++/**
+  * trun_remove_range - apply a replay entry for a truncation to the TNC.
+  * @c: UBIFS file-system description object
+  * @r: replay entry of truncation
+@@ -200,24 +219,22 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
+  */
+ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+ {
+-      int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
++      int err;
+-      dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
+-              r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
++      dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ",
++               r->lnum, r->offs, r->len, r->deletion, r->sqnum);
+       /* Set c->replay_sqnum to help deal with dangling branches. */
+       c->replay_sqnum = r->sqnum;
+-      if (r->flags & REPLAY_REF)
+-              err = set_bud_lprops(c, r);
+-      else if (is_hash_key(c, &r->key)) {
+-              if (deletion)
++      if (is_hash_key(c, &r->key)) {
++              if (r->deletion)
+                       err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
+               else
+                       err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
+                                              r->len, &r->nm);
+       } else {
+-              if (deletion)
++              if (r->deletion)
+                       switch (key_type(c, &r->key)) {
+                       case UBIFS_INO_KEY:
+                       {
+@@ -240,7 +257,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+                       return err;
+               if (c->need_recovery)
+-                      err = ubifs_recover_size_accum(c, &r->key, deletion,
++                      err = ubifs_recover_size_accum(c, &r->key, r->deletion,
+                                                      r->new_size);
+       }
+@@ -248,68 +265,77 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
+ }
+ /**
+- * destroy_replay_tree - destroy the replay.
+- * @c: UBIFS file-system description object
++ * replay_entries_cmp - compare 2 replay entries.
++ * @priv: UBIFS file-system description object
++ * @a: first replay entry
++ * @a: second replay entry
+  *
+- * Destroy the replay tree.
++ * This is a comparios function for 'list_sort()' which compares 2 replay
++ * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has
++ * greater sequence number and %-1 otherwise.
+  */
+-static void destroy_replay_tree(struct ubifs_info *c)
++static int replay_entries_cmp(void *priv, struct list_head *a,
++                            struct list_head *b)
+ {
+-      struct rb_node *this = c->replay_tree.rb_node;
+-      struct replay_entry *r;
+-
+-      while (this) {
+-              if (this->rb_left) {
+-                      this = this->rb_left;
+-                      continue;
+-              } else if (this->rb_right) {
+-                      this = this->rb_right;
+-                      continue;
+-              }
+-              r = rb_entry(this, struct replay_entry, rb);
+-              this = rb_parent(this);
+-              if (this) {
+-                      if (this->rb_left == &r->rb)
+-                              this->rb_left = NULL;
+-                      else
+-                              this->rb_right = NULL;
+-              }
+-              if (is_hash_key(c, &r->key))
+-                      kfree(r->nm.name);
+-              kfree(r);
+-      }
+-      c->replay_tree = RB_ROOT;
++      struct replay_entry *ra, *rb;
++
++      cond_resched();
++      if (a == b)
++              return 0;
++
++      ra = list_entry(a, struct replay_entry, list);
++      rb = list_entry(b, struct replay_entry, list);
++      ubifs_assert(ra->sqnum != rb->sqnum);
++      if (ra->sqnum > rb->sqnum)
++              return 1;
++      return -1;
+ }
+ /**
+- * apply_replay_tree - apply the replay tree to the TNC.
++ * apply_replay_list - apply the replay list to the TNC.
+  * @c: UBIFS file-system description object
+  *
+- * Apply the replay tree.
+- * Returns zero in case of success and a negative error code in case of
+- * failure.
++ * Apply all entries in the replay list to the TNC. Returns zero in case of
++ * success and a negative error code in case of failure.
+  */
+-static int apply_replay_tree(struct ubifs_info *c)
++static int apply_replay_list(struct ubifs_info *c)
+ {
+-      struct rb_node *this = rb_first(&c->replay_tree);
++      struct replay_entry *r;
++      int err;
+-      while (this) {
+-              struct replay_entry *r;
+-              int err;
++      list_sort(c, &c->replay_list, &replay_entries_cmp);
++      list_for_each_entry(r, &c->replay_list, list) {
+               cond_resched();
+-              r = rb_entry(this, struct replay_entry, rb);
+               err = apply_replay_entry(c, r);
+               if (err)
+                       return err;
+-              this = rb_next(this);
+       }
++
+       return 0;
+ }
+ /**
+- * insert_node - insert a node to the replay tree.
++ * destroy_replay_list - destroy the replay.
++ * @c: UBIFS file-system description object
++ *
++ * Destroy the replay list.
++ */
++static void destroy_replay_list(struct ubifs_info *c)
++{
++      struct replay_entry *r, *tmp;
++
++      list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
++              if (is_hash_key(c, &r->key))
++                      kfree(r->nm.name);
++              list_del(&r->list);
++              kfree(r);
++      }
++}
++
++/**
++ * insert_node - insert a node to the replay list
+  * @c: UBIFS file-system description object
+  * @lnum: node logical eraseblock number
+  * @offs: node offset
+@@ -321,39 +347,25 @@ static int apply_replay_tree(struct ubifs_info *c)
+  * @old_size: truncation old size
+  * @new_size: truncation new size
+  *
+- * This function inserts a scanned non-direntry node to the replay tree. The
+- * replay tree is an RB-tree containing @struct replay_entry elements which are
+- * indexed by the sequence number. The replay tree is applied at the very end
+- * of the replay process. Since the tree is sorted in sequence number order,
+- * the older modifications are applied first. This function returns zero in
+- * case of success and a negative error code in case of failure.
++ * This function inserts a scanned non-direntry node to the replay list. The
++ * replay list contains @struct replay_entry elements, and we sort this list in
++ * sequence number order before applying it. The replay list is applied at the
++ * very end of the replay process. Since the list is sorted in sequence number
++ * order, the older modifications are applied first. This function returns zero
++ * in case of success and a negative error code in case of failure.
+  */
+ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+                      union ubifs_key *key, unsigned long long sqnum,
+                      int deletion, int *used, loff_t old_size,
+                      loff_t new_size)
+ {
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+       struct replay_entry *r;
++      dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
++
+       if (key_inum(c, key) >= c->highest_inum)
+               c->highest_inum = key_inum(c, key);
+-      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              } else if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay");
+-              return -EINVAL;
+-      }
+-
+       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+       if (!r)
+               return -ENOMEM;
+@@ -363,19 +375,18 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+       r->lnum = lnum;
+       r->offs = offs;
+       r->len = len;
++      r->deletion = !!deletion;
+       r->sqnum = sqnum;
+-      r->flags = (deletion ? REPLAY_DELETION : 0);
++      key_copy(c, key, &r->key);
+       r->old_size = old_size;
+       r->new_size = new_size;
+-      key_copy(c, key, &r->key);
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
++      list_add_tail(&r->list, &c->replay_list);
+       return 0;
+ }
+ /**
+- * insert_dent - insert a directory entry node into the replay tree.
++ * insert_dent - insert a directory entry node into the replay list.
+  * @c: UBIFS file-system description object
+  * @lnum: node logical eraseblock number
+  * @offs: node offset
+@@ -387,43 +398,25 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
+  * @deletion: non-zero if this is a deletion
+  * @used: number of bytes in use in a LEB
+  *
+- * This function inserts a scanned directory entry node to the replay tree.
+- * Returns zero in case of success and a negative error code in case of
+- * failure.
+- *
+- * This function is also used for extended attribute entries because they are
+- * implemented as directory entry nodes.
++ * This function inserts a scanned directory entry node or an extended
++ * attribute entry to the replay list. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+                      union ubifs_key *key, const char *name, int nlen,
+                      unsigned long long sqnum, int deletion, int *used)
+ {
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+       struct replay_entry *r;
+       char *nbuf;
++      dbg_mntk(key, "add LEB %d:%d, key ", lnum, offs);
+       if (key_inum(c, key) >= c->highest_inum)
+               c->highest_inum = key_inum(c, key);
+-      dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              }
+-              if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay");
+-              return -EINVAL;
+-      }
+-
+       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+       if (!r)
+               return -ENOMEM;
++
+       nbuf = kmalloc(nlen + 1, GFP_KERNEL);
+       if (!nbuf) {
+               kfree(r);
+@@ -435,17 +428,15 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
+       r->lnum = lnum;
+       r->offs = offs;
+       r->len = len;
++      r->deletion = !!deletion;
+       r->sqnum = sqnum;
++      key_copy(c, key, &r->key);
+       r->nm.len = nlen;
+       memcpy(nbuf, name, nlen);
+       nbuf[nlen] = '\0';
+       r->nm.name = nbuf;
+-      r->flags = (deletion ? REPLAY_DELETION : 0);
+-      key_copy(c, key, &r->key);
+-      ubifs_assert(!*p);
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
++      list_add_tail(&r->list, &c->replay_list);
+       return 0;
+ }
+@@ -482,29 +473,90 @@ int ubifs_validate_entry(struct ubifs_info *c,
+ }
+ /**
++ * is_last_bud - check if the bud is the last in the journal head.
++ * @c: UBIFS file-system description object
++ * @bud: bud description object
++ *
++ * This function checks if bud @bud is the last bud in its journal head. This
++ * information is then used by 'replay_bud()' to decide whether the bud can
++ * have corruptions or not. Indeed, only last buds can be corrupted by power
++ * cuts. Returns %1 if this is the last bud, and %0 if not.
++ */
++static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
++{
++      struct ubifs_jhead *jh = &c->jheads[bud->jhead];
++      struct ubifs_bud *next;
++      uint32_t data;
++      int err;
++
++      if (list_is_last(&bud->list, &jh->buds_list))
++              return 1;
++
++      /*
++       * The following is a quirk to make sure we work correctly with UBIFS
++       * images used with older UBIFS.
++       *
++       * Normally, the last bud will be the last in the journal head's list
++       * of bud. However, there is one exception if the UBIFS image belongs
++       * to older UBIFS. This is fairly unlikely: one would need to use old
++       * UBIFS, then have a power cut exactly at the right point, and then
++       * try to mount this image with new UBIFS.
++       *
++       * The exception is: it is possible to have 2 buds A and B, A goes
++       * before B, and B is the last, bud B is contains no data, and bud A is
++       * corrupted at the end. The reason is that in older versions when the
++       * journal code switched the next bud (from A to B), it first added a
++       * log reference node for the new bud (B), and only after this it
++       * synchronized the write-buffer of current bud (A). But later this was
++       * changed and UBIFS started to always synchronize the write-buffer of
++       * the bud (A) before writing the log reference for the new bud (B).
++       *
++       * But because older UBIFS always synchronized A's write-buffer before
++       * writing to B, we can recognize this exceptional situation but
++       * checking the contents of bud B - if it is empty, then A can be
++       * treated as the last and we can recover it.
++       *
++       * TODO: remove this piece of code in a couple of years (today it is
++       * 16.05.2011).
++       */
++      next = list_entry(bud->list.next, struct ubifs_bud, list);
++      if (!list_is_last(&next->list, &jh->buds_list))
++              return 0;
++
++      err = ubifs_leb_read(c, next->lnum, (char *)&data, next->start, 4, 1);
++      if (err)
++              return 0;
++
++      return data == 0xFFFFFFFF;
++}
++
++/**
+  * replay_bud - replay a bud logical eraseblock.
+  * @c: UBIFS file-system description object
+- * @lnum: bud logical eraseblock number to replay
+- * @offs: bud start offset
+- * @jhead: journal head to which this bud belongs
+- * @free: amount of free space in the bud is returned here
+- * @dirty: amount of dirty space from padding and deletion nodes is returned
+- * here
++ * @b: bud entry which describes the bud
+  *
+- * This function returns zero in case of success and a negative error code in
+- * case of failure.
++ * This function replays bud @bud, recovers it if needed, and adds all nodes
++ * from this bud to the replay list. Returns zero in case of success and a
++ * negative error code in case of failure.
+  */
+-static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+-                    int *free, int *dirty)
++static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
+ {
+-      int err = 0, used = 0;
++      int is_last = is_last_bud(c, b->bud);
++      int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
+       struct ubifs_scan_leb *sleb;
+       struct ubifs_scan_node *snod;
+-      struct ubifs_bud *bud;
+-      dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
+-      if (c->need_recovery)
+-              sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
++      dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d",
++              lnum, b->bud->jhead, offs, is_last);
++
++      if (c->need_recovery && is_last)
++              /*
++               * Recover only last LEBs in the journal heads, because power
++               * cuts may cause corruptions only in these LEBs, because only
++               * these LEBs could possibly be written to at the power cut
++               * time.
++               */
++              sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead);
+       else
+               sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
+       if (IS_ERR(sleb))
+@@ -620,19 +672,13 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
+                       goto out;
+       }
+-      bud = ubifs_search_bud(c, lnum);
+-      if (!bud)
+-              BUG();
+-
++      ubifs_assert(ubifs_search_bud(c, lnum));
+       ubifs_assert(sleb->endpt - offs >= used);
+       ubifs_assert(sleb->endpt % c->min_io_size == 0);
+-      if (sleb->endpt + c->min_io_size <= c->leb_size && !c->ro_mount)
+-              err = ubifs_wbuf_seek_nolock(&c->jheads[jhead].wbuf, lnum,
+-                                           sleb->endpt, UBI_SHORTTERM);
+-
+-      *dirty = sleb->endpt - offs - used;
+-      *free = c->leb_size - sleb->endpt;
++      b->dirty = sleb->endpt - offs - used;
++      b->free = c->leb_size - sleb->endpt;
++      dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, b->dirty, b->free);
+ out:
+       ubifs_scan_destroy(sleb);
+@@ -646,55 +692,6 @@ out_dump:
+ }
+ /**
+- * insert_ref_node - insert a reference node to the replay tree.
+- * @c: UBIFS file-system description object
+- * @lnum: node logical eraseblock number
+- * @offs: node offset
+- * @sqnum: sequence number
+- * @free: amount of free space in bud
+- * @dirty: amount of dirty space from padding and deletion nodes
+- *
+- * This function inserts a reference node to the replay tree and returns zero
+- * in case of success or a negative error code in case of failure.
+- */
+-static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+-                         unsigned long long sqnum, int free, int dirty)
+-{
+-      struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
+-      struct replay_entry *r;
+-
+-      dbg_mnt("add ref LEB %d:%d", lnum, offs);
+-      while (*p) {
+-              parent = *p;
+-              r = rb_entry(parent, struct replay_entry, rb);
+-              if (sqnum < r->sqnum) {
+-                      p = &(*p)->rb_left;
+-                      continue;
+-              } else if (sqnum > r->sqnum) {
+-                      p = &(*p)->rb_right;
+-                      continue;
+-              }
+-              ubifs_err("duplicate sqnum in replay tree");
+-              return -EINVAL;
+-      }
+-
+-      r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
+-      if (!r)
+-              return -ENOMEM;
+-
+-      r->lnum = lnum;
+-      r->offs = offs;
+-      r->sqnum = sqnum;
+-      r->flags = REPLAY_REF;
+-      r->free = free;
+-      r->dirty = dirty;
+-
+-      rb_link_node(&r->rb, parent, p);
+-      rb_insert_color(&r->rb, &c->replay_tree);
+-      return 0;
+-}
+-
+-/**
+  * replay_buds - replay all buds.
+  * @c: UBIFS file-system description object
+  *
+@@ -704,17 +701,16 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
+ static int replay_buds(struct ubifs_info *c)
+ {
+       struct bud_entry *b;
+-      int err, uninitialized_var(free), uninitialized_var(dirty);
++      int err;
++      unsigned long long prev_sqnum = 0;
+       list_for_each_entry(b, &c->replay_buds, list) {
+-              err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
+-                               &free, &dirty);
+-              if (err)
+-                      return err;
+-              err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
+-                                    free, dirty);
++              err = replay_bud(c, b);
+               if (err)
+                       return err;
++
++              ubifs_assert(b->sqnum > prev_sqnum);
++              prev_sqnum = b->sqnum;
+       }
+       return 0;
+@@ -1054,25 +1050,29 @@ int ubifs_replay_journal(struct ubifs_info *c)
+       if (err)
+               goto out;
+-      err = apply_replay_tree(c);
++      err = apply_replay_list(c);
++      if (err)
++              goto out;
++
++      err = set_buds_lprops(c);
+       if (err)
+               goto out;
+       /*
+-       * UBIFS budgeting calculations use @c->budg_uncommitted_idx variable
+-       * to roughly estimate index growth. Things like @c->min_idx_lebs
++       * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
++       * to roughly estimate index growth. Things like @c->bi.min_idx_lebs
+        * depend on it. This means we have to initialize it to make sure
+        * budgeting works properly.
+        */
+-      c->budg_uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
+-      c->budg_uncommitted_idx *= c->max_idx_node_sz;
++      c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
++      c->bi.uncommitted_idx *= c->max_idx_node_sz;
+       ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
+       dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
+               "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
+               (unsigned long)c->highest_inum);
+ out:
+-      destroy_replay_tree(c);
++      destroy_replay_list(c);
+       destroy_bud_list(c);
+       c->replaying = 0;
+       return err;
+diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
+index bf31b47..771f7fb 100644
+--- a/fs/ubifs/sb.c
++++ b/fs/ubifs/sb.c
+@@ -247,7 +247,7 @@ static int create_default_filesystem(struct ubifs_info *c)
+       mst->total_dirty = cpu_to_le64(tmp64);
+       /*  The indexing LEB does not contribute to dark space */
+-      tmp64 = (c->main_lebs - 1) * c->dark_wm;
++      tmp64 = ((long long)(c->main_lebs - 1) * c->dark_wm);
+       mst->total_dark = cpu_to_le64(tmp64);
+       mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
+@@ -410,13 +410,23 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+       }
+       if (c->main_lebs < UBIFS_MIN_MAIN_LEBS) {
+-              err = 7;
++              ubifs_err("too few main LEBs count %d, must be at least %d",
++                        c->main_lebs, UBIFS_MIN_MAIN_LEBS);
+               goto failed;
+       }
+-      if (c->max_bud_bytes < (long long)c->leb_size * UBIFS_MIN_BUD_LEBS ||
+-          c->max_bud_bytes > (long long)c->leb_size * c->main_lebs) {
+-              err = 8;
++      max_bytes = (long long)c->leb_size * UBIFS_MIN_BUD_LEBS;
++      if (c->max_bud_bytes < max_bytes) {
++              ubifs_err("too small journal (%lld bytes), must be at least "
++                        "%lld bytes",  c->max_bud_bytes, max_bytes);
++              goto failed;
++      }
++
++      max_bytes = (long long)c->leb_size * c->main_lebs;
++      if (c->max_bud_bytes > max_bytes) {
++              ubifs_err("too large journal size (%lld bytes), only %lld bytes"
++                        "available in the main area",
++                        c->max_bud_bytes, max_bytes);
+               goto failed;
+       }
+@@ -450,7 +460,6 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
+               goto failed;
+       }
+-      max_bytes = c->main_lebs * (long long)c->leb_size;
+       if (c->rp_size < 0 || max_bytes < c->rp_size) {
+               err = 14;
+               goto failed;
+@@ -475,7 +484,8 @@ failed:
+  * @c: UBIFS file-system description object
+  *
+  * This function returns a pointer to the superblock node or a negative error
+- * code.
++ * code. Note, the user of this function is responsible of kfree()'ing the
++ * returned superblock buffer.
+  */
+ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
+ {
+@@ -616,6 +626,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
+       c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
+       memcpy(&c->uuid, &sup->uuid, 16);
+       c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
++      c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+       /* Automatically increase file system size to the maximum size */
+       c->old_leb_cnt = c->leb_cnt;
+@@ -650,3 +661,152 @@ out:
+       kfree(sup);
+       return err;
+ }
++
++/**
++ * fixup_leb - fixup/unmap an LEB containing free space.
++ * @c: UBIFS file-system description object
++ * @lnum: the LEB number to fix up
++ * @len: number of used bytes in LEB (starting at offset 0)
++ *
++ * This function reads the contents of the given LEB number @lnum, then fixes
++ * it up, so that empty min. I/O units in the end of LEB are actually erased on
++ * flash (rather than being just all-0xff real data). If the LEB is completely
++ * empty, it is simply unmapped.
++ */
++static int fixup_leb(struct ubifs_info *c, int lnum, int len)
++{
++      int err;
++
++      ubifs_assert(len >= 0);
++      ubifs_assert(len % c->min_io_size == 0);
++      ubifs_assert(len < c->leb_size);
++
++      if (len == 0) {
++              dbg_mnt("unmap empty LEB %d", lnum);
++              return ubifs_leb_unmap(c, lnum);
++      }
++
++      dbg_mnt("fixup LEB %d, data len %d", lnum, len);
++      err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
++      if (err)
++              return err;
++
++      return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
++}
++
++/**
++ * fixup_free_space - find & remap all LEBs containing free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function walks through all LEBs in the filesystem and fiexes up those
++ * containing free/empty space.
++ */
++static int fixup_free_space(struct ubifs_info *c)
++{
++      int lnum, err = 0;
++      struct ubifs_lprops *lprops;
++
++      ubifs_get_lprops(c);
++
++      /* Fixup LEBs in the master area */
++      for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) {
++              err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz);
++              if (err)
++                      goto out;
++      }
++
++      /* Unmap unused log LEBs */
++      lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
++      while (lnum != c->ltail_lnum) {
++              err = fixup_leb(c, lnum, 0);
++              if (err)
++                      goto out;
++              lnum = ubifs_next_log_lnum(c, lnum);
++      }
++
++      /* Fixup the current log head */
++      err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
++      if (err)
++              goto out;
++
++      /* Fixup LEBs in the LPT area */
++      for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
++              int free = c->ltab[lnum - c->lpt_first].free;
++
++              if (free > 0) {
++                      err = fixup_leb(c, lnum, c->leb_size - free);
++                      if (err)
++                              goto out;
++              }
++      }
++
++      /* Unmap LEBs in the orphans area */
++      for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
++              err = fixup_leb(c, lnum, 0);
++              if (err)
++                      goto out;
++      }
++
++      /* Fixup LEBs in the main area */
++      for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
++              lprops = ubifs_lpt_lookup(c, lnum);
++              if (IS_ERR(lprops)) {
++                      err = PTR_ERR(lprops);
++                      goto out;
++              }
++
++              if (lprops->free > 0) {
++                      err = fixup_leb(c, lnum, c->leb_size - lprops->free);
++                      if (err)
++                              goto out;
++              }
++      }
++
++out:
++      ubifs_release_lprops(c);
++      return err;
++}
++
++/**
++ * ubifs_fixup_free_space - find & fix all LEBs with free space.
++ * @c: UBIFS file-system description object
++ *
++ * This function fixes up LEBs containing free space on first mount, if the
++ * appropriate flag was set when the FS was created. Each LEB with one or more
++ * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure
++ * the free space is actually erased. E.g., this is necessary for some NAND
++ * chips, since the free space may have been programmed like real "0xff" data
++ * (generating a non-0xff ECC), causing future writes to the not-really-erased
++ * NAND pages to behave badly. After the space is fixed up, the superblock flag
++ * is cleared, so that this is skipped for all future mounts.
++ */
++int ubifs_fixup_free_space(struct ubifs_info *c)
++{
++      int err;
++      struct ubifs_sb_node *sup;
++
++      ubifs_assert(c->space_fixup);
++      ubifs_assert(!c->ro_mount);
++
++      ubifs_msg("start fixing up free space");
++
++      err = fixup_free_space(c);
++      if (err)
++              return err;
++
++      sup = ubifs_read_sb_node(c);
++      if (IS_ERR(sup))
++              return PTR_ERR(sup);
++
++      /* Free-space fixup is no longer required */
++      c->space_fixup = 0;
++      sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
++
++      err = ubifs_write_sb_node(c, sup);
++      kfree(sup);
++      if (err)
++              return err;
++
++      ubifs_msg("free space fixup complete");
++      return err;
++}
+diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
+index 3e1ee57..37383e8 100644
+--- a/fs/ubifs/scan.c
++++ b/fs/ubifs/scan.c
+@@ -148,7 +148,7 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
+       INIT_LIST_HEAD(&sleb->nodes);
+       sleb->buf = sbuf;
+-      err = ubi_read(c->ubi, lnum, sbuf + offs, offs, c->leb_size - offs);
++      err = ubifs_leb_read(c, lnum, sbuf + offs, offs, c->leb_size - offs, 0);
+       if (err && err != -EBADMSG) {
+               ubifs_err("cannot read %d bytes from LEB %d:%d,"
+                         " error %d", c->leb_size - offs, lnum, offs, err);
+@@ -240,7 +240,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
+       int len;
+       ubifs_err("corruption at LEB %d:%d", lnum, offs);
+-      if (dbg_failure_mode)
++      if (dbg_is_tst_rcvry(c))
+               return;
+       len = c->leb_size - offs;
+       if (len > 8192)
+@@ -328,7 +328,7 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
+               if (!quiet)
+                       ubifs_err("empty space starts at non-aligned offset %d",
+                                 offs);
+-              goto corrupted;;
++              goto corrupted;
+       }
+       ubifs_end_scan(c, sleb, lnum, offs);
+diff --git a/fs/ubifs/shrinker.c b/fs/ubifs/shrinker.c
+index 46961c0..d8f5d0f 100644
+--- a/fs/ubifs/shrinker.c
++++ b/fs/ubifs/shrinker.c
+@@ -283,7 +283,11 @@ int ubifs_shrinker(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+       long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
+       if (nr == 0)
+-              return clean_zn_cnt;
++              /*
++               * Due to the way UBIFS updates the clean znode counter it may
++               * temporarily be negative.
++               */
++              return clean_zn_cnt >= 0 ? clean_zn_cnt : 1;
+       if (!clean_zn_cnt) {
+               /*
+diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
+index 91fac54..83651cd 100644
+--- a/fs/ubifs/super.c
++++ b/fs/ubifs/super.c
+@@ -85,7 +85,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+       if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA)
+               return 4;
+-      if (ui->xattr && (inode->i_mode & S_IFMT) != S_IFREG)
++      if (ui->xattr && !S_ISREG(inode->i_mode))
+               return 5;
+       if (!ubifs_compr_present(ui->compr_type)) {
+@@ -94,7 +94,7 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
+                          ubifs_compr_name(ui->compr_type));
+       }
+-      err = dbg_check_dir_size(c, inode);
++      err = dbg_check_dir(c, inode);
+       return err;
+ }
+@@ -367,7 +367,7 @@ out:
+               ubifs_release_dirty_inode_budget(c, ui);
+       else {
+               /* We've deleted something - clean the "no space" flags */
+-              c->nospace = c->nospace_rp = 0;
++              c->bi.nospace = c->bi.nospace_rp = 0;
+               smp_wmb();
+       }
+ done:
+@@ -504,9 +504,12 @@ static int init_constants_early(struct ubifs_info *c)
+       c->leb_cnt = c->vi.size;
+       c->leb_size = c->vi.usable_leb_size;
++      c->leb_start = c->di.leb_start;
+       c->half_leb_size = c->leb_size / 2;
+       c->min_io_size = c->di.min_io_size;
+       c->min_io_shift = fls(c->min_io_size) - 1;
++      c->max_write_size = c->di.max_write_size;
++      c->max_write_shift = fls(c->max_write_size) - 1;
+       if (c->leb_size < UBIFS_MIN_LEB_SZ) {
+               ubifs_err("too small LEBs (%d bytes), min. is %d bytes",
+@@ -526,6 +529,18 @@ static int init_constants_early(struct ubifs_info *c)
+       }
+       /*
++       * Maximum write size has to be greater or equivalent to min. I/O
++       * size, and be multiple of min. I/O size.
++       */
++      if (c->max_write_size < c->min_io_size ||
++          c->max_write_size % c->min_io_size ||
++          !is_power_of_2(c->max_write_size)) {
++              ubifs_err("bad write buffer size %d for %d min. I/O unit",
++                        c->max_write_size, c->min_io_size);
++              return -EINVAL;
++      }
++
++      /*
+        * UBIFS aligns all node to 8-byte boundary, so to make function in
+        * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is
+        * less than 8.
+@@ -533,6 +548,10 @@ static int init_constants_early(struct ubifs_info *c)
+       if (c->min_io_size < 8) {
+               c->min_io_size = 8;
+               c->min_io_shift = 3;
++              if (c->max_write_size < c->min_io_size) {
++                      c->max_write_size = c->min_io_size;
++                      c->max_write_shift = c->min_io_shift;
++              }
+       }
+       c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size);
+@@ -667,11 +686,11 @@ static int init_constants_sb(struct ubifs_info *c)
+        * be compressed and direntries are of the maximum size.
+        *
+        * Note, data, which may be stored in inodes is budgeted separately, so
+-       * it is not included into 'c->inode_budget'.
++       * it is not included into 'c->bi.inode_budget'.
+        */
+-      c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
+-      c->inode_budget = UBIFS_INO_NODE_SZ;
+-      c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
++      c->bi.page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
++      c->bi.inode_budget = UBIFS_INO_NODE_SZ;
++      c->bi.dent_budget = UBIFS_MAX_DENT_NODE_SZ;
+       /*
+        * When the amount of flash space used by buds becomes
+@@ -715,7 +734,7 @@ static void init_constants_master(struct ubifs_info *c)
+ {
+       long long tmp64;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->report_rp_size = ubifs_reported_space(c, c->rp_size);
+       /*
+@@ -784,15 +803,18 @@ static int alloc_wbufs(struct ubifs_info *c)
+               c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
+               c->jheads[i].wbuf.jhead = i;
++              c->jheads[i].grouped = 1;
+       }
+       c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
+       /*
+        * Garbage Collector head likely contains long-term data and
+-       * does not need to be synchronized by timer.
++       * does not need to be synchronized by timer. Also GC head nodes are
++       * not grouped.
+        */
+       c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
+       c->jheads[GCHD].wbuf.no_timer = 1;
++      c->jheads[GCHD].grouped = 0;
+       return 0;
+ }
+@@ -884,7 +906,7 @@ static int check_volume_empty(struct ubifs_info *c)
+       c->empty = 1;
+       for (lnum = 0; lnum < c->leb_cnt; lnum++) {
+-              err = ubi_is_mapped(c->ubi, lnum);
++              err = ubifs_is_mapped(c, lnum);
+               if (unlikely(err < 0))
+                       return err;
+               if (err == 1) {
+@@ -1117,8 +1139,8 @@ static int check_free_space(struct ubifs_info *c)
+ {
+       ubifs_assert(c->dark_wm > 0);
+       if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
+-              ubifs_err("insufficient free space to mount in read/write mode");
+-              dbg_dump_budg(c);
++              ubifs_err("insufficient free space to mount in R/W mode");
++              dbg_dump_budg(c, &c->bi);
+               dbg_dump_lprops(c);
+               return -ENOSPC;
+       }
+@@ -1194,11 +1216,14 @@ static int mount_ubifs(struct ubifs_info *c)
+       if (c->bulk_read == 1)
+               bu_init(c);
+-      /*
+-       * We have to check all CRCs, even for data nodes, when we mount the FS
+-       * (specifically, when we are replaying).
+-       */
+-      c->always_chk_crc = 1;
++      if (!c->ro_mount) {
++              c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
++                                             GFP_KERNEL);
++              if (!c->write_reserve_buf)
++                      goto out_free;
++      }
++
++      c->mounting = 1;
+       err = ubifs_read_superblock(c);
+       if (err)
+@@ -1227,12 +1252,12 @@ static int mount_ubifs(struct ubifs_info *c)
+               goto out_free;
+       }
++      err = alloc_wbufs(c);
++      if (err)
++              goto out_cbuf;
++
+       sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
+       if (!c->ro_mount) {
+-              err = alloc_wbufs(c);
+-              if (err)
+-                      goto out_cbuf;
+-
+               /* Create background thread */
+               c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
+               if (IS_ERR(c->bgt)) {
+@@ -1254,12 +1279,25 @@ static int mount_ubifs(struct ubifs_info *c)
+       if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
+               ubifs_msg("recovery needed");
+               c->need_recovery = 1;
+-              if (!c->ro_mount) {
+-                      err = ubifs_recover_inl_heads(c, c->sbuf);
+-                      if (err)
+-                              goto out_master;
+-              }
+-      } else if (!c->ro_mount) {
++      }
++
++      if (c->need_recovery && !c->ro_mount) {
++              err = ubifs_recover_inl_heads(c, c->sbuf);
++              if (err)
++                      goto out_master;
++      }
++
++      err = ubifs_lpt_init(c, 1, !c->ro_mount);
++      if (err)
++              goto out_master;
++
++      if (!c->ro_mount && c->space_fixup) {
++              err = ubifs_fixup_free_space(c);
++              if (err)
++                      goto out_master;
++      }
++
++      if (!c->ro_mount) {
+               /*
+                * Set the "dirty" flag so that if we reboot uncleanly we
+                * will notice this immediately on the next mount.
+@@ -1267,14 +1305,10 @@ static int mount_ubifs(struct ubifs_info *c)
+               c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+               err = ubifs_write_master(c);
+               if (err)
+-                      goto out_master;
++                      goto out_lpt;
+       }
+-      err = ubifs_lpt_init(c, 1, !c->ro_mount);
+-      if (err)
+-              goto out_lpt;
+-
+-      err = dbg_check_idx_size(c, c->old_idx_sz);
++      err = dbg_check_idx_size(c, c->bi.old_idx_sz);
+       if (err)
+               goto out_lpt;
+@@ -1283,7 +1317,7 @@ static int mount_ubifs(struct ubifs_info *c)
+               goto out_journal;
+       /* Calculate 'min_idx_lebs' after journal replay */
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
+       if (err)
+@@ -1374,7 +1408,7 @@ static int mount_ubifs(struct ubifs_info *c)
+       if (err)
+               goto out_infos;
+-      c->always_chk_crc = 0;
++      c->mounting = 0;
+       ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
+                 c->vi.ubi_num, c->vi.vol_id, c->vi.name);
+@@ -1395,6 +1429,7 @@ static int mount_ubifs(struct ubifs_info *c)
+       dbg_msg("compiled on:         " __DATE__ " at " __TIME__);
+       dbg_msg("min. I/O unit size:  %d bytes", c->min_io_size);
++      dbg_msg("max. write size:     %d bytes", c->max_write_size);
+       dbg_msg("LEB size:            %d bytes (%d KiB)",
+               c->leb_size, c->leb_size >> 10);
+       dbg_msg("data journal heads:  %d",
+@@ -1411,7 +1446,8 @@ static int mount_ubifs(struct ubifs_info *c)
+               c->main_lebs, c->main_first, c->leb_cnt - 1);
+       dbg_msg("index LEBs:          %d", c->lst.idx_lebs);
+       dbg_msg("total index bytes:   %lld (%lld KiB, %lld MiB)",
+-              c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
++              c->bi.old_idx_sz, c->bi.old_idx_sz >> 10,
++              c->bi.old_idx_sz >> 20);
+       dbg_msg("key hash type:       %d", c->key_hash_type);
+       dbg_msg("tree fanout:         %d", c->fanout);
+       dbg_msg("reserved GC LEB:     %d", c->gc_lnum);
+@@ -1424,9 +1460,9 @@ static int mount_ubifs(struct ubifs_info *c)
+               UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ);
+       dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
+               UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
+-      dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu",
+-              UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+-              UBIFS_MAX_DENT_NODE_SZ);
++      dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu, idx %d",
++              UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
++              UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout));
+       dbg_msg("dead watermark:      %d", c->dead_wm);
+       dbg_msg("dark watermark:      %d", c->dark_wm);
+       dbg_msg("LEB overhead:        %d", c->leb_overhead);
+@@ -1466,6 +1502,7 @@ out_wbufs:
+ out_cbuf:
+       kfree(c->cbuf);
+ out_free:
++      kfree(c->write_reserve_buf);
+       kfree(c->bu.buf);
+       vfree(c->ileb_buf);
+       vfree(c->sbuf);
+@@ -1504,6 +1541,7 @@ static void ubifs_umount(struct ubifs_info *c)
+       kfree(c->cbuf);
+       kfree(c->rcvrd_mst_node);
+       kfree(c->mst_node);
++      kfree(c->write_reserve_buf);
+       kfree(c->bu.buf);
+       vfree(c->ileb_buf);
+       vfree(c->sbuf);
+@@ -1535,7 +1573,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+       mutex_lock(&c->umount_mutex);
+       dbg_save_space_info(c);
+       c->remounting_rw = 1;
+-      c->always_chk_crc = 1;
++      c->ro_mount = 0;
+       err = check_free_space(c);
+       if (err)
+@@ -1551,6 +1589,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+               }
+               sup->leb_cnt = cpu_to_le32(c->leb_cnt);
+               err = ubifs_write_sb_node(c, sup);
++              kfree(sup);
+               if (err)
+                       goto out;
+       }
+@@ -1590,16 +1629,14 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+               goto out;
+       }
+-      err = ubifs_lpt_init(c, 0, 1);
+-      if (err)
++      c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
++      if (!c->write_reserve_buf)
+               goto out;
+-      err = alloc_wbufs(c);
++      err = ubifs_lpt_init(c, 0, 1);
+       if (err)
+               goto out;
+-      ubifs_create_buds_lists(c);
+-
+       /* Create background thread */
+       c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
+       if (IS_ERR(c->bgt)) {
+@@ -1634,20 +1671,37 @@ static int ubifs_remount_rw(struct ubifs_info *c)
+       if (err)
+               goto out;
++      dbg_gen("re-mounted read-write");
++      c->remounting_rw = 0;
++
+       if (c->need_recovery) {
+               c->need_recovery = 0;
+               ubifs_msg("deferred recovery completed");
++      } else {
++              /*
++               * Do not run the debugging space check if the were doing
++               * recovery, because when we saved the information we had the
++               * file-system in a state where the TNC and lprops has been
++               * modified in memory, but all the I/O operations (including a
++               * commit) were deferred. So the file-system was in
++               * "non-committed" state. Now the file-system is in committed
++               * state, and of course the amount of free space will change
++               * because, for example, the old index size was imprecise.
++               */
++              err = dbg_check_space_info(c);
++      }
++
++      if (c->space_fixup) {
++              err = ubifs_fixup_free_space(c);
++              if (err)
++                      goto out;
+       }
+-      dbg_gen("re-mounted read-write");
+-      c->ro_mount = 0;
+-      c->remounting_rw = 0;
+-      c->always_chk_crc = 0;
+-      err = dbg_check_space_info(c);
+       mutex_unlock(&c->umount_mutex);
+       return err;
+ out:
++      c->ro_mount = 1;
+       vfree(c->orph_buf);
+       c->orph_buf = NULL;
+       if (c->bgt) {
+@@ -1655,11 +1709,12 @@ out:
+               c->bgt = NULL;
+       }
+       free_wbufs(c);
++      kfree(c->write_reserve_buf);
++      c->write_reserve_buf = NULL;
+       vfree(c->ileb_buf);
+       c->ileb_buf = NULL;
+       ubifs_lpt_free(c, 1);
+       c->remounting_rw = 0;
+-      c->always_chk_crc = 0;
+       mutex_unlock(&c->umount_mutex);
+       return err;
+ }
+@@ -1696,9 +1751,10 @@ static void ubifs_remount_ro(struct ubifs_info *c)
+       if (err)
+               ubifs_ro_mode(c, err);
+-      free_wbufs(c);
+       vfree(c->orph_buf);
+       c->orph_buf = NULL;
++      kfree(c->write_reserve_buf);
++      c->write_reserve_buf = NULL;
+       vfree(c->ileb_buf);
+       c->ileb_buf = NULL;
+       ubifs_lpt_free(c, 1);
+@@ -1722,10 +1778,11 @@ static void ubifs_put_super(struct super_block *sb)
+        * of the media. For example, there will be dirty inodes if we failed
+        * to write them back because of I/O errors.
+        */
+-      ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
+-      ubifs_assert(c->budg_idx_growth == 0);
+-      ubifs_assert(c->budg_dd_growth == 0);
+-      ubifs_assert(c->budg_data_growth == 0);
++      if (!c->ro_error) {
++              ubifs_assert(c->bi.idx_growth == 0);
++              ubifs_assert(c->bi.dd_growth == 0);
++              ubifs_assert(c->bi.data_growth == 0);
++      }
+       /*
+        * The 'c->umount_lock' prevents races between UBIFS memory shrinker
+@@ -1929,6 +1986,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+       mutex_init(&c->mst_mutex);
+       mutex_init(&c->umount_mutex);
+       mutex_init(&c->bu_mutex);
++      mutex_init(&c->write_reserve_mutex);
+       init_waitqueue_head(&c->cmt_wq);
+       c->buds = RB_ROOT;
+       c->old_idx = RB_ROOT;
+@@ -1946,6 +2004,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
+       INIT_LIST_HEAD(&c->old_buds);
+       INIT_LIST_HEAD(&c->orph_list);
+       INIT_LIST_HEAD(&c->orph_new);
++      c->no_chk_data_crc = 1;
+       c->vfs_sb = sb;
+       c->highest_inum = UBIFS_FIRST_INO;
+diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
+index ad9cf01..16ad84d 100644
+--- a/fs/ubifs/tnc.c
++++ b/fs/ubifs/tnc.c
+@@ -223,7 +223,7 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
+       __set_bit(DIRTY_ZNODE, &zn->flags);
+       __clear_bit(COW_ZNODE, &zn->flags);
+-      ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++      ubifs_assert(!ubifs_zn_obsolete(znode));
+       __set_bit(OBSOLETE_ZNODE, &znode->flags);
+       if (znode->level != 0) {
+@@ -271,7 +271,7 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
+       struct ubifs_znode *zn;
+       int err;
+-      if (!test_bit(COW_ZNODE, &znode->flags)) {
++      if (!ubifs_zn_cow(znode)) {
+               /* znode is not being committed */
+               if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
+                       atomic_long_inc(&c->dirty_zn_cnt);
+@@ -344,12 +344,11 @@ static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+               return err;
+       }
+-      lnc_node = kmalloc(zbr->len, GFP_NOFS);
++      lnc_node = kmemdup(node, zbr->len, GFP_NOFS);
+       if (!lnc_node)
+               /* We don't have to have the cache, so no error */
+               return 0;
+-      memcpy(lnc_node, node, zbr->len);
+       zbr->leaf = lnc_node;
+       return 0;
+ }
+@@ -447,8 +446,11 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+  *
+  * Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
+  * is true (it is controlled by corresponding mount option). However, if
+- * @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
+- * checked.
++ * @c->mounting or @c->remounting_rw is true (we are mounting or re-mounting to
++ * R/W mode), @c->no_chk_data_crc is ignored and CRC is checked. This is
++ * because during mounting or re-mounting from R/O mode to R/W mode we may read
++ * journal nodes (when replying the journal or doing the recovery) and the
++ * journal nodes may potentially be corrupted, so checking is required.
+  */
+ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+                        int len, int lnum, int offs)
+@@ -459,7 +461,7 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+       dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
+-      err = ubi_read(c->ubi, lnum, buf, offs, len);
++      err = ubifs_leb_read(c, lnum, buf, offs, len, 1);
+       if (err) {
+               ubifs_err("cannot read node type %d from LEB %d:%d, error %d",
+                         type, lnum, offs, err);
+@@ -476,7 +478,8 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+       if (node_len != len)
+               return 0;
+-      if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
++      if (type == UBIFS_DATA_NODE && c->no_chk_data_crc && !c->mounting &&
++          !c->remounting_rw)
+               return 1;
+       crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
+@@ -502,7 +505,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+ {
+       int ret;
+-      dbg_tnc("LEB %d:%d, key %s", zbr->lnum, zbr->offs, DBGKEY(key));
++      dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs);
+       ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum,
+                           zbr->offs);
+@@ -516,8 +519,8 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+                       ret = 0;
+       }
+       if (ret == 0 && c->replaying)
+-              dbg_mnt("dangling branch LEB %d:%d len %d, key %s",
+-                      zbr->lnum, zbr->offs, zbr->len, DBGKEY(key));
++              dbg_mntk(key, "dangling branch LEB %d:%d len %d, key ",
++                      zbr->lnum, zbr->offs, zbr->len);
+       return ret;
+ }
+@@ -992,9 +995,9 @@ static int fallible_resolve_collision(struct ubifs_info *c,
+       if (adding || !o_znode)
+               return 0;
+-      dbg_mnt("dangling match LEB %d:%d len %d %s",
++      dbg_mntk(key, "dangling match LEB %d:%d len %d key ",
+               o_znode->zbranch[o_n].lnum, o_znode->zbranch[o_n].offs,
+-              o_znode->zbranch[o_n].len, DBGKEY(key));
++              o_znode->zbranch[o_n].len);
+       *zn = o_znode;
+       *n = o_n;
+       return 1;
+@@ -1176,7 +1179,7 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       unsigned long time = get_seconds();
+-      dbg_tnc("search key %s", DBGKEY(key));
++      dbg_tnck(key, "search key ");
+       ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
+       znode = c->zroot.znode;
+@@ -1312,7 +1315,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       unsigned long time = get_seconds();
+-      dbg_tnc("search and dirty key %s", DBGKEY(key));
++      dbg_tnck(key, "search and dirty key ");
+       znode = c->zroot.znode;
+       if (unlikely(!znode)) {
+@@ -1662,7 +1665,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
+       if (!overlap) {
+               /* We may safely unlock the write-buffer and read the data */
+               spin_unlock(&wbuf->lock);
+-              return ubi_read(c->ubi, lnum, buf, offs, len);
++              return ubifs_leb_read(c, lnum, buf, offs, len, 0);
+       }
+       /* Don't read under wbuf */
+@@ -1676,7 +1679,7 @@ static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
+       if (rlen > 0)
+               /* Read everything that goes before write-buffer */
+-              return ubi_read(c->ubi, lnum, buf, offs, rlen);
++              return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
+       return 0;
+ }
+@@ -1719,8 +1722,8 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
+       if (!keys_eq(c, &zbr->key, &key1)) {
+               ubifs_err("bad key in node at LEB %d:%d",
+                         zbr->lnum, zbr->offs);
+-              dbg_tnc("looked for key %s found node's key %s",
+-                      DBGKEY(&zbr->key), DBGKEY1(&key1));
++              dbg_tnck(&zbr->key, "looked for key ");
++              dbg_tnck(&key1, "found node's key ");
+               goto out_err;
+       }
+@@ -1763,7 +1766,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+       if (wbuf)
+               err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
+       else
+-              err = ubi_read(c->ubi, lnum, bu->buf, offs, len);
++              err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
+       /* Check for a race with GC */
+       if (maybe_leb_gced(c, lnum, bu->gc_seq))
+@@ -1773,7 +1776,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+               ubifs_err("failed to read from LEB %d:%d, error %d",
+                         lnum, offs, err);
+               dbg_dump_stack();
+-              dbg_tnc("key %s", DBGKEY(&bu->key));
++              dbg_tnck(&bu->key, "key ");
+               return err;
+       }
+@@ -1808,7 +1811,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
+       int found, n, err;
+       struct ubifs_znode *znode;
+-      dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key));
++      dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
+       mutex_lock(&c->tnc_mutex);
+       found = ubifs_lookup_level0(c, key, &znode, &n);
+       if (!found) {
+@@ -1982,8 +1985,7 @@ again:
+       zp = znode->parent;
+       if (znode->child_cnt < c->fanout) {
+               ubifs_assert(n != c->fanout);
+-              dbg_tnc("inserted at %d level %d, key %s", n, znode->level,
+-                      DBGKEY(key));
++              dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level);
+               insert_zbranch(znode, zbr, n);
+@@ -1998,7 +2000,7 @@ again:
+        * Unfortunately, @znode does not have more empty slots and we have to
+        * split it.
+        */
+-      dbg_tnc("splitting level %d, key %s", znode->level, DBGKEY(key));
++      dbg_tnck(key, "splitting level %d, key ", znode->level);
+       if (znode->alt)
+               /*
+@@ -2092,7 +2094,7 @@ do_split:
+       }
+       /* Insert new key and branch */
+-      dbg_tnc("inserting at %d level %d, key %s", n, zn->level, DBGKEY(key));
++      dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level);
+       insert_zbranch(zi, zbr, n);
+@@ -2168,7 +2170,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("%d:%d, len %d, key %s", lnum, offs, len, DBGKEY(key));
++      dbg_tnck(key, "%d:%d, len %d, key ", lnum, offs, len);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (!found) {
+               struct ubifs_zbranch zbr;
+@@ -2217,8 +2219,8 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("old LEB %d:%d, new LEB %d:%d, len %d, key %s", old_lnum,
+-              old_offs, lnum, offs, len, DBGKEY(key));
++      dbg_tnck(key, "old LEB %d:%d, new LEB %d:%d, len %d, key ", old_lnum,
++               old_offs, lnum, offs, len);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2300,8 +2302,8 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("LEB %d:%d, name '%.*s', key %s", lnum, offs, nm->len, nm->name,
+-              DBGKEY(key));
++      dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
++               lnum, offs, nm->len, nm->name);
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2394,7 +2396,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+       /* Delete without merge for now */
+       ubifs_assert(znode->level == 0);
+       ubifs_assert(n >= 0 && n < c->fanout);
+-      dbg_tnc("deleting %s", DBGKEY(&znode->zbranch[n].key));
++      dbg_tnck(&znode->zbranch[n].key, "deleting key ");
+       zbr = &znode->zbranch[n];
+       lnc_free(zbr);
+@@ -2419,7 +2421,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+        */
+       do {
+-              ubifs_assert(!test_bit(OBSOLETE_ZNODE, &znode->flags));
++              ubifs_assert(!ubifs_zn_obsolete(znode));
+               ubifs_assert(ubifs_zn_dirty(znode));
+               zp = znode->parent;
+@@ -2475,9 +2477,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
+                       c->zroot.offs = zbr->offs;
+                       c->zroot.len = zbr->len;
+                       c->zroot.znode = znode;
+-                      ubifs_assert(!test_bit(OBSOLETE_ZNODE,
+-                                   &zp->flags));
+-                      ubifs_assert(test_bit(DIRTY_ZNODE, &zp->flags));
++                      ubifs_assert(!ubifs_zn_obsolete(zp));
++                      ubifs_assert(ubifs_zn_dirty(zp));
+                       atomic_long_dec(&c->dirty_zn_cnt);
+                       if (zp->cnext) {
+@@ -2505,7 +2506,7 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("key %s", DBGKEY(key));
++      dbg_tnck(key, "key ");
+       found = lookup_level0_dirty(c, key, &znode, &n);
+       if (found < 0) {
+               err = found;
+@@ -2536,7 +2537,7 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+       struct ubifs_znode *znode;
+       mutex_lock(&c->tnc_mutex);
+-      dbg_tnc("%.*s, key %s", nm->len, nm->name, DBGKEY(key));
++      dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
+       err = lookup_level0_dirty(c, key, &znode, &n);
+       if (err < 0)
+               goto out_unlock;
+@@ -2553,11 +2554,11 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
+               if (err) {
+                       /* Ensure the znode is dirtied */
+                       if (znode->cnext || !ubifs_zn_dirty(znode)) {
+-                                  znode = dirty_cow_bottom_up(c, znode);
+-                                  if (IS_ERR(znode)) {
+-                                          err = PTR_ERR(znode);
+-                                          goto out_unlock;
+-                                  }
++                              znode = dirty_cow_bottom_up(c, znode);
++                              if (IS_ERR(znode)) {
++                                      err = PTR_ERR(znode);
++                                      goto out_unlock;
++                              }
+                       }
+                       err = tnc_delete(c, znode, n);
+               }
+@@ -2651,7 +2652,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
+                               dbg_dump_znode(c, znode);
+                               goto out_unlock;
+                       }
+-                      dbg_tnc("removing %s", DBGKEY(key));
++                      dbg_tnck(key, "removing key ");
+               }
+               if (k) {
+                       for (i = n + 1 + k; i < znode->child_cnt; i++)
+@@ -2771,7 +2772,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
+       struct ubifs_zbranch *zbr;
+       union ubifs_key *dkey;
+-      dbg_tnc("%s %s", nm->name ? (char *)nm->name : "(lowest)", DBGKEY(key));
++      dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
+       ubifs_assert(is_hash_key(c, key));
+       mutex_lock(&c->tnc_mutex);
+@@ -2861,7 +2862,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
+               struct ubifs_znode *znode = cnext;
+               cnext = cnext->cnext;
+-              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++              if (ubifs_zn_obsolete(znode))
+                       kfree(znode);
+       } while (cnext && cnext != c->cnext);
+ }
+@@ -2872,12 +2873,13 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
+  */
+ void ubifs_tnc_close(struct ubifs_info *c)
+ {
+-      long clean_freed;
+-
+       tnc_destroy_cnext(c);
+       if (c->zroot.znode) {
+-              clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
+-              atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt);
++              long n;
++
++              ubifs_destroy_tnc_subtree(c->zroot.znode);
++              n = atomic_long_read(&c->clean_zn_cnt);
++              atomic_long_sub(n, &ubifs_clean_zn_cnt);
+       }
+       kfree(c->gap_lebs);
+       kfree(c->ilebs);
+@@ -3296,7 +3298,7 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+       if (!S_ISREG(inode->i_mode))
+               return 0;
+-      if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
++      if (!dbg_is_chk_gen(c))
+               return 0;
+       block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
+@@ -3329,12 +3331,13 @@ int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+ out_dump:
+       block = key_block(c, key);
+-      ubifs_err("inode %lu has size %lld, but there are data at offset %lld "
+-                "(data key %s)", (unsigned long)inode->i_ino, size,
+-                ((loff_t)block) << UBIFS_BLOCK_SHIFT, DBGKEY(key));
++      ubifs_err("inode %lu has size %lld, but there are data at offset %lld",
++                (unsigned long)inode->i_ino, size,
++                ((loff_t)block) << UBIFS_BLOCK_SHIFT);
++      mutex_unlock(&c->tnc_mutex);
+       dbg_dump_inode(c, inode);
+       dbg_dump_stack();
+-      err = -EINVAL;
++      return -EINVAL;
+ out_unlock:
+       mutex_unlock(&c->tnc_mutex);
+diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
+index 53288e5..4c15f07 100644
+--- a/fs/ubifs/tnc_commit.c
++++ b/fs/ubifs/tnc_commit.c
+@@ -22,6 +22,7 @@
+ /* This file implements TNC functions for committing */
++#include <linux/random.h>
+ #include "ubifs.h"
+ /**
+@@ -87,8 +88,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
+       atomic_long_dec(&c->dirty_zn_cnt);
+       ubifs_assert(ubifs_zn_dirty(znode));
+-      ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
++      ubifs_assert(ubifs_zn_cow(znode));
++      /*
++       * Note, unlike 'write_index()' we do not add memory barriers here
++       * because this function is called with @c->tnc_mutex locked.
++       */
+       __clear_bit(DIRTY_ZNODE, &znode->flags);
+       __clear_bit(COW_ZNODE, &znode->flags);
+@@ -377,15 +382,13 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
+                               c->gap_lebs = NULL;
+                               return err;
+                       }
+-                      if (!dbg_force_in_the_gaps_enabled) {
++                      if (!dbg_is_chk_index(c)) {
+                               /*
+                                * Do not print scary warnings if the debugging
+                                * option which forces in-the-gaps is enabled.
+                                */
+-                              ubifs_err("out of space");
+-                              spin_lock(&c->space_lock);
+-                              dbg_dump_budg(c);
+-                              spin_unlock(&c->space_lock);
++                              ubifs_warn("out of space");
++                              dbg_dump_budg(c, &c->bi);
+                               dbg_dump_lprops(c);
+                       }
+                       /* Try to commit anyway */
+@@ -493,25 +496,6 @@ static int layout_in_empty_space(struct ubifs_info *c)
+               else
+                       next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+-              if (c->min_io_size == 1) {
+-                      buf_offs += ALIGN(len, 8);
+-                      if (next_len) {
+-                              if (buf_offs + next_len <= c->leb_size)
+-                                      continue;
+-                              err = ubifs_update_one_lp(c, lnum, 0,
+-                                              c->leb_size - buf_offs, 0, 0);
+-                              if (err)
+-                                      return err;
+-                              lnum = -1;
+-                              continue;
+-                      }
+-                      err = ubifs_update_one_lp(c, lnum,
+-                                      c->leb_size - buf_offs, 0, 0, 0);
+-                      if (err)
+-                              return err;
+-                      break;
+-              }
+-
+               /* Update buffer positions */
+               wlen = used + len;
+               used += ALIGN(len, 8);
+@@ -660,7 +644,7 @@ static int get_znodes_to_commit(struct ubifs_info *c)
+       }
+       cnt += 1;
+       while (1) {
+-              ubifs_assert(!test_bit(COW_ZNODE, &znode->flags));
++              ubifs_assert(!ubifs_zn_cow(znode));
+               __set_bit(COW_ZNODE, &znode->flags);
+               znode->alt = 0;
+               cnext = find_next_dirty(znode);
+@@ -706,7 +690,7 @@ static int alloc_idx_lebs(struct ubifs_info *c, int cnt)
+               c->ilebs[c->ileb_cnt++] = lnum;
+               dbg_cmt("LEB %d", lnum);
+       }
+-      if (dbg_force_in_the_gaps())
++      if (dbg_is_chk_index(c) && !(random32() & 7))
+               return -ENOSPC;
+       return 0;
+ }
+@@ -796,16 +780,16 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
+       spin_lock(&c->space_lock);
+       /*
+        * Although we have not finished committing yet, update size of the
+-       * committed index ('c->old_idx_sz') and zero out the index growth
++       * committed index ('c->bi.old_idx_sz') and zero out the index growth
+        * budget. It is OK to do this now, because we've reserved all the
+        * space which is needed to commit the index, and it is save for the
+        * budgeting subsystem to assume the index is already committed,
+        * even though it is not.
+        */
+-      ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+-      c->old_idx_sz = c->calc_idx_sz;
+-      c->budg_uncommitted_idx = 0;
+-      c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
++      ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
++      c->bi.old_idx_sz = c->calc_idx_sz;
++      c->bi.uncommitted_idx = 0;
++      c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       spin_unlock(&c->space_lock);
+       mutex_unlock(&c->tnc_mutex);
+@@ -832,7 +816,7 @@ static int write_index(struct ubifs_info *c)
+       struct ubifs_idx_node *idx;
+       struct ubifs_znode *znode, *cnext;
+       int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
+-      int avail, wlen, err, lnum_pos = 0;
++      int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
+       cnext = c->enext;
+       if (!cnext)
+@@ -909,7 +893,7 @@ static int write_index(struct ubifs_info *c)
+               cnext = znode->cnext;
+               ubifs_assert(ubifs_zn_dirty(znode));
+-              ubifs_assert(test_bit(COW_ZNODE, &znode->flags));
++              ubifs_assert(ubifs_zn_cow(znode));
+               /*
+                * It is important that other threads should see %DIRTY_ZNODE
+@@ -924,6 +908,28 @@ static int write_index(struct ubifs_info *c)
+               clear_bit(COW_ZNODE, &znode->flags);
+               smp_mb__after_clear_bit();
++              /*
++               * We have marked the znode as clean but have not updated the
++               * @c->clean_zn_cnt counter. If this znode becomes dirty again
++               * before 'free_obsolete_znodes()' is called, then
++               * @c->clean_zn_cnt will be decremented before it gets
++               * incremented (resulting in 2 decrements for the same znode).
++               * This means that @c->clean_zn_cnt may become negative for a
++               * while.
++               *
++               * Q: why we cannot increment @c->clean_zn_cnt?
++               * A: because we do not have the @c->tnc_mutex locked, and the
++               *    following code would be racy and buggy:
++               *
++               *    if (!ubifs_zn_obsolete(znode)) {
++               *            atomic_long_inc(&c->clean_zn_cnt);
++               *            atomic_long_inc(&ubifs_clean_zn_cnt);
++               *    }
++               *
++               *    Thus, we just delay the @c->clean_zn_cnt update until we
++               *    have the mutex locked.
++               */
++
+               /* Do not access znode from this point on */
+               /* Update buffer positions */
+@@ -940,65 +946,38 @@ static int write_index(struct ubifs_info *c)
+               else
+                       next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
+-              if (c->min_io_size == 1) {
+-                      /*
+-                       * Write the prepared index node immediately if there is
+-                       * no minimum IO size
+-                       */
+-                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+-                                            wlen, UBI_SHORTTERM);
+-                      if (err)
+-                              return err;
+-                      buf_offs += ALIGN(wlen, 8);
+-                      if (next_len) {
+-                              used = 0;
+-                              avail = buf_len;
+-                              if (buf_offs + next_len > c->leb_size) {
+-                                      err = ubifs_update_one_lp(c, lnum,
+-                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
+-                                      if (err)
+-                                              return err;
+-                                      lnum = -1;
+-                              }
++              nxt_offs = buf_offs + used + next_len;
++              if (next_len && nxt_offs <= c->leb_size) {
++                      if (avail > 0)
+                               continue;
+-                      }
++                      else
++                              blen = buf_len;
+               } else {
+-                      int blen, nxt_offs = buf_offs + used + next_len;
+-
+-                      if (next_len && nxt_offs <= c->leb_size) {
+-                              if (avail > 0)
+-                                      continue;
+-                              else
+-                                      blen = buf_len;
+-                      } else {
+-                              wlen = ALIGN(wlen, 8);
+-                              blen = ALIGN(wlen, c->min_io_size);
+-                              ubifs_pad(c, c->cbuf + wlen, blen - wlen);
+-                      }
+-                      /*
+-                       * The buffer is full or there are no more znodes
+-                       * to do
+-                       */
+-                      err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs,
+-                                            blen, UBI_SHORTTERM);
+-                      if (err)
+-                              return err;
+-                      buf_offs += blen;
+-                      if (next_len) {
+-                              if (nxt_offs > c->leb_size) {
+-                                      err = ubifs_update_one_lp(c, lnum,
+-                                              LPROPS_NC, 0, 0, LPROPS_TAKEN);
+-                                      if (err)
+-                                              return err;
+-                                      lnum = -1;
+-                              }
+-                              used -= blen;
+-                              if (used < 0)
+-                                      used = 0;
+-                              avail = buf_len - used;
+-                              memmove(c->cbuf, c->cbuf + blen, used);
+-                              continue;
++                      wlen = ALIGN(wlen, 8);
++                      blen = ALIGN(wlen, c->min_io_size);
++                      ubifs_pad(c, c->cbuf + wlen, blen - wlen);
++              }
++
++              /* The buffer is full or there are no more znodes to do */
++              err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
++                                    UBI_SHORTTERM);
++              if (err)
++                      return err;
++              buf_offs += blen;
++              if (next_len) {
++                      if (nxt_offs > c->leb_size) {
++                              err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
++                                                        0, LPROPS_TAKEN);
++                              if (err)
++                                      return err;
++                              lnum = -1;
+                       }
++                      used -= blen;
++                      if (used < 0)
++                              used = 0;
++                      avail = buf_len - used;
++                      memmove(c->cbuf, c->cbuf + blen, used);
++                      continue;
+               }
+               break;
+       }
+@@ -1031,7 +1010,7 @@ static void free_obsolete_znodes(struct ubifs_info *c)
+       do {
+               znode = cnext;
+               cnext = znode->cnext;
+-              if (test_bit(OBSOLETE_ZNODE, &znode->flags))
++              if (ubifs_zn_obsolete(znode))
+                       kfree(znode);
+               else {
+                       znode->cnext = NULL;
+diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
+index b48db99..dc28fe6 100644
+--- a/fs/ubifs/tnc_misc.c
++++ b/fs/ubifs/tnc_misc.c
+@@ -328,8 +328,8 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
+               case UBIFS_XENT_KEY:
+                       break;
+               default:
+-                      dbg_msg("bad key type at slot %d: %s", i,
+-                              DBGKEY(&zbr->key));
++                      dbg_msg("bad key type at slot %d: %d",
++                              i, key_type(c, &zbr->key));
+                       err = 3;
+                       goto out_dump;
+               }
+@@ -475,7 +475,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+                                     zbr->offs);
+       if (err) {
+-              dbg_tnc("key %s", DBGKEY(key));
++              dbg_tnck(key, "key ");
+               return err;
+       }
+@@ -484,8 +484,8 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+       if (!keys_eq(c, key, &key1)) {
+               ubifs_err("bad key in node at LEB %d:%d",
+                         zbr->lnum, zbr->offs);
+-              dbg_tnc("looked for key %s found node's key %s",
+-                      DBGKEY(key), DBGKEY1(&key1));
++              dbg_tnck(key, "looked for key ");
++              dbg_tnck(&key1, "but found node's key ");
+               dbg_dump_node(c, node);
+               return -EINVAL;
+       }
+diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
+index 191ca78..e24380c 100644
+--- a/fs/ubifs/ubifs-media.h
++++ b/fs/ubifs/ubifs-media.h
+@@ -408,9 +408,11 @@ enum {
+  * Superblock flags.
+  *
+  * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
++ * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
+  */
+ enum {
+       UBIFS_FLG_BIGLPT = 0x02,
++      UBIFS_FLG_SPACE_FIXUP = 0x04,
+ };
+ /**
+@@ -434,7 +436,7 @@ struct ubifs_ch {
+       __u8 node_type;
+       __u8 group_type;
+       __u8 padding[2];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * union ubifs_dev_desc - device node descriptor.
+@@ -448,7 +450,7 @@ struct ubifs_ch {
+ union ubifs_dev_desc {
+       __le32 new;
+       __le64 huge;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_ino_node - inode node.
+@@ -509,7 +511,7 @@ struct ubifs_ino_node {
+       __le16 compr_type;
+       __u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
+       __u8 data[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_dent_node - directory entry node.
+@@ -534,7 +536,7 @@ struct ubifs_dent_node {
+       __le16 nlen;
+       __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
+       __u8 name[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_data_node - data node.
+@@ -555,7 +557,7 @@ struct ubifs_data_node {
+       __le16 compr_type;
+       __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
+       __u8 data[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_trun_node - truncation node.
+@@ -575,7 +577,7 @@ struct ubifs_trun_node {
+       __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
+       __le64 old_size;
+       __le64 new_size;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_pad_node - padding node.
+@@ -586,7 +588,7 @@ struct ubifs_trun_node {
+ struct ubifs_pad_node {
+       struct ubifs_ch ch;
+       __le32 pad_len;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_sb_node - superblock node.
+@@ -644,7 +646,7 @@ struct ubifs_sb_node {
+       __u8 uuid[16];
+       __le32 ro_compat_version;
+       __u8 padding2[3968];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_mst_node - master node.
+@@ -711,7 +713,7 @@ struct ubifs_mst_node {
+       __le32 idx_lebs;
+       __le32 leb_cnt;
+       __u8 padding[344];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_ref_node - logical eraseblock reference node.
+@@ -727,7 +729,7 @@ struct ubifs_ref_node {
+       __le32 offs;
+       __le32 jhead;
+       __u8 padding[28];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_branch - key/reference/length branch
+@@ -741,7 +743,7 @@ struct ubifs_branch {
+       __le32 offs;
+       __le32 len;
+       __u8 key[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_idx_node - indexing node.
+@@ -755,7 +757,7 @@ struct ubifs_idx_node {
+       __le16 child_cnt;
+       __le16 level;
+       __u8 branches[];
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_cs_node - commit start node.
+@@ -765,7 +767,7 @@ struct ubifs_idx_node {
+ struct ubifs_cs_node {
+       struct ubifs_ch ch;
+       __le64 cmt_no;
+-} __attribute__ ((packed));
++} __packed;
+ /**
+  * struct ubifs_orph_node - orphan node.
+@@ -777,6 +779,6 @@ struct ubifs_orph_node {
+       struct ubifs_ch ch;
+       __le64 cmt_no;
+       __le64 inos[];
+-} __attribute__ ((packed));
++} __packed;
+ #endif /* __UBIFS_MEDIA_H__ */
+diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
+index 381d6b2..caf9e4b 100644
+--- a/fs/ubifs/ubifs.h
++++ b/fs/ubifs/ubifs.h
+@@ -84,9 +84,6 @@
+ #define INUM_WARN_WATERMARK 0xFFF00000
+ #define INUM_WATERMARK      0xFFFFFF00
+-/* Largest key size supported in this implementation */
+-#define CUR_MAX_KEY_LEN UBIFS_SK_LEN
+-
+ /* Maximum number of entries in each LPT (LEB category) heap */
+ #define LPT_HEAP_SZ 256
+@@ -151,6 +148,12 @@
+  */
+ #define WORST_COMPR_FACTOR 2
++/*
++ * How much memory is needed for a buffer where we comress a data node.
++ */
++#define COMPRESSED_DATA_NODE_BUF_SZ \
++      (UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR)
++
+ /* Maximum expected tree height for use by bottom_up_buf */
+ #define BOTTOM_UP_HEIGHT 64
+@@ -224,14 +227,14 @@ enum {
+  * LPT cnode flag bits.
+  *
+  * DIRTY_CNODE: cnode is dirty
+- * COW_CNODE: cnode is being committed and must be copied before writing
+  * OBSOLETE_CNODE: cnode is being committed and has been copied (or deleted),
+- * so it can (and must) be freed when the commit is finished
++ *                 so it can (and must) be freed when the commit is finished
++ * COW_CNODE: cnode is being committed and must be copied before writing
+  */
+ enum {
+       DIRTY_CNODE    = 0,
+-      COW_CNODE      = 1,
+-      OBSOLETE_CNODE = 2,
++      OBSOLETE_CNODE = 1,
++      COW_CNODE      = 2,
+ };
+ /*
+@@ -271,10 +274,10 @@ struct ubifs_old_idx {
+ /* The below union makes it easier to deal with keys */
+ union ubifs_key {
+-      uint8_t u8[CUR_MAX_KEY_LEN];
+-      uint32_t u32[CUR_MAX_KEY_LEN/4];
+-      uint64_t u64[CUR_MAX_KEY_LEN/8];
+-      __le32 j32[CUR_MAX_KEY_LEN/4];
++      uint8_t u8[UBIFS_SK_LEN];
++      uint32_t u32[UBIFS_SK_LEN/4];
++      uint64_t u64[UBIFS_SK_LEN/8];
++      __le32 j32[UBIFS_SK_LEN/4];
+ };
+ /**
+@@ -383,9 +386,9 @@ struct ubifs_gced_idx_leb {
+  * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
+  * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
+  * make sure @inode->i_size is always changed under @ui_mutex, because it
+- * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would deadlock
+- * with 'ubifs_writepage()' (see file.c). All the other inode fields are
+- * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
++ * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would
++ * deadlock with 'ubifs_writepage()' (see file.c). All the other inode fields
++ * are changed under @ui_mutex, so they do not need "shadow" fields. Note, one
+  * could consider to rework locking and base it on "shadow" fields.
+  */
+ struct ubifs_inode {
+@@ -646,6 +649,7 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
+  * @offs: write-buffer offset in this logical eraseblock
+  * @avail: number of bytes available in the write-buffer
+  * @used:  number of used bytes in the write-buffer
++ * @size: write-buffer size (in [@c->min_io_size, @c->max_write_size] range)
+  * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
+  * %UBI_UNKNOWN)
+  * @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
+@@ -680,6 +684,7 @@ struct ubifs_wbuf {
+       int offs;
+       int avail;
+       int used;
++      int size;
+       int dtype;
+       int jhead;
+       int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
+@@ -714,12 +719,14 @@ struct ubifs_bud {
+  * struct ubifs_jhead - journal head.
+  * @wbuf: head's write-buffer
+  * @buds_list: list of bud LEBs belonging to this journal head
++ * @grouped: non-zero if UBIFS groups nodes when writing to this journal head
+  *
+  * Note, the @buds list is protected by the @c->buds_lock.
+  */
+ struct ubifs_jhead {
+       struct ubifs_wbuf wbuf;
+       struct list_head buds_list;
++      unsigned int grouped:1;
+ };
+ /**
+@@ -929,6 +936,40 @@ struct ubifs_mount_opts {
+       unsigned int compr_type:2;
+ };
++/**
++ * struct ubifs_budg_info - UBIFS budgeting information.
++ * @idx_growth: amount of bytes budgeted for index growth
++ * @data_growth: amount of bytes budgeted for cached data
++ * @dd_growth: amount of bytes budgeted for cached data that will make
++ *             other data dirty
++ * @uncommitted_idx: amount of bytes were budgeted for growth of the index, but
++ *                   which still have to be taken into account because the index
++ *                   has not been committed so far
++ * @old_idx_sz: size of index on flash
++ * @min_idx_lebs: minimum number of LEBs required for the index
++ * @nospace: non-zero if the file-system does not have flash space (used as
++ *           optimization)
++ * @nospace_rp: the same as @nospace, but additionally means that even reserved
++ *              pool is full
++ * @page_budget: budget for a page (constant, nenver changed after mount)
++ * @inode_budget: budget for an inode (constant, nenver changed after mount)
++ * @dent_budget: budget for a directory entry (constant, nenver changed after
++ *               mount)
++ */
++struct ubifs_budg_info {
++      long long idx_growth;
++      long long data_growth;
++      long long dd_growth;
++      long long uncommitted_idx;
++      unsigned long long old_idx_sz;
++      int min_idx_lebs;
++      unsigned int nospace:1;
++      unsigned int nospace_rp:1;
++      int page_budget;
++      int inode_budget;
++      int dent_budget;
++};
++
+ struct ubifs_debug_info;
+ /**
+@@ -972,6 +1013,7 @@ struct ubifs_debug_info;
+  * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
+  *
+  * @big_lpt: flag that LPT is too big to write whole during commit
++ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
+  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
+  *                   recovery)
+  * @bulk_read: enable bulk-reads
+@@ -1003,6 +1045,11 @@ struct ubifs_debug_info;
+  * @bu_mutex: protects the pre-allocated bulk-read buffer and @c->bu
+  * @bu: pre-allocated bulk-read information
+  *
++ * @write_reserve_mutex: protects @write_reserve_buf
++ * @write_reserve_buf: on the write path we allocate memory, which might
++ *                     sometimes be unavailable, in which case we use this
++ *                     write reserve buffer
++ *
+  * @log_lebs: number of logical eraseblocks in the log
+  * @log_bytes: log size in bytes
+  * @log_last: last LEB of the log
+@@ -1024,7 +1071,12 @@ struct ubifs_debug_info;
+  *
+  * @min_io_size: minimal input/output unit size
+  * @min_io_shift: number of bits in @min_io_size minus one
++ * @max_write_size: maximum amount of bytes the underlying flash can write at a
++ *                  time (MTD write buffer size)
++ * @max_write_shift: number of bits in @max_write_size minus one
+  * @leb_size: logical eraseblock size in bytes
++ * @leb_start: starting offset of logical eraseblocks within physical
++ *             eraseblocks
+  * @half_leb_size: half LEB size
+  * @idx_leb_size: how many bytes of an LEB are effectively available when it is
+  *                used to store indexing nodes (@leb_size - @max_idx_node_sz)
+@@ -1039,32 +1091,14 @@ struct ubifs_debug_info;
+  * @dirty_zn_cnt: number of dirty znodes
+  * @clean_zn_cnt: number of clean znodes
+  *
+- * @budg_idx_growth: amount of bytes budgeted for index growth
+- * @budg_data_growth: amount of bytes budgeted for cached data
+- * @budg_dd_growth: amount of bytes budgeted for cached data that will make
+- *                  other data dirty
+- * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
+- *                        but which still have to be taken into account because
+- *                        the index has not been committed so far
+- * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
+- *              @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
+- *              @nospace, and @nospace_rp;
+- * @min_idx_lebs: minimum number of LEBs required for the index
+- * @old_idx_sz: size of index on flash
++ * @space_lock: protects @bi and @lst
++ * @lst: lprops statistics
++ * @bi: budgeting information
+  * @calc_idx_sz: temporary variable which is used to calculate new index size
+  *               (contains accurate new index size at end of TNC commit start)
+- * @lst: lprops statistics
+- * @nospace: non-zero if the file-system does not have flash space (used as
+- *           optimization)
+- * @nospace_rp: the same as @nospace, but additionally means that even reserved
+- *              pool is full
+- *
+- * @page_budget: budget for a page
+- * @inode_budget: budget for an inode
+- * @dent_budget: budget for a directory entry
+  *
+  * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
+- * I/O unit
++ *                 I/O unit
+  * @mst_node_alsz: master node aligned size
+  * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
+  * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
+@@ -1166,22 +1200,20 @@ struct ubifs_debug_info;
+  * @rp_uid: reserved pool user ID
+  * @rp_gid: reserved pool group ID
+  *
+- * @empty: if the UBI device is empty
+- * @replay_tree: temporary tree used during journal replay
++ * @empty: %1 if the UBI device is empty
++ * @need_recovery: %1 if the file-system needs recovery
++ * @replaying: %1 during journal replay
++ * @mounting: %1 while mounting
++ * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
+  * @replay_list: temporary list used during journal replay
+  * @replay_buds: list of buds to replay
+  * @cs_sqnum: sequence number of first node in the log (commit start node)
+  * @replay_sqnum: sequence number of node currently being replayed
+- * @need_recovery: file-system needs recovery
+- * @replaying: set to %1 during journal replay
+  * @unclean_leb_list: LEBs to recover when re-mounting R/O mounted FS to R/W
+  *                    mode
+  * @rcvrd_mst_node: recovered master node to write when re-mounting R/O mounted
+  *                  FS to R/W mode
+  * @size_tree: inode size information for recovery
+- * @remounting_rw: set while re-mounting from R/O mode to R/W mode
+- * @always_chk_crc: always check CRCs (while mounting and remounting to R/W
+- *                  mode)
+  * @mount_opts: UBIFS-specific mount options
+  *
+  * @dbg: debugging-related information
+@@ -1221,6 +1253,7 @@ struct ubifs_info {
+       wait_queue_head_t cmt_wq;
+       unsigned int big_lpt:1;
++      unsigned int space_fixup:1;
+       unsigned int no_chk_data_crc:1;
+       unsigned int bulk_read:1;
+       unsigned int default_compr:2;
+@@ -1250,6 +1283,9 @@ struct ubifs_info {
+       struct mutex bu_mutex;
+       struct bu_info bu;
++      struct mutex write_reserve_mutex;
++      void *write_reserve_buf;
++
+       int log_lebs;
+       long long log_bytes;
+       int log_last;
+@@ -1271,7 +1307,10 @@ struct ubifs_info {
+       int min_io_size;
+       int min_io_shift;
++      int max_write_size;
++      int max_write_shift;
+       int leb_size;
++      int leb_start;
+       int half_leb_size;
+       int idx_leb_size;
+       int leb_cnt;
+@@ -1285,21 +1324,10 @@ struct ubifs_info {
+       atomic_long_t dirty_zn_cnt;
+       atomic_long_t clean_zn_cnt;
+-      long long budg_idx_growth;
+-      long long budg_data_growth;
+-      long long budg_dd_growth;
+-      long long budg_uncommitted_idx;
+       spinlock_t space_lock;
+-      int min_idx_lebs;
+-      unsigned long long old_idx_sz;
+-      unsigned long long calc_idx_sz;
+       struct ubifs_lp_stats lst;
+-      unsigned int nospace:1;
+-      unsigned int nospace_rp:1;
+-
+-      int page_budget;
+-      int inode_budget;
+-      int dent_budget;
++      struct ubifs_budg_info bi;
++      unsigned long long calc_idx_sz;
+       int ref_node_alsz;
+       int mst_node_alsz;
+@@ -1402,19 +1430,18 @@ struct ubifs_info {
+       gid_t rp_gid;
+       /* The below fields are used only during mounting and re-mounting */
+-      int empty;
+-      struct rb_root replay_tree;
++      unsigned int empty:1;
++      unsigned int need_recovery:1;
++      unsigned int replaying:1;
++      unsigned int mounting:1;
++      unsigned int remounting_rw:1;
+       struct list_head replay_list;
+       struct list_head replay_buds;
+       unsigned long long cs_sqnum;
+       unsigned long long replay_sqnum;
+-      int need_recovery;
+-      int replaying;
+       struct list_head unclean_leb_list;
+       struct ubifs_mst_node *rcvrd_mst_node;
+       struct rb_root size_tree;
+-      int remounting_rw;
+-      int always_chk_crc;
+       struct ubifs_mount_opts mount_opts;
+ #ifdef CONFIG_UBIFS_FS_DEBUG
+@@ -1438,6 +1465,15 @@ extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
+ /* io.c */
+ void ubifs_ro_mode(struct ubifs_info *c, int err);
++int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
++                 int len, int even_ebadmsg);
++int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
++                  int len, int dtype);
++int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
++                   int dtype);
++int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
++int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
++int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
+ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
+ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
+                          int dtype);
+@@ -1605,6 +1641,7 @@ int ubifs_write_master(struct ubifs_info *c);
+ int ubifs_read_superblock(struct ubifs_info *c);
+ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
+ int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
++int ubifs_fixup_free_space(struct ubifs_info *c);
+ /* replay.c */
+ int ubifs_validate_entry(struct ubifs_info *c,
+@@ -1713,11 +1750,11 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
+ int ubifs_recover_master_node(struct ubifs_info *c);
+ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
+ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
+-                                       int offs, void *sbuf, int grouped);
++                                       int offs, void *sbuf, int jhead);
+ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
+                                            int offs, void *sbuf);
+-int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
+-int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf);
++int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf);
++int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf);
+ int ubifs_rcvry_gc_commit(struct ubifs_info *c);
+ int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
+                            int deletion, loff_t new_size);
+diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
+index c74400f..2fdc4fa 100644
+--- a/fs/ubifs/xattr.c
++++ b/fs/ubifs/xattr.c
+@@ -79,9 +79,9 @@ enum {
+       SECURITY_XATTR,
+ };
+-static const struct inode_operations none_inode_operations;
+-static const struct address_space_operations none_address_operations;
+-static const struct file_operations none_file_operations;
++static const struct inode_operations empty_iops;
++static const struct file_operations empty_fops;
++static struct address_space_operations empty_aops;
+ /**
+  * create_xattr - create an extended attribute.
+@@ -130,20 +130,19 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
+       }
+       /* Re-define all operations to be "nothing" */
+-      inode->i_mapping->a_ops = &none_address_operations;
+-      inode->i_op = &none_inode_operations;
+-      inode->i_fop = &none_file_operations;
++      inode->i_mapping->a_ops = &empty_aops;
++      inode->i_op = &empty_iops;
++      inode->i_fop = &empty_fops;
+       inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA;
+       ui = ubifs_inode(inode);
+       ui->xattr = 1;
+       ui->flags |= UBIFS_XATTR_FL;
+-      ui->data = kmalloc(size, GFP_NOFS);
++      ui->data = kmemdup(value, size, GFP_NOFS);
+       if (!ui->data) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+-      memcpy(ui->data, value, size);
+       inode->i_size = ui->ui_size = size;
+       ui->data_len = size;
+@@ -204,12 +203,11 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
+               return err;
+       kfree(ui->data);
+-      ui->data = kmalloc(size, GFP_NOFS);
++      ui->data = kmemdup(value, size, GFP_NOFS);
+       if (!ui->data) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+-      memcpy(ui->data, value, size);
+       inode->i_size = ui->ui_size = size;
+       ui->data_len = size;
+diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
+index b31bd9e..db4836b 100644
+--- a/include/linux/mtd/ubi.h
++++ b/include/linux/mtd/ubi.h
+@@ -21,7 +21,7 @@
+ #ifndef __LINUX_UBI_H__
+ #define __LINUX_UBI_H__
+-#include <asm/ioctl.h>
++#include <linux/ioctl.h>
+ #include <linux/types.h>
+ #include <mtd/ubi-user.h>
+@@ -87,7 +87,7 @@ enum {
+  * physical eraseblock size and on how much bytes UBI headers consume. But
+  * because of the volume alignment (@alignment), the usable size of logical
+  * eraseblocks if a volume may be less. The following equation is true:
+- *    @usable_leb_size = LEB size - (LEB size mod @alignment),
++ *    @usable_leb_size = LEB size - (LEB size mod @alignment),
+  * where LEB size is the logical eraseblock size defined by the UBI device.
+  *
+  * The alignment is multiple to the minimal flash input/output unit size or %1
+@@ -116,29 +116,53 @@ struct ubi_volume_info {
+  * struct ubi_device_info - UBI device description data structure.
+  * @ubi_num: ubi device number
+  * @leb_size: logical eraseblock size on this UBI device
++ * @leb_start: starting offset of logical eraseblocks within physical
++ *             eraseblocks
+  * @min_io_size: minimal I/O unit size
++ * @max_write_size: maximum amount of bytes the underlying flash can write at a
++ *                  time (MTD write buffer size)
+  * @ro_mode: if this device is in read-only mode
+  * @cdev: UBI character device major and minor numbers
+  *
+  * Note, @leb_size is the logical eraseblock size offered by the UBI device.
+  * Volumes of this UBI device may have smaller logical eraseblock size if their
+  * alignment is not equivalent to %1.
++ *
++ * The @max_write_size field describes flash write maximum write unit. For
++ * example, NOR flash allows for changing individual bytes, so @min_io_size is
++ * %1. However, it does not mean than NOR flash has to write data byte-by-byte.
++ * Instead, CFI NOR flashes have a write-buffer of, e.g., 64 bytes, and when
++ * writing large chunks of data, they write 64-bytes at a time. Obviously, this
++ * improves write throughput.
++ *
++ * Also, the MTD device may have N interleaved (striped) flash chips
++ * underneath, in which case @min_io_size can be physical min. I/O size of
++ * single flash chip, while @max_write_size can be N * @min_io_size.
++ *
++ * The @max_write_size field is always greater or equivalent to @min_io_size.
++ * E.g., some NOR flashes may have (@min_io_size = 1, @max_write_size = 64). In
++ * contrast, NAND flashes usually have @min_io_size = @max_write_size = NAND
++ * page size.
+  */
+ struct ubi_device_info {
+       int ubi_num;
+       int leb_size;
++      int leb_start;
+       int min_io_size;
++      int max_write_size;
+       int ro_mode;
+       dev_t cdev;
+ };
+ /*
+- * enum - volume notification types.
+- * @UBI_VOLUME_ADDED: volume has been added
+- * @UBI_VOLUME_REMOVED: start volume volume
+- * @UBI_VOLUME_RESIZED: volume size has been re-sized
+- * @UBI_VOLUME_RENAMED: volume name has been re-named
+- * @UBI_VOLUME_UPDATED: volume name has been updated
++ * Volume notification types.
++ * @UBI_VOLUME_ADDED: a volume has been added (an UBI device was attached or a
++ *                    volume was created)
++ * @UBI_VOLUME_REMOVED: a volume has been removed (an UBI device was detached
++ *                    or a volume was removed)
++ * @UBI_VOLUME_RESIZED: a volume has been re-sized
++ * @UBI_VOLUME_RENAMED: a volume has been re-named
++ * @UBI_VOLUME_UPDATED: data has been written to a volume
+  *
+  * These constants define which type of event has happened when a volume
+  * notification function is invoked.
diff --git a/recipes/linux/linux-vusolo2-2.6.37/vusolo2_defconfig b/recipes/linux/linux-vusolo2-2.6.37/vusolo2_defconfig
new file mode 100644 (file)
index 0000000..edda06c
--- /dev/null
@@ -0,0 +1,1909 @@
+#
+# Automatically generated make config: don't edit
+# Linux/mips 2.6.37-2.8 Kernel Configuration
+# Thu Aug 23 13:51:32 2012
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+CONFIG_BRCMSTB=y
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+
+#
+# Broadcom STB options
+#
+# CONFIG_BRCM_LEGACY is not set
+# CONFIG_BCM7125C0 is not set
+# CONFIG_BCM7231B0 is not set
+# CONFIG_BCM7340B0 is not set
+# CONFIG_BCM7344B0 is not set
+CONFIG_BCM7346B0=y
+# CONFIG_BCM7358A0 is not set
+# CONFIG_BCM7405B0 is not set
+# CONFIG_BCM7405D0 is not set
+# CONFIG_BCM7408B0 is not set
+# CONFIG_BCM7420C0 is not set
+# CONFIG_BCM7425B0 is not set
+# CONFIG_BCM7429A0 is not set
+# CONFIG_BCM7435A0 is not set
+# CONFIG_BCM7468B0 is not set
+# CONFIG_BCM7550A0 is not set
+# CONFIG_BCM7550B0 is not set
+# CONFIG_BCM7552B0 is not set
+
+#
+# Memory map
+#
+CONFIG_BRCM_UPPER_MEMORY=y
+# CONFIG_BRCM_OVERRIDE_RAM_SIZE is not set
+
+#
+# Onchip peripherals
+#
+CONFIG_BRCM_CONSOLE_DEVICE=0
+CONFIG_BRCM_FLASH=y
+# CONFIG_BRCM_FIXED_MTD_PARTITIONS is not set
+CONFIG_MTD_BRCMNAND=y
+CONFIG_SPI_BRCMSTB=y
+CONFIG_BCMGENET=y
+
+#
+# BCMGENET options
+#
+CONFIG_BCMGENET_0_GPHY=y
+# CONFIG_BCMGENET_1_GPHY is not set
+# CONFIG_BCMGENET_RX_DESC_THROTTLE is not set
+CONFIG_BCMGENET_NAPI=y
+# CONFIG_BCMGENET_RX_CSUM is not set
+# CONFIG_BCMGENET_TX_CSUM is not set
+# CONFIG_BCMGENET_DUMP_DATA is not set
+# CONFIG_BCMGENET_DUMP_TRACE is not set
+CONFIG_BRCM_MOCA=y
+CONFIG_BRCM_USB=y
+# CONFIG_BRCM_OVERRIDE_USB is not set
+CONFIG_BRCM_SDIO=y
+CONFIG_BRCM_PM=y
+CONFIG_CSRC_WKTMR=y
+# CONFIG_CSRC_UPG is not set
+
+#
+# Miscellaneous options
+#
+# CONFIG_BRCM_FORCE_DOCSIS is not set
+CONFIG_BRCM_LIBGCC=y
+# CONFIG_BRCM_SCSI_NO_RW10_RETRIES is not set
+CONFIG_BRCM_WLAN_MODULES=y
+# CONFIG_BRCM_DEBUG_OPTIONS is not set
+CONFIG_BMIPS5000=y
+CONFIG_BRCM_HAS_16550=y
+CONFIG_BRCM_HAS_UARTA=y
+CONFIG_BRCM_HAS_UARTB=y
+CONFIG_BRCM_HAS_UARTC=y
+CONFIG_BRCM_UARTA_IS_16550=y
+CONFIG_BRCM_UARTB_IS_16550=y
+CONFIG_BRCM_UARTC_IS_16550=y
+CONFIG_BRCM_GENET_V2=y
+CONFIG_BRCM_GENET_VERSION=2
+CONFIG_BRCM_HAS_GENET=y
+CONFIG_BRCM_HAS_GENET_0=y
+CONFIG_BRCM_HAS_GENET_1=y
+CONFIG_BRCM_HAS_MOCA=y
+CONFIG_BRCM_HAS_MOCA_11_PLUS=y
+CONFIG_BRCM_MOCA_VERS=0x1102
+CONFIG_BRCM_MOCA_ON_GENET_1=y
+CONFIG_BRCM_HAS_MOCA_MIDRF=y
+CONFIG_BRCM_HAS_SATA=y
+CONFIG_BRCM_HAS_SATA3=y
+# CONFIG_BRCM_SATA_75MHZ_PLL is not set
+# CONFIG_BRCM_SATA_SINGLE_PORT is not set
+CONFIG_BRCM_HAS_NOR=y
+CONFIG_BRCM_HAS_NAND_MINOR_0=y
+CONFIG_BRCM_HAS_NAND_MAJOR_5=y
+CONFIG_BRCMNAND_MAJOR_VERS=5
+CONFIG_BRCMNAND_MINOR_VERS=0
+CONFIG_BRCM_HAS_NAND=y
+CONFIG_BRCM_HAS_SPI=y
+CONFIG_BRCM_HAS_BSPI_V4=y
+CONFIG_BRCM_BSPI_MAJOR_VERS=4
+CONFIG_BRCM_HAS_WKTMR=y
+CONFIG_BRCM_HAS_SDIO=y
+CONFIG_BRCM_HAS_SDIO_V1=y
+CONFIG_BRCM_ZSCM_L2=y
+CONFIG_BRCM_CPU_DIV=y
+CONFIG_BRCM_HAS_XKS01=y
+CONFIG_BRCM_HAS_XI=y
+CONFIG_BRCM_HAS_UPPER_MEMORY=y
+CONFIG_BRCM_UPPER_768MB=y
+CONFIG_BRCM_HAS_1GB_MEMC0=y
+CONFIG_BRCM_HAS_DIGITAL_DDR_PHY=y
+CONFIG_BRCM_HAS_STANDBY=y
+CONFIG_BRCM_HAS_AON=y
+CONFIG_BRCM_PWR_HANDSHAKE=y
+CONFIG_BRCM_PWR_HANDSHAKE_V1=y
+CONFIG_BRCM_HAS_USB_CAPS=y
+CONFIG_BRCM_PLATFORM_DEFAULTS=y
+CONFIG_BCM7346=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_BOOT_RAW=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CFE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_BOARD_SCACHE=y
+CONFIG_MIPS_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_HIGHMEM is not set
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SMP=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_USE_OF is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
+# CONFIG_HAVE_SPARSE_IRQ is not set
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_PENDING_IRQ is not set
+# CONFIG_AUTO_IRQ_AFFINITY is not set
+CONFIG_IRQ_PER_CPU=y
+# CONFIG_HARDIRQS_SW_RESEND is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+CONFIG_MTD_ABSENT=y
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IWMC3200TOP is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_SATA_MV is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_MII=y
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM63XX_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+CONFIG_REALTEK_PHY=y
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_STMMAC_ETH is not set
+CONFIG_NETDEV_10000=y
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=m
+# CONFIG_RT2500USB is not set
+CONFIG_RT73USB=m
+# CONFIG_RT2800USB is not set
+CONFIG_RT2X00_LIB_USB=m
+CONFIG_RT2X00_LIB=m
+CONFIG_RT2X00_LIB_FIRMWARE=y
+CONFIG_RT2X00_LIB_CRYPTO=y
+# CONFIG_RT2X00_DEBUG is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+CONFIG_ZD1211RW=m
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=y
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DVB_CORE=y
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_LIRC=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+CONFIG_IR_RC5_SZ_DECODER=y
+CONFIG_IR_LIRC_CODEC=y
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+CONFIG_MEDIA_TUNER_CUSTOMISE=y
+
+#
+# Customize TV tuners
+#
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_MT2131=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_MEDIA_TUNER_MXL5007T=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MAX2165=m
+CONFIG_MEDIA_TUNER_TDA18218=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_DVB_DYNAMIC_MINORS=y
+CONFIG_DVB_CAPTURE_DRIVERS=y
+# CONFIG_TTPCI_EEPROM is not set
+
+#
+# Supported USB Adapters
+#
+# CONFIG_DVB_USB is not set
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported DVB Frontends
+#
+CONFIG_DVB_FE_CUSTOMISE=y
+
+#
+# Customise DVB Frontends
+#
+
+#
+# Multistandard (satellite) frontends
+#
+CONFIG_DVB_STB0899=m
+CONFIG_DVB_STB6100=m
+CONFIG_DVB_STV090x=m
+CONFIG_DVB_STV6110x=m
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_ZL10036=m
+CONFIG_DVB_ZL10039=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0288=m
+CONFIG_DVB_STB6000=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_STV6110=m
+CONFIG_DVB_STV0900=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_TDA8261=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TUA6100=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+CONFIG_DVB_MB86A16=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_S5H1432=m
+CONFIG_DVB_DRX397XD=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+CONFIG_DVB_AF9013=m
+CONFIG_DVB_EC100=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_LGDT3305=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_S5H1411=m
+
+#
+# ISDB-T (terrestrial) frontends
+#
+CONFIG_DVB_S921=m
+CONFIG_DVB_DIB8000=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+CONFIG_DVB_ISL6405=m
+CONFIG_DVB_ISL6421=m
+CONFIG_DVB_ISL6423=m
+CONFIG_DVB_LGS8GL5=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_TDA665x=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_MIPS=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_BKL=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/recipes/linux/linux-vusolo2-3.1.1/vusolo2_defconfig b/recipes/linux/linux-vusolo2-3.1.1/vusolo2_defconfig
new file mode 100644 (file)
index 0000000..56abc77
--- /dev/null
@@ -0,0 +1,1888 @@
+#
+# Automatically generated make config: don't edit
+# Linux/mips 2.6.37-2.6 Kernel Configuration
+# Tue May  8 19:33:05 2012
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_ALCHEMY is not set
+# CONFIG_AR7 is not set
+# CONFIG_BCM47XX is not set
+# CONFIG_BCM63XX is not set
+CONFIG_BRCMSTB=y
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_MACH_JZ4740 is not set
+# CONFIG_LASAT is not set
+# CONFIG_MACH_LOONGSON is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_NEC_MARKEINS is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_NXP_STB220 is not set
+# CONFIG_NXP_STB225 is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_PNX8550_STB810 is not set
+# CONFIG_PMC_MSP is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_POWERTV is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP28 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SNI_RM is not set
+# CONFIG_MACH_TX39XX is not set
+# CONFIG_MACH_TX49XX is not set
+# CONFIG_MIKROTIK_RB532 is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set
+# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set
+# CONFIG_ALCHEMY_GPIO_INDIRECT is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+
+#
+# Broadcom STB options
+#
+# CONFIG_BRCM_LEGACY is not set
+# CONFIG_BCM7125C0 is not set
+# CONFIG_BCM7231A0 is not set
+# CONFIG_BCM7231B0 is not set
+# CONFIG_BCM7340B0 is not set
+# CONFIG_BCM7344A0 is not set
+# CONFIG_BCM7344B0 is not set
+# CONFIG_BCM7346A0 is not set
+CONFIG_BCM7346B0=y
+# CONFIG_BCM7358A0 is not set
+# CONFIG_BCM7405B0 is not set
+# CONFIG_BCM7405D0 is not set
+# CONFIG_BCM7408B0 is not set
+# CONFIG_BCM7420C0 is not set
+# CONFIG_BCM7425A0 is not set
+# CONFIG_BCM7425B0 is not set
+# CONFIG_BCM7429A0 is not set
+# CONFIG_BCM7435A0 is not set
+# CONFIG_BCM7468B0 is not set
+# CONFIG_BCM7550A0 is not set
+# CONFIG_BCM7550B0 is not set
+# CONFIG_BCM7552A0 is not set
+# CONFIG_BCM7552B0 is not set
+
+#
+# Memory map
+#
+CONFIG_BRCM_UPPER_MEMORY=y
+# CONFIG_BRCM_OVERRIDE_RAM_SIZE is not set
+
+#
+# Onchip peripherals
+#
+CONFIG_BRCM_CONSOLE_DEVICE=0
+CONFIG_BRCM_FLASH=y
+# CONFIG_BRCM_FIXED_MTD_PARTITIONS is not set
+CONFIG_MTD_BRCMNAND=y
+CONFIG_SPI_BRCMSTB=y
+CONFIG_BCMGENET=y
+
+#
+# BCMGENET options
+#
+# CONFIG_BCMGENET_0_GPHY is not set
+# CONFIG_BCMGENET_1_GPHY is not set
+# CONFIG_BCMGENET_RX_DESC_THROTTLE is not set
+CONFIG_BCMGENET_NAPI=y
+# CONFIG_BCMGENET_RX_CSUM is not set
+# CONFIG_BCMGENET_TX_CSUM is not set
+# CONFIG_BCMGENET_DUMP_DATA is not set
+# CONFIG_BCMGENET_DUMP_TRACE is not set
+CONFIG_BRCM_MOCA=y
+CONFIG_BRCM_USB=y
+# CONFIG_BRCM_OVERRIDE_USB is not set
+CONFIG_BRCM_SDIO=y
+CONFIG_BRCM_PM=y
+CONFIG_CSRC_WKTMR=y
+# CONFIG_CSRC_UPG is not set
+
+#
+# Miscellaneous options
+#
+# CONFIG_BRCM_FORCE_DOCSIS is not set
+CONFIG_BRCM_LIBGCC=y
+# CONFIG_BRCM_SCSI_NO_RW10_RETRIES is not set
+CONFIG_BRCM_WLAN_MODULES=y
+# CONFIG_BRCM_DEBUG_OPTIONS is not set
+CONFIG_BMIPS5000=y
+CONFIG_BRCM_HAS_16550=y
+CONFIG_BRCM_HAS_UARTA=y
+CONFIG_BRCM_HAS_UARTB=y
+CONFIG_BRCM_HAS_UARTC=y
+CONFIG_BRCM_UARTA_IS_16550=y
+CONFIG_BRCM_UARTB_IS_16550=y
+CONFIG_BRCM_UARTC_IS_16550=y
+CONFIG_BRCM_GENET_V2=y
+CONFIG_BRCM_GENET_VERSION=2
+CONFIG_BRCM_HAS_GENET=y
+CONFIG_BRCM_HAS_GENET_0=y
+CONFIG_BRCM_HAS_GENET_1=y
+CONFIG_BRCM_HAS_MOCA=y
+CONFIG_BRCM_HAS_MOCA_11_PLUS=y
+CONFIG_BRCM_MOCA_VERS=0x1102
+CONFIG_BRCM_MOCA_ON_GENET_1=y
+CONFIG_BRCM_HAS_MOCA_MIDRF=y
+CONFIG_BRCM_HAS_SATA=y
+CONFIG_BRCM_HAS_SATA3=y
+# CONFIG_BRCM_SATA_75MHZ_PLL is not set
+# CONFIG_BRCM_SATA_SINGLE_PORT is not set
+CONFIG_BRCM_HAS_NOR=y
+CONFIG_BRCM_HAS_NAND_MINOR_0=y
+CONFIG_BRCM_HAS_NAND_MAJOR_5=y
+CONFIG_BRCMNAND_MAJOR_VERS=5
+CONFIG_BRCMNAND_MINOR_VERS=0
+CONFIG_BRCM_HAS_NAND=y
+CONFIG_BRCM_HAS_SPI=y
+CONFIG_BRCM_HAS_BSPI_V4=y
+CONFIG_BRCM_BSPI_MAJOR_VERS=4
+CONFIG_BRCM_HAS_WKTMR=y
+CONFIG_BRCM_HAS_SDIO=y
+CONFIG_BRCM_HAS_SDIO_V1=y
+CONFIG_BRCM_ZSCM_L2=y
+CONFIG_BRCM_CPU_DIV=y
+CONFIG_BRCM_HAS_XKS01=y
+CONFIG_BRCM_HAS_XI=y
+CONFIG_BRCM_HAS_UPPER_MEMORY=y
+CONFIG_BRCM_UPPER_768MB=y
+CONFIG_BRCM_HAS_1GB_MEMC0=y
+CONFIG_BRCM_HAS_DIGITAL_DDR_PHY=y
+CONFIG_BRCM_HAS_STANDBY=y
+CONFIG_BRCM_HAS_AON=y
+CONFIG_BRCM_PWR_HANDSHAKE=y
+CONFIG_BRCM_PWR_HANDSHAKE_V1=y
+CONFIG_BRCM_HAS_USB_CAPS=y
+CONFIG_BRCM_PLATFORM_DEFAULTS=y
+CONFIG_BCM7346=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_ARCH_SUPPORTS_OPROFILE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_BOOT_RAW=y
+CONFIG_CEVT_R4K_LIB=y
+CONFIG_CEVT_R4K=y
+CONFIG_CFE=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+# CONFIG_NO_IOPORT is not set
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_HARDWARE_WATCHPOINTS=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_BOARD_SCACHE=y
+CONFIG_MIPS_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_HIGHMEM is not set
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_SMP=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_48 is not set
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+CONFIG_HZ_1000=y
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_HZ=1000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_KEXEC is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_USE_OF is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set
+# CONFIG_HAVE_SPARSE_IRQ is not set
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_PENDING_IRQ is not set
+# CONFIG_AUTO_IRQ_AFFINITY is not set
+CONFIG_IRQ_PER_CPU=y
+# CONFIG_HARDIRQS_SW_RESEND is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_FREEZER=y
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_MMU=y
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options
+#
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_HIBERNATION is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_OPS=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=y
+CONFIG_BRIDGE=y
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+CONFIG_RPS=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_WEXT_PRIV=y
+CONFIG_CFG80211=y
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_LIB80211=y
+# CONFIG_LIB80211_DEBUG is not set
+CONFIG_MAC80211=y
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+CONFIG_MTD_ABSENT=y
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+CONFIG_M25PXX_USE_FAST_READ=y
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IWMC3200TOP is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_SATA_MV is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_MII=y
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_ATH_COMMON is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IWM is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_P54_COMMON is not set
+CONFIG_RT2X00=y
+# CONFIG_RT2500USB is not set
+# CONFIG_RT73USB is not set
+# CONFIG_RT2800USB is not set
+# CONFIG_WL1251 is not set
+# CONFIG_WL12XX is not set
+CONFIG_ZD1211RW=y
+# CONFIG_ZD1211RW_DEBUG is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=y
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+# CONFIG_USB_NET_CDC_EEM is not set
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC75XX is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=y
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+CONFIG_USB_NET_CDC_SUBSET=y
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+CONFIG_USB_NET_ZAURUS=y
+# CONFIG_USB_NET_CX82310_ETH is not set
+# CONFIG_USB_NET_INT51X1 is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_USB_SIERRA_NET is not set
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX3107 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC35892 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DVB_CORE=y
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_LIRC=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+CONFIG_IR_RC5_SZ_DECODER=y
+CONFIG_IR_LIRC_CODEC=y
+# CONFIG_IR_IMON is not set
+# CONFIG_IR_MCEUSB is not set
+# CONFIG_IR_STREAMZAP is not set
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+CONFIG_MEDIA_TUNER_CUSTOMISE=y
+
+#
+# Customize TV tuners
+#
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_MT2131=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_MEDIA_TUNER_MXL5007T=m
+CONFIG_MEDIA_TUNER_MC44S803=m
+CONFIG_MEDIA_TUNER_MAX2165=m
+CONFIG_MEDIA_TUNER_TDA18218=m
+CONFIG_DVB_MAX_ADAPTERS=8
+CONFIG_DVB_DYNAMIC_MINORS=y
+CONFIG_DVB_CAPTURE_DRIVERS=y
+# CONFIG_TTPCI_EEPROM is not set
+
+#
+# Supported USB Adapters
+#
+# CONFIG_DVB_USB is not set
+# CONFIG_SMS_SIANO_MDTV is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported DVB Frontends
+#
+CONFIG_DVB_FE_CUSTOMISE=y
+
+#
+# Customise DVB Frontends
+#
+
+#
+# Multistandard (satellite) frontends
+#
+CONFIG_DVB_STB0899=m
+CONFIG_DVB_STB6100=m
+CONFIG_DVB_STV090x=m
+CONFIG_DVB_STV6110x=m
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_ZL10036=m
+CONFIG_DVB_ZL10039=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0288=m
+CONFIG_DVB_STB6000=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_STV6110=m
+CONFIG_DVB_STV0900=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_TDA8261=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TUNER_CX24113=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TUA6100=m
+CONFIG_DVB_CX24116=m
+CONFIG_DVB_SI21XX=m
+CONFIG_DVB_DS3000=m
+CONFIG_DVB_MB86A16=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+CONFIG_DVB_S5H1432=m
+CONFIG_DVB_DRX397XD=m
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+CONFIG_DVB_AF9013=m
+CONFIG_DVB_EC100=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+CONFIG_DVB_OR51211=m
+CONFIG_DVB_OR51132=m
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_LGDT3305=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_S5H1411=m
+
+#
+# ISDB-T (terrestrial) frontends
+#
+CONFIG_DVB_S921=m
+CONFIG_DVB_DIB8000=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+CONFIG_DVB_TUNER_DIB0090=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+CONFIG_DVB_ISL6405=m
+CONFIG_DVB_ISL6421=m
+CONFIG_DVB_ISL6423=m
+CONFIG_DVB_LGS8GL5=m
+CONFIG_DVB_LGS8GXX=m
+CONFIG_DVB_ATBM8830=m
+CONFIG_DVB_TDA665x=m
+CONFIG_DVB_IX2505V=m
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SOUND_OSS_CORE_PRECLAIM=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_MIPS=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX_FF is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_ROCCAT_PYRA is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_UAS is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_YUREX is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_USE_FOR_EXT23=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=y
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+CONFIG_BKL=y
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LKDTM is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_SPINLOCK_TEST is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/recipes/linux/linux-vusolo2_2.6.37.bb b/recipes/linux/linux-vusolo2_2.6.37.bb
new file mode 100644 (file)
index 0000000..979a338
--- /dev/null
@@ -0,0 +1,56 @@
+DESCRIPTION = "Linux kernel for vuplus solo2"
+LICENSE = "GPL"
+
+KV = "2.6.37"
+
+SRCREV = ""
+
+MODULE = "linux-2.6.37"
+
+#SRC_URI += "git:///home/shcheong/work/stb/sw/7356/refsw/linux/stblinux-2.6.37_org;protocol=file;branch=master;tag=${SRCREV} \
+#        file://${MACHINE}_defconfig \
+#        "
+SRC_URI += "file://stblinux-2.6.37-2.8.tar.bz2 \
+        file://dvb-core.patch;patch=1;pnum=1 \
+       file://fix_cpu_proc.patch;patch=1;pnum=1 \
+       file://bcmgenet_oobctrl.patch;patch=1;pnum=1 \
+        file://${MACHINE}_defconfig \
+       "
+
+#      file://brcm_disable_enet1.patch;patch=1;pnum=1 \
+#      file://brcm_nand_timing.patch;patch=1;pnum=1 \
+
+
+#S = "${WORKDIR}/git"
+S = "${WORKDIR}/stblinux-2.6.37"
+
+inherit kernel
+
+FILES_kernel-image = "/boot/vmlinux.gz /boot/autoexec.bat"
+
+export OS = "Linux"
+KERNEL_IMAGETYPE = "vmlinux"
+KERNEL_OUTPUT = "vmlinux"
+KERNEL_OBJECT_SUFFIX = "ko"
+
+
+do_configure_prepend() {
+        oe_machinstall -m 0644 ${WORKDIR}/${MACHINE}_defconfig ${S}/.config
+        oe_runmake oldconfig
+}
+
+kernel_do_install_append() {
+        install -d ${D}/${KERNEL_IMAGEDEST}
+        install -m 0755 ${KERNEL_OUTPUT} ${D}/${KERNEL_IMAGEDEST}
+        gzip ${D}/${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}
+}
+
+pkg_postinst_kernel-image () {
+        if [ -d /proc/stb ] ; then
+                flash_eraseall -j /dev/mtd1
+                nandwrite -p /dev/mtd1 /${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}.gz
+        fi
+        rm -f /${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}.gz
+        true
+}
+
diff --git a/recipes/opera-bb/files/opera-hbbtv.tar.gz b/recipes/opera-bb/files/opera-hbbtv.tar.gz
new file mode 100644 (file)
index 0000000..e357f2f
Binary files /dev/null and b/recipes/opera-bb/files/opera-hbbtv.tar.gz differ
diff --git a/recipes/opera-bb/opera-hbbtv_0.1.bb b/recipes/opera-bb/opera-hbbtv_0.1.bb
new file mode 100755 (executable)
index 0000000..296baa2
--- /dev/null
@@ -0,0 +1,19 @@
+DESCRIPTION = "opera-hbbtv"
+PRIORITY = "required"
+PR = "r0"
+
+INHIBIT_PACKAGE_STRIP = "1"
+
+SRC_URI = "file://opera-hbbtv.tar.gz"
+S = "${WORKDIR}/opera-hbbtv"
+
+do_compile() {
+}
+
+do_install() {
+        install -d ${D}/usr/local/hbb-browser
+       mv ${S}/* ${D}/usr/local/hbb-browser/
+}
+
+FILES_${PN} = "/"
+
diff --git a/recipes/opkg/opkg-collateral/vu7425/dest b/recipes/opkg/opkg-collateral/vu7425/dest
new file mode 100644 (file)
index 0000000..e6ddfb1
--- /dev/null
@@ -0,0 +1,4 @@
+dest root /
+dest ram /media/ram/
+dest hdd /media/hdd/
+dest usb /media/usb/
diff --git a/recipes/opkg/opkg-collateral/vuduo2/dest b/recipes/opkg/opkg-collateral/vuduo2/dest
new file mode 100644 (file)
index 0000000..e6ddfb1
--- /dev/null
@@ -0,0 +1,4 @@
+dest root /
+dest ram /media/ram/
+dest hdd /media/hdd/
+dest usb /media/usb/
diff --git a/recipes/opkg/opkg-collateral/vusolo2/dest b/recipes/opkg/opkg-collateral/vusolo2/dest
new file mode 100644 (file)
index 0000000..e6ddfb1
--- /dev/null
@@ -0,0 +1,4 @@
+dest root /
+dest ram /media/ram/
+dest hdd /media/hdd/
+dest usb /media/usb/
diff --git a/recipes/png-util/files/png_util.cpp b/recipes/png-util/files/png_util.cpp
new file mode 100755 (executable)
index 0000000..2736202
--- /dev/null
@@ -0,0 +1,179 @@
+#include "png_util.h"
+
+static int x, y;
+static int width, height;
+
+static png_byte color_type;
+static png_byte bit_depth;
+
+static png_structp png_ptr;
+static png_infop info_ptr;
+static int number_of_passes;
+static png_bytep * row_pointers = 0;
+static png_bytep row_pointers_bit_shift = 0;
+static int row_byte_len = 0;
+
+//#define UNIT_TEST 1
+#ifdef UNIT_TEST
+int fd = open("/tmp/dump.txt", O_WRONLY|O_CREAT|O_LARGEFILE, 0644);
+#endif
+
+static int read_png_file(char* file_name)
+{
+       /* 8 is the maximum size that can be checked */
+        char header[8] = {0,};
+
+        /* open file and test for it being a png */
+        FILE *fp = fopen(file_name, "rb");
+        if (!fp) 
+       {
+                fprintf(stderr, "[read_png_file] File %s could not be opened for reading\n", file_name);
+               return 0;
+       }
+
+        fread(header, 1, 8, fp);
+        if (png_sig_cmp((png_byte*)header, 0, 8)) 
+       {
+                fprintf(stderr, "[read_png_file] File %s is not recognized as a PNG file\n", file_name);
+               return 0;
+       }
+
+        /* initialize stuff */
+        png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+        if (!png_ptr) 
+       {
+                fprintf(stderr, "[read_png_file] png_create_read_struct failed\n");
+               return 0;
+       }
+
+        info_ptr = png_create_info_struct(png_ptr);
+        if (!info_ptr) 
+       {
+                fprintf(stderr, "[read_png_file] png_create_info_struct failed\n");
+               return 0;
+       }
+
+        if (setjmp(png_jmpbuf(png_ptr))) 
+       {
+                fprintf(stderr, "[read_png_file] Error during init_io\n");
+               return 0;
+       }
+
+        png_init_io(png_ptr, fp);
+        png_set_sig_bytes(png_ptr, 8);
+
+        png_read_info(png_ptr, info_ptr);
+
+        width = png_get_image_width(png_ptr, info_ptr);
+        height = png_get_image_height(png_ptr, info_ptr);
+        color_type = png_get_color_type(png_ptr, info_ptr);
+        bit_depth = png_get_bit_depth(png_ptr, info_ptr);
+
+        number_of_passes = png_set_interlace_handling(png_ptr);
+        png_read_update_info(png_ptr, info_ptr);
+
+        /* read file */
+        if (setjmp(png_jmpbuf(png_ptr))) 
+       {
+                fprintf(stderr, "[read_png_file] Error during read_image\n");
+               return 0;
+       }
+
+       if(row_pointers == 0) 
+       {
+               row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
+               row_byte_len = png_get_rowbytes(png_ptr,info_ptr);
+               for (y=0; y<height; y++) 
+               {
+                       row_pointers[y] = (png_byte*) malloc(row_byte_len);
+               }
+               row_pointers_bit_shift = (unsigned char*) malloc(sizeof(unsigned char) * height * width * 2);
+       }
+
+        png_read_image(png_ptr, row_pointers);
+        fclose(fp);
+       return 1;
+}
+
+PNGUtil *PNGUtil::instance = 0;
+
+PNGUtil::PNGUtil() 
+{
+       instance = this;
+       device_fd = -1;
+}
+
+PNGUtil::~PNGUtil()
+{
+       disconnect();
+}
+
+PNGUtil *PNGUtil::getInstance()
+{
+       return instance;
+}
+
+int PNGUtil::connect()
+{
+       const char* device_file_name = "/dev/lcd2";
+       device_fd = open("/dev/lcd2", O_RDWR);
+       if(device_fd <0)
+               return 0;
+       return 1;
+}
+
+void PNGUtil::disconnect() 
+{
+       if(device_fd >= 0)
+       {
+               close(device_fd);
+               device_fd = -1;
+       }
+}
+
+int PNGUtil::send(char* png_file_name) 
+{
+       if(device_fd < 0) 
+       {
+               fprintf(stderr, "unloaded!! retry.. connect!!\n");
+               return 0;
+       }
+       if(!read_png_file(png_file_name))
+       {
+               return 0;
+       }
+       {
+               
+               int i,j;
+               int row_pointers_ptr = 0;
+               int row_pointers_2_ptr = 0;
+               
+               for(i=0;i<height;i++)
+               {
+                       for(j=0;j<row_byte_len;j+=3)
+                       {
+                               row_pointers_bit_shift[row_pointers_2_ptr]=(row_pointers[i][j]&248)|(row_pointers[i][j+1]>>5);
+                               row_pointers_bit_shift[row_pointers_2_ptr+1]=((row_pointers[i][j+1]&28)<<3)|(row_pointers[i][j+2]>>3);
+                               row_pointers_2_ptr += 2;
+                       }
+               }
+       }
+#ifdef UNIT_TEST
+       {
+               int w = write(fd, row_pointers_bit_shift , height * width * 2);
+               printf("write to dst_fd : %d\n",w);
+       }
+#endif
+#ifndef UNIT_TEST
+       {
+               int w=-1;
+               w = write(device_fd, row_pointers_bit_shift, height * width * 2);
+               printf("write ret : %d\n",w);
+//             ret = ioctl(device_fd, 0);
+               printf("write to /dev/lcd2 : %d\n",w);
+       }
+#endif
+       return 1;
+}
+
diff --git a/recipes/png-util/files/png_util.h b/recipes/png-util/files/png_util.h
new file mode 100755 (executable)
index 0000000..de0b655
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _PNG_UTIL_H_
+#define _PNG_UTIL_H_
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <png.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+using namespace std;
+
+class PNGUtil {
+private:
+       static PNGUtil *instance;
+       int device_fd;
+
+public :
+       PNGUtil();
+       ~PNGUtil();
+       int  connect();
+       void disconnect();
+       int  send(char* png_file_name);
+       static PNGUtil *getInstance();
+};
+
+
+#if defined(__cplusplus)
+};
+#endif
+
+#endif /*_PNG_UTIL_H_*/
diff --git a/recipes/png-util/files/png_util.i b/recipes/png-util/files/png_util.i
new file mode 100755 (executable)
index 0000000..e84131e
--- /dev/null
@@ -0,0 +1,6 @@
+%module png_util
+%{
+#include "png_util.h"
+%}
+%include "png_util.h"
+
diff --git a/recipes/png-util/png-util_1.0.bb b/recipes/png-util/png-util_1.0.bb
new file mode 100755 (executable)
index 0000000..d010ab5
--- /dev/null
@@ -0,0 +1,16 @@
+DESCRIPTION = "PNG Assistant"
+PR = "r0"
+
+SRC_URI = "\
+       file://png_util.cpp \
+       file://png_util.h \
+       file://png_util.i \
+"
+
+do_compile() {
+       swig -python -c++ ${WORKDIR}/png_util.i
+       ${CXX} -O2 -c -fPIC ${WORKDIR}/png_util.cpp ${WORKDIR}/png_util_wrap.cxx -I${STAGING_INCDIR}/python2.6
+       ${CXX} -shared ${WORKDIR}/png-util-1.0/png_util.o ${WORKDIR}/png-util-1.0/png_util_wrap.o -o _png_util.so -L${STAGING_LIBDIR} -lpng -fPIC
+       mv ${WORKDIR}/png_util.py ${WORKDIR}/png-util-1.0
+}
+
diff --git a/recipes/sysvinit/sysvinit/vu7425/inittab b/recipes/sysvinit/sysvinit/vu7425/inittab
new file mode 100755 (executable)
index 0000000..29c67a0
--- /dev/null
@@ -0,0 +1,32 @@
+# /etc/inittab: init(8) configuration.
+# $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $
+
+# The default runlevel.
+id:3:initdefault:
+
+# Boot-time system configuration/initialization script.
+# This is run first except when booting in emergency (-b) mode.
+si::sysinit:/etc/init.d/rcS
+
+# What to do in single-user mode.
+~~:S:wait:/sbin/sulogin
+
+# /etc/init.d executes the S and K scripts upon change
+# of runlevel.
+#
+# Runlevel 0 is halt.
+# Runlevel 1 is single-user.
+# Runlevels 2-5 are multi-user.
+# Runlevel 6 is reboot.
+
+l0:0:wait:/etc/init.d/rc 0
+l1:1:wait:/etc/init.d/rc 1
+l2:2:wait:/etc/init.d/rc 2
+l3:3:wait:/etc/init.d/rc 3
+l4:4:wait:/etc/init.d/rc 4
+l5:5:wait:/etc/init.d/rc 5
+l6:6:wait:/etc/init.d/rc 6
+# Normally not reached, but fallthrough in case of emergency.
+z6:6:respawn:/sbin/sulogin
+
+S:5:respawn:/sbin/getty ttyS0 115200
diff --git a/recipes/sysvinit/sysvinit/vuduo2/inittab b/recipes/sysvinit/sysvinit/vuduo2/inittab
new file mode 100755 (executable)
index 0000000..29c67a0
--- /dev/null
@@ -0,0 +1,32 @@
+# /etc/inittab: init(8) configuration.
+# $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $
+
+# The default runlevel.
+id:3:initdefault:
+
+# Boot-time system configuration/initialization script.
+# This is run first except when booting in emergency (-b) mode.
+si::sysinit:/etc/init.d/rcS
+
+# What to do in single-user mode.
+~~:S:wait:/sbin/sulogin
+
+# /etc/init.d executes the S and K scripts upon change
+# of runlevel.
+#
+# Runlevel 0 is halt.
+# Runlevel 1 is single-user.
+# Runlevels 2-5 are multi-user.
+# Runlevel 6 is reboot.
+
+l0:0:wait:/etc/init.d/rc 0
+l1:1:wait:/etc/init.d/rc 1
+l2:2:wait:/etc/init.d/rc 2
+l3:3:wait:/etc/init.d/rc 3
+l4:4:wait:/etc/init.d/rc 4
+l5:5:wait:/etc/init.d/rc 5
+l6:6:wait:/etc/init.d/rc 6
+# Normally not reached, but fallthrough in case of emergency.
+z6:6:respawn:/sbin/sulogin
+
+S:5:respawn:/sbin/getty ttyS0 115200
diff --git a/recipes/sysvinit/sysvinit/vusolo2/inittab b/recipes/sysvinit/sysvinit/vusolo2/inittab
new file mode 100755 (executable)
index 0000000..29c67a0
--- /dev/null
@@ -0,0 +1,32 @@
+# /etc/inittab: init(8) configuration.
+# $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $
+
+# The default runlevel.
+id:3:initdefault:
+
+# Boot-time system configuration/initialization script.
+# This is run first except when booting in emergency (-b) mode.
+si::sysinit:/etc/init.d/rcS
+
+# What to do in single-user mode.
+~~:S:wait:/sbin/sulogin
+
+# /etc/init.d executes the S and K scripts upon change
+# of runlevel.
+#
+# Runlevel 0 is halt.
+# Runlevel 1 is single-user.
+# Runlevels 2-5 are multi-user.
+# Runlevel 6 is reboot.
+
+l0:0:wait:/etc/init.d/rc 0
+l1:1:wait:/etc/init.d/rc 1
+l2:2:wait:/etc/init.d/rc 2
+l3:3:wait:/etc/init.d/rc 3
+l4:4:wait:/etc/init.d/rc 4
+l5:5:wait:/etc/init.d/rc 5
+l6:6:wait:/etc/init.d/rc 6
+# Normally not reached, but fallthrough in case of emergency.
+z6:6:respawn:/sbin/sulogin
+
+S:5:respawn:/sbin/getty ttyS0 115200
index d3da6a6..07ca28b 100644 (file)
@@ -20,7 +20,6 @@ PACKAGES = "\
 RPROVIDES_task-vuplus-enigma2 = "task-vuplus-ui"
 DESCRIPTION_task-vuplus-enigma2 = "Vuplus: Enigma2 Dependencies"
 RDEPENDS_task-vuplus-enigma2 = "\
-  vuplus-blindscan-utils \
   enigma2 \
   enigma2-defaultservices \
   enigma2-plugin-extensions-mediascanner \
@@ -41,6 +40,7 @@ RDEPENDS_task-vuplus-enigma2 = "\
   enigma2-plugin-systemplugins-devicemanager \
 "
 
+
 RRECOMMENDS_task-vuplus-enigma2 = "\
   aio-grab \
   python-crypt \
@@ -63,8 +63,23 @@ RDEPENDS_task-vuplus-enigma2_append_bm750 = "\
   enigma2-plugin-systemplugins-fancontrol \
   enigma2-plugin-extensions-hbbtv \
 "
+RDEPENDS_task-vuplus-enigma2_append_vuduo2 = "\
+  enigma2-plugin-systemplugins-remotecontrolcode \
+  enigma2-plugin-systemplugins-hdmicec \
+  enigma2-plugin-extensions-openwebif \
+  enigma2-plugin-extensions-hbbtv \
+  duo2lcd4linux \
+"
+
+RDEPENDS_task-vuplus-enigma2_append_vusolo2 = "\
+  enigma2-plugin-extensions-openwebif \
+  enigma2-plugin-systemplugins-remotecontrolcode \
+  enigma2-plugin-systemplugins-hdmicec \
+  enigma2-plugin-extensions-hbbtv \
+"
 
 RDEPENDS_task-vuplus-enigma2_append_vuuno = "\
+  vuplus-blindscan-utils \
   enigma2-plugin-systemplugins-fpgaupgrade \
   enigma2-plugin-systemplugins-blindscan \
   enigma2-plugin-systemplugins-manualfancontrol \
@@ -72,6 +87,7 @@ RDEPENDS_task-vuplus-enigma2_append_vuuno = "\
   enigma2-plugin-extensions-hbbtv \
 "
 RDEPENDS_task-vuplus-enigma2_append_vuultimo = "\
+  vuplus-blindscan-utils \
   enigma2-plugin-systemplugins-firmwareupgrade \
   enigma2-plugin-systemplugins-blindscan \
   enigma2-plugin-systemplugins-manualfancontrol \
index f9e47ef..b012a6e 100644 (file)
@@ -36,9 +36,9 @@ WLAN_USB_MODULES = "\
 "
 
 WLAN_USB_MODULES_LEGACY = "\
-  zd1211b \
-  wlan-rt73 \
-  r8712u \
+#  zd1211b \
+#  wlan-rt73 \
+#  r8712u \
   rt3070 \
   r8192cu \
 "
@@ -58,6 +58,16 @@ RDEPENDS_${PN}_append_vuuno = "\
 RDEPENDS_${PN}_append_vuultimo = "\
   ${@base_contains('PREFERRED_VERSION_linux-vuultimo', '2.6.18', '${WLAN_USB_MODULES_LEGACY}', '${WLAN_CRYPTO_MODULES} ${WLAN_USB_MODULES}', d)} \
 "
+RDEPENDS_${PN}_append_vu7425 = "\
+  ${@base_contains('PREFERRED_VERSION_linux-vuvu7425', '2.6.18', '${WLAN_USB_MODULES_LEGACY}', '${WLAN_CRYPTO_MODULES} ${WLAN_USB_MODULES}', d)} \
+"
+#RDEPENDS_${PN}_append_vuduo2 = "\
+#  ${@base_contains('PREFERRED_VERSION_linux-vuduo2', '2.6.18', '${WLAN_USB_MODULES_LEGACY}', '${WLAN_CRYPTO_MODULES} ${WLAN_USB_MODULES}', d)} \
+#"
+
+RDEPENDS_${PN}_append_vuduo2 = '${WLAN_USB_MODULES_LEGACY}'
+RDEPENDS_${PN}_append_vusolo2 = '${WLAN_USB_MODULES_LEGACY}'
+
 
 PACKAGE_ARCH = "${MACHINE_ARCH}"
 
index 542383a..71ff5fd 100644 (file)
@@ -5,7 +5,6 @@ MAINTAINER = "Felix Domke <tmbinc@elitdvb.net>"
 SRC_URI = "git://git.opendreambox.org/git/obi/libdvbsi++.git;protocol=git"
 
 SRCREV = "49b0c78a0b0db3efd0a49c4cf2fc1c7f4bf21c15"
-
 PV = "1.0+git${SRCPV}"
 PKGV = "1.0+git${GITPKGV}"
 PR = "r1"
index d9576c4..30c5b92 100755 (executable)
@@ -65,6 +65,19 @@ SRC_URI_append_vuultimo = " \
        file://resize_framebuffer.diff;patch=1 \
        file://allow_different_demux.diff;patch=1"
 
+SRC_URI_append_vu7425 = " \
+       file://32bpp.diff;patch=1 \
+       file://resize_framebuffer.diff;patch=1 \
+       file://allow_different_demux.diff;patch=1"
+SRC_URI_append_vuduo2 = " \
+       file://32bpp.diff;patch=1 \
+       file://resize_framebuffer.diff;patch=1 \
+       file://allow_different_demux.diff;patch=1"
+SRC_URI_append_vusolo2 = " \
+       file://32bpp.diff;patch=1 \
+       file://resize_framebuffer.diff;patch=1 \
+       file://allow_different_demux.diff;patch=1"
+
 S = "${WORKDIR}/libs"
 EXTRA_OECONF = "--with-target=native"
 
index a582847..d18de14 100755 (executable)
@@ -36,6 +36,9 @@ SRC_URI_append_bm750 = " file://41-od-linux-2.6.18-misc.rules"
 SRC_URI_append_vusolo = " file://41-od-linux-2.6.18-misc.rules"
 SRC_URI_append_vuuno = " file://41-od-linux-2.6.18-misc.rules"
 SRC_URI_append_vuultimo = " file://41-od-linux-2.6.18-misc.rules"
+SRC_URI_append_vu7425 = " file://41-od-linux-2.6.18-misc.rules"
+SRC_URI_append_vuduo2 = " file://41-od-linux-2.6.18-misc.rules"
+SRC_URI_append_vusolo2 = " file://41-od-linux-2.6.18-misc.rules"
 
 
 require udev.inc
index ac1d055..ca53c02 100644 (file)
@@ -7,13 +7,15 @@ IMAGES_VERSION = "1"
 BINARY_VERSION = "7"
 
 PV = "${BINARY_VERSION}.${IMAGES_VERSION}"
-PR = "r5"
+PR = "r6"
 
 KERNEL_VERSION = "${@base_contains('PREFERRED_VERSION_linux-${MACHINE}', '2.6.18', '2.6.18', '3.1.1', d)}"
 
 SRC_URI = "file://bootlogo.mvi file://backdrop.mvi file://bootlogo_wait.mvi file://switchoff.mvi"
 SRC_URI_append_vuuno = " file://splash_cfe_auto.bin"
 SRC_URI_append_vuultimo = " file://splash_cfe_auto.bin"
+SRC_URI_append_vuduo2 = " file://initrd_cfe_auto.bin file://splash_cfe_auto.bin"
+SRC_URI_append_vusolo2 = " file://initrd_cfe_auto.bin file://splash_cfe_auto.bin"
 
 S = "${WORKDIR}/"
 
@@ -44,29 +46,50 @@ do_install_vuultimo() {
                 install -m 0755 ${S}/$i.mvi ${D}/usr/share/$i.mvi;
                 ln -sf /usr/share/$i.mvi ${D}/boot/$i.mvi;
         done;
+        install -m 0755 ${S}/vmlinuz.initrd ${D}/boot/vmlinuz.initrd
+        install -m 0755 ${S}/splash_cfe_auto.bin ${D}/boot/splash_cfe_auto.bin
+}
+do_install_vuduo2() {
+       install -d ${D}/boot
+        install -d ${D}/usr/share
+        for i in ${MVI}; do
+                install -m 0755 ${S}/$i.mvi ${D}/usr/share/$i.mvi;
+                ln -sf /usr/share/$i.mvi ${D}/boot/$i.mvi;
+        done;
+        install -m 0755 ${S}/initrd_cfe_auto.bin ${D}/boot/initrd_cfe_auto.bin
+        install -m 0755 ${S}/splash_cfe_auto.bin ${D}/boot/splash_cfe_auto.bin
+}
+do_install_vusolo2() {
+       install -d ${D}/boot
+        install -d ${D}/usr/share
+        for i in ${MVI}; do
+                install -m 0755 ${S}/$i.mvi ${D}/usr/share/$i.mvi;
+                ln -sf /usr/share/$i.mvi ${D}/boot/$i.mvi;
+        done;
+        install -m 0755 ${S}/initrd_cfe_auto.bin ${D}/boot/initrd_cfe_auto.bin
         install -m 0755 ${S}/splash_cfe_auto.bin ${D}/boot/splash_cfe_auto.bin
 }
 
 pkg_preinst() {
-       if [ "${KERNEL_VERSION}" = "3.1.1" ]; then
+       if [ "${KERNEL_VERSION}" = "2.6.18" ]; then
                [ -d /proc/stb ] && mount -o rw,remount /boot
        fi
 }
 
 pkg_postinst() {
-       if [ "${KERNEL_VERSION}" = "3.1.1" ]; then
+       if [ "${KERNEL_VERSION}" = "2.6.18" ]; then
                [ -d /proc/stb ] && mount -o ro,remount /boot
        fi
 }
 
 pkg_prerm() {
-       if [ "${KERNEL_VERSION}" = "3.1.1" ]; then
+       if [ "${KERNEL_VERSION}" = "2.6.18" ]; then
                [ -d /proc/stb ] && mount -o rw,remount /boot
        fi
 }
 
 pkg_postrm() {
-       if [ "${KERNEL_VERSION}" = "3.1.1" ]; then
+       if [ "${KERNEL_VERSION}" = "2.6.18" ]; then
                [ -d /proc/stb ] && mount -o ro,remount /boot
        fi
 }
diff --git a/recipes/vuplus/vuplus-bootlogo/vuduo2/initrd_cfe_auto.bin b/recipes/vuplus/vuplus-bootlogo/vuduo2/initrd_cfe_auto.bin
new file mode 100644 (file)
index 0000000..4e4e4ee
Binary files /dev/null and b/recipes/vuplus/vuplus-bootlogo/vuduo2/initrd_cfe_auto.bin differ
diff --git a/recipes/vuplus/vuplus-bootlogo/vuduo2/splash_cfe_auto.bin b/recipes/vuplus/vuplus-bootlogo/vuduo2/splash_cfe_auto.bin
new file mode 100755 (executable)
index 0000000..3845d2a
Binary files /dev/null and b/recipes/vuplus/vuplus-bootlogo/vuduo2/splash_cfe_auto.bin differ
diff --git a/recipes/vuplus/vuplus-bootlogo/vusolo2/initrd_cfe_auto.bin b/recipes/vuplus/vuplus-bootlogo/vusolo2/initrd_cfe_auto.bin
new file mode 100644 (file)
index 0000000..c407c70
Binary files /dev/null and b/recipes/vuplus/vuplus-bootlogo/vusolo2/initrd_cfe_auto.bin differ
diff --git a/recipes/vuplus/vuplus-bootlogo/vusolo2/splash_cfe_auto.bin b/recipes/vuplus/vuplus-bootlogo/vusolo2/splash_cfe_auto.bin
new file mode 100755 (executable)
index 0000000..3845d2a
Binary files /dev/null and b/recipes/vuplus/vuplus-bootlogo/vusolo2/splash_cfe_auto.bin differ
index 1d27651..a71fb1b 100755 (executable)
@@ -4,6 +4,7 @@ PRIORITY = "required"
 LICENSE = "proprietary"
 
 KV = "${@base_contains('PREFERRED_VERSION_linux-${MACHINE}', '2.6.18', '2.6.18', '3.1.1', d)}"
+KV_vusolo2 = "${@base_contains('PREFERRED_VERSION_linux-${MACHINE}', '2.6.18', '2.6.18', '2.6.37', d)}"
 
 PV = "${KV}"
 
@@ -11,11 +12,15 @@ SRCDATE_bm750 = "20120824"
 SRCDATE_vusolo = "20120824"
 SRCDATE_vuuno = "20120824"
 SRCDATE_vuultimo = "20120824"
+SRCDATE_vuduo2 = "20120829"
+SRCDATE_vusolo2 = "20120829"
 
 MODULES_NAME_bm750 = "procmk\ndvb-bcm7335\nbrcmfb"
 MODULES_NAME_vusolo = "procmk\ndvb-bcm7325\nbrcmfb"
 MODULES_NAME_vuuno = "procmk\ndvb-bcm7413\nbrcmfb\nfpga_directc"
 MODULES_NAME_vuultimo = "procmk\ndvb-bcm7413\nbrcmfb\nfpga_directc"
+MODULES_NAME_vuduo2 = "procmk\ndvb-bcm7424\nbrcmfb\nfpga_directc"
+MODULES_NAME_vusolo2 = "procmk\ndvb-bcm7356\nbrcmfb\nfpga_directc"
 
 RDEPENDS_2.6.18 = "initscripts-vuplus kernel (${KV}) kernel-module-firmware-class kernel-module-input kernel-module-evdev kernel-module-i2c-core kernel-module-snd kernel-module-snd-pcm"
 RDEPENDS_3.1 = "initscripts-vuplus kernel (${KV})" 
@@ -34,7 +39,7 @@ PR = "r19-${SRCDATE}"
 DEPENDS = " module-init-tools"
 RDEPENDS_append_vuplus = " module-init-tools-depmod"
 
-SRC_URI = "http://archive.vuplus.com/download/drivers/vuplus-dvb-modules-${MACHINE}-${PV}-${PREFERRED_GCC_VERSION}-${SRCDATE}.tar.gz "
+SRC_URI = "http://archive.vuplus.com/download/drivers/beta/private/vuplus-dvb-modules-${MACHINE}-${PV}-${PREFERRED_GCC_VERSION}-${SRCDATE}.tar.gz "
 
 S = "${WORKDIR}"
 
@@ -50,6 +55,26 @@ do_install() {
        fi
 }
 
+do_install_vusolo2() {
+        install -d ${D}/lib/modules/2.6.37-2.8/extra
+        for f in *.ko; do
+                install -m 0644 ${WORKDIR}/$f ${D}/lib/modules/2.6.37-2.8/extra/$f;
+        done
+       install -d ${D}/etc/modutils
+       echo -e "${MODULES_NAME}" > ${D}/etc/modutils/vuplus-dvb-modules
+       echo -e "${MODULES_NAME}" > ${D}/etc/modules
+}
+
+do_install_vuduo2() {
+        install -d ${D}/lib/modules/2.6.37-2.8/extra
+        for f in *.ko; do
+                install -m 0644 ${WORKDIR}/$f ${D}/lib/modules/2.6.37-2.8/extra/$f;
+        done
+       install -d ${D}/etc/modutils
+       echo -e "${MODULES_NAME}" > ${D}/etc/modutils/vuplus-dvb-modules
+       echo -e "${MODULES_NAME}" > ${D}/etc/modules
+}
+
 pkg_postinst_vuplus-dvb-modules () {
         if [ -d /proc/stb ]; then
                 depmod -ae