diff options
author | schon <schon@dev03-server> | 2012-06-07 14:25:36 (GMT) |
---|---|---|
committer | schon <schon@dev03-server> | 2012-06-07 14:25:36 (GMT) |
commit | 651825e164ecd956a740d14fd1857eae16b341c5 (patch) | |
tree | 73cef9e305b81e3e5a6c44201fc850797225d39b | |
parent | 346c59523461c0aa89bf3a6de8edef4ce3ce15f9 (diff) |
Latest duo2
33 files changed, 14108 insertions, 95 deletions
diff --git a/conf/distro/vuplus.conf b/conf/distro/vuplus.conf index b97034e..2dac728 100644 --- a/conf/distro/vuplus.conf +++ b/conf/distro/vuplus.conf @@ -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/vuduo2.conf b/conf/machine/vuduo2.conf index 9be37e4..382dd70 100644 --- a/conf/machine/vuduo2.conf +++ b/conf/machine/vuduo2.conf @@ -93,12 +93,12 @@ IMAGE_CMD_jffs2 = " \ --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; \ + 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; \ cd ${DEPLOY_DIR_IMAGE}; \ - zip ${IMAGE_NAME}_usb.zip vuplus/ultimo/*; \ + zip ${IMAGE_NAME}_usb.zip vuplus/duo2/*; \ rm -rf vuplus; \ " @@ -115,20 +115,15 @@ 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; \ + mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/duo2; \ + cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${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; \ cd ${DEPLOY_DIR_IMAGE}; \ - zip ${IMAGE_NAME}_usb.zip vuplus/ultimo/*; \ + zip ${IMAGE_NAME}_usb.zip vuplus/duo2/*; \ rm -rf vuplus; \ " diff --git a/conf/machine/vusolo2.conf b/conf/machine/vusolo2.conf index a61f766..aed3933 100644 --- a/conf/machine/vusolo2.conf +++ b/conf/machine/vusolo2.conf @@ -91,12 +91,12 @@ IMAGE_CMD_jffs2 = " \ --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; \ + 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; \ cd ${DEPLOY_DIR_IMAGE}; \ - zip ${IMAGE_NAME}_usb.zip vuplus/ultimo/*; \ + zip ${IMAGE_NAME}_usb.zip vuplus/solo2/*; \ rm -rf vuplus; \ " @@ -112,20 +112,15 @@ 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; \ + mkdir -p ${DEPLOY_DIR_IMAGE}/vuplus/solo2; \ + cp ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.rootfs.ubi ${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; \ cd ${DEPLOY_DIR_IMAGE}; \ - zip ${IMAGE_NAME}_usb.zip vuplus/ultimo/*; \ + zip ${IMAGE_NAME}_usb.zip vuplus/solo2/*; \ rm -rf vuplus; \ " 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 index 0000000..adccbb1 --- /dev/null +++ b/recipes/directfb/directfb-1.4.2/directfb-vuplus-blit.patch @@ -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 index 0000000..1633e41 --- /dev/null +++ b/recipes/directfb/directfb-1.4.2/directfbrc @@ -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 diff --git a/recipes/directfb/directfb.inc b/recipes/directfb/directfb.inc index 9066ff2..1af76d3 100644 --- a/recipes/directfb/directfb.inc +++ b/recipes/directfb/directfb.inc @@ -38,6 +38,8 @@ do_stage() { do_install() { oe_runmake 'DESTDIR=${D}' install + install -d ${D}${sysconfdir} + install -m 755 ${WORKDIR}/directfbrc ${D}${sysconfdir} } diff --git a/recipes/directfb/directfb_1.4.2.bb b/recipes/directfb/directfb_1.4.2.bb index 1e15186..4c91d2d 100644 --- a/recipes/directfb/directfb_1.4.2.bb +++ b/recipes/directfb/directfb_1.4.2.bb @@ -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 index 0000000..e95b4fc --- /dev/null +++ b/recipes/duo2lcd4linux/duo2lcd4linux_0.1.bb @@ -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 Binary files differnew file mode 100644 index 0000000..862a8e0 --- /dev/null +++ b/recipes/duo2lcd4linux/files/LCD4linux.tar.gz diff --git a/recipes/enigma2/enigma2.bb b/recipes/enigma2/enigma2.bb index 7ad25cf..6034493 100644 --- a/recipes/enigma2/enigma2.bb +++ b/recipes/enigma2/enigma2.bb @@ -3,7 +3,8 @@ MAINTAINER = "Felix Domke <tmbinc@elitedvb.net>" DEPENDS = "jpeg libungif libmad libpng libsigc++-1.2 gettext-native \ dreambox-dvbincludes freetype libdvbsi++ python swig-native \ libfribidi libxmlccwrap libdreamdvd gstreamer gst-plugin-dvbmediasink \ - gst-plugins-bad gst-plugins-good gst-plugins-ugly python-wifi" + gst-plugins-bad gst-plugins-good gst-plugins-ugly python-wifi \ + directfb mpfr gmp tslib opera-hbbtv" RDEPENDS = "python-codecs python-core python-lang python-re python-threading \ python-xml python-fcntl gst-plugin-decodebin gst-plugin-decodebin2 python-stringold \ python-pickle gst-plugin-app \ @@ -66,6 +67,7 @@ DESCRIPTION_append_enigma2-plugin-systemplugins-wirelesslansetup = "configure wi RDEPENDS_enigma2-plugin-systemplugins-wirelesslansetup = "wpa-supplicant wireless-tools python-wifi" DESCRIPTION_append_enigma2-plugin-systemplugins-networkwizard = "provides easy step by step network configuration" RDEPENDS_enigma2-plugin-extensions-webbrowser = "python-gdata libqtwebkite4 vuplus-webbrowser-utils qt4-embedded-fonts qt4-embedded-plugin-imageformat-gif qt4-embedded-plugin-imageformat-ico qt4-embedded-plugin-imageformat-jpeg qt4-embedded-plugin-imageformat-mng qt4-embedded-plugin-imageformat-svg qt4-embedded-plugin-imageformat-tiff qt4-embedded-plugin-iconengine-svgicon " +RDEPENDS_enigma2-plugin-extensions-hbbtv = "tslib-conf libts-1.0-0 libsysfs2 directfb libgmp3 libmpfr1 opera-hbbtv" PN = "enigma2" PR = "r1" @@ -118,6 +120,7 @@ SRC_URI = "git://code.vuplus.com/git/dvbapp.git;protocol=http;branch=${BRANCH};t file://enigma2_vuplus_mediaplayer_subtitle.patch;patch=1;pnum=1 \ file://enigma2_vuplus_remove_dreambox_enigma.patch;patch=1;pnum=1 \ file://enigma2_vuplus_vfd_mode.patch;patch=1;pnum=1 \ + file://enigma2-hbbtv_20120604.patch;patch=1;pnum=1 \ file://MyriadPro-Regular.otf \ file://MyriadPro-Semibold.otf \ file://MyriadPro-SemiboldIt.otf \ @@ -143,11 +146,6 @@ SRC_URI_append_vu7425 = " \ file://skin_user.xml \ file://vfd_icons \ " -SRC_URI_append_vuduo2 = " \ - file://analog.ttf \ - file://skin_user.xml \ - file://vfd_icons \ -" def change_po(): import os @@ -220,18 +218,6 @@ do_install_append_vuultimo() { install -d ${D}/usr/share/enigma2/vfd_icons/ install -m 0755 ${WORKDIR}/vfd_icons/*.png ${D}/usr/share/enigma2/vfd_icons/ } -do_install_append_vu7425() { - install -m 0755 ${WORKDIR}/analog.ttf ${D}/usr/share/fonts/ - install -m 0755 ${WORKDIR}/skin_user.xml ${D}/usr/share/enigma2/defaults/ - install -d ${D}/usr/share/enigma2/vfd_icons/ - install -m 0755 ${WORKDIR}/vfd_icons/*.png ${D}/usr/share/enigma2/vfd_icons/ -} -do_install_append_vuduo2() { - install -m 0755 ${WORKDIR}/analog.ttf ${D}/usr/share/fonts/ - install -m 0755 ${WORKDIR}/skin_user.xml ${D}/usr/share/enigma2/defaults/ - install -d ${D}/usr/share/enigma2/vfd_icons/ - install -m 0755 ${WORKDIR}/vfd_icons/*.png ${D}/usr/share/enigma2/vfd_icons/ -} python populate_packages_prepend () { enigma2_plugindir = bb.data.expand('${libdir}/enigma2/python/Plugins', d) diff --git a/recipes/enigma2/enigma2/vuplus/enigma2-hbbtv_20120604.patch b/recipes/enigma2/enigma2/vuplus/enigma2-hbbtv_20120604.patch new file mode 100644 index 0000000..1aa3bda --- /dev/null +++ b/recipes/enigma2/enigma2/vuplus/enigma2-hbbtv_20120604.patch @@ -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; + } 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 index 0000000..6b9f24f --- /dev/null +++ b/recipes/linux/linux-vuduo2-3.1.1/brcm_disable_enet1.patch @@ -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/vuduo2_defconfig b/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig index 19261c0..a3c024e 100644 --- a/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig +++ b/recipes/linux/linux-vuduo2-3.1.1/vuduo2_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux/mips 2.6.37-2.4 Kernel Configuration -# Wed Mar 14 16:14:58 2012 +# Linux/mips 2.6.37-2.8 Kernel Configuration +# Thu Jun 7 19:50:36 2012 # CONFIG_MIPS=y @@ -57,36 +57,23 @@ 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 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_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 @@ -115,7 +102,7 @@ CONFIG_BCMGENET_NAPI=y # 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_MOCA is not set CONFIG_BRCM_USB=y # CONFIG_BRCM_OVERRIDE_USB is not set CONFIG_BRCM_SDIO=y @@ -140,15 +127,15 @@ 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_GENET_V3=y +CONFIG_BRCM_GENET_VERSION=3 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_GENET_1=y +# CONFIG_BRCM_HAS_MOCA=y +# CONFIG_BRCM_HAS_MOCA_20=y +# CONFIG_BRCM_MOCA_VERS=0x2000 +# 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 @@ -170,6 +157,7 @@ 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 @@ -178,7 +166,7 @@ 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_PWR_HANDSHAKE_V1=y CONFIG_BRCM_PLATFORM_DEFAULTS=y CONFIG_BCM7425=y CONFIG_RWSEM_GENERIC_SPINLOCK=y @@ -859,7 +847,7 @@ CONFIG_SATA_PMP=y # Controllers with non-SFF native interface # CONFIG_SATA_AHCI=y -# CONFIG_SATA_AHCI_PLATFORM is not set +CONFIG_SATA_AHCI_PLATFORM=y # CONFIG_SATA_INIC162X is not set # CONFIG_SATA_SIL24 is not set CONFIG_ATA_SFF=y diff --git a/recipes/linux/linux-vuduo2_3.1.1.bb b/recipes/linux/linux-vuduo2_3.1.1.bb index 917410c..efc2a9b 100644 --- a/recipes/linux/linux-vuduo2_3.1.1.bb +++ b/recipes/linux/linux-vuduo2_3.1.1.bb @@ -1,4 +1,4 @@ -CRIPTION = "Linux kernel for vuplus duo2" +DESCRIPTION = "Linux kernel for vuplus duo2" LICENSE = "GPL" KV = "3.1.1" @@ -6,13 +6,13 @@ SRCREV = "r0" MODULE = "linux-3.1.1" -SRC_URI += "file://stblinux-2.6.37-2.4.tar.bz2 \ +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://ubifs_packport.patch;patch=1;pnum=1 \ - file://${MACHINE}_defconfig \ + file://brcm_disable_enet1.patch;patch=1;pnum=1 \ + file://${MACHINE}_defconfig \ " S = "${WORKDIR}/stblinux-2.6.37" 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 index 0000000..698443d --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/brcm_disable_enet1.patch @@ -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/debug.patch b/recipes/linux/linux-vusolo2-2.6.37/debug.patch new file mode 100644 index 0000000..5576999 --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/debug.patch @@ -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 index 0000000..87b1738 --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/dvb-core.patch @@ -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 index 0000000..2074d6a --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/fix_cpu_proc.patch @@ -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 index 0000000..ac9cfbb --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/pinmux.patch @@ -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 Binary files differnew file mode 100644 index 0000000..dbb8ab2 --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.4.tar.bz2 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 Binary files differnew file mode 100644 index 0000000..0a75327 --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/stblinux-2.6.37-2.8.tar.bz2 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 index 0000000..193c5e6 --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/ubifs_packport.patch @@ -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 index 0000000..f065646 --- /dev/null +++ b/recipes/linux/linux-vusolo2-2.6.37/vusolo2_defconfig @@ -0,0 +1,1883 @@ +# +# Automatically generated make config: don't edit +# Linux/mips 2.6.37-2.8 Kernel Configuration +# Thu May 10 15:53:56 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 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=m +# CONFIG_RT2500USB is not set +CONFIG_RT73USB=m +# CONFIG_RT2800USB 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=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_3.1.1.bb b/recipes/linux/linux-vusolo2_2.6.37.bb index 58a683b..fd0fecf 100644 --- a/recipes/linux/linux-vusolo2_3.1.1.bb +++ b/recipes/linux/linux-vusolo2_2.6.37.bb @@ -1,16 +1,25 @@ -CRIPTION = "Linux kernel for vuplus solo2" +DESCRIPTION = "Linux kernel for vuplus solo2" LICENSE = "GPL" -KV = "3.1.1" + +KV = "2.6.37" SRCREV = "" -MODULE = "linux-3.1.1" +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} \ +#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://brcm_disable_enet1.patch;patch=1;pnum=1 \ file://${MACHINE}_defconfig \ - " + " + -S = "${WORKDIR}/git" +#S = "${WORKDIR}/git" +S = "${WORKDIR}/stblinux-2.6.37" inherit kernel diff --git a/recipes/opera-bb/files/opera-hbbtv.tar.gz b/recipes/opera-bb/files/opera-hbbtv.tar.gz Binary files differnew file mode 100644 index 0000000..412679a --- /dev/null +++ b/recipes/opera-bb/files/opera-hbbtv.tar.gz diff --git a/recipes/opera-bb/opera-hbbtv_0.1.bb b/recipes/opera-bb/opera-hbbtv_0.1.bb new file mode 100755 index 0000000..296baa2 --- /dev/null +++ b/recipes/opera-bb/opera-hbbtv_0.1.bb @@ -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/ralink/files/2011_0719_RT3070_RT3370_RT5370_RT5372_Linux_STA_V2.5.0.3_DPO.tar.bz2 b/recipes/ralink/files/2011_0719_RT3070_RT3370_RT5370_RT5372_Linux_STA_V2.5.0.3_DPO.tar.bz2 Binary files differnew file mode 100755 index 0000000..36be4fc --- /dev/null +++ b/recipes/ralink/files/2011_0719_RT3070_RT3370_RT5370_RT5372_Linux_STA_V2.5.0.3_DPO.tar.bz2 diff --git a/recipes/ralink/rt3070_2.5.0.3.bb b/recipes/ralink/rt3070_2.5.0.3.bb new file mode 100644 index 0000000..f95770c --- /dev/null +++ b/recipes/ralink/rt3070_2.5.0.3.bb @@ -0,0 +1,30 @@ +DESCRIPTION = "Driver for Ralink RT8070/RT3070/RT3370 USB 802.11abgn WiFi sticks" +SECTION = "kernel/modules" +LICENSE = "GPL" +SRCNAME = "rt3070" + +inherit module + +PR = "r0" + +SRC_URI = "file://2011_0719_RT3070_RT3370_RT5370_RT5372_Linux_STA_V2.5.0.3_DPO.tar.bz2 \ + file://makefile_2.5.0.3.patch;patch=1 \ + file://config_2.5.0.3.patch;patch=1 \ + " + +FILES_${PN} += " /lib/firmware/rt2870.bin" + +S = "${WORKDIR}/2011_0719_RT3070_RT3370_RT5370_RT5372_Linux_STA_V${PV}_DPO" + +EXTRA_OEMAKE = "LINUX_SRC=${STAGING_KERNEL_DIR}" + +do_install() { + install -d ${D}${base_libdir}/modules/${KERNEL_VERSION}/drivers/net/wireless + install -d ${D}${sysconfdir}/Wireless/RT2870STA + install -m 0644 ${S}/*sta${KERNEL_OBJECT_SUFFIX} ${D}${base_libdir}/modules/${KERNEL_VERSION}/drivers/net/wireless + install -m 0644 ${S}/RT2870STA.dat ${D}${sysconfdir}/Wireless/RT2870STA/ + install -d ${D}/lib/firmware + install -m 0644 ${S}/common/rt2870.bin ${D}/lib/firmware/ +} + +PACKAGE_ARCH = "${MACHINE_ARCH}" diff --git a/recipes/tasks/task-vuplus-enigma2.bb b/recipes/tasks/task-vuplus-enigma2.bb index d932a13..ff76713 100644 --- a/recipes/tasks/task-vuplus-enigma2.bb +++ b/recipes/tasks/task-vuplus-enigma2.bb @@ -31,6 +31,7 @@ RDEPENDS_task-vuplus-enigma2 = "\ enigma2-skins-meta \ " + RRECOMMENDS_task-vuplus-enigma2 = "\ aio-grab \ python-crypt \ @@ -39,6 +40,7 @@ RRECOMMENDS_task-vuplus-enigma2 = "\ python-twisted-protocols \ python-twisted-web \ enigma2-plugin-extensions-mediaplayer \ + enigma2-plugin-extensions-hbbtv \ enigma2-plugin-extensions-pictureplayer \ enigma2-plugin-systemplugins-skinselector \ enigma2-plugin-systemplugins-ui3dsetup \ diff --git a/recipes/tasks/task-vuplus-wlan.bb b/recipes/tasks/task-vuplus-wlan.bb index df9ebf0..4142fa2 100644 --- a/recipes/tasks/task-vuplus-wlan.bb +++ b/recipes/tasks/task-vuplus-wlan.bb @@ -61,7 +61,7 @@ RDEPENDS_${PN}_append_vu7425 = "\ 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 = "\ +RDEPENDS_${PN}_append_vusolo2 = "\ ${@base_contains('PREFERRED_VERSION_linux-vusolo2', '2.6.18', '${WLAN_USB_MODULES_LEGACY}', '${WLAN_CRYPTO_MODULES} ${WLAN_USB_MODULES}', d)} \ " diff --git a/recipes/tuxbox/libdvbsi++.bb b/recipes/tuxbox/libdvbsi++.bb index ecdf416..8502318 100644 --- a/recipes/tuxbox/libdvbsi++.bb +++ b/recipes/tuxbox/libdvbsi++.bb @@ -2,13 +2,15 @@ DESCRIPTION = "libdvbsi++ by obi@saftware.de" DEPENDS = "dreambox-dvbincludes" MAINTAINER = "Felix Domke <tmbinc@elitdvb.net>" -SRC_URI = "cvs://anoncvs@cvs.tuxbox.org/cvs/tuxbox;module=apps/dvb/libdvbsi++;method=ext" +SRC_URI = "git://git.opendreambox.org/git/obi/libdvbsi++.git;protocol=git" -SRCDATE = "20090224" +SRCREV = "49b0c78a0b0db3efd0a49c4cf2fc1c7f4bf21c15" + +PV = "1.0+git${SRCPV}" +PKGV = "1.0+git${GITPKGV}" PR = "r0" -PV = "0.0+cvs${SRCDATE}" -S = "${WORKDIR}/libdvbsi++" +S = "${WORKDIR}/git" inherit autotools pkgconfig diff --git a/recipes/vuplus/vuplus-bootlogo.bb b/recipes/vuplus/vuplus-bootlogo.bb index ac1d055..4216219 100644 --- a/recipes/vuplus/vuplus-bootlogo.bb +++ b/recipes/vuplus/vuplus-bootlogo.bb @@ -48,25 +48,25 @@ do_install_vuultimo() { } 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-dvb-modules.bb b/recipes/vuplus/vuplus-dvb-modules.bb index cca7c34..ebb4648 100755 --- a/recipes/vuplus/vuplus-dvb-modules.bb +++ b/recipes/vuplus/vuplus-dvb-modules.bb @@ -5,6 +5,7 @@ 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}" @@ -12,15 +13,15 @@ SRCDATE_bm750 = "20111213" SRCDATE_vusolo = "20111213" SRCDATE_vuuno = "20111213" SRCDATE_vuultimo = "20111213" -SRCDATE_vuduo2 = "20111213" -SRCDATE_vusolo2 = "20120508" +SRCDATE_vuduo2 = "20120605" +SRCDATE_vusolo2 = "20120523" 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-bcm7413\nbrcmfb\nfpga_directc" -MODULES_NAME_vusolo2 = "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})" @@ -52,6 +53,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 |